added time-to-take-action 3s option;
use stretch over bouncing overscroll; fixed time shift wheel scroll bar
This commit is contained in:
parent
512c507942
commit
44ed934a8c
8 changed files with 65 additions and 46 deletions
|
@ -10,6 +10,8 @@ extension ExtraAccessibilityTimeout on AccessibilityTimeout {
|
||||||
return context.l10n.settingsSystemDefault;
|
return context.l10n.settingsSystemDefault;
|
||||||
case AccessibilityTimeout.appDefault:
|
case AccessibilityTimeout.appDefault:
|
||||||
return context.l10n.settingsDefault;
|
return context.l10n.settingsDefault;
|
||||||
|
case AccessibilityTimeout.s3:
|
||||||
|
return context.l10n.timeSeconds(3);
|
||||||
case AccessibilityTimeout.s10:
|
case AccessibilityTimeout.s10:
|
||||||
return context.l10n.timeSeconds(10);
|
return context.l10n.timeSeconds(10);
|
||||||
case AccessibilityTimeout.s30:
|
case AccessibilityTimeout.s30:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
enum AccessibilityAnimations { system, disabled, enabled }
|
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 }
|
enum AvesThemeColorMode { monochrome, polychrome }
|
||||||
|
|
||||||
|
|
|
@ -81,14 +81,13 @@ class _FilterBarState extends State<FilterBar> {
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
height: FilterBar.preferredHeight,
|
height: FilterBar.preferredHeight,
|
||||||
child: NotificationListener<ScrollNotification>(
|
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
|
// does not misinterpret filter bar scrolling for collection scrolling
|
||||||
onNotification: (notification) => true,
|
onNotification: (notification) => true,
|
||||||
child: AnimatedList(
|
child: AnimatedList(
|
||||||
key: _animatedListKey,
|
key: _animatedListKey,
|
||||||
initialItemCount: widget.filters.length,
|
initialItemCount: widget.filters.length,
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
physics: const BouncingScrollPhysics(),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
itemBuilder: (context, index, animation) {
|
itemBuilder: (context, index, animation) {
|
||||||
if (index >= widget.filters.length) return const SizedBox();
|
if (index >= widget.filters.length) return const SizedBox();
|
||||||
|
|
|
@ -105,6 +105,8 @@ mixin FeedbackMixin {
|
||||||
return Duration(milliseconds: millis);
|
return Duration(milliseconds: millis);
|
||||||
case AccessibilityTimeout.appDefault:
|
case AccessibilityTimeout.appDefault:
|
||||||
return appDefaultDuration;
|
return appDefaultDuration;
|
||||||
|
case AccessibilityTimeout.s3:
|
||||||
|
return const Duration(seconds: 3);
|
||||||
case AccessibilityTimeout.s10:
|
case AccessibilityTimeout.s10:
|
||||||
return const Duration(seconds: 10);
|
return const Duration(seconds: 10);
|
||||||
case AccessibilityTimeout.s30:
|
case AccessibilityTimeout.s30:
|
||||||
|
|
|
@ -41,39 +41,51 @@ class _WheelSelectorState<T> extends State<WheelSelector<T>> {
|
||||||
const background = Colors.transparent;
|
const background = Colors.transparent;
|
||||||
final foreground = DefaultTextStyle.of(context).style.color!;
|
final foreground = DefaultTextStyle.of(context).style.color!;
|
||||||
|
|
||||||
return Padding(
|
return NotificationListener<ScrollNotification>(
|
||||||
padding: const EdgeInsets.all(8),
|
// cancel notification bubbling so that the dialog scroll bar
|
||||||
child: SizedBox(
|
// does not misinterpret wheel scrolling for dialog content scrolling
|
||||||
width: itemSize.width,
|
onNotification: (notification) => true,
|
||||||
height: itemSize.height * 3,
|
child: Padding(
|
||||||
child: ShaderMask(
|
padding: const EdgeInsets.all(8),
|
||||||
shaderCallback: LinearGradient(
|
child: SizedBox(
|
||||||
begin: Alignment.topCenter,
|
width: itemSize.width,
|
||||||
end: Alignment.bottomCenter,
|
height: itemSize.height * 3,
|
||||||
colors: [
|
child: ShaderMask(
|
||||||
background,
|
shaderCallback: LinearGradient(
|
||||||
foreground,
|
begin: Alignment.topCenter,
|
||||||
foreground,
|
end: Alignment.bottomCenter,
|
||||||
background,
|
colors: [
|
||||||
],
|
background,
|
||||||
).createShader,
|
foreground,
|
||||||
child: ListWheelScrollView(
|
foreground,
|
||||||
controller: _controller,
|
background,
|
||||||
physics: const FixedExtentScrollPhysics(parent: BouncingScrollPhysics()),
|
],
|
||||||
diameterRatio: 1.2,
|
).createShader,
|
||||||
itemExtent: itemSize.height,
|
child: Theme(
|
||||||
squeeze: 1.3,
|
data: Theme.of(context).copyWith(
|
||||||
onSelectedItemChanged: (i) => valueNotifier.value = values[i],
|
scrollbarTheme: ScrollbarThemeData(
|
||||||
children: values
|
thumbVisibility: MaterialStateProperty.all(false),
|
||||||
.map((i) => SizedBox.fromSize(
|
),
|
||||||
size: itemSize,
|
),
|
||||||
child: Text(
|
child: ListWheelScrollView(
|
||||||
'$i',
|
controller: _controller,
|
||||||
textAlign: widget.textAlign,
|
physics: const FixedExtentScrollPhysics(parent: BouncingScrollPhysics()),
|
||||||
style: widget.textStyle,
|
diameterRatio: 1.2,
|
||||||
),
|
itemExtent: itemSize.height,
|
||||||
))
|
squeeze: 1.3,
|
||||||
.toList(),
|
onSelectedItemChanged: (i) => valueNotifier.value = values[i],
|
||||||
|
children: values
|
||||||
|
.map((i) => SizedBox.fromSize(
|
||||||
|
size: itemSize,
|
||||||
|
child: Text(
|
||||||
|
'$i',
|
||||||
|
textAlign: widget.textAlign,
|
||||||
|
style: widget.textStyle,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -78,7 +78,6 @@ class ExpandableFilterRow extends StatelessWidget {
|
||||||
height: AvesFilterChip.minChipHeight,
|
height: AvesFilterChip.minChipHeight,
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
physics: const BouncingScrollPhysics(),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: horizontalPadding),
|
padding: const EdgeInsets.symmetric(horizontal: horizontalPadding),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return index < filterList.length ? _buildFilterChip(filterList[index]) : const SizedBox();
|
return index < filterList.length ? _buildFilterChip(filterList[index]) : const SizedBox();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AvesDialog extends StatelessWidget {
|
class AvesDialog extends StatelessWidget {
|
||||||
final String? title;
|
final String? title;
|
||||||
final ScrollController? scrollController;
|
final ScrollController scrollController;
|
||||||
final List<Widget>? scrollableContent;
|
final List<Widget>? scrollableContent;
|
||||||
final bool hasScrollBar;
|
final bool hasScrollBar;
|
||||||
final double horizontalContentPadding;
|
final double horizontalContentPadding;
|
||||||
|
@ -16,16 +16,17 @@ class AvesDialog extends StatelessWidget {
|
||||||
static const double controlCaptionPadding = 16;
|
static const double controlCaptionPadding = 16;
|
||||||
static const double borderWidth = 1.0;
|
static const double borderWidth = 1.0;
|
||||||
|
|
||||||
const AvesDialog({
|
AvesDialog({
|
||||||
super.key,
|
super.key,
|
||||||
this.title,
|
this.title,
|
||||||
this.scrollController,
|
ScrollController? scrollController,
|
||||||
this.scrollableContent,
|
this.scrollableContent,
|
||||||
this.hasScrollBar = true,
|
this.hasScrollBar = true,
|
||||||
this.horizontalContentPadding = defaultHorizontalContentPadding,
|
this.horizontalContentPadding = defaultHorizontalContentPadding,
|
||||||
this.content,
|
this.content,
|
||||||
required this.actions,
|
required this.actions,
|
||||||
}) : assert((scrollableContent != null) ^ (content != null));
|
}) : assert((scrollableContent != null) ^ (content != null)),
|
||||||
|
scrollController = scrollController ?? ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -56,10 +57,8 @@ class AvesDialog extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrollableContent != null) {
|
if (scrollableContent != null) {
|
||||||
final _scrollController = scrollController ?? ScrollController();
|
|
||||||
|
|
||||||
Widget child = ListView(
|
Widget child = ListView(
|
||||||
controller: _scrollController,
|
controller: scrollController,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: scrollableContent!,
|
children: scrollableContent!,
|
||||||
);
|
);
|
||||||
|
@ -76,7 +75,14 @@ class AvesDialog extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Scrollbar(
|
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,
|
child: child,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,7 +54,6 @@ class _CrumbLineState extends State<CrumbLine> {
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
physics: const BouncingScrollPhysics(),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
Widget _buildText(String text) => Padding(
|
Widget _buildText(String text) => Padding(
|
||||||
|
|
Loading…
Reference in a new issue