diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72005807b..08e2f89df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Changed
+
+- check Media Store changes when resuming app
+- disabling animations also applies to pop up menus
+
## [v1.10.5] - 2024-02-22
### Added
diff --git a/lib/model/settings/enums/accessibility_animations.dart b/lib/model/settings/enums/accessibility_animations.dart
index a336c2601..25f9e0fc0 100644
--- a/lib/model/settings/enums/accessibility_animations.dart
+++ b/lib/model/settings/enums/accessibility_animations.dart
@@ -1,5 +1,7 @@
import 'package:aves/model/settings/settings.dart';
+import 'package:aves/theme/durations.dart';
import 'package:aves_model/aves_model.dart';
+import 'package:flutter/widgets.dart';
extension ExtraAccessibilityAnimations on AccessibilityAnimations {
bool get animate {
@@ -14,4 +16,17 @@ extension ExtraAccessibilityAnimations on AccessibilityAnimations {
return true;
}
}
+
+ Duration get popUpAnimationDuration => animate ? ADurations.popupMenuAnimation : Duration.zero;
+
+ Duration get popUpAnimationDelay => popUpAnimationDuration + const Duration(milliseconds: ADurations.transitionMarginMillis);
+
+ AnimationStyle get popUpAnimationStyle {
+ return animate
+ ? AnimationStyle(
+ curve: Curves.easeInOutCubic,
+ duration: popUpAnimationDuration,
+ )
+ : AnimationStyle.noAnimation;
+ }
}
diff --git a/lib/theme/durations.dart b/lib/theme/durations.dart
index 486c51874..56e852d78 100644
--- a/lib/theme/durations.dart
+++ b/lib/theme/durations.dart
@@ -2,12 +2,13 @@ import 'package:flutter/foundation.dart';
class ADurations {
// Flutter animations (with margin)
- static const popupMenuAnimation = Duration(milliseconds: 300 + 20); // ref `_kMenuDuration` used in `_PopupMenuRoute`
+ static const transitionMarginMillis = 20;
+
// page transition duration also available via `ModalRoute.of(context)!.transitionDuration * timeDilation`
- static const pageTransitionAnimation = Duration(milliseconds: 300 + 20); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
- static const dialogTransitionAnimation = Duration(milliseconds: 150 + 20); // ref `transitionDuration` used in `DialogRoute`
- static const drawerTransitionAnimation = Duration(milliseconds: 246 + 20); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
- static const toggleableTransitionAnimation = Duration(milliseconds: 200 + 20); // ref `_kToggleDuration` used in `ToggleableStateMixin`
+ static const pageTransitionAnimation = Duration(milliseconds: 300 + transitionMarginMillis); // ref `transitionDuration` used in `MaterialRouteTransitionMixin`
+ static const dialogTransitionAnimation = Duration(milliseconds: 150 + transitionMarginMillis); // ref `transitionDuration` used in `DialogRoute`
+ static const drawerTransitionAnimation = Duration(milliseconds: 246 + transitionMarginMillis); // ref `_kBaseSettleDuration` used in `DrawerControllerState`
+ static const toggleableTransitionAnimation = Duration(milliseconds: 200 + transitionMarginMillis); // ref `_kToggleDuration` used in `ToggleableStateMixin`
// common animations
static const sweeperOpacityAnimation = Duration(milliseconds: 150);
@@ -16,6 +17,7 @@ class ADurations {
static const appBarTitleAnimation = Duration(milliseconds: 300);
static const appBarActionChangeAnimation = Duration(milliseconds: 200);
+ static const popupMenuAnimation = Duration(milliseconds: 300);
// filter grids animations
static const chipDecorationAnimation = Duration(milliseconds: 200);
diff --git a/lib/widgets/collection/app_bar.dart b/lib/widgets/collection/app_bar.dart
index abe5553f9..2fb992ffe 100644
--- a/lib/widgets/collection/app_bar.dart
+++ b/lib/widgets/collection/app_bar.dart
@@ -7,6 +7,7 @@ import 'package:aves/model/filters/query.dart';
import 'package:aves/model/filters/trash.dart';
import 'package:aves/model/query.dart';
import 'package:aves/model/selection.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart';
@@ -382,6 +383,7 @@ class _CollectionAppBarState extends State with SingleTickerPr
(action) => _buildButtonIcon(context, action, enabled: canApply(action), selection: selection),
);
+ final animations = context.select((s) => s.accessibilityAnimations);
return [
...quickActionButtons,
PopupMenuButton(
@@ -432,9 +434,10 @@ class _CollectionAppBarState extends State with SingleTickerPr
},
onSelected: (action) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
await _onActionSelected(action);
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
];
}
diff --git a/lib/widgets/common/basic/popup/menu_button.dart b/lib/widgets/common/basic/popup/menu_button.dart
index 36d18607f..6e69368fd 100644
--- a/lib/widgets/common/basic/popup/menu_button.dart
+++ b/lib/widgets/common/basic/popup/menu_button.dart
@@ -21,6 +21,7 @@ class AvesPopupMenuButton extends PopupMenuButton {
super.enableFeedback,
super.iconSize,
this.onMenuOpened,
+ super.popUpAnimationStyle,
});
@override
diff --git a/lib/widgets/common/identity/aves_filter_chip.dart b/lib/widgets/common/identity/aves_filter_chip.dart
index 59ddfb083..e8d230fce 100644
--- a/lib/widgets/common/identity/aves_filter_chip.dart
+++ b/lib/widgets/common/identity/aves_filter_chip.dart
@@ -11,7 +11,6 @@ import 'package:aves/model/filters/tag.dart';
import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/view/view.dart';
import 'package:aves/widgets/collection/filter_bar.dart';
@@ -117,6 +116,7 @@ class AvesFilterChip extends StatefulWidget {
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
final actionDelegate = ChipActionDelegate();
+ final animations = context.read().accessibilityAnimations;
final selectedAction = await showMenu(
context: context,
position: RelativeRect.fromRect(tapPosition & touchArea, Offset.zero & overlay.size),
@@ -149,10 +149,11 @@ class AvesFilterChip extends StatefulWidget {
);
}),
],
+ popUpAnimationStyle: animations.popUpAnimationStyle,
);
if (selectedAction != null) {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
actionDelegate.onActionSelected(context, filter, selectedAction);
}
}
diff --git a/lib/widgets/debug/app_debug_page.dart b/lib/widgets/debug/app_debug_page.dart
index b625314ce..9b8296419 100644
--- a/lib/widgets/debug/app_debug_page.dart
+++ b/lib/widgets/debug/app_debug_page.dart
@@ -4,9 +4,9 @@ import 'package:aves/model/favourites.dart';
import 'package:aves/model/filters/location.dart';
import 'package:aves/model/filters/path.dart';
import 'package:aves/model/filters/tag.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
import 'package:aves/widgets/common/basic/scaffold.dart';
@@ -25,6 +25,7 @@ import 'package:aves/widgets/debug/media_store_scan_dialog.dart';
import 'package:aves/widgets/debug/report.dart';
import 'package:aves/widgets/debug/settings.dart';
import 'package:aves/widgets/debug/storage.dart';
+import 'package:aves_model/aves_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart';
@@ -36,6 +37,7 @@ class AppDebugPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final animations = context.select((s) => s.accessibilityAnimations);
return Directionality(
textDirection: TextDirection.ltr,
child: AvesScaffold(
@@ -56,9 +58,10 @@ class AppDebugPage extends StatelessWidget {
.toList(),
onSelected: (action) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
unawaited(_onActionSelected(context, action));
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
],
diff --git a/lib/widgets/dialogs/entry_editors/rename_entry_set_page.dart b/lib/widgets/dialogs/entry_editors/rename_entry_set_page.dart
index 6e55b82c2..8f09dc16b 100644
--- a/lib/widgets/dialogs/entry_editors/rename_entry_set_page.dart
+++ b/lib/widgets/dialogs/entry_editors/rename_entry_set_page.dart
@@ -2,8 +2,8 @@ import 'dart:math';
import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/naming_pattern.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/styles.dart';
import 'package:aves/widgets/collection/collection_grid.dart';
@@ -14,8 +14,10 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/grid/theme.dart';
import 'package:aves/widgets/common/identity/buttons/outlined_button.dart';
import 'package:aves/widgets/common/thumbnail/decorated.dart';
+import 'package:aves_model/aves_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
+import 'package:provider/provider.dart';
class RenameEntrySetPage extends StatefulWidget {
static const routeName = '/rename_entry_set';
@@ -62,6 +64,7 @@ class _RenameEntrySetPageState extends State {
final l10n = context.l10n;
final textScaler = MediaQuery.textScalerOf(context);
final effectiveThumbnailExtent = max(thumbnailExtent, textScaler.scale(thumbnailExtent));
+ final animations = context.select((s) => s.accessibilityAnimations);
return AvesScaffold(
appBar: AppBar(
title: Text(l10n.renameEntrySetPageTitle),
@@ -104,11 +107,12 @@ class _RenameEntrySetPageState extends State {
},
onSelected: (key) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
_insertProcessor(key);
},
tooltip: l10n.renameEntrySetPageInsertTooltip,
icon: const Icon(AIcons.add),
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
],
diff --git a/lib/widgets/dialogs/pick_dialogs/album_pick_page.dart b/lib/widgets/dialogs/pick_dialogs/album_pick_page.dart
index 769f14f80..634341c88 100644
--- a/lib/widgets/dialogs/pick_dialogs/album_pick_page.dart
+++ b/lib/widgets/dialogs/pick_dialogs/album_pick_page.dart
@@ -2,6 +2,7 @@ import 'package:aves/app_mode.dart';
import 'package:aves/model/filters/album.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/selection.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/album.dart';
import 'package:aves/model/source/collection_source.dart';
@@ -205,6 +206,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
required bool Function(ChipSetAction action) isVisible,
required void Function(ChipSetAction action) onActionSelected,
}) {
+ final animations = context.select((s) => s.accessibilityAnimations);
return [
if (widget.moveType != null)
..._quickActions.where(isVisible).map(
@@ -227,9 +229,10 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
FocusManager.instance.primaryFocus?.unfocus();
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
onActionSelected(action);
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
];
}
diff --git a/lib/widgets/filter_grids/common/app_bar.dart b/lib/widgets/filter_grids/common/app_bar.dart
index f39bba04e..a9cf68144 100644
--- a/lib/widgets/filter_grids/common/app_bar.dart
+++ b/lib/widgets/filter_grids/common/app_bar.dart
@@ -4,6 +4,7 @@ import 'package:aves/app_mode.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/query.dart';
import 'package:aves/model/selection.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/theme/durations.dart';
@@ -329,6 +330,7 @@ class _FilterGridAppBarState _buildButtonIcon(context, actionDelegate, action, enabled: canApply(action)),
);
+ final animations = context.select((s) => s.accessibilityAnimations);
return [
...quickActionButtons,
PopupMenuButton(
@@ -366,9 +368,10 @@ class _FilterGridAppBarState with SingleTickerProviderStateMixin
) async {
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
const touchArea = Size(kMinInteractiveDimension, kMinInteractiveDimension);
+ final animations = context.read().accessibilityAnimations;
final selectedAction = await showMenu(
context: context,
position: RelativeRect.fromRect(tapLocalPosition & touchArea, Offset.zero & overlay.size),
@@ -482,10 +484,11 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
MapClusterAction.removeLocation,
].map(_buildMenuItem),
],
+ popUpAnimationStyle: animations.popUpAnimationStyle,
);
if (selectedAction != null) {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
final delegate = EntrySetActionDelegate();
switch (selectedAction) {
case MapClusterAction.editLocation:
diff --git a/lib/widgets/settings/privacy/file_picker/file_picker_page.dart b/lib/widgets/settings/privacy/file_picker/file_picker_page.dart
index a458578b0..668f3d2d8 100644
--- a/lib/widgets/settings/privacy/file_picker/file_picker_page.dart
+++ b/lib/widgets/settings/privacy/file_picker/file_picker_page.dart
@@ -1,5 +1,6 @@
import 'dart:io';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/theme/durations.dart';
@@ -18,6 +19,7 @@ import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
+import 'package:provider/provider.dart';
class FilePickerPage extends StatefulWidget {
static const routeName = '/file_picker';
@@ -57,6 +59,7 @@ class _FilePickerPageState extends State {
return !isHidden;
}
}).toList();
+ final animations = context.select((s) => s.accessibilityAnimations);
return PopScope(
canPop: _directory.relativeDir.isEmpty,
onPopInvoked: (didPop) {
@@ -82,13 +85,14 @@ class _FilePickerPageState extends State {
},
onSelected: (action) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
switch (action) {
case _PickerAction.toggleHiddenView:
settings.filePickerShowHiddenFiles = !showHidden;
setState(() {});
}
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
],
diff --git a/lib/widgets/settings/settings_mobile_page.dart b/lib/widgets/settings/settings_mobile_page.dart
index 27633b15b..c4ee713fd 100644
--- a/lib/widgets/settings/settings_mobile_page.dart
+++ b/lib/widgets/settings/settings_mobile_page.dart
@@ -1,10 +1,11 @@
import 'dart:convert';
import 'dart:typed_data';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
+import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/ref/mime_types.dart';
import 'package:aves/services/common/services.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/action_mixins/feedback.dart';
@@ -45,6 +46,7 @@ class _SettingsMobilePageState extends State with FeedbackMi
@override
Widget build(BuildContext context) {
+ final animations = context.select((s) => s.accessibilityAnimations);
return AvesScaffold(
appBar: AppBar(
title: InteractiveAppBarTitle(
@@ -72,9 +74,10 @@ class _SettingsMobilePageState extends State with FeedbackMi
},
onSelected: (action) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
_onActionSelected(action);
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
].map((v) => FontSizeIconTheme(child: v)).toList(),
),
diff --git a/lib/widgets/viewer/info/info_app_bar.dart b/lib/widgets/viewer/info/info_app_bar.dart
index 178cf8bc1..c3c06e24d 100644
--- a/lib/widgets/viewer/info/info_app_bar.dart
+++ b/lib/widgets/viewer/info/info_app_bar.dart
@@ -2,9 +2,9 @@ import 'package:aves/app_mode.dart';
import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/extensions/props.dart';
import 'package:aves/model/selection.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/view/view.dart';
@@ -49,6 +49,7 @@ class InfoAppBar extends StatelessWidget {
final commonActions = EntryActions.commonMetadataActions.where(isVisible);
final formatSpecificActions = EntryActions.formatSpecificMetadataActions.where(isVisible);
final useTvLayout = settings.useTvLayout;
+ final animations = context.select((s) => s.accessibilityAnimations);
return SliverAppBar(
leading: useTvLayout
? null
@@ -91,9 +92,10 @@ class InfoAppBar extends StatelessWidget {
],
onSelected: (action) async {
// wait for the popup menu to hide before proceeding with the action
- await Future.delayed(ADurations.popupMenuAnimation * timeDilation);
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
actionDelegate.onActionSelected(context, entry, collection, action);
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
].map((v) => FontSizeIconTheme(child: v)).toList(),
floating: true,
diff --git a/lib/widgets/viewer/overlay/viewer_buttons.dart b/lib/widgets/viewer/overlay/viewer_buttons.dart
index 4c3069986..88a8508e5 100644
--- a/lib/widgets/viewer/overlay/viewer_buttons.dart
+++ b/lib/widgets/viewer/overlay/viewer_buttons.dart
@@ -4,9 +4,9 @@ import 'package:aves/app_mode.dart';
import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/extensions/multipage.dart';
import 'package:aves/model/entry/extensions/props.dart';
+import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
-import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/view/view.dart';
import 'package:aves/widgets/common/action_controls/quick_choosers/move_button.dart';
@@ -250,6 +250,7 @@ class _ViewerButtonRowContentState extends State {
final exportActions = widget.exportActions;
final videoActions = widget.videoActions;
final hasOverflowMenu = pageEntry.canRotate || pageEntry.canFlip || topLevelActions.isNotEmpty || exportActions.isNotEmpty || videoActions.isNotEmpty;
+ final animations = context.select((s) => s.accessibilityAnimations);
return Selector(
selector: (context, vc) => vc.getController(pageEntry),
builder: (context, videoController, child) {
@@ -301,10 +302,11 @@ class _ViewerButtonRowContentState extends State {
]
];
},
- onSelected: (action) {
+ onSelected: (action) async {
_popupExpandedNotifier.value = null;
// wait for the popup menu to hide before proceeding with the action
- Future.delayed(ADurations.popupMenuAnimation * timeDilation, () => widget.actionDelegate.onActionSelected(context, action));
+ await Future.delayed(animations.popUpAnimationDelay * timeDilation);
+ widget.actionDelegate.onActionSelected(context, action);
},
onCanceled: () {
_popupExpandedNotifier.value = null;
@@ -316,6 +318,7 @@ class _ViewerButtonRowContentState extends State {
// so we make sure overlay stays visible
const ToggleOverlayNotification(visible: true).dispatch(context);
},
+ popUpAnimationStyle: animations.popUpAnimationStyle,
),
),
),