added time-to-take-action 3s option;

use stretch over bouncing overscroll;
fixed time shift wheel scroll bar
This commit is contained in:
Thibault Deckers 2022-05-23 12:34:41 +09:00
parent 512c507942
commit 44ed934a8c
8 changed files with 65 additions and 46 deletions

View file

@ -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:

View file

@ -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 }

View file

@ -81,14 +81,13 @@ class _FilterBarState extends State<FilterBar> {
color: Colors.transparent,
height: FilterBar.preferredHeight,
child: NotificationListener<ScrollNotification>(
// 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();

View file

@ -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:

View file

@ -41,39 +41,51 @@ class _WheelSelectorState<T> extends State<WheelSelector<T>> {
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<ScrollNotification>(
// 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(),
),
),
),
),
),

View file

@ -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();

View file

@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
class AvesDialog extends StatelessWidget {
final String? title;
final ScrollController? scrollController;
final ScrollController scrollController;
final List<Widget>? 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,
),
);

View file

@ -54,7 +54,6 @@ class _CrumbLineState extends State<CrumbLine> {
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(