#24 viewer: added option to show/hide info on overlay
This commit is contained in:
parent
80d7de43ed
commit
6ea9923a92
4 changed files with 113 additions and 75 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,33 +25,42 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return MediaQueryDataProvider(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Settings'),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Consumer<Settings>(
|
||||
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<Settings>(
|
||||
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<SettingsPage> {
|
|||
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'),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -51,6 +51,8 @@ class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
|||
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<ViewerBottomOverlay> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final hasEdgeContent = settings.showOverlayInfo || multiPageController != null;
|
||||
return BlurredRect(
|
||||
enabled: hasEdgeContent,
|
||||
child: Selector<MediaQueryData, Tuple3<double, EdgeInsets, EdgeInsets>>(
|
||||
selector: (c, mq) => Tuple3(mq.size.width, mq.viewInsets, mq.viewPadding),
|
||||
builder: (c, mq, child) {
|
||||
|
@ -84,7 +88,7 @@ class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
|||
final availableWidth = mqWidth - viewPadding.horizontal;
|
||||
|
||||
return Container(
|
||||
color: kOverlayBackgroundColor,
|
||||
color: hasEdgeContent ? kOverlayBackgroundColor: Colors.transparent,
|
||||
padding: viewInsets + viewPadding.copyWith(top: 0),
|
||||
child: FutureBuilder<OverlayMetadata>(
|
||||
future: _detailLoader,
|
||||
|
@ -100,7 +104,7 @@ class _ViewerBottomOverlayState extends State<ViewerBottomOverlay> {
|
|||
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<MediaQueryData, Orientation>(
|
||||
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,
|
||||
|
|
Loading…
Reference in a new issue