// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

/// Flutter code sample for [ScrollNotificationObserver].

void main() => runApp(const ScrollNotificationObserverApp());

class ScrollNotificationObserverApp extends StatelessWidget {
  const ScrollNotificationObserverApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // The Scaffold widget contains a [ScrollNotificationObserver].
      // This is used by [AppBar] for its scrolled under behavior.
      //
      // We can use [ScrollNotificationObserver.maybeOf] to get the
      // state of this [ScrollNotificationObserver] from descendants
      // of the Scaffold widget.
      //
      // If you're not using a [Scaffold] widget, you can create a  [ScrollNotificationObserver]
      // to notify its descendants of scroll notifications by adding it to the subtree.
      home: Scaffold(
        appBar: AppBar(title: const Text('ScrollNotificationObserver Sample')),
        body: const ScrollNotificationObserverExample(),
      ),
    );
  }
}

class ScrollNotificationObserverExample extends StatefulWidget {
  const ScrollNotificationObserverExample({super.key});

  @override
  State<ScrollNotificationObserverExample> createState() =>
      _ScrollNotificationObserverExampleState();
}

class _ScrollNotificationObserverExampleState extends State<ScrollNotificationObserverExample> {
  ScrollNotificationObserverState? _scrollNotificationObserver;
  ScrollController controller = ScrollController();
  bool _scrolledDown = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // Remove any previous listener.
    _scrollNotificationObserver?.removeListener(_handleScrollNotification);
    // Get the ScrollNotificationObserverState from the Scaffold widget.
    _scrollNotificationObserver = ScrollNotificationObserver.maybeOf(context);
    // Add a new listener.
    _scrollNotificationObserver?.addListener(_handleScrollNotification);
  }

  @override
  void dispose() {
    if (_scrollNotificationObserver != null) {
      _scrollNotificationObserver!.removeListener(_handleScrollNotification);
      _scrollNotificationObserver = null;
    }
    controller.dispose();
    super.dispose();
  }

  void _handleScrollNotification(ScrollNotification notification) {
    // Check if the notification is a scroll update notification and if the
    // `notification.depth` is 0. This way we only listen to the scroll
    // notifications from the closest scrollable, instead of those that may be nested.
    if (notification is ScrollUpdateNotification &&
        defaultScrollNotificationPredicate(notification)) {
      final ScrollMetrics metrics = notification.metrics;
      // Check if the user scrolled down.
      if (_scrolledDown != metrics.extentBefore > 0) {
        setState(() {
          _scrolledDown = metrics.extentBefore > 0;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        SampleList(controller: controller),
        // Show the button only if the user scrolled down.
        if (_scrolledDown)
          Positioned(
            right: 25,
            bottom: 20,
            child: Center(
              child: GestureDetector(
                onTap: () {
                  // Scroll to the top when the user taps the button.
                  controller.animateTo(
                    0,
                    duration: const Duration(milliseconds: 200),
                    curve: Curves.fastOutSlowIn,
                  );
                },
                child: const Card(
                  child: Padding(
                    padding: EdgeInsets.all(8.0),
                    child: Column(
                      children: <Widget>[Icon(Icons.arrow_upward_rounded), Text('Scroll to top')],
                    ),
                  ),
                ),
              ),
            ),
          ),
      ],
    );
  }
}

class SampleList extends StatelessWidget {
  const SampleList({super.key, required this.controller});

  final ScrollController controller;

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: controller,
      itemCount: 30,
      itemBuilder: (BuildContext context, int index) {
        return ListTile(title: Text('Item $index'));
      },
    );
  }
}
