import 'dart:ui'; import 'package:aves/model/filters/favourite.dart'; import 'package:aves/model/filters/mime.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/album.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/location.dart'; import 'package:aves/model/source/tag.dart'; import 'package:aves/services/services.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/theme/icons.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/widgets/about/about_page.dart'; import 'package:aves/widgets/common/extensions/build_context.dart'; import 'package:aves/widgets/common/extensions/media_query.dart'; import 'package:aves/widgets/common/identity/aves_logo.dart'; import 'package:aves/widgets/debug/app_debug_page.dart'; import 'package:aves/widgets/drawer/album_tile.dart'; import 'package:aves/widgets/drawer/collection_tile.dart'; import 'package:aves/widgets/drawer/tile.dart'; import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/filter_grids/countries_page.dart'; import 'package:aves/widgets/filter_grids/tags_page.dart'; import 'package:aves/widgets/settings/settings_page.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class AppDrawer extends StatefulWidget { const AppDrawer({Key? key}) : super(key: key); @override _AppDrawerState createState() => _AppDrawerState(); } class _AppDrawerState extends State { late Future _newVersionLoader; CollectionSource get source => context.read(); @override void initState() { super.initState(); _newVersionLoader = availability.isNewVersionAvailable; } @override Widget build(BuildContext context) { final hiddenFilters = settings.hiddenFilters; final showVideos = !hiddenFilters.contains(MimeFilter.video); final showFavourites = !hiddenFilters.contains(FavouriteFilter.instance); final drawerItems = [ _buildHeader(context), allCollectionTile, if (showVideos) videoTile, if (showFavourites) favouriteTile, _buildSpecialAlbumSection(), const Divider(), albumListTile, countryListTile, tagListTile, if (!kReleaseMode) ...[ const Divider(), debugTile, ], ]; return Drawer( child: ListTileTheme.merge( selectedColor: Theme.of(context).accentColor, child: Selector( selector: (c, mq) => mq.effectiveBottomPadding, builder: (c, mqPaddingBottom, child) { final iconTheme = IconTheme.of(context); return SingleChildScrollView( padding: EdgeInsets.only(bottom: mqPaddingBottom), child: IconTheme( data: iconTheme.copyWith( size: iconTheme.size! * MediaQuery.textScaleFactorOf(context), ), child: Column( children: drawerItems, ), ), ); }, ), ), ); } Widget _buildHeader(BuildContext context) { Future goTo(String routeName, WidgetBuilder pageBuilder) async { Navigator.pop(context); await Future.delayed(Durations.drawerTransitionAnimation); await Navigator.push( context, MaterialPageRoute( settings: RouteSettings(name: routeName), builder: pageBuilder, )); } return Container( padding: const EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 8), color: Theme.of(context).accentColor, child: SafeArea( bottom: false, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Align( alignment: AlignmentDirectional.centerStart, child: Wrap( spacing: 16, crossAxisAlignment: WrapCrossAlignment.center, children: [ const AvesLogo(size: 64), Text( context.l10n.appName, style: const TextStyle( fontSize: 44, fontWeight: FontWeight.w300, letterSpacing: 1.0, fontFeatures: [FontFeature.enable('smcp')], ), ), ], ), ), const SizedBox(height: 8), OutlinedButtonTheme( data: OutlinedButtonThemeData( style: ButtonStyle( foregroundColor: MaterialStateProperty.all(Colors.white), overlayColor: MaterialStateProperty.all(Colors.white24), ), ), child: Wrap( spacing: 8, runSpacing: 8, children: [ OutlinedButton.icon( key: const Key('drawer-about-button'), onPressed: () => goTo(AboutPage.routeName, (_) => const AboutPage()), icon: const Icon(AIcons.info), label: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(context.l10n.aboutPageTitle), FutureBuilder( future: _newVersionLoader, builder: (context, snapshot) { final newVersion = snapshot.data == true; final badgeSize = 8.0 * MediaQuery.textScaleFactorOf(context); return AnimatedOpacity( duration: Durations.newsBadgeAnimation, opacity: newVersion ? 1 : 0, child: Padding( padding: const EdgeInsetsDirectional.only(start: 2), child: DecoratedBox( decoration: BoxDecoration( border: const Border.fromBorderSide(BorderSide(color: Colors.white70)), borderRadius: BorderRadius.all(Radius.circular(badgeSize)), ), child: Icon( Icons.circle, size: badgeSize, color: Colors.red, ), ), ), ); }, ), ], ), ), OutlinedButton.icon( key: const Key('drawer-settings-button'), onPressed: () => goTo(SettingsPage.routeName, (_) => const SettingsPage()), icon: const Icon(AIcons.settings), label: Text(context.l10n.settingsPageTitle), ), ], ), ) ], ), ), ); } Widget _buildSpecialAlbumSection() { return StreamBuilder( stream: source.eventBus.on(), builder: (context, snapshot) { final specialAlbums = source.rawAlbums.where((album) { final type = androidFileUtils.getAlbumType(album); return [AlbumType.camera, AlbumType.screenshots].contains(type); }).toList() ..sort(source.compareAlbumsByName); if (specialAlbums.isEmpty) return const SizedBox.shrink(); return Column( children: [ const Divider(), ...specialAlbums.map((album) => AlbumTile(album: album)), ], ); }); } // tiles Widget get allCollectionTile => CollectionNavTile( leading: const Icon(AIcons.allCollection), title: context.l10n.drawerCollectionAll, filter: null, ); Widget get videoTile => CollectionNavTile( leading: const Icon(AIcons.video), title: context.l10n.drawerCollectionVideos, filter: MimeFilter.video, ); Widget get favouriteTile => CollectionNavTile( leading: const Icon(AIcons.favourite), title: context.l10n.drawerCollectionFavourites, filter: FavouriteFilter.instance, ); Widget get albumListTile => NavTile( icon: AIcons.album, title: context.l10n.albumPageTitle, trailing: StreamBuilder( stream: source.eventBus.on(), builder: (context, _) => Text('${source.rawAlbums.length}'), ), routeName: AlbumListPage.routeName, pageBuilder: (_) => const AlbumListPage(), ); Widget get countryListTile => NavTile( icon: AIcons.location, title: context.l10n.countryPageTitle, trailing: StreamBuilder( stream: source.eventBus.on(), builder: (context, _) => Text('${source.sortedCountries.length}'), ), routeName: CountryListPage.routeName, pageBuilder: (_) => const CountryListPage(), ); Widget get tagListTile => NavTile( icon: AIcons.tag, title: context.l10n.tagPageTitle, trailing: StreamBuilder( stream: source.eventBus.on(), builder: (context, _) => Text('${source.sortedTags.length}'), ), routeName: TagListPage.routeName, pageBuilder: (_) => const TagListPage(), ); Widget get debugTile => NavTile( icon: AIcons.debug, title: 'Debug', topLevel: false, routeName: AppDebugPage.routeName, pageBuilder: (_) => const AppDebugPage(), ); }