settings: added option to show album list on launch

This commit is contained in:
Thibault Deckers 2020-08-17 09:45:22 +09:00
parent 1d77ec9e5e
commit 6bc416b6b6
5 changed files with 177 additions and 117 deletions

View file

@ -16,13 +16,14 @@ class Settings {
Settings._private(); Settings._private();
// preferences // preferences
static const catalogTimeZoneKey = 'catalog_time_zone';
static const collectionGroupFactorKey = 'collection_group_factor'; static const collectionGroupFactorKey = 'collection_group_factor';
static const collectionSortFactorKey = 'collection_sort_factor'; static const collectionSortFactorKey = 'collection_sort_factor';
static const collectionTileExtentKey = 'collection_tile_extent'; static const collectionTileExtentKey = 'collection_tile_extent';
static const hasAcceptedTermsKey = 'has_accepted_terms';
static const infoMapStyleKey = 'info_map_style'; static const infoMapStyleKey = 'info_map_style';
static const infoMapZoomKey = 'info_map_zoom'; static const infoMapZoomKey = 'info_map_zoom';
static const catalogTimeZoneKey = 'catalog_time_zone'; static const launchPageKey = 'launch_page';
static const hasAcceptedTermsKey = 'has_accepted_terms';
Future<void> init() async { Future<void> init() async {
_prefs = await SharedPreferences.getInstance(); _prefs = await SharedPreferences.getInstance();
@ -52,14 +53,6 @@ class Settings {
} }
} }
EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values);
set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString());
double get infoMapZoom => _prefs.getDouble(infoMapZoomKey) ?? 12;
set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue);
String get catalogTimeZone => _prefs.getString(catalogTimeZoneKey) ?? ''; String get catalogTimeZone => _prefs.getString(catalogTimeZoneKey) ?? '';
set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue); set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue);
@ -76,10 +69,22 @@ class Settings {
set collectionTileExtent(double newValue) => setAndNotify(collectionTileExtentKey, newValue); set collectionTileExtent(double newValue) => setAndNotify(collectionTileExtentKey, newValue);
EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values);
set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString());
double get infoMapZoom => _prefs.getDouble(infoMapZoomKey) ?? 12;
set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue);
bool get hasAcceptedTerms => getBoolOrDefault(hasAcceptedTermsKey, false); bool get hasAcceptedTerms => getBoolOrDefault(hasAcceptedTermsKey, false);
set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue); set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue);
LaunchPage get launchPage => getEnumOrDefault(launchPageKey, LaunchPage.collection, LaunchPage.values);
set launchPage(LaunchPage newValue) => setAndNotify(launchPageKey, newValue.toString());
// convenience methods // convenience methods
// ignore: avoid_positional_boolean_parameters // ignore: avoid_positional_boolean_parameters
@ -124,3 +129,18 @@ class Settings {
} }
} }
} }
enum LaunchPage { collection, albums }
extension ExtraLaunchPage on LaunchPage {
String get name {
switch (this) {
case LaunchPage.collection:
return 'All Media';
case LaunchPage.albums:
return 'Albums';
default:
return toString();
}
}
}

View file

@ -3,9 +3,7 @@ import 'dart:ui';
import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/album.dart';
import 'package:aves/model/filters/favourite.dart'; import 'package:aves/model/filters/favourite.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/filters/location.dart';
import 'package:aves/model/filters/mime.dart'; import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/filters/tag.dart';
import 'package:aves/model/mime_types.dart'; import 'package:aves/model/mime_types.dart';
import 'package:aves/model/settings.dart'; import 'package:aves/model/settings.dart';
import 'package:aves/model/source/album.dart'; import 'package:aves/model/source/album.dart';
@ -16,7 +14,6 @@ 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/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/album/empty.dart';
import 'package:aves/widgets/common/aves_logo.dart'; import 'package:aves/widgets/common/aves_logo.dart';
import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/icons.dart';
import 'package:aves/widgets/debug_page.dart'; import 'package:aves/widgets/debug_page.dart';
@ -100,7 +97,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: () => _goToSettings(context), onTap: () => _goTo((_) => SettingsPage()),
), ),
); );
final aboutEntry = SafeArea( final aboutEntry = SafeArea(
@ -109,7 +106,7 @@ class _AppDrawerState extends State<AppDrawer> {
child: ListTile( child: ListTile(
leading: Icon(AIcons.info), leading: Icon(AIcons.info),
title: Text('About'), title: Text('About'),
onTap: () => _goToAbout(context), onTap: () => _goTo((_) => AboutPage()),
), ),
); );
@ -134,7 +131,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: () => _goToDebug(context), onTap: () => _goTo((_) => DebugPage(source: source)),
), ),
), ),
], ],
@ -215,7 +212,7 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goToAlbums(context), onTap: () => _goTo((_) => AlbumListPage(source: source)),
), ),
); );
} }
@ -237,7 +234,7 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goToCountries(context), onTap: () => _goTo((_) => CountryListPage(source: source)),
), ),
); );
} }
@ -259,98 +256,14 @@ class _AppDrawerState extends State<AppDrawer> {
), ),
); );
}), }),
onTap: () => _goToTags(context), onTap: () => _goTo((_) => TagListPage(source: source)),
), ),
); );
} }
void _goToAlbums(BuildContext context) { void _goTo(WidgetBuilder builder) {
Navigator.pop(context); Navigator.pop(context);
Navigator.push( Navigator.push(context, MaterialPageRoute(builder: builder));
context,
MaterialPageRoute(
builder: (context) => FilterNavigationPage(
source: source,
title: 'Albums',
filterEntries: source.getAlbumEntries(),
filterBuilder: (s) => AlbumFilter(s, source.getUniqueAlbumName(s)),
emptyBuilder: () => EmptyContent(
icon: AIcons.album,
text: 'No albums',
),
),
),
);
}
void _goToCountries(BuildContext context) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterNavigationPage(
source: source,
title: 'Countries',
filterEntries: source.getCountryEntries(),
filterBuilder: (s) => LocationFilter(LocationLevel.country, s),
emptyBuilder: () => EmptyContent(
icon: AIcons.location,
text: 'No countries',
),
),
),
);
}
void _goToTags(BuildContext context) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterNavigationPage(
source: source,
title: 'Tags',
filterEntries: source.getTagEntries(),
filterBuilder: (s) => TagFilter(s),
emptyBuilder: () => EmptyContent(
icon: AIcons.tag,
text: 'No tags',
),
),
),
);
}
void _goToSettings(BuildContext context) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingsPage(),
),
);
}
void _goToAbout(BuildContext context) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AboutPage(),
),
);
}
void _goToDebug(BuildContext context) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DebugPage(
source: source,
),
),
);
} }
} }

View file

@ -2,13 +2,19 @@ import 'dart:ui';
import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/album.dart';
import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/filters/location.dart';
import 'package:aves/model/filters/tag.dart';
import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_entry.dart';
import 'package:aves/model/settings.dart'; import 'package:aves/model/settings.dart';
import 'package:aves/model/source/album.dart';
import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.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/utils/android_file_utils.dart'; import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/durations.dart'; import 'package:aves/utils/durations.dart';
import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/album/collection_page.dart';
import 'package:aves/widgets/album/empty.dart';
import 'package:aves/widgets/album/thumbnail/raster.dart'; import 'package:aves/widgets/album/thumbnail/raster.dart';
import 'package:aves/widgets/album/thumbnail/vector.dart'; import 'package:aves/widgets/album/thumbnail/vector.dart';
import 'package:aves/widgets/app_drawer.dart'; import 'package:aves/widgets/app_drawer.dart';
@ -20,6 +26,75 @@ import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class AlbumListPage extends StatelessWidget {
final CollectionSource source;
const AlbumListPage({@required this.source});
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: source.eventBus.on<AlbumsChangedEvent>(),
builder: (context, snapshot) => FilterNavigationPage(
source: source,
title: 'Albums',
filterEntries: source.getAlbumEntries(),
filterBuilder: (s) => AlbumFilter(s, source.getUniqueAlbumName(s)),
emptyBuilder: () => EmptyContent(
icon: AIcons.album,
text: 'No albums',
),
),
);
}
}
class CountryListPage extends StatelessWidget {
final CollectionSource source;
const CountryListPage({@required this.source});
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: source.eventBus.on<LocationsChangedEvent>(),
builder: (context, snapshot) => FilterNavigationPage(
source: source,
title: 'Countries',
filterEntries: source.getCountryEntries(),
filterBuilder: (s) => LocationFilter(LocationLevel.country, s),
emptyBuilder: () => EmptyContent(
icon: AIcons.location,
text: 'No countries',
),
),
);
}
}
class TagListPage extends StatelessWidget {
final CollectionSource source;
const TagListPage({@required this.source});
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: source.eventBus.on<TagsChangedEvent>(),
builder: (context, snapshot) => FilterNavigationPage(
source: source,
title: 'Tags',
filterEntries: source.getTagEntries(),
filterBuilder: (s) => TagFilter(s),
emptyBuilder: () => EmptyContent(
icon: AIcons.tag,
text: 'No tags',
),
),
);
}
}
class FilterNavigationPage extends StatelessWidget { class FilterNavigationPage extends StatelessWidget {
final CollectionSource source; final CollectionSource source;
final String title; final String title;
@ -48,7 +123,12 @@ class FilterNavigationPage extends StatelessWidget {
), ),
filterEntries: filterEntries, filterEntries: filterEntries,
filterBuilder: filterBuilder, filterBuilder: filterBuilder,
emptyBuilder: emptyBuilder, emptyBuilder: () => ValueListenableBuilder<SourceState>(
valueListenable: source.stateNotifier,
builder: (context, sourceState, child) {
return sourceState != SourceState.loading && emptyBuilder != null ? emptyBuilder() : SizedBox.shrink();
},
),
onPressed: (filter) => Navigator.pushAndRemoveUntil( onPressed: (filter) => Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute( MaterialPageRoute(

View file

@ -8,6 +8,7 @@ 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/icons.dart';
import 'package:aves/widgets/filter_grid_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';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -101,11 +102,17 @@ class _HomePageState extends State<HomePage> {
return SingleFullscreenPage(entry: _viewerEntry); return SingleFullscreenPage(entry: _viewerEntry);
} }
if (_mediaStore != null) { if (_mediaStore != null) {
return CollectionPage(CollectionLens( switch(settings.launchPage) {
source: _mediaStore, case LaunchPage.albums:
groupFactor: settings.collectionGroupFactor, return AlbumListPage(source: _mediaStore);
sortFactor: settings.collectionSortFactor, break;
)); case LaunchPage.collection:
return CollectionPage(CollectionLens(
source: _mediaStore,
groupFactor: settings.collectionGroupFactor,
sortFactor: settings.collectionSortFactor,
));
}
} }
return SizedBox.shrink(); return SizedBox.shrink();
}); });

View file

@ -1,4 +1,5 @@
import 'package:aves/model/settings.dart'; import 'package:aves/model/settings.dart';
import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart';
import 'package:aves/widgets/fullscreen/info/location_section.dart'; import 'package:aves/widgets/fullscreen/info/location_section.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -17,7 +18,17 @@ class SettingsPage extends StatelessWidget {
child: ListView( child: ListView(
padding: EdgeInsets.all(16), padding: EdgeInsets.all(16),
children: [ children: [
Text('Maps'), Text('General', style: Constants.titleTextStyle),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('Launch Page:'),
SizedBox(width: 8),
Flexible(child: LaunchPageSelector()),
],
),
SizedBox(height: 16),
Text('Maps', style: Constants.titleTextStyle),
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -45,10 +56,10 @@ class _InfoMapStyleSelectorState extends State<InfoMapStyleSelector> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DropdownButton<EntryMapStyle>( return DropdownButton<EntryMapStyle>(
items: EntryMapStyle.values items: EntryMapStyle.values
.map((style) => DropdownMenuItem( .map((selected) => DropdownMenuItem(
value: style, value: selected,
child: Text( child: Text(
style.name, selected.name,
softWrap: false, softWrap: false,
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
maxLines: 1, maxLines: 1,
@ -56,8 +67,37 @@ class _InfoMapStyleSelectorState extends State<InfoMapStyleSelector> {
)) ))
.toList(), .toList(),
value: settings.infoMapStyle, value: settings.infoMapStyle,
onChanged: (style) { onChanged: (selected) {
settings.infoMapStyle = style; settings.infoMapStyle = selected;
setState(() {});
},
);
}
}
class LaunchPageSelector extends StatefulWidget {
@override
_LaunchPageSelectorState createState() => _LaunchPageSelectorState();
}
class _LaunchPageSelectorState extends State<LaunchPageSelector> {
@override
Widget build(BuildContext context) {
return DropdownButton<LaunchPage>(
items: LaunchPage.values
.map((selected) => DropdownMenuItem(
value: selected,
child: Text(
selected.name,
softWrap: false,
overflow: TextOverflow.fade,
maxLines: 1,
),
))
.toList(),
value: settings.launchPage,
onChanged: (selected) {
settings.launchPage = selected;
setState(() {}); setState(() {});
}, },
); );