diff --git a/lib/model/metadata/overlay.dart b/lib/model/metadata/overlay.dart index 9dc983af3..1858642c1 100644 --- a/lib/model/metadata/overlay.dart +++ b/lib/model/metadata/overlay.dart @@ -12,6 +12,8 @@ class OverlayMetadata extends Equatable { bool get isEmpty => aperture == null && exposureTime == null && focalLength == null && iso == null; + bool get isNotEmpty => !isEmpty; + const OverlayMetadata({ this.aperture, this.exposureTime, diff --git a/lib/model/settings/defaults.dart b/lib/model/settings/defaults.dart index dd6c75106..cf06d1c38 100644 --- a/lib/model/settings/defaults.dart +++ b/lib/model/settings/defaults.dart @@ -60,9 +60,11 @@ class SettingsDefaults { // viewer static const viewerQuickActions = [ + EntryAction.rotateScreen, EntryAction.toggleFavourite, EntryAction.share, - EntryAction.rotateScreen, + EntryAction.edit, + EntryAction.delete, ]; static const showOverlayOnOpening = true; static const showOverlayMinimap = false; diff --git a/lib/widgets/collection/app_bar.dart b/lib/widgets/collection/app_bar.dart index 773b54a4f..c6cde915d 100644 --- a/lib/widgets/collection/app_bar.dart +++ b/lib/widgets/collection/app_bar.dart @@ -361,27 +361,38 @@ class _CollectionAppBarState extends State with SingleTickerPr ); Widget buildItem(EntrySetAction action) => Expanded( - child: PopupMenuItem( - value: action, - enabled: canApply(action), - child: Tooltip( - message: action.getText(context), - child: Center(child: action.getIcon()), + child: Material( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + clipBehavior: Clip.antiAlias, + child: PopupMenuItem( + value: action, + enabled: canApply(action), + child: Tooltip( + message: action.getText(context), + child: Center(child: action.getIcon()), + ), ), ), ); return PopupMenuItem( - child: Row( - children: [ - buildDivider(), - buildItem(EntrySetAction.rotateCCW), - buildDivider(), - buildItem(EntrySetAction.rotateCW), - buildDivider(), - buildItem(EntrySetAction.flip), - buildDivider(), - ], + child: TooltipTheme( + data: TooltipTheme.of(context).copyWith( + preferBelow: false, + ), + child: Row( + children: [ + buildDivider(), + buildItem(EntrySetAction.rotateCCW), + buildDivider(), + buildItem(EntrySetAction.rotateCW), + buildDivider(), + buildItem(EntrySetAction.flip), + buildDivider(), + ], + ), ), ); } diff --git a/lib/widgets/viewer/overlay/details.dart b/lib/widgets/viewer/overlay/details.dart index cfc166590..8d21aad87 100644 --- a/lib/widgets/viewer/overlay/details.dart +++ b/lib/widgets/viewer/overlay/details.dart @@ -139,8 +139,7 @@ class ViewerDetailOverlayContent extends StatelessWidget { Widget build(BuildContext context) { final infoMaxWidth = availableWidth - padding.horizontal; final positionTitle = _PositionTitleRow(entry: pageEntry, collectionPosition: position, multiPageController: multiPageController); - final hasShootingDetails = details != null && !details!.isEmpty && settings.showOverlayShootingDetails; - final animationDuration = context.select((v) => v.viewerOverlayChangeAnimation); + final showShooting = settings.showOverlayShootingDetails; return DefaultTextStyle( style: Theme.of(context).textTheme.bodyText2!.copyWith( @@ -156,40 +155,38 @@ class ViewerDetailOverlayContent extends StatelessWidget { builder: (context, orientation, child) { final twoColumns = orientation == Orientation.landscape && infoMaxWidth / 2 > _subRowMinWidth; final subRowWidth = twoColumns ? min(_subRowMinWidth, infoMaxWidth / 2) : infoMaxWidth; + final collapsedShooting = twoColumns && showShooting; + final collapsedLocation = twoColumns && !showShooting; + + final rows = []; + if (positionTitle.isNotEmpty) { + rows.add(positionTitle); + rows.add(const SizedBox(height: _interRowPadding)); + } + if (twoColumns) { + rows.add( + Row( + children: [ + _buildDateSubRow(subRowWidth), + if (collapsedShooting) _buildShootingSubRow(context, subRowWidth), + if (collapsedLocation) _buildLocationSubRow(context, subRowWidth), + ], + ), + ); + } else { + rows.add(_buildDateSubRow(subRowWidth)); + if (showShooting) { + rows.add(_buildShootingFullRow(context, subRowWidth)); + } + } + if (!collapsedLocation) { + rows.add(_buildLocationFullRow(context)); + } return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (positionTitle.isNotEmpty) positionTitle, - if (twoColumns) - Padding( - padding: const EdgeInsets.only(top: _interRowPadding), - child: Row( - children: [ - SizedBox( - width: subRowWidth, - child: _DateRow( - entry: pageEntry, - multiPageController: multiPageController, - )), - _buildDuoShootingRow(subRowWidth, hasShootingDetails, animationDuration), - ], - ), - ) - else ...[ - Container( - padding: const EdgeInsets.only(top: _interRowPadding), - width: subRowWidth, - child: _DateRow( - entry: pageEntry, - multiPageController: multiPageController, - ), - ), - _buildSoloShootingRow(subRowWidth, hasShootingDetails, animationDuration), - ], - _buildSoloLocationRow(animationDuration), - ], + children: rows, ); }, ), @@ -197,56 +194,88 @@ class ViewerDetailOverlayContent extends StatelessWidget { ); } - Widget _buildSoloLocationRow(Duration animationDuration) => AnimatedSwitcher( - duration: animationDuration, - switchInCurve: Curves.easeInOutCubic, - switchOutCurve: Curves.easeInOutCubic, - transitionBuilder: _soloTransition, - child: pageEntry.hasGps - ? Container( - padding: const EdgeInsets.only(top: _interRowPadding), - child: _LocationRow(entry: pageEntry), - ) - : const SizedBox(), + Widget _buildDateSubRow(double subRowWidth) => SizedBox( + width: subRowWidth, + child: _DateRow( + entry: pageEntry, + multiPageController: multiPageController, + ), ); - Widget _buildSoloShootingRow(double subRowWidth, bool hasShootingDetails, Duration animationDuration) => AnimatedSwitcher( - duration: animationDuration, - switchInCurve: Curves.easeInOutCubic, - switchOutCurve: Curves.easeInOutCubic, - transitionBuilder: _soloTransition, - child: hasShootingDetails - ? Container( - padding: const EdgeInsets.only(top: _interRowPadding), - width: subRowWidth, - child: _ShootingRow(details!), - ) - : const SizedBox(), + Widget _buildShootingFullRow(BuildContext context, double subRowWidth) => _buildFullRowSwitcher( + context: context, + visible: details != null && details!.isNotEmpty, + builder: (context) => SizedBox( + width: subRowWidth, + child: _ShootingRow(details!), + ), ); - Widget _buildDuoShootingRow(double subRowWidth, bool hasShootingDetails, Duration animationDuration) => AnimatedSwitcher( - duration: animationDuration, + Widget _buildShootingSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher( + context: context, + subRowWidth: subRowWidth, + visible: details != null && details!.isNotEmpty, + builder: (context) => _ShootingRow(details!), + ); + + Widget _buildLocationFullRow(BuildContext context) => _buildFullRowSwitcher( + context: context, + visible: pageEntry.hasGps, + builder: (context) => _LocationRow(entry: pageEntry), + ); + + Widget _buildLocationSubRow(BuildContext context, double subRowWidth) => _buildSubRowSwitcher( + context: context, + subRowWidth: subRowWidth, + visible: pageEntry.hasGps, + builder: (context) => _LocationRow(entry: pageEntry), + ); + + Widget _buildSubRowSwitcher({ + required BuildContext context, + required double subRowWidth, + required bool visible, + required WidgetBuilder builder, + }) => + AnimatedSwitcher( + duration: context.select((v) => v.viewerOverlayChangeAnimation), switchInCurve: Curves.easeInOutCubic, switchOutCurve: Curves.easeInOutCubic, transitionBuilder: (child, animation) => FadeTransition( opacity: animation, child: child, ), - child: hasShootingDetails + child: visible ? SizedBox( width: subRowWidth, - child: _ShootingRow(details!), + child: builder(context), ) : const SizedBox(), ); - static Widget _soloTransition(Widget child, Animation animation) => FadeTransition( - opacity: animation, - child: SizeTransition( - axisAlignment: 1, - sizeFactor: animation, - child: child, + Widget _buildFullRowSwitcher({ + required BuildContext context, + required bool visible, + required WidgetBuilder builder, + }) => + AnimatedSwitcher( + duration: context.select((v) => v.viewerOverlayChangeAnimation), + switchInCurve: Curves.easeInOutCubic, + switchOutCurve: Curves.easeInOutCubic, + transitionBuilder: (child, animation) => FadeTransition( + opacity: animation, + child: SizeTransition( + axisAlignment: 1, + sizeFactor: animation, + child: child, + ), ), + child: visible + ? Padding( + padding: const EdgeInsets.only(top: _interRowPadding), + child: builder(context), + ) + : const SizedBox(), ); } diff --git a/lib/widgets/viewer/overlay/viewer_button_row.dart b/lib/widgets/viewer/overlay/viewer_button_row.dart index 0461daefc..a13158e12 100644 --- a/lib/widgets/viewer/overlay/viewer_button_row.dart +++ b/lib/widgets/viewer/overlay/viewer_button_row.dart @@ -352,11 +352,17 @@ class ViewerButtonRowContent extends StatelessWidget { ); Widget buildItem(EntryAction action) => Expanded( - child: PopupMenuItem( - value: action, - child: Tooltip( - message: action.getText(context), - child: Center(child: action.getIcon()), + child: Material( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + clipBehavior: Clip.antiAlias, + child: PopupMenuItem( + value: action, + child: Tooltip( + message: action.getText(context), + child: Center(child: action.getIcon()), + ), ), ), );