diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index 05e64142a..9fa81b662 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -44,6 +44,9 @@ class Settings extends ChangeNotifier { static const tagSortFactorKey = 'tag_sort_factor'; static const pinnedFiltersKey = 'pinned_filters'; + // viewer + static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details'; + // info static const infoMapStyleKey = 'info_map_style'; static const infoMapZoomKey = 'info_map_zoom'; @@ -150,6 +153,12 @@ class Settings extends ChangeNotifier { set pinnedFilters(Set newValue) => setAndNotify(pinnedFiltersKey, newValue.map((filter) => filter.toJson()).toList()); + // viewer + + bool get showOverlayShootingDetails => getBoolOrDefault(showOverlayShootingDetailsKey, true); + + set showOverlayShootingDetails(bool newValue) => setAndNotify(showOverlayShootingDetailsKey, newValue); + // info EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values); diff --git a/lib/widgets/fullscreen/overlay/bottom.dart b/lib/widgets/fullscreen/overlay/bottom.dart index 30216ad98..38c5b1e06 100644 --- a/lib/widgets/fullscreen/overlay/bottom.dart +++ b/lib/widgets/fullscreen/overlay/bottom.dart @@ -151,7 +151,7 @@ class _FullscreenBottomOverlayContent extends AnimatedWidget { if (position != null) position, if (entry.bestTitle != null) entry.bestTitle, ].join(' – '); - final hasShootingDetails = details != null && !details.isEmpty; + final hasShootingDetails = details != null && !details.isEmpty && settings.showOverlayShootingDetails; return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 00936493d..99aa0eed3 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -3,6 +3,7 @@ import 'package:aves/model/settings/home_page.dart'; import 'package:aves/model/settings/screen_on.dart'; import 'package:aves/model/settings/settings.dart'; import 'package:aves/utils/constants.dart'; +import 'package:aves/widgets/common/aves_expansion_tile.dart'; import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/highlight_title.dart'; @@ -11,9 +12,16 @@ import 'package:aves/widgets/settings/svg_background.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -class SettingsPage extends StatelessWidget { +class SettingsPage extends StatefulWidget { static const routeName = '/settings'; + @override + _SettingsPageState createState() => _SettingsPageState(); +} + +class _SettingsPageState extends State { + final ValueNotifier _expandedNotifier = ValueNotifier(null); + @override Widget build(BuildContext context) { return MediaQueryDataProvider( @@ -26,98 +34,13 @@ class SettingsPage extends StatelessWidget { body: SafeArea( child: Consumer( builder: (context, settings, child) => ListView( - padding: EdgeInsets.symmetric(vertical: 16), + padding: EdgeInsets.all(8), children: [ - SectionTitle('Navigation'), - ListTile( - title: Text('Home'), - subtitle: Text(settings.homePage.name), - onTap: () async { - final value = await showDialog( - context: context, - builder: (context) => AvesSelectionDialog( - initialValue: settings.homePage, - options: Map.fromEntries(HomePageSetting.values.map((v) => MapEntry(v, v.name))), - title: 'Home', - ), - ); - if (value != null) { - settings.homePage = value; - } - }, - ), - SwitchListTile( - value: settings.mustBackTwiceToExit, - onChanged: (v) => settings.mustBackTwiceToExit = v, - title: Text('Tap “back” twice to exit'), - ), - SectionTitle('Display'), - ListTile( - title: Text('Keep screen on'), - subtitle: Text(settings.keepScreenOn.name), - onTap: () async { - final value = await showDialog( - context: context, - builder: (context) => AvesSelectionDialog( - initialValue: settings.keepScreenOn, - options: Map.fromEntries(KeepScreenOn.values.map((v) => MapEntry(v, v.name))), - title: 'Keep Screen On', - ), - ); - if (value != null) { - settings.keepScreenOn = value; - } - }, - ), - ListTile( - title: Text('SVG background'), - trailing: SvgBackgroundSelector(), - ), - ListTile( - title: Text('Coordinate format'), - subtitle: Text(settings.coordinateFormat.name), - onTap: () async { - final value = await showDialog( - context: context, - builder: (context) => AvesSelectionDialog( - initialValue: settings.coordinateFormat, - options: Map.fromEntries(CoordinateFormat.values.map((v) => MapEntry(v, v.name))), - optionSubtitleBuilder: (dynamic value) { - // dynamic declaration followed by cast, as workaround for generics limitation - final formatter = (value as CoordinateFormat); - return formatter.format(Constants.pointNemo); - }, - title: 'Coordinate Format', - ), - ); - if (value != null) { - settings.coordinateFormat = value; - } - }, - ), - SectionTitle('Thumbnails'), - SwitchListTile( - value: settings.showThumbnailLocation, - onChanged: (v) => settings.showThumbnailLocation = v, - title: Text('Show location icon'), - ), - SwitchListTile( - value: settings.showThumbnailRaw, - onChanged: (v) => settings.showThumbnailRaw = v, - title: Text('Show raw icon'), - ), - SwitchListTile( - value: settings.showThumbnailVideoDuration, - onChanged: (v) => settings.showThumbnailVideoDuration = v, - title: Text('Show video duration'), - ), - SectionTitle('Privacy'), - SwitchListTile( - value: settings.isCrashlyticsEnabled, - onChanged: (v) => settings.isCrashlyticsEnabled = v, - title: Text('Allow anonymous analytics and crash reporting'), - ), - GrantedDirectories(), + _buildNavigationSection(context), + _buildDisplaySection(context), + _buildThumbnailsSection(context), + _buildViewerSection(context), + _buildPrivacySection(context), ], ), ), @@ -126,6 +49,146 @@ class SettingsPage extends StatelessWidget { ), ); } + + Widget _buildNavigationSection(BuildContext context) { + return AvesExpansionTile( + title: 'Navigation', + expandedNotifier: _expandedNotifier, + children: [ + ListTile( + title: Text('Home'), + subtitle: Text(settings.homePage.name), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: settings.homePage, + options: Map.fromEntries(HomePageSetting.values.map((v) => MapEntry(v, v.name))), + title: 'Home', + ), + ); + if (value != null) { + settings.homePage = value; + } + }, + ), + SwitchListTile( + value: settings.mustBackTwiceToExit, + onChanged: (v) => settings.mustBackTwiceToExit = v, + title: Text('Tap “back” twice to exit'), + ), + ], + ); + } + + Widget _buildDisplaySection(BuildContext context) { + return AvesExpansionTile( + title: 'Display', + expandedNotifier: _expandedNotifier, + children: [ + ListTile( + title: Text('Keep screen on'), + subtitle: Text(settings.keepScreenOn.name), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: settings.keepScreenOn, + options: Map.fromEntries(KeepScreenOn.values.map((v) => MapEntry(v, v.name))), + title: 'Keep Screen On', + ), + ); + if (value != null) { + settings.keepScreenOn = value; + } + }, + ), + ListTile( + title: Text('SVG background'), + trailing: SvgBackgroundSelector(), + ), + ListTile( + title: Text('Coordinate format'), + subtitle: Text(settings.coordinateFormat.name), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: settings.coordinateFormat, + options: Map.fromEntries(CoordinateFormat.values.map((v) => MapEntry(v, v.name))), + optionSubtitleBuilder: (dynamic value) { + // dynamic declaration followed by cast, as workaround for generics limitation + final formatter = (value as CoordinateFormat); + return formatter.format(Constants.pointNemo); + }, + title: 'Coordinate Format', + ), + ); + if (value != null) { + settings.coordinateFormat = value; + } + }, + ), + ], + ); + } + + Widget _buildThumbnailsSection(BuildContext context) { + return AvesExpansionTile( + title: 'Thumbnails', + expandedNotifier: _expandedNotifier, + children: [ + SwitchListTile( + value: settings.showThumbnailLocation, + onChanged: (v) => settings.showThumbnailLocation = v, + title: Text('Show location icon'), + ), + SwitchListTile( + value: settings.showThumbnailRaw, + onChanged: (v) => settings.showThumbnailRaw = v, + title: Text('Show raw icon'), + ), + SwitchListTile( + value: settings.showThumbnailVideoDuration, + onChanged: (v) => settings.showThumbnailVideoDuration = v, + title: Text('Show video duration'), + ), + ], + ); + } + + Widget _buildViewerSection(BuildContext context) { + return AvesExpansionTile( + title: 'Viewer', + expandedNotifier: _expandedNotifier, + children: [ + SwitchListTile( + value: settings.showOverlayShootingDetails, + onChanged: (v) => settings.showOverlayShootingDetails = v, + title: Text('Show shooting details'), + ), + ], + ); + } + + Widget _buildPrivacySection(BuildContext context) { + return AvesExpansionTile( + title: 'Privacy', + expandedNotifier: _expandedNotifier, + children: [ + SwitchListTile( + value: settings.isCrashlyticsEnabled, + onChanged: (v) => settings.isCrashlyticsEnabled = v, + title: Text('Allow anonymous analytics and crash reporting'), + ), + Container( + alignment: AlignmentDirectional.topStart, + padding: EdgeInsets.only(bottom: 16), + child: GrantedDirectories(), + ), + ], + ); + } } class SectionTitle extends StatelessWidget {