From 44ed934a8c7a034e044ffe844304da53d555c79b Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 23 May 2022 12:34:41 +0900 Subject: [PATCH] added time-to-take-action 3s option; use stretch over bouncing overscroll; fixed time shift wheel scroll bar --- .../settings/enums/accessibility_timeout.dart | 2 + lib/model/settings/enums/enums.dart | 2 +- lib/widgets/collection/filter_bar.dart | 3 +- .../common/action_mixins/feedback.dart | 2 + lib/widgets/common/basic/wheel.dart | 78 +++++++++++-------- lib/widgets/common/expandable_filter_row.dart | 1 - lib/widgets/dialogs/aves_dialog.dart | 22 ++++-- .../privacy/file_picker/crumb_line.dart | 1 - 8 files changed, 65 insertions(+), 46 deletions(-) diff --git a/lib/model/settings/enums/accessibility_timeout.dart b/lib/model/settings/enums/accessibility_timeout.dart index b5ef55d78..d9b9f1ebd 100644 --- a/lib/model/settings/enums/accessibility_timeout.dart +++ b/lib/model/settings/enums/accessibility_timeout.dart @@ -10,6 +10,8 @@ extension ExtraAccessibilityTimeout on AccessibilityTimeout { return context.l10n.settingsSystemDefault; case AccessibilityTimeout.appDefault: return context.l10n.settingsDefault; + case AccessibilityTimeout.s3: + return context.l10n.timeSeconds(3); case AccessibilityTimeout.s10: return context.l10n.timeSeconds(10); case AccessibilityTimeout.s30: diff --git a/lib/model/settings/enums/enums.dart b/lib/model/settings/enums/enums.dart index 073555371..6ec4c8714 100644 --- a/lib/model/settings/enums/enums.dart +++ b/lib/model/settings/enums/enums.dart @@ -1,6 +1,6 @@ enum AccessibilityAnimations { system, disabled, enabled } -enum AccessibilityTimeout { system, appDefault, s10, s30, s60, s120 } +enum AccessibilityTimeout { system, appDefault, s3, s10, s30, s60, s120 } enum AvesThemeColorMode { monochrome, polychrome } diff --git a/lib/widgets/collection/filter_bar.dart b/lib/widgets/collection/filter_bar.dart index f6b779cbd..ee4129c49 100644 --- a/lib/widgets/collection/filter_bar.dart +++ b/lib/widgets/collection/filter_bar.dart @@ -81,14 +81,13 @@ class _FilterBarState extends State { color: Colors.transparent, height: FilterBar.preferredHeight, child: NotificationListener( - // cancel notification bubbling so that the draggable scrollbar + // cancel notification bubbling so that the draggable scroll bar // does not misinterpret filter bar scrolling for collection scrolling onNotification: (notification) => true, child: AnimatedList( key: _animatedListKey, initialItemCount: widget.filters.length, scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 4), itemBuilder: (context, index, animation) { if (index >= widget.filters.length) return const SizedBox(); diff --git a/lib/widgets/common/action_mixins/feedback.dart b/lib/widgets/common/action_mixins/feedback.dart index df15e5a22..c302e6ebb 100644 --- a/lib/widgets/common/action_mixins/feedback.dart +++ b/lib/widgets/common/action_mixins/feedback.dart @@ -105,6 +105,8 @@ mixin FeedbackMixin { return Duration(milliseconds: millis); case AccessibilityTimeout.appDefault: return appDefaultDuration; + case AccessibilityTimeout.s3: + return const Duration(seconds: 3); case AccessibilityTimeout.s10: return const Duration(seconds: 10); case AccessibilityTimeout.s30: diff --git a/lib/widgets/common/basic/wheel.dart b/lib/widgets/common/basic/wheel.dart index c6b552b6c..1f47a87af 100644 --- a/lib/widgets/common/basic/wheel.dart +++ b/lib/widgets/common/basic/wheel.dart @@ -41,39 +41,51 @@ class _WheelSelectorState extends State> { const background = Colors.transparent; final foreground = DefaultTextStyle.of(context).style.color!; - return Padding( - padding: const EdgeInsets.all(8), - child: SizedBox( - width: itemSize.width, - height: itemSize.height * 3, - child: ShaderMask( - shaderCallback: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - background, - foreground, - foreground, - background, - ], - ).createShader, - child: ListWheelScrollView( - controller: _controller, - physics: const FixedExtentScrollPhysics(parent: BouncingScrollPhysics()), - diameterRatio: 1.2, - itemExtent: itemSize.height, - squeeze: 1.3, - onSelectedItemChanged: (i) => valueNotifier.value = values[i], - children: values - .map((i) => SizedBox.fromSize( - size: itemSize, - child: Text( - '$i', - textAlign: widget.textAlign, - style: widget.textStyle, - ), - )) - .toList(), + return NotificationListener( + // cancel notification bubbling so that the dialog scroll bar + // does not misinterpret wheel scrolling for dialog content scrolling + onNotification: (notification) => true, + child: Padding( + padding: const EdgeInsets.all(8), + child: SizedBox( + width: itemSize.width, + height: itemSize.height * 3, + child: ShaderMask( + shaderCallback: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + background, + foreground, + foreground, + background, + ], + ).createShader, + child: Theme( + data: Theme.of(context).copyWith( + scrollbarTheme: ScrollbarThemeData( + thumbVisibility: MaterialStateProperty.all(false), + ), + ), + child: ListWheelScrollView( + controller: _controller, + physics: const FixedExtentScrollPhysics(parent: BouncingScrollPhysics()), + diameterRatio: 1.2, + itemExtent: itemSize.height, + squeeze: 1.3, + onSelectedItemChanged: (i) => valueNotifier.value = values[i], + children: values + .map((i) => SizedBox.fromSize( + size: itemSize, + child: Text( + '$i', + textAlign: widget.textAlign, + style: widget.textStyle, + ), + )) + .toList(), + ), + ), ), ), ), diff --git a/lib/widgets/common/expandable_filter_row.dart b/lib/widgets/common/expandable_filter_row.dart index 903412dc8..fc3083d93 100644 --- a/lib/widgets/common/expandable_filter_row.dart +++ b/lib/widgets/common/expandable_filter_row.dart @@ -78,7 +78,6 @@ class ExpandableFilterRow extends StatelessWidget { height: AvesFilterChip.minChipHeight, child: ListView.separated( scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: horizontalPadding), itemBuilder: (context, index) { return index < filterList.length ? _buildFilterChip(filterList[index]) : const SizedBox(); diff --git a/lib/widgets/dialogs/aves_dialog.dart b/lib/widgets/dialogs/aves_dialog.dart index 42a27caa8..0421e4fc5 100644 --- a/lib/widgets/dialogs/aves_dialog.dart +++ b/lib/widgets/dialogs/aves_dialog.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; class AvesDialog extends StatelessWidget { final String? title; - final ScrollController? scrollController; + final ScrollController scrollController; final List? scrollableContent; final bool hasScrollBar; final double horizontalContentPadding; @@ -16,16 +16,17 @@ class AvesDialog extends StatelessWidget { static const double controlCaptionPadding = 16; static const double borderWidth = 1.0; - const AvesDialog({ + AvesDialog({ super.key, this.title, - this.scrollController, + ScrollController? scrollController, this.scrollableContent, this.hasScrollBar = true, this.horizontalContentPadding = defaultHorizontalContentPadding, this.content, required this.actions, - }) : assert((scrollableContent != null) ^ (content != null)); + }) : assert((scrollableContent != null) ^ (content != null)), + scrollController = scrollController ?? ScrollController(); @override Widget build(BuildContext context) { @@ -56,10 +57,8 @@ class AvesDialog extends StatelessWidget { } if (scrollableContent != null) { - final _scrollController = scrollController ?? ScrollController(); - Widget child = ListView( - controller: _scrollController, + controller: scrollController, shrinkWrap: true, children: scrollableContent!, ); @@ -76,7 +75,14 @@ class AvesDialog extends StatelessWidget { ), ), child: Scrollbar( - controller: _scrollController, + controller: scrollController, + notificationPredicate: (notification) { + // as of Flutter v3.0.1, the `Scrollbar` does not only respond to the nearest `ScrollView` + // despite the `defaultScrollNotificationPredicate` checking notification depth, + // as the notifications coming from the controller in `ListWheelScrollView` in `WheelSelector` still have a depth of 0. + // Cancelling notification bubbling seems ineffective, so we check the metrics type as a workaround. + return defaultScrollNotificationPredicate(notification) && notification.metrics is! FixedExtentMetrics; + }, child: child, ), ); diff --git a/lib/widgets/settings/privacy/file_picker/crumb_line.dart b/lib/widgets/settings/privacy/file_picker/crumb_line.dart index d25c29e54..e38838d64 100644 --- a/lib/widgets/settings/privacy/file_picker/crumb_line.dart +++ b/lib/widgets/settings/privacy/file_picker/crumb_line.dart @@ -54,7 +54,6 @@ class _CrumbLineState extends State { child: ListView.builder( scrollDirection: Axis.horizontal, controller: _controller, - physics: const BouncingScrollPhysics(), padding: const EdgeInsets.symmetric(horizontal: 8), itemBuilder: (context, index) { Widget _buildText(String text) => Padding(