improved support for disable animations
This commit is contained in:
@@ -683,6 +683,9 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
// Layer 5: Page load progress indicator (animates with toolbar visibility)
|
// Layer 5: Page load progress indicator (animates with toolbar visibility)
|
||||||
Consumer(
|
Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(
|
||||||
|
context,
|
||||||
|
);
|
||||||
final toolbarState = ref.watch(
|
final toolbarState = ref.watch(
|
||||||
toolbarVisibilityControllerProvider(selectedTabId),
|
toolbarVisibilityControllerProvider(selectedTabId),
|
||||||
);
|
);
|
||||||
@@ -691,7 +694,9 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
(!tabInFullScreen &&
|
(!tabInFullScreen &&
|
||||||
toolbarState == ToolbarVisibility.visible);
|
toolbarState == ToolbarVisibility.visible);
|
||||||
return AnimatedPositioned(
|
return AnimatedPositioned(
|
||||||
duration: _AnimatedToolbar._kAnimationDuration,
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: _AnimatedToolbar._kAnimationDuration,
|
||||||
curve: Curves.easeInOutQuart,
|
curve: Curves.easeInOutQuart,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
@@ -730,6 +735,9 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
// Layer 6: Find in Page widget (above toolbar or keyboard, whichever is higher)
|
// Layer 6: Find in Page widget (above toolbar or keyboard, whichever is higher)
|
||||||
Consumer(
|
Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(
|
||||||
|
context,
|
||||||
|
);
|
||||||
final toolbarState = ref.watch(
|
final toolbarState = ref.watch(
|
||||||
toolbarVisibilityControllerProvider(selectedTabId),
|
toolbarVisibilityControllerProvider(selectedTabId),
|
||||||
);
|
);
|
||||||
@@ -738,7 +746,9 @@ class BrowserScreen extends HookConsumerWidget {
|
|||||||
(!tabInFullScreen &&
|
(!tabInFullScreen &&
|
||||||
toolbarState == ToolbarVisibility.visible);
|
toolbarState == ToolbarVisibility.visible);
|
||||||
return AnimatedPositioned(
|
return AnimatedPositioned(
|
||||||
duration: _AnimatedToolbar._kAnimationDuration,
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: _AnimatedToolbar._kAnimationDuration,
|
||||||
curve: Curves.easeInOutQuart,
|
curve: Curves.easeInOutQuart,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
@@ -1111,17 +1121,22 @@ class _SiteSettingsSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final draggableScrollableController = useDraggableScrollableController();
|
final draggableScrollableController = useDraggableScrollableController();
|
||||||
|
|
||||||
void handleClearSiteDataExpansion(bool isExpanded) {
|
void handleClearSiteDataExpansion(bool isExpanded) {
|
||||||
if (isExpanded) {
|
if (isExpanded) {
|
||||||
unawaited(
|
if (disableAnimations) {
|
||||||
draggableScrollableController.animateTo(
|
draggableScrollableController.jumpTo(1.0);
|
||||||
1.0,
|
} else {
|
||||||
duration: const Duration(milliseconds: 300),
|
unawaited(
|
||||||
curve: Curves.decelerate,
|
draggableScrollableController.animateTo(
|
||||||
),
|
1.0,
|
||||||
);
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.decelerate,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class TabViewScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final tabsViewMode = ref.watch(tabsViewModeControllerProvider);
|
final tabsViewMode = ref.watch(tabsViewModeControllerProvider);
|
||||||
final tabsReorderable = ref.watch(tabsReorderableControllerProvider);
|
final tabsReorderable = ref.watch(tabsReorderableControllerProvider);
|
||||||
|
|
||||||
@@ -51,7 +52,10 @@ class TabViewScreen extends HookConsumerWidget {
|
|||||||
final scrollController = useScrollController(keys: [tabsReorderable]);
|
final scrollController = useScrollController(keys: [tabsReorderable]);
|
||||||
|
|
||||||
// Track FAB visibility based on scroll direction
|
// Track FAB visibility based on scroll direction
|
||||||
final isFabVisible = useScrollVisibility(scrollController);
|
final isFabVisible = useScrollVisibility(
|
||||||
|
scrollController,
|
||||||
|
disableAnimations: disableAnimations,
|
||||||
|
);
|
||||||
|
|
||||||
return Dialog.fullscreen(
|
return Dialog.fullscreen(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
@@ -87,11 +91,15 @@ class TabViewScreen extends HookConsumerWidget {
|
|||||||
floatingActionButton: isSyncedScope
|
floatingActionButton: isSyncedScope
|
||||||
? null
|
? null
|
||||||
: AnimatedSlide(
|
: AnimatedSlide(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
opacity: isFabVisible.value ? 1.0 : 0.0,
|
opacity: isFabVisible.value ? 1.0 : 0.0,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
|||||||
+11
-5
@@ -462,6 +462,7 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final showIsolatedTabUi = ref.watch(
|
final showIsolatedTabUi = ref.watch(
|
||||||
generalSettingsWithDefaultsProvider.select((s) => s.showIsolatedTabUi),
|
generalSettingsWithDefaultsProvider.select((s) => s.showIsolatedTabUi),
|
||||||
);
|
);
|
||||||
@@ -523,11 +524,16 @@ class QuickTabSwitcher extends HookConsumerWidget {
|
|||||||
showTitles: showTitles,
|
showTitles: showTitles,
|
||||||
showIsolatedTabUi: showIsolatedTabUi,
|
showIsolatedTabUi: showIsolatedTabUi,
|
||||||
onSelected: (item) async {
|
onSelected: (item) async {
|
||||||
final animation = chipScrollController.animateTo(
|
Future<void>? animation;
|
||||||
0,
|
if (disableAnimations) {
|
||||||
duration: const Duration(milliseconds: 200),
|
chipScrollController.jumpTo(0);
|
||||||
curve: Curves.easeOutBack,
|
} else {
|
||||||
);
|
animation = chipScrollController.animateTo(
|
||||||
|
0,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeOutBack,
|
||||||
|
);
|
||||||
|
}
|
||||||
if (item.isHistory) {
|
if (item.isHistory) {
|
||||||
await ref
|
await ref
|
||||||
.read(tabRepositoryProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
|
|||||||
+4
-1
@@ -47,6 +47,7 @@ class DraggableFab extends HookConsumerWidget {
|
|||||||
final mediaQuery = MediaQuery.of(context);
|
final mediaQuery = MediaQuery.of(context);
|
||||||
final screenSize = mediaQuery.size;
|
final screenSize = mediaQuery.size;
|
||||||
final padding = mediaQuery.padding;
|
final padding = mediaQuery.padding;
|
||||||
|
final disableAnimations = mediaQuery.disableAnimations;
|
||||||
|
|
||||||
final isDragging = useState(false);
|
final isDragging = useState(false);
|
||||||
final customOffset = useState<Offset?>(null);
|
final customOffset = useState<Offset?>(null);
|
||||||
@@ -98,7 +99,9 @@ class DraggableFab extends HookConsumerWidget {
|
|||||||
dragStartPosition.value = null;
|
dragStartPosition.value = null;
|
||||||
},
|
},
|
||||||
child: AnimatedScale(
|
child: AnimatedScale(
|
||||||
duration: const Duration(milliseconds: 150),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 150),
|
||||||
scale: isDragging.value ? 1.1 : 1.0,
|
scale: isDragging.value ? 1.1 : 1.0,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
|||||||
+30
-17
@@ -142,6 +142,7 @@ class _TabGridView extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final canManualReorder = ref.watch(canManualTabReorderProvider);
|
final canManualReorder = ref.watch(canManualTabReorderProvider);
|
||||||
final reorderEnabled = tabsReorderable && canManualReorder;
|
final reorderEnabled = tabsReorderable && canManualReorder;
|
||||||
|
|
||||||
@@ -220,13 +221,17 @@ class _TabGridView extends HookConsumerWidget {
|
|||||||
tabStart >= viewportStart && tabEnd <= viewportEnd;
|
tabStart >= viewportStart && tabEnd <= viewportEnd;
|
||||||
|
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
unawaited(
|
if (disableAnimations) {
|
||||||
scrollController.animateTo(
|
scrollController.jumpTo(tabStart);
|
||||||
tabStart,
|
} else {
|
||||||
duration: const Duration(milliseconds: 200),
|
unawaited(
|
||||||
curve: Curves.easeInOut,
|
scrollController.animateTo(
|
||||||
),
|
tabStart,
|
||||||
);
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
didInitialScroll.value = true;
|
didInitialScroll.value = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -470,21 +475,25 @@ class ViewTabGridWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final isFabVisible = useState(true);
|
final isFabVisible = useState(true);
|
||||||
final lastSheetSize = useRef(0.0);
|
final lastSheetSize = useRef(0.0);
|
||||||
final isInitialized = useRef(false);
|
final isInitialized = useRef(false);
|
||||||
|
|
||||||
// Delay initialization to ignore initial animations
|
// Delay initialization to ignore initial animations
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
final timer = Timer(const Duration(milliseconds: 500), () {
|
final timer = Timer(
|
||||||
isInitialized.value = true;
|
disableAnimations ? Duration.zero : const Duration(milliseconds: 500),
|
||||||
// Initialize lastSheetSize with current size
|
() {
|
||||||
if (draggableScrollableController?.isAttached == true) {
|
isInitialized.value = true;
|
||||||
lastSheetSize.value = draggableScrollableController!.size;
|
// Initialize lastSheetSize with current size
|
||||||
}
|
if (draggableScrollableController?.isAttached == true) {
|
||||||
});
|
lastSheetSize.value = draggableScrollableController!.size;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
return timer.cancel;
|
return timer.cancel;
|
||||||
}, []);
|
}, [disableAnimations]);
|
||||||
|
|
||||||
// Listen to DraggableScrollableController for sheet size changes
|
// Listen to DraggableScrollableController for sheet size changes
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
@@ -571,11 +580,15 @@ class ViewTabGridWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
if (showNewTabFab)
|
if (showNewTabFab)
|
||||||
AnimatedSlide(
|
AnimatedSlide(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
opacity: isFabVisible.value ? 1.0 : 0.0,
|
opacity: isFabVisible.value ? 1.0 : 0.0,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
|
|||||||
+30
-17
@@ -204,6 +204,7 @@ class _TabListView extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLocalTabsView(BuildContext context, WidgetRef ref) {
|
Widget _buildLocalTabsView(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final containerId = ref.watch(selectedContainerProvider);
|
final containerId = ref.watch(selectedContainerProvider);
|
||||||
final canManualReorder = ref.watch(canManualTabReorderProvider);
|
final canManualReorder = ref.watch(canManualTabReorderProvider);
|
||||||
final reorderEnabled = tabsReorderable && canManualReorder;
|
final reorderEnabled = tabsReorderable && canManualReorder;
|
||||||
@@ -263,13 +264,17 @@ class _TabListView extends HookConsumerWidget {
|
|||||||
scrollController.position.maxScrollExtent,
|
scrollController.position.maxScrollExtent,
|
||||||
);
|
);
|
||||||
|
|
||||||
unawaited(
|
if (disableAnimations) {
|
||||||
scrollController.animateTo(
|
scrollController.jumpTo(targetOffset);
|
||||||
targetOffset,
|
} else {
|
||||||
duration: const Duration(milliseconds: 200),
|
unawaited(
|
||||||
curve: Curves.easeInOut,
|
scrollController.animateTo(
|
||||||
),
|
targetOffset,
|
||||||
);
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
didInitialScroll.value = true;
|
didInitialScroll.value = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -465,6 +470,7 @@ class ViewTabListWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final isSyncedScope = ref.watch(
|
final isSyncedScope = ref.watch(
|
||||||
effectiveTabsTrayScopeProvider.select(
|
effectiveTabsTrayScopeProvider.select(
|
||||||
(scope) => scope == TabsTrayScope.synced,
|
(scope) => scope == TabsTrayScope.synced,
|
||||||
@@ -477,15 +483,18 @@ class ViewTabListWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Delay initialization to ignore initial animations
|
// Delay initialization to ignore initial animations
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
final timer = Timer(const Duration(milliseconds: 500), () {
|
final timer = Timer(
|
||||||
isInitialized.value = true;
|
disableAnimations ? Duration.zero : const Duration(milliseconds: 500),
|
||||||
// Initialize lastSheetSize with current size
|
() {
|
||||||
if (draggableScrollableController?.isAttached == true) {
|
isInitialized.value = true;
|
||||||
lastSheetSize.value = draggableScrollableController!.size;
|
// Initialize lastSheetSize with current size
|
||||||
}
|
if (draggableScrollableController?.isAttached == true) {
|
||||||
});
|
lastSheetSize.value = draggableScrollableController!.size;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
return timer.cancel;
|
return timer.cancel;
|
||||||
}, []);
|
}, [disableAnimations]);
|
||||||
|
|
||||||
// Listen to DraggableScrollableController for sheet size changes
|
// Listen to DraggableScrollableController for sheet size changes
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
@@ -572,11 +581,15 @@ class ViewTabListWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
if (showNewTabFab && !isSyncedScope)
|
if (showNewTabFab && !isSyncedScope)
|
||||||
AnimatedSlide(
|
AnimatedSlide(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
offset: isFabVisible.value ? Offset.zero : const Offset(0, 2),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
opacity: isFabVisible.value ? 1.0 : 0.0,
|
opacity: isFabVisible.value ? 1.0 : 0.0,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
|
|||||||
+14
-7
@@ -211,6 +211,9 @@ class ViewTabTreesWidget extends HookConsumerWidget {
|
|||||||
child: HookConsumer(
|
child: HookConsumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
final containerId = ref.watch(selectedContainerProvider);
|
final containerId = ref.watch(selectedContainerProvider);
|
||||||
|
|
||||||
@@ -265,13 +268,17 @@ class ViewTabTreesWidget extends HookConsumerWidget {
|
|||||||
final offset = (index ~/ 2) * itemSize.height;
|
final offset = (index ~/ 2) * itemSize.height;
|
||||||
|
|
||||||
if (offset != scrollController.offset) {
|
if (offset != scrollController.offset) {
|
||||||
unawaited(
|
if (disableAnimations) {
|
||||||
scrollController.animateTo(
|
scrollController.jumpTo(offset);
|
||||||
offset,
|
} else {
|
||||||
duration: const Duration(milliseconds: 200),
|
unawaited(
|
||||||
curve: Curves.easeInOut,
|
scrollController.animateTo(
|
||||||
),
|
offset,
|
||||||
);
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -126,6 +126,7 @@ class _Segment extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final colorScheme = theme.colorScheme;
|
final colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
@@ -140,7 +141,9 @@ class _Segment extends StatelessWidget {
|
|||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeOutCubic,
|
curve: Curves.easeOutCubic,
|
||||||
color: bgColor,
|
color: bgColor,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
@@ -149,7 +152,9 @@ class _Segment extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Icon(icon, color: fgColor, size: 18),
|
Icon(icon, color: fgColor, size: 18),
|
||||||
AnimatedSize(
|
AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeOutCubic,
|
curve: Curves.easeOutCubic,
|
||||||
child: isSelected
|
child: isSelected
|
||||||
? Padding(
|
? Padding(
|
||||||
|
|||||||
+4
-1
@@ -54,6 +54,7 @@ class SearchModuleHeader extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final isCollapsed = displayState == SearchModuleDisplayState.collapsed;
|
final isCollapsed = displayState == SearchModuleDisplayState.collapsed;
|
||||||
final isExpanded = displayState == SearchModuleDisplayState.expanded;
|
final isExpanded = displayState == SearchModuleDisplayState.expanded;
|
||||||
final showTrailing = !isCollapsed && totalCount > previewLimit;
|
final showTrailing = !isCollapsed && totalCount > previewLimit;
|
||||||
@@ -75,7 +76,9 @@ class SearchModuleHeader extends StatelessWidget {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
AnimatedRotation(
|
AnimatedRotation(
|
||||||
turns: isCollapsed ? -0.25 : 0,
|
turns: isCollapsed ? -0.25 : 0,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 200),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.expand_more,
|
Icons.expand_more,
|
||||||
size: 20,
|
size: 20,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final selectedColor = useState(initialContainer.color);
|
final selectedColor = useState(initialContainer.color);
|
||||||
final contextualIdentity = useState(
|
final contextualIdentity = useState(
|
||||||
initialContainer.metadata.contextualIdentity,
|
initialContainer.metadata.contextualIdentity,
|
||||||
@@ -136,7 +137,9 @@ class ContainerEditScreen extends HookConsumerWidget {
|
|||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 300),
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 24,
|
width: 24,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|||||||
+10
-5
@@ -67,6 +67,7 @@ class _MaterialPickerState extends State<MaterialPicker> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
final isPortrait =
|
final isPortrait =
|
||||||
MediaQuery.of(context).orientation == Orientation.portrait ||
|
MediaQuery.of(context).orientation == Orientation.portrait ||
|
||||||
widget.portraitOnly;
|
widget.portraitOnly;
|
||||||
@@ -143,7 +144,9 @@ class _MaterialPickerState extends State<MaterialPicker> {
|
|||||||
: const EdgeInsets.fromLTRB(7, 0, 7, 0),
|
: const EdgeInsets.fromLTRB(7, 0, 7, 0),
|
||||||
child: Align(
|
child: Align(
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 300),
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -235,7 +238,9 @@ class _MaterialPickerState extends State<MaterialPicker> {
|
|||||||
child: Align(
|
child: Align(
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: disableAnimations
|
||||||
|
? Duration.zero
|
||||||
|
: const Duration(milliseconds: 500),
|
||||||
width: isPortrait
|
width: isPortrait
|
||||||
? (_currentShading == color ? 250 : 230)
|
? (_currentShading == color ? 250 : 230)
|
||||||
: (_currentShading == color ? 50 : 30),
|
: (_currentShading == color ? 50 : 30),
|
||||||
@@ -308,9 +313,9 @@ class _MaterialPickerState extends State<MaterialPicker> {
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
: AnimatedOpacity(
|
: AnimatedOpacity(
|
||||||
duration: const Duration(
|
duration: disableAnimations
|
||||||
milliseconds: 300,
|
? Duration.zero
|
||||||
),
|
: const Duration(milliseconds: 300),
|
||||||
opacity: _currentShading == color
|
opacity: _currentShading == color
|
||||||
? 1
|
? 1
|
||||||
: 0,
|
: 0,
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class OnboardingScreen extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
||||||
|
|
||||||
final pageController = usePageController();
|
final pageController = usePageController();
|
||||||
|
|
||||||
@@ -95,10 +96,14 @@ class OnboardingScreen extends HookConsumerWidget {
|
|||||||
visible: currentPage.value > 0,
|
visible: currentPage.value > 0,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await pageController.previousPage(
|
if (disableAnimations) {
|
||||||
duration: const Duration(milliseconds: 250),
|
pageController.jumpToPage(currentPage.value - 1);
|
||||||
curve: Curves.easeInOut,
|
} else {
|
||||||
);
|
await pageController.previousPage(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.chevron_left),
|
icon: const Icon(Icons.chevron_left),
|
||||||
label: const Text('Previous'),
|
label: const Text('Previous'),
|
||||||
@@ -121,10 +126,14 @@ class OnboardingScreen extends HookConsumerWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await pageController.nextPage(
|
if (disableAnimations) {
|
||||||
duration: const Duration(milliseconds: 250),
|
pageController.jumpToPage(currentPage.value + 1);
|
||||||
curve: Curves.easeInOut,
|
} else {
|
||||||
);
|
await pageController.nextPage(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
iconAlignment: IconAlignment.end,
|
iconAlignment: IconAlignment.end,
|
||||||
icon: const Icon(Icons.chevron_right),
|
icon: const Icon(Icons.chevron_right),
|
||||||
|
|||||||
@@ -44,43 +44,59 @@ ValueNotifier<bool> useScrollVisibility(
|
|||||||
double hideThreshold = 5.0,
|
double hideThreshold = 5.0,
|
||||||
double showThreshold = 5.0,
|
double showThreshold = 5.0,
|
||||||
Duration initializationDelay = const Duration(milliseconds: 1000),
|
Duration initializationDelay = const Duration(milliseconds: 1000),
|
||||||
|
bool disableAnimations = false,
|
||||||
}) {
|
}) {
|
||||||
final isVisible = useState(true);
|
final isVisible = useState(true);
|
||||||
final lastScrollOffset = useRef(0.0);
|
final lastScrollOffset = useRef(0.0);
|
||||||
final isInitialized = useRef(false);
|
final isInitialized = useRef(false);
|
||||||
|
|
||||||
useEffect(() {
|
useEffect(
|
||||||
// Start timer to enable scroll listener after initialization delay
|
() {
|
||||||
final timer = Timer(initializationDelay, () {
|
// Start timer to enable scroll listener after initialization delay
|
||||||
isInitialized.value = true;
|
final timer = Timer(
|
||||||
});
|
disableAnimations ? Duration.zero : initializationDelay,
|
||||||
|
() {
|
||||||
|
if (scrollController.hasClients) {
|
||||||
|
lastScrollOffset.value = scrollController.offset;
|
||||||
|
}
|
||||||
|
isInitialized.value = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
void scrollListener() {
|
void scrollListener() {
|
||||||
// Ignore scroll events until initialization is complete
|
// Ignore scroll events until initialization is complete
|
||||||
if (!isInitialized.value) return;
|
if (!isInitialized.value) return;
|
||||||
|
|
||||||
final currentOffset = scrollController.offset;
|
final currentOffset = scrollController.offset;
|
||||||
final difference = currentOffset - lastScrollOffset.value;
|
final difference = currentOffset - lastScrollOffset.value;
|
||||||
|
|
||||||
// Hide when scrolling down beyond threshold
|
// Hide when scrolling down beyond threshold
|
||||||
if (difference > hideThreshold && isVisible.value) {
|
if (difference > hideThreshold && isVisible.value) {
|
||||||
isVisible.value = false;
|
isVisible.value = false;
|
||||||
}
|
}
|
||||||
// Show when scrolling up beyond threshold or at top
|
// Show when scrolling up beyond threshold or at top
|
||||||
else if ((difference < -showThreshold || currentOffset <= 0) &&
|
else if ((difference < -showThreshold || currentOffset <= 0) &&
|
||||||
!isVisible.value) {
|
!isVisible.value) {
|
||||||
isVisible.value = true;
|
isVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastScrollOffset.value = currentOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastScrollOffset.value = currentOffset;
|
scrollController.addListener(scrollListener);
|
||||||
}
|
return () {
|
||||||
|
timer.cancel();
|
||||||
scrollController.addListener(scrollListener);
|
scrollController.removeListener(scrollListener);
|
||||||
return () {
|
};
|
||||||
timer.cancel();
|
},
|
||||||
scrollController.removeListener(scrollListener);
|
[
|
||||||
};
|
scrollController,
|
||||||
}, [scrollController, hideThreshold, showThreshold, initializationDelay]);
|
hideThreshold,
|
||||||
|
showThreshold,
|
||||||
|
initializationDelay,
|
||||||
|
disableAnimations,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
return isVisible;
|
return isVisible;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,19 @@ void useSyncPageWithTab(
|
|||||||
TabController tabController,
|
TabController tabController,
|
||||||
PageController pageController, {
|
PageController pageController, {
|
||||||
void Function(int index)? onIndexChanged,
|
void Function(int index)? onIndexChanged,
|
||||||
|
bool disableAnimations = false,
|
||||||
}) {
|
}) {
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
Future<void> syncPage() async {
|
Future<void> syncPage() async {
|
||||||
await pageController.animateToPage(
|
if (disableAnimations) {
|
||||||
tabController.index,
|
pageController.jumpToPage(tabController.index);
|
||||||
curve: Curves.linear,
|
} else {
|
||||||
duration: const Duration(milliseconds: 300),
|
await pageController.animateToPage(
|
||||||
);
|
tabController.index,
|
||||||
|
curve: Curves.linear,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
);
|
||||||
|
}
|
||||||
onIndexChanged?.call(tabController.index);
|
onIndexChanged?.call(tabController.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +44,10 @@ void useSyncPageWithTab(
|
|||||||
if (!tabController.indexIsChanging) {
|
if (!tabController.indexIsChanging) {
|
||||||
final index = pageController.page!.round();
|
final index = pageController.page!.round();
|
||||||
|
|
||||||
tabController.animateTo(index);
|
tabController.animateTo(
|
||||||
|
index,
|
||||||
|
duration: disableAnimations ? Duration.zero : kTabScrollDuration,
|
||||||
|
);
|
||||||
onIndexChanged?.call(index);
|
onIndexChanged?.call(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,5 +59,5 @@ void useSyncPageWithTab(
|
|||||||
tabController.removeListener(syncPage);
|
tabController.removeListener(syncPage);
|
||||||
pageController.removeListener(syncTab);
|
pageController.removeListener(syncTab);
|
||||||
};
|
};
|
||||||
}, [tabController, pageController]);
|
}, [tabController, pageController, disableAnimations]);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user