content: import 'dart:math';
  
  import 'package:flutter/material.dart';
  
  import '../../../../shared/const/app.dart';
  import '../../../../shared/const/app_images.dart';
  import '../../../../shared/controllers/theme_controller.dart';
  import '../../../../shared/utils/app_scroll_behavior.dart';
  import '../../../../shared/utils/breakpoint.dart';
  import '../../../../shared/utils/link_text_span.dart';
  import '../../../../shared/utils/random_color.dart';
  import '../../../../shared/widgets/universal/svg_asset_image.dart';
  import '../../../../shared/widgets/universal/svg_asset_image_switcher.dart';
  import '../../shared/theme_mode_switch_list_tile.dart';
  
  /// An example that show what an app using the theme might look like
  class AppExampleUndraw extends StatefulWidget {
    const AppExampleUndraw({super.key, required this.controller});
  
    final ThemeController controller;
  
    @override
    State<AppExampleUndraw> createState() => _AppExampleUndrawState();
  }
  
  class _AppExampleUndrawState extends State<AppExampleUndraw> {
    static const int _maxTiles = 500;
    late List<MaterialColor> imageColors;
  
    @override
    void initState() {
      super.initState();
      // Generate a random image color data list that we will build widgets from.
      // We generate this data list in the stateful widget's init class because
      // we want its colors to remain static as long as the page is not rebuilt.
      // So we will get a new random colored image list, but only every time
      // we rebuild the screen, not as we scroll it back and forth or rescale it,
      // that could be done too, but it feels a bit too random.
      imageColors = List<MaterialColor>.generate(
          _maxTiles, (int index) => RandomColor().randomMaterialColor());
    }
  
    @override
    Widget build(BuildContext context) {
      final EdgeInsets safeArea = MediaQuery.viewPaddingOf(context);
  
      return ScrollConfiguration(
        behavior: const DragScrollBehavior(),
        child: Scaffold(
          extendBodyBehindAppBar: true,
          extendBody: true,
          appBar: AppBar(
            title: const Text('Undraw'),
            actions: const <Widget>[UndrawAbout(useRootNavigator: false)],
          ),
          drawer: AppExampleDrawer(controller: widget.controller),
          bottomNavigationBar: const AppExampleNavigationBar(),
          body: SafeArea(
            top: false,
            bottom: false,
            child: BreakpointBuilder(
              type: BreakType.large,
              builder: (BuildContext context, Breakpoint breakpoint) {
                return CustomScrollView(
                  primary: false,
                  slivers: <Widget>[
                    SliverPadding(
                      padding: EdgeInsetsDirectional.only(
                        top: 16 + safeArea.top + kToolbarHeight,
                        start: 16,
                        end: 16,
                      ),
                      sliver: SliverList(
                        delegate: SliverChildListDelegate(
                          <Widget>[
                            const PageHeader(
                              icon: Icon(Icons.local_florist_outlined),
                              heading: Text('Undraw Images'),
                            ),
                            const Divider(),
                            const PageIntro(
                              introTop: Text(
                                'This demo shows Undraw SVG images '
                                'in a grid and then randomly '
                                'animates in a new one.\n'
                                '\n'
                                'Each image has its own random wait before it '
                                'switches and also a random switch animation '
                                'time. Each time the screen is built, every '
                                'image box gets a new random colored border, '
                                'with good contrast in light theme mode and a '
                                'less saturated version of same color in dark '
                                'mode.\n',
                              ),
                              introBottom: Text(
                                'Each image is colored dynamically to match '
                                'the color of its border. This is done by '
                                'changing a color text string in the image SVG '
                                'file. This demo is mostly a stress test for '
                                'Flutter, especially for Web builds. '
                                'We could make the grid of switching images '
                                'infinite, but this demo stops at $_maxTiles '
                                'images in the grid.\n',
                              ),
                              imageAssets: AppImages.undraw,
                            ),
                          ],
                        ),
                      ),
                    ),
                    SliverPadding(
                      padding: EdgeInsetsDirectional.only(
                          start: 16, end: 16, bottom: 90 + safeArea.bottom),
                      sliver: SliverGrid(
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                          crossAxisCount: breakpoint.columns ~/ 2,
                          mainAxisSpacing: breakpoint.gutters / 2,
                          crossAxisSpacing: breakpoint.gutters / 2,
                          childAspectRatio: 1.4,
                        ),
                        delegate: SliverChildBuilderDelegate(
                          (BuildContext ctx, int index) {
                            return RandomImageWidget(
                              imageColor: imageColors[index],
                              borderWidth: breakpoint.columns.toDouble() / 2 + 4,
                            );
                          },
                          childCount: imageColors.length,
                        ),
                      ),
                    )
                  ],
                );
              },
              // ),
            ),
          ),
        ),
      );
    }
  }
  
  // Show a random image from the list of all the SVG images we have in our
  // constant AppImages.allImages list.
  // Not only will we randomly show an image from the list, the display time
  // until we shift in a new image is randomized a bit as is the switch
  // animation transition time.
  // After a theme change the next shown random image will be themed in the color
  // hue that is more suitable for the theme mode.
  class RandomImageWidget extends StatelessWidget {
    const RandomImageWidget({
      super.key,
      required this.imageColor,
      this.borderRadius,
      this.borderWidth = 10.0,
    });
  
    final MaterialColor imageColor;
    // Defaults to theme radius of Card if not defined.
    final double? borderRadius;
    final double borderWidth;
  
    @override
    Widget build(BuildContext context) {
      final ThemeData theme = Theme.of(context);
      final bool useMaterial3 = theme.useMaterial3;
      final bool isLight = theme.brightness == Brightness.light;
      final Random random = Random();
  
      // Default starting point value based on M3 and M2 mode spec values
      double radius = useMaterial3 ? 12 : 4;
      if (borderRadius == null) {
        // Is themed? Get the radius from the theme and used it, if it was.
        final ShapeBorder? cardShape = theme.cardTheme.shape;
        if (cardShape != null && cardShape is RoundedRectangleBorder) {
          final BorderRadius shape = cardShape.borderRadius as BorderRadius;
          radius = shape.bottomLeft.x;
        }
      } else {
        // If a passed value was used we use that
        radius = borderRadius!;
      }
      return Card(
        color: theme.colorScheme.onInverseSurface,
        shadowColor: Colors.transparent,
        elevation: 0,
        clipBehavior: Clip.antiAlias,
        shape: RoundedRectangleBorder(
          side: BorderSide(
              color: isLight ? imageColor[700]! : imageColor[200]!,
              width: borderWidth),
          borderRadius: BorderRadius.all(Radius.circular(radius)),
        ),
        child: SvgAssetImageSwitcher(
          assetNames: AppImages.allImages,
          color: isLight ? imageColor[700]! : imageColor[400]!,
          padding: EdgeInsets.all(borderWidth * 4),
          fit: BoxFit.contain,
          switchType: ImageSwitchType.random,
          showDuration: Duration(milliseconds: 2000 + random.nextInt(2000)),
          switchDuration: Duration(milliseconds: 200 + random.nextInt(250)),
        ),
      );
    }
  }
  
  class AppExampleDrawer extends StatefulWidget {
    const AppExampleDrawer({super.key, required this.controller});
  
    final ThemeController controller;
  
    @override
    State<AppExampleDrawer> createState() => _AppExampleDrawerState();
  }
  
  class _AppExampleDrawerState extends State<AppExampleDrawer> {
    int selectedIndex = 0;
  
    @override
    Widget build(BuildContext context) {
      final ThemeData theme = Theme.of(context);
      final TextTheme textTheme = theme.textTheme;
      return GestureDetector(
        onTap: () {
          Navigator.pop(context);
        },
        child: NavigationDrawer(
          selectedIndex: selectedIndex,
          onDestinationSelected: (int value) {
            setState(() {
              selectedIndex = value;
            });
          },
          children: <Widget>[
            CircleAvatar(
              radius: 60,
              backgroundColor: theme.colorScheme.secondaryContainer,
              child: SvgAssetImage(
                assetName: AppImages.nature,
                color: theme.colorScheme.secondary,
              ),
            ),
            Center(
              child: Text(
                'Undraw',
                style: textTheme.headlineMedium,
              ),
            ),
            const SizedBox(height: 16),
            ThemeModeSwitchListTile(controller: widget.controller),
            const Divider(),
            const NavigationDrawerDestination(
              icon: Icon(Icons.image),
              label: Text('Images'),
            ),
            const NavigationDrawerDestination(
              icon: Icon(Icons.beenhere),
              label: Text('Notifications'),
            ),
            const NavigationDrawerDestination(
              icon: Badge(
                label: Text('12'),
                child: Icon(Icons.chat_bubble),
              ),
              label: Text('Chat'),
            ),
            const Divider(),
            const NavigationDrawerDestination(
              icon: Icon(Icons.logout),
              label: Text('Logout'),
            ),
          ],
        ),
      );
    }
  }
  
  class AppExampleNavigationBar extends StatefulWidget {
    const AppExampleNavigationBar({super.key});
  
    @override
    State<AppExampleNavigationBar> createState() =>
        _AppExampleNavigationBarState();
  }
  
  class _AppExampleNavigationBarState extends State<AppExampleNavigationBar> {
    int buttonIndex = 0;
  
    @override
    Widget build(BuildContext context) {
      return NavigationBar(
        selectedIndex: buttonIndex,
        onDestinationSelected: (int value) {
          setState(() {
            buttonIndex = value;
          });
        },
        destinations: const <NavigationDestination>[
          NavigationDestination(
            icon: Icon(Icons.image),
            label: 'Images',
          ),
          NavigationDestination(
            icon: Icon(Icons.beenhere),
            label: 'Notifications',
          ),
          NavigationDestination(
            icon: Badge(
              label: Text('12'),
              child: Icon(Icons.chat_bubble),
            ),
            label: 'Chat',
          ),
        ],
      );
    }
  }
  
  // A page header widget that is used in this demo to show the value of the
  // selected destination returned by Flexfold onDestination. Used only for
  // demo purposes in the example application.
  class PageHeader extends StatelessWidget {
    const PageHeader({
      super.key,
      required this.icon,
      required this.heading,
    });
  
    final Widget icon;
    final Widget heading;
  
    @override
    Widget build(BuildContext context) {
      final ThemeData theme = Theme.of(context);
      return Row(
        children: <Widget>[
          Padding(
            padding: const EdgeInsetsDirectional.only(end: 8),
            child: IconTheme(
              data: IconThemeData(
                size: 35,
                color: theme.colorScheme.primary,
              ),
              child: icon,
            ),
          ),
          Padding(
            padding: const EdgeInsetsDirectional.only(end: 8),
            child: DefaultTextStyle(
              style: theme.textTheme.headlineMedium!,
              child: heading,
            ),
          ),
        ],
      );
    }
  }
  
  // A page intro class that uses a responsive layout to change the layout
  // of the intro text and page related image(s) on a large canvas and phone
  // sized layouts.
  class PageIntro extends StatelessWidget {
    const PageIntro({
      super.key,
      this.introTop,
      this.introBottom,
      required this.imageAssets,
    });
    final Widget? introTop;
    final Widget? introBottom;
    final List<String> imageAssets;
  
    @override
    Widget build(BuildContext context) {
      final ThemeData theme = Theme.of(context);
      final Widget styledIntroTop = DefaultTextStyle(
        style: theme.textTheme.bodyLarge!,
        child: introTop ?? const Text(''),
      );
      final Widget styledIntroBottom = DefaultTextStyle(
        style: theme.textTheme.bodyLarge!,
        child: introBottom ?? const Text(''),
      );
  
      return Padding(
        padding: const EdgeInsets.only(top: 8),
        child: LayoutBuilder(
          builder: (BuildContext context, BoxConstraints size) {
            if (size.maxWidth < 600) {
              // PHONE: Small canvas, layout out all in one column
              return Column(
                children: <Widget>[
                  if (introTop != null) styledIntroTop,
                  _imageSwitcher(context),
                  if (introBottom != null) styledIntroBottom,
                ],
              );
            } else {
              // TABLET/DESKTOP: Larger canvas uses a column with a row in it
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      if (introTop != null)
                        Flexible(
                          flex: 3,
                          child: styledIntroTop,
                        ),
                      Flexible(flex: 2, child: _imageSwitcher(context)),
                    ],
                  ),
                  if (introBottom != null) styledIntroBottom,
                ],
              );
            }
          },
        ),
      );
    }
  
    Widget _imageSwitcher(BuildContext context) {
      return SvgAssetImageSwitcher(
        assetNames: imageAssets,
        color: Theme.of(context).colorScheme.primary,
        alignment: Alignment.center,
        height: 250,
        width: 250,
        padding: const EdgeInsets.all(20),
        fit: BoxFit.contain,
        switchType: ImageSwitchType.random,
      );
    }
  }
  
  /// An about icon button used on the example's app app bar.
  class UndrawAbout extends StatelessWidget {
    const UndrawAbout({super.key, this.color, this.useRootNavigator = true});
  
    /// The color used on the icon button.
    ///
    /// If null, default to Icon() class default color.
    final Color? color;
  
    /// Use root navigator?
    final bool useRootNavigator;
  
    @override
    Widget build(BuildContext context) {
      return IconButton(
        icon: Icon(Icons.info, color: color),
        onPressed: () {
          showUndrawAboutDialog(context, useRootNavigator);
        },
      );
    }
  }
  
  /// This [showUndrawAboutDialog] function is based on the [AboutDialog] example
  /// that exist(ed) in the Flutter Gallery App.
  void showUndrawAboutDialog(BuildContext context,
      [bool useRootNavigator = true]) {
    final ThemeData theme = Theme.of(context);
    final TextStyle aboutTextStyle = theme.textTheme.bodyLarge!;
    final TextStyle footerStyle = theme.textTheme.bodySmall!;
    final TextStyle linkStyle =
        theme.textTheme.bodyLarge!.copyWith(color: theme.colorScheme.primary);
  
    final Size mediaSize = MediaQuery.sizeOf(context);
    final double width = mediaSize.width;
    final double height = mediaSize.height;
  
    final Uri sourceLink = Uri(
      scheme: 'https',
      host: 'undraw.co',
      path: 'illustrations',
    );
  
    showAboutDialog(
      context: context,
      applicationName: 'Undraw images',
      applicationVersion: '1.0',
      useRootNavigator: useRootNavigator,
      applicationIcon: Icon(
        Icons.local_florist_outlined,
        size: 50,
        color: theme.colorScheme.primary,
      ),
      applicationLegalese: '© 2023 Images by Katerina Limpitsouni',
      children: <Widget>[
        Padding(
          padding: const EdgeInsets.only(top: 24),
          child: RichText(
            text: TextSpan(
              children: <TextSpan>[
                TextSpan(
                  style: aboutTextStyle,
                  text: 'Shows how to use Undraw images '
                      'and color them dynamically in a Flutter app. '
                      'Also demonstrates the NavigationBar and '
                      'NavigationDrawer in an app.\n'
                      '\n'
                      'To learn more about the wonderful Undraw '
                      'images, please visit ',
                ),
                LinkTextSpan(
                  style: linkStyle,
                  uri: sourceLink,
                  text: 'undraw.co',
                ),
                TextSpan(
                  style: aboutTextStyle,
                  text: '.\n\n',
                ),
                TextSpan(
                  style: footerStyle,
                  text: 'Built with Flutter ${App.flutterVersion}, '
                      'using ${App.packageName} '
                      '${App.version}\n'
                      'Media size (w:${width.toStringAsFixed(0)}, '
                      'h:${height.toStringAsFixed(0)})\n\n',
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
  