diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index 5ccc1f7ea..008affa65 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -47,6 +47,7 @@ class Settings extends ChangeNotifier { // viewer static const showOverlayMinimapKey = 'show_overlay_minimap'; + static const showOverlayInfoKey = 'show_overlay_info'; static const showOverlayShootingDetailsKey = 'show_overlay_shooting_details'; // info @@ -166,6 +167,10 @@ class Settings extends ChangeNotifier { set showOverlayMinimap(bool newValue) => setAndNotify(showOverlayMinimapKey, newValue); + bool get showOverlayInfo => getBoolOrDefault(showOverlayInfoKey, true); + + set showOverlayInfo(bool newValue) => setAndNotify(showOverlayInfoKey, newValue); + bool get showOverlayShootingDetails => getBoolOrDefault(showOverlayShootingDetailsKey, true); set showOverlayShootingDetails(bool newValue) => setAndNotify(showOverlayShootingDetailsKey, newValue); diff --git a/lib/widgets/common/fx/blurred.dart b/lib/widgets/common/fx/blurred.dart index a3f606ede..d14d3e214 100644 --- a/lib/widgets/common/fx/blurred.dart +++ b/lib/widgets/common/fx/blurred.dart @@ -5,18 +5,25 @@ import 'package:flutter/material.dart'; final _filter = ImageFilter.blur(sigmaX: 4, sigmaY: 4); class BlurredRect extends StatelessWidget { + final bool enabled; final Widget child; - const BlurredRect({Key key, this.child}) : super(key: key); + const BlurredRect({ + Key key, + this.enabled = true, + this.child, + }) : super(key: key); @override Widget build(BuildContext context) { - return ClipRect( - child: BackdropFilter( - filter: _filter, - child: child, - ), - ); + return enabled + ? ClipRect( + child: BackdropFilter( + filter: _filter, + child: child, + ), + ) + : child; } } diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 65c320102..e82cab105 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -25,33 +25,42 @@ class _SettingsPageState extends State { @override Widget build(BuildContext context) { + final theme = Theme.of(context); return MediaQueryDataProvider( child: Scaffold( appBar: AppBar( title: Text('Settings'), ), - body: SafeArea( - child: Consumer( - builder: (context, settings, child) => AnimationLimiter( - child: ListView( - padding: EdgeInsets.all(8), - children: AnimationConfiguration.toStaggeredList( - duration: Durations.staggeredAnimation, - delay: Durations.staggeredAnimationDelay, - childAnimationBuilder: (child) => SlideAnimation( - verticalOffset: 50.0, - child: FadeInAnimation( - child: child, + body: Theme( + data: theme.copyWith( + textTheme: theme.textTheme.copyWith( + // dense style font for tile subtitles, without modifying title font + bodyText2: TextStyle(fontSize: 12), + ), + ), + child: SafeArea( + child: Consumer( + builder: (context, settings, child) => AnimationLimiter( + child: ListView( + padding: EdgeInsets.all(8), + children: AnimationConfiguration.toStaggeredList( + duration: Durations.staggeredAnimation, + delay: Durations.staggeredAnimationDelay, + childAnimationBuilder: (child) => SlideAnimation( + verticalOffset: 50.0, + child: FadeInAnimation( + child: child, + ), ), + children: [ + _buildNavigationSection(context), + _buildDisplaySection(context), + _buildThumbnailsSection(context), + _buildViewerSection(context), + _buildSearchSection(context), + _buildPrivacySection(context), + ], ), - children: [ - _buildNavigationSection(context), - _buildDisplaySection(context), - _buildThumbnailsSection(context), - _buildViewerSection(context), - _buildSearchSection(context), - _buildPrivacySection(context), - ], ), ), ), @@ -188,9 +197,15 @@ class _SettingsPageState extends State { onChanged: (v) => settings.showOverlayMinimap = v, title: Text('Show minimap'), ), + SwitchListTile( + value: settings.showOverlayInfo, + onChanged: (v) => settings.showOverlayInfo = v, + title: Text('Show information'), + subtitle: Text('Show title, date, location, etc.'), + ), SwitchListTile( value: settings.showOverlayShootingDetails, - onChanged: (v) => settings.showOverlayShootingDetails = v, + onChanged: settings.showOverlayInfo ? (v) => settings.showOverlayShootingDetails = v : null, title: Text('Show shooting details'), ), ], diff --git a/lib/widgets/viewer/overlay/bottom.dart b/lib/widgets/viewer/overlay/bottom.dart index 62daeddd7..5ba8cce42 100644 --- a/lib/widgets/viewer/overlay/bottom.dart +++ b/lib/widgets/viewer/overlay/bottom.dart @@ -51,6 +51,8 @@ class _ViewerBottomOverlayState extends State { return index < entries.length ? entries[index] : null; } + MultiPageController get multiPageController => widget.multiPageController; + @override void initState() { super.initState(); @@ -71,7 +73,9 @@ class _ViewerBottomOverlayState extends State { @override Widget build(BuildContext context) { + final hasEdgeContent = settings.showOverlayInfo || multiPageController != null; return BlurredRect( + enabled: hasEdgeContent, child: Selector>( selector: (c, mq) => Tuple3(mq.size.width, mq.viewInsets, mq.viewPadding), builder: (c, mq, child) { @@ -84,7 +88,7 @@ class _ViewerBottomOverlayState extends State { final availableWidth = mqWidth - viewPadding.horizontal; return Container( - color: kOverlayBackgroundColor, + color: hasEdgeContent ? kOverlayBackgroundColor: Colors.transparent, padding: viewInsets + viewPadding.copyWith(top: 0), child: FutureBuilder( future: _detailLoader, @@ -100,7 +104,7 @@ class _ViewerBottomOverlayState extends State { details: _lastDetails, position: widget.showPosition ? '${widget.index + 1}/${widget.entries.length}' : null, availableWidth: availableWidth, - multiPageController: widget.multiPageController, + multiPageController: multiPageController, ); }, ), @@ -136,8 +140,6 @@ class _BottomOverlayContent extends AnimatedWidget { @override Widget build(BuildContext context) { - final infoMaxWidth = availableWidth - infoPadding.horizontal; - return DefaultTextStyle( style: Theme.of(context).textTheme.bodyText2.copyWith( shadows: [Constants.embossShadow], @@ -150,48 +152,11 @@ class _BottomOverlayContent extends AnimatedWidget { child: Selector( selector: (c, mq) => mq.orientation, builder: (c, orientation, child) { - final twoColumns = orientation == Orientation.landscape && infoMaxWidth / 2 > _subRowMinWidth; - final subRowWidth = twoColumns ? min(_subRowMinWidth, infoMaxWidth / 2) : infoMaxWidth; - final positionTitle = _PositionTitleRow(entry: entry, collectionPosition: position, multiPageController: multiPageController); - final hasShootingDetails = details != null && !details.isEmpty && settings.showOverlayShootingDetails; + Widget infoColumn; - Widget infoColumn = Padding( - padding: infoPadding, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (positionTitle.isNotEmpty) positionTitle, - _buildSoloLocationRow(), - if (twoColumns) - Padding( - padding: EdgeInsets.only(top: _interRowPadding), - child: Row( - children: [ - Container( - width: subRowWidth, - child: _DateRow( - entry: entry, - multiPageController: multiPageController, - )), - _buildDuoShootingRow(subRowWidth, hasShootingDetails), - ], - ), - ) - else ...[ - Container( - padding: EdgeInsets.only(top: _interRowPadding), - width: subRowWidth, - child: _DateRow( - entry: entry, - multiPageController: multiPageController, - ), - ), - _buildSoloShootingRow(subRowWidth, hasShootingDetails), - ], - ], - ), - ); + if (settings.showOverlayInfo) { + infoColumn = _buildInfoColumn(orientation); + } if (multiPageController != null) { infoColumn = Column( @@ -203,18 +168,64 @@ class _BottomOverlayContent extends AnimatedWidget { controller: multiPageController, availableWidth: availableWidth, ), - infoColumn, + if (infoColumn != null) infoColumn, ], ); } - return infoColumn; + return infoColumn ?? SizedBox(); }, ), ), ); } + Widget _buildInfoColumn(Orientation orientation) { + final infoMaxWidth = availableWidth - infoPadding.horizontal; + final twoColumns = orientation == Orientation.landscape && infoMaxWidth / 2 > _subRowMinWidth; + final subRowWidth = twoColumns ? min(_subRowMinWidth, infoMaxWidth / 2) : infoMaxWidth; + final positionTitle = _PositionTitleRow(entry: entry, collectionPosition: position, multiPageController: multiPageController); + final hasShootingDetails = details != null && !details.isEmpty && settings.showOverlayShootingDetails; + + return Padding( + padding: infoPadding, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (positionTitle.isNotEmpty) positionTitle, + _buildSoloLocationRow(), + if (twoColumns) + Padding( + padding: EdgeInsets.only(top: _interRowPadding), + child: Row( + children: [ + Container( + width: subRowWidth, + child: _DateRow( + entry: entry, + multiPageController: multiPageController, + )), + _buildDuoShootingRow(subRowWidth, hasShootingDetails), + ], + ), + ) + else ...[ + Container( + padding: EdgeInsets.only(top: _interRowPadding), + width: subRowWidth, + child: _DateRow( + entry: entry, + multiPageController: multiPageController, + ), + ), + _buildSoloShootingRow(subRowWidth, hasShootingDetails), + ], + ], + ), + ); + } + Widget _buildSoloLocationRow() => AnimatedSwitcher( duration: Durations.viewerOverlayChangeAnimation, switchInCurve: Curves.easeInOutCubic,