current route identification

This commit is contained in:
Thibault Deckers 2020-09-03 13:20:42 +09:00
parent 67f873b3f5
commit daedad57fa
27 changed files with 147 additions and 69 deletions

View file

@ -5,6 +5,8 @@ on:
branches: branches:
- develop - develop
# TODO TLAD run `flutter format -l 1000 .` and fail if any
jobs: jobs:
build: build:
name: Check code quality. name: Check code quality.

View file

@ -155,7 +155,7 @@ extension ExtraHomePageSetting on HomePageSetting {
String get name { String get name {
switch (this) { switch (this) {
case HomePageSetting.collection: case HomePageSetting.collection:
return 'All Media'; return 'Collection';
case HomePageSetting.albums: case HomePageSetting.albums:
return 'Albums'; return 'Albums';
default: default:

View file

@ -0,0 +1,5 @@
import 'package:flutter/widgets.dart';
extension ExtraContext on BuildContext {
String get currentRouteName => ModalRoute.of(this)?.settings?.name;
}

View file

@ -7,6 +7,8 @@ import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
class AboutPage extends StatelessWidget { class AboutPage extends StatelessWidget {
static const routeName = '/about';
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(

View file

@ -134,7 +134,10 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
Widget _buildAppBarTitle() { Widget _buildAppBarTitle() {
if (collection.isBrowsing) { if (collection.isBrowsing) {
Widget title = Text(AvesApp.mode == AppMode.pick ? 'Select' : 'Aves', key: Key('appbar-title')); Widget title = Text(
AvesApp.mode == AppMode.pick ? 'Select' : 'Collection',
key: Key('appbar-title'),
);
if (AvesApp.mode == AppMode.main) { if (AvesApp.mode == AppMode.main) {
title = SourceStateAwareAppBarTitle( title = SourceStateAwareAppBarTitle(
title: title, title: title,
@ -345,6 +348,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
return Navigator.push( return Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: StatsPage.routeName),
builder: (context) => StatsPage( builder: (context) => StatsPage(
collection: collection, collection: collection,
), ),

View file

@ -8,6 +8,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class CollectionPage extends StatelessWidget { class CollectionPage extends StatelessWidget {
static const routeName = '/collection';
final CollectionLens collection; final CollectionLens collection;
const CollectionPage(this.collection); const CollectionPage(this.collection);

View file

@ -5,7 +5,7 @@ import 'package:aves/services/viewer_service.dart';
import 'package:aves/widgets/album/grid/list_known_extent.dart'; import 'package:aves/widgets/album/grid/list_known_extent.dart';
import 'package:aves/widgets/album/grid/list_section_layout.dart'; import 'package:aves/widgets/album/grid/list_section_layout.dart';
import 'package:aves/widgets/album/thumbnail/decorated.dart'; import 'package:aves/widgets/album/thumbnail/decorated.dart';
import 'package:aves/widgets/common/transparent_material_page_route.dart'; import 'package:aves/widgets/common/routes.dart';
import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -85,6 +85,7 @@ class GridThumbnail extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
TransparentMaterialPageRoute( TransparentMaterialPageRoute(
settings: RouteSettings(name: MultiFullscreenPage.routeName),
pageBuilder: (c, a, sa) => MultiFullscreenPage( pageBuilder: (c, a, sa) => MultiFullscreenPage(
collection: collection, collection: collection,
initialEntry: entry, initialEntry: entry,

View file

@ -12,6 +12,7 @@ import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/location.dart'; import 'package:aves/model/source/location.dart';
import 'package:aves/model/source/tag.dart'; import 'package:aves/model/source/tag.dart';
import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/flutter_utils.dart';
import 'package:aves/widgets/about/about_page.dart'; import 'package:aves/widgets/about/about_page.dart';
import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/album/collection_page.dart';
import 'package:aves/widgets/common/aves_logo.dart'; import 'package:aves/widgets/common/aves_logo.dart';
@ -75,10 +76,10 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
final allMediaEntry = _FilteredCollectionNavTile( final allCollectionEntry = _FilteredCollectionNavTile(
source: source, source: source,
leading: Icon(AIcons.allMedia), leading: Icon(AIcons.allCollection),
title: 'All media', title: 'All collection',
filter: null, filter: null,
); );
final videoEntry = _FilteredCollectionNavTile( final videoEntry = _FilteredCollectionNavTile(
@ -99,7 +100,7 @@ class _AppDrawerState extends State<AppDrawer> {
child: ListTile( child: ListTile(
leading: Icon(AIcons.settings), leading: Icon(AIcons.settings),
title: Text('Preferences'), title: Text('Preferences'),
onTap: () => _goTo((_) => SettingsPage()), onTap: () => _goTo(SettingsPage.routeName, (_) => SettingsPage()),
), ),
); );
final aboutEntry = SafeArea( final aboutEntry = SafeArea(
@ -108,20 +109,20 @@ class _AppDrawerState extends State<AppDrawer> {
child: ListTile( child: ListTile(
leading: Icon(AIcons.info), leading: Icon(AIcons.info),
title: Text('About'), title: Text('About'),
onTap: () => _goTo((_) => AboutPage()), onTap: () => _goTo(AboutPage.routeName, (_) => AboutPage()),
), ),
); );
final drawerItems = <Widget>[ final drawerItems = <Widget>[
header, header,
allMediaEntry, allCollectionEntry,
videoEntry, videoEntry,
favouriteEntry, favouriteEntry,
_buildSpecialAlbumSection(), _buildSpecialAlbumSection(),
Divider(), Divider(),
_buildRegularAlbumSection(), _buildAlbumListEntry(),
_buildCountrySection(), _buildCountryListEntry(),
_buildTagSection(), _buildTagListEntry(),
Divider(), Divider(),
settingsEntry, settingsEntry,
aboutEntry, aboutEntry,
@ -133,7 +134,7 @@ class _AppDrawerState extends State<AppDrawer> {
child: ListTile( child: ListTile(
leading: Icon(AIcons.debug), leading: Icon(AIcons.debug),
title: Text('Debug'), title: Text('Debug'),
onTap: () => _goTo((_) => DebugPage(source: source)), onTap: () => _goTo(DebugPage.routeName, (_) => DebugPage(source: source)),
), ),
), ),
], ],
@ -184,7 +185,7 @@ class _AppDrawerState extends State<AppDrawer> {
builder: (context, snapshot) { builder: (context, snapshot) {
final specialAlbums = source.sortedAlbums.where((album) { final specialAlbums = source.sortedAlbums.where((album) {
final type = androidFileUtils.getAlbumType(album); final type = androidFileUtils.getAlbumType(album);
return type != AlbumType.regular && type != AlbumType.app; return [AlbumType.camera, AlbumType.screenshots].contains(type);
}); });
if (specialAlbums.isEmpty) return SizedBox.shrink(); if (specialAlbums.isEmpty) return SizedBox.shrink();
@ -197,7 +198,7 @@ class _AppDrawerState extends State<AppDrawer> {
}); });
} }
Widget _buildRegularAlbumSection() { Widget _buildAlbumListEntry() {
return SafeArea( return SafeArea(
top: false, top: false,
bottom: false, bottom: false,
@ -215,12 +216,12 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goTo((_) => AlbumListPage(source: source)), onTap: () => _goTo(AlbumListPage.routeName, (_) => AlbumListPage(source: source)),
), ),
); );
} }
Widget _buildCountrySection() { Widget _buildCountryListEntry() {
return SafeArea( return SafeArea(
top: false, top: false,
bottom: false, bottom: false,
@ -237,12 +238,12 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goTo((_) => CountryListPage(source: source)), onTap: () => _goTo(CountryListPage.routeName, (_) => CountryListPage(source: source)),
), ),
); );
} }
Widget _buildTagSection() { Widget _buildTagListEntry() {
return SafeArea( return SafeArea(
top: false, top: false,
bottom: false, bottom: false,
@ -259,14 +260,21 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goTo((_) => TagListPage(source: source)), onTap: () => _goTo(TagListPage.routeName, (_) => TagListPage(source: source)),
), ),
); );
} }
void _goTo(WidgetBuilder builder) { void _goTo(String routeName, WidgetBuilder builder) {
Navigator.pop(context); Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: builder)); if (routeName != context.currentRouteName) {
Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: builder,
));
}
} }
} }
@ -306,6 +314,7 @@ class _FilteredCollectionNavTile extends StatelessWidget {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(CollectionLens( builder: (context) => CollectionPage(CollectionLens(
source: source, source: source,
filters: [filter], filters: [filter],

View file

@ -174,6 +174,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: FullscreenDebugPage.routeName),
builder: (context) => FullscreenDebugPage(entry: entry), builder: (context) => FullscreenDebugPage(entry: entry),
), ),
); );

View file

@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:outline_material_icons/outline_material_icons.dart';
class AIcons { class AIcons {
static const IconData allMedia = OMIcons.collections; static const IconData allCollection = OMIcons.collections;
static const IconData image = OMIcons.photo; static const IconData image = OMIcons.photo;
static const IconData video = OMIcons.movie; static const IconData video = OMIcons.movie;
static const IconData vector = OMIcons.code; static const IconData vector = OMIcons.code;

View file

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class DirectMaterialPageRoute<T> extends PageRouteBuilder<T> {
DirectMaterialPageRoute({
RouteSettings settings,
@required WidgetBuilder builder,
}) : super(
settings: settings,
transitionDuration: Duration.zero,
pageBuilder: (c, a, sa) => builder(c),
);
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return child;
}
}
class TransparentMaterialPageRoute<T> extends PageRouteBuilder<T> {
TransparentMaterialPageRoute({
RouteSettings settings,
@required RoutePageBuilder pageBuilder,
}) : super(settings: settings, pageBuilder: pageBuilder);
@override
bool get opaque => false;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
final theme = Theme.of(context).pageTransitionsTheme;
return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child);
}
}

View file

@ -1,16 +0,0 @@
import 'package:flutter/material.dart';
class TransparentMaterialPageRoute<T> extends PageRouteBuilder<T> {
TransparentMaterialPageRoute({
@required RoutePageBuilder pageBuilder,
}) : super(pageBuilder: pageBuilder);
@override
bool get opaque => false;
@override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
final theme = Theme.of(context).pageTransitionsTheme;
return theme.buildTransitions<T>(this, context, animation, secondaryAnimation, child);
}
}

View file

@ -18,6 +18,8 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:outline_material_icons/outline_material_icons.dart';
class DebugPage extends StatefulWidget { class DebugPage extends StatefulWidget {
static const routeName = '/debug';
final CollectionSource source; final CollectionSource source;
const DebugPage({this.source}); const DebugPage({this.source});

View file

@ -17,6 +17,8 @@ import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AlbumListPage extends StatelessWidget { class AlbumListPage extends StatelessWidget {
static const routeName = '/albums';
final CollectionSource source; final CollectionSource source;
const AlbumListPage({@required this.source}); const AlbumListPage({@required this.source});

View file

@ -7,6 +7,8 @@ import 'package:aves/widgets/filter_grids/filter_grid_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class CountryListPage extends StatelessWidget { class CountryListPage extends StatelessWidget {
static const routeName = '/countries';
final CollectionSource source; final CollectionSource source;
const CountryListPage({@required this.source}); const CountryListPage({@required this.source});

View file

@ -56,6 +56,7 @@ class FilterNavigationPage extends StatelessWidget {
onPressed: (filter) => Navigator.pushAndRemoveUntil( onPressed: (filter) => Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(CollectionLens( builder: (context) => CollectionPage(CollectionLens(
source: source, source: source,
filters: [filter], filters: [filter],

View file

@ -7,6 +7,8 @@ import 'package:aves/widgets/filter_grids/filter_grid_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TagListPage extends StatelessWidget { class TagListPage extends StatelessWidget {
static const routeName = '/tags';
final CollectionSource source; final CollectionSource source;
const TagListPage({@required this.source}); const TagListPage({@required this.source});

View file

@ -10,6 +10,8 @@ import 'package:flutter/material.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class FullscreenDebugPage extends StatefulWidget { class FullscreenDebugPage extends StatefulWidget {
static const routeName = '/fullscreen/debug';
final ImageEntry entry; final ImageEntry entry;
const FullscreenDebugPage({@required this.entry}); const FullscreenDebugPage({@required this.entry});

View file

@ -275,6 +275,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)), builder: (context) => CollectionPage(collection.derive(filter)),
), ),
(route) => false, (route) => false,
@ -323,7 +324,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
} }
void _onLeave() { void _onLeave() {
if (!ModalRoute.of(context).canPop) { if (!Navigator.canPop(context)) {
// exit app when trying to pop a fullscreen page that is a viewer for a single entry // exit app when trying to pop a fullscreen page that is a viewer for a single entry
exit(0); exit(0);
} }

View file

@ -5,6 +5,8 @@ import 'package:aves/widgets/fullscreen/fullscreen_body.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MultiFullscreenPage extends AnimatedWidget { class MultiFullscreenPage extends AnimatedWidget {
static const routeName = '/fullscreen';
final CollectionLens collection; final CollectionLens collection;
final ImageEntry initialEntry; final ImageEntry initialEntry;
@ -30,6 +32,8 @@ class MultiFullscreenPage extends AnimatedWidget {
} }
class SingleFullscreenPage extends StatelessWidget { class SingleFullscreenPage extends StatelessWidget {
static const routeName = '/fullscreen';
final ImageEntry entry; final ImageEntry entry;
const SingleFullscreenPage({ const SingleFullscreenPage({

View file

@ -126,7 +126,7 @@ class _TopOverlayRow extends StatelessWidget {
children: [ children: [
OverlayButton( OverlayButton(
scale: scale, scale: scale,
child: ModalRoute.of(context)?.canPop ?? true ? BackButton() : CloseButton(), child: Navigator.canPop(context) ? BackButton() : CloseButton(),
), ),
Spacer(), Spacer(),
...quickActions.map(_buildOverlayButton), ...quickActions.map(_buildOverlayButton),

View file

@ -7,7 +7,7 @@ import 'package:aves/services/viewer_service.dart';
import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/album/collection_page.dart';
import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart'; import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart';
import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/routes.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/filter_grids/albums_page.dart';
import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -17,6 +17,8 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:screen/screen.dart'; import 'package:screen/screen.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
static const routeName = '/';
const HomePage(); const HomePage();
@override @override
@ -26,16 +28,18 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> { class _HomePageState extends State<HomePage> {
MediaStoreSource _mediaStore; MediaStoreSource _mediaStore;
ImageEntry _viewerEntry; ImageEntry _viewerEntry;
Future<void> _appSetup;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_appSetup = _setup(); _setup();
imageCache.maximumSizeBytes = 512 * (1 << 20); imageCache.maximumSizeBytes = 512 * (1 << 20);
Screen.keepOn(true); Screen.keepOn(true);
} }
@override
Widget build(BuildContext context) => Scaffold();
Future<void> _setup() async { Future<void> _setup() async {
final permissions = await [ final permissions = await [
Permission.storage, Permission.storage,
@ -80,6 +84,8 @@ class _HomePageState extends State<HomePage> {
await _mediaStore.init(); await _mediaStore.init();
unawaited(_mediaStore.refresh()); unawaited(_mediaStore.refresh());
} }
unawaited(Navigator.pushReplacement(context, _getRedirectRoute()));
} }
Future<ImageEntry> _initViewerEntry({@required String uri, @required String mimeType}) async { Future<ImageEntry> _initViewerEntry({@required String uri, @required String mimeType}) async {
@ -92,30 +98,36 @@ class _HomePageState extends State<HomePage> {
return entry; return entry;
} }
@override Route _getRedirectRoute() {
Widget build(BuildContext context) { switch (AvesApp.mode) {
return FutureBuilder<void>( case AppMode.view:
future: _appSetup, return DirectMaterialPageRoute(
builder: (context, snapshot) { settings: RouteSettings(name: SingleFullscreenPage.routeName),
if (snapshot.hasError) return Icon(AIcons.error); builder: (_) => SingleFullscreenPage(entry: _viewerEntry),
if (snapshot.connectionState != ConnectionState.done) return Scaffold(); );
if (AvesApp.mode == AppMode.view) { case AppMode.main:
return SingleFullscreenPage(entry: _viewerEntry); case AppMode.pick:
if (_mediaStore != null) {
switch (settings.homePage) {
case HomePageSetting.albums:
return DirectMaterialPageRoute(
settings: RouteSettings(name: AlbumListPage.routeName),
builder: (_) => AlbumListPage(source: _mediaStore),
);
case HomePageSetting.collection:
return DirectMaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (_) => CollectionPage(
CollectionLens(
source: _mediaStore,
groupFactor: settings.collectionGroupFactor,
sortFactor: settings.collectionSortFactor,
),
),
);
} }
if (_mediaStore != null) { }
switch (settings.homePage) { }
case HomePageSetting.albums: return null;
return AlbumListPage(source: _mediaStore);
break;
case HomePageSetting.collection:
return CollectionPage(CollectionLens(
source: _mediaStore,
groupFactor: settings.collectionGroupFactor,
sortFactor: settings.collectionSortFactor,
));
}
}
return SizedBox.shrink();
});
} }
} }

View file

@ -7,6 +7,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class SettingsPage extends StatelessWidget { class SettingsPage extends StatelessWidget {
static const routeName = '/settings';
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MediaQueryDataProvider( return MediaQueryDataProvider(

View file

@ -90,6 +90,7 @@ class FilterTable extends StatelessWidget {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)), builder: (context) => CollectionPage(collection.derive(filter)),
), ),
(route) => false, (route) => false,

View file

@ -20,6 +20,8 @@ import 'package:intl/intl.dart';
import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:percent_indicator/linear_percent_indicator.dart';
class StatsPage extends StatelessWidget { class StatsPage extends StatelessWidget {
static const routeName = '/collection/stats';
final CollectionLens collection; final CollectionLens collection;
final Map<String, int> entryCountPerCountry = {}, entryCountPerPlace = {}, entryCountPerTag = {}; final Map<String, int> entryCountPerCountry = {}, entryCountPerPlace = {}, entryCountPerTag = {};
@ -236,6 +238,7 @@ class StatsPage extends StatelessWidget {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)), builder: (context) => CollectionPage(collection.derive(filter)),
), ),
(route) => false, (route) => false,

View file

@ -107,6 +107,7 @@ class _WelcomePageState extends State<WelcomePage> {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(
settings: RouteSettings(name: HomePage.routeName),
builder: (context) => HomePage(), builder: (context) => HomePage(),
), ),
(route) => false, (route) => false,

View file

@ -56,7 +56,7 @@ void agreeToTerms() {
await driver.tap(find.byValueKey('continue-button')); await driver.tap(find.byValueKey('continue-button'));
await driver.waitUntilNoTransientCallbacks(); await driver.waitUntilNoTransientCallbacks();
expect(await driver.getText(find.byValueKey('appbar-title')), 'Aves'); expect(await driver.getText(find.byValueKey('appbar-title')), 'Collection');
}); });
} }