// 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.

// Flutter code sample for [Overlay].

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: OverlayExample(),
    );
  }
}

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

  @override
  State<OverlayExample> createState() => _OverlayExampleState();
}

class _OverlayExampleState extends State<OverlayExample> {
  OverlayEntry? overlayEntry;
  int currentPageIndex = 0;

  void createHighlightOverlay({
    required AlignmentDirectional alignment,
    required Color borderColor,
  }) {
    // Remove the existing OverlayEntry.
    removeHighlightOverlay();

    assert(overlayEntry == null);

    overlayEntry = OverlayEntry(
      // Create a new OverlayEntry.
      builder: (BuildContext context) {
        // Align is used to position the highlight overlay
        // relative to the NavigationBar destination.
        return SafeArea(
          child: Align(
            alignment: alignment,
            heightFactor: 1.0,
            child: DefaultTextStyle(
              style: const TextStyle(
                color: Colors.blue,
                fontWeight: FontWeight.bold,
                fontSize: 14.0,
              ),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  const Text('Tap here for'),
                  Builder(builder: (BuildContext context) {
                    switch (currentPageIndex) {
                      case 0:
                        return const Column(
                          children: <Widget>[
                            Text(
                              'Explore page',
                                style: TextStyle(
                                  color: Colors.red,
                                ),
                              ),
                            Icon(
                              Icons.arrow_downward,
                              color: Colors.red
                            ),
                          ],
                        );
                      case 1:
                        return const Column(
                          children: <Widget>[
                            Text(
                              'Commute page',
                                style: TextStyle(
                                  color: Colors.green,
                                ),
                              ),
                            Icon(
                              Icons.arrow_downward,
                              color: Colors.green
                            ),
                          ],
                        );
                      case 2:
                        return const Column(
                          children: <Widget>[
                            Text(
                              'Saved page',
                                style: TextStyle(
                                  color: Colors.orange,
                                ),
                              ),
                            Icon(
                              Icons.arrow_downward,
                              color: Colors.orange
                            ),
                          ],
                        );
                      default:
                        return const Text('No page selected.');
                    }
                  }),
                  SizedBox(
                    width: MediaQuery.of(context).size.width / 3,
                    height: 80.0,
                    child: Center(
                      child: Container(
                        decoration: BoxDecoration(
                          border: Border.all(
                            color: borderColor,
                            width: 4.0,
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );

    // Add the OverlayEntry to the Overlay.
    Overlay.of(context, debugRequiredFor: widget).insert(overlayEntry!);
  }

  // Remove the OverlayEntry.
  void removeHighlightOverlay() {
    overlayEntry?.remove();
    overlayEntry = null;
  }

  @override
  void dispose() {
    // Make sure to remove OverlayEntry when the widget is disposed.
    removeHighlightOverlay();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Overlay Sample'),
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: currentPageIndex,
        destinations: const <NavigationDestination>[
          NavigationDestination(
            icon: Icon(Icons.explore),
            label: 'Explore',
          ),
          NavigationDestination(
            icon: Icon(Icons.commute),
            label: 'Commute',
          ),
          NavigationDestination(
            selectedIcon: Icon(Icons.bookmark),
            icon: Icon(Icons.bookmark_border),
            label: 'Saved',
          ),
        ],
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'Use Overlay to highlight a NavigationBar destination',
            style: Theme.of(context).textTheme.bodyMedium,
          ),
          const SizedBox(height: 20.0),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              // This creates a highlight Overlay for
              // the Explore item.
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    currentPageIndex = 0;
                  });
                  createHighlightOverlay(
                    alignment: AlignmentDirectional.bottomStart,
                    borderColor: Colors.red,
                  );
                },
                child: const Text('Explore'),
              ),
              const SizedBox(width: 20.0),
              // This creates a highlight Overlay for
              // the Commute item.
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    currentPageIndex = 1;
                  });
                  createHighlightOverlay(
                    alignment: AlignmentDirectional.bottomCenter,
                    borderColor: Colors.green,
                  );
                },
                child: const Text('Commute'),
              ),
              const SizedBox(width: 20.0),
              // This creates a highlight Overlay for
              // the Saved item.
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    currentPageIndex = 2;
                  });
                  createHighlightOverlay(
                    alignment: AlignmentDirectional.bottomEnd,
                    borderColor: Colors.orange,
                  );
                },
                child: const Text('Saved'),
              ),
            ],
          ),
          const SizedBox(height: 10.0),
          ElevatedButton(
            onPressed: () {
              removeHighlightOverlay();
            },
            child: const Text('Remove Overlay'),
          ),
        ],
      ),
    );
  }
}
