From 19fc039723bf87eb34f82cc06b2e3aab7d59bf78 Mon Sep 17 00:00:00 2001 From: Vadim <44135514+vodemn@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:26:34 +0100 Subject: [PATCH] ML-137 Dialogs improvements (#138) * Force dialogs to have the same width * Fix `DialogPicker` bouncing when the first selected item is near the end --- .../dialog_filter/widget_dialog_filter.dart | 148 +++++++++--------- .../dialog_picker/widget_dialog_picker.dart | 40 ++--- .../widget_dialog_picker_range.dart | 79 +++++----- 3 files changed, 139 insertions(+), 128 deletions(-) diff --git a/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart b/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart index 76cd729..eb03e23 100644 --- a/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart +++ b/lib/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/res/dimens.dart'; @@ -34,18 +35,20 @@ class _DialogFilterState extends State> { bool get _hasAnySelected => checkboxValues.contains(true); bool get _hasAnyUnselected => checkboxValues.contains(false); - late final ScrollController _scrollController; + final ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); - int i = 0; - for (; i < checkboxValues.length; i++) { - if (checkboxValues[i]) { - break; + SchedulerBinding.instance.addPostFrameCallback((_) { + int i = 0; + for (; i < checkboxValues.length; i++) { + if (checkboxValues[i]) { + break; + } } - } - _scrollController = ScrollController(initialScrollOffset: Dimens.grid56 * i); + _scrollController.jumpTo((Dimens.grid56 * i).clamp(0, _scrollController.position.maxScrollExtent)); + }); } @override @@ -61,79 +64,80 @@ class _DialogFilterState extends State> { titlePadding: Dimens.dialogIconTitlePadding, title: Text(widget.title), contentPadding: EdgeInsets.zero, - content: Column( - children: [ - Padding( - padding: Dimens.dialogIconTitlePadding, - child: Text(widget.description), - ), - const Divider(), - Expanded( - child: SingleChildScrollView( - controller: _scrollController, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.min, - children: List.generate( - widget.values.length, - (index) => CheckboxListTile( - value: checkboxValues[index], - controlAffinity: ListTileControlAffinity.leading, - title: Text( - widget.titleAdapter(context, widget.values[index]), - style: Theme.of(context).textTheme.bodyLarge, + content: SizedBox( + width: double.maxFinite, + child: Column( + children: [ + Padding( + padding: Dimens.dialogIconTitlePadding, + child: Text(widget.description), + ), + const Divider(), + Expanded( + child: SingleChildScrollView( + controller: _scrollController, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: List.generate( + widget.values.length, + (index) => CheckboxListTile( + value: checkboxValues[index], + controlAffinity: ListTileControlAffinity.leading, + title: Text( + widget.titleAdapter(context, widget.values[index]), + style: Theme.of(context).textTheme.bodyLarge, + ), + onChanged: (value) { + if (value != null) { + setState(() { + checkboxValues[index] = value; + }); + } + }, ), - onChanged: (value) { - if (value != null) { - setState(() { - checkboxValues[index] = value; - }); - } - }, ), ), ), ), - ), - const Divider(), - Padding( - padding: Dimens.dialogActionsPadding, - child: Row( - children: [ - SizedBox( - width: 40, - child: IconButton( - padding: EdgeInsets.zero, - icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect), - onPressed: _toggleAll, - tooltip: _hasAnyUnselected - ? S.of(context).tooltipSelectAll - : S.of(context).tooltipDesecelectAll, + const Divider(), + Padding( + padding: Dimens.dialogActionsPadding, + child: Row( + children: [ + SizedBox( + width: 40, + child: IconButton( + padding: EdgeInsets.zero, + icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect), + onPressed: _toggleAll, + tooltip: _hasAnyUnselected ? S.of(context).tooltipSelectAll : S.of(context).tooltipDesecelectAll, + ), ), - ), - const Spacer(), - TextButton( - onPressed: Navigator.of(context).pop, - child: Text(S.of(context).cancel), - ), - TextButton( - onPressed: _hasAnySelected - ? () { - final List selectedValues = []; - for (int i = 0; i < widget.values.length; i++) { - if (checkboxValues[i]) { - selectedValues.add(widget.values[i]); + const Spacer(), + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(S.of(context).cancel), + ), + TextButton( + onPressed: _hasAnySelected + ? () { + final List selectedValues = []; + for (int i = 0; i < widget.values.length; i++) { + if (checkboxValues[i]) { + selectedValues.add(widget.values[i]); + } } + Navigator.of(context).pop(selectedValues); } - Navigator.of(context).pop(selectedValues); - } - : null, - child: Text(S.of(context).save), - ), - ], - ), - ) - ], + : null, + child: Text(S.of(context).save), + ), + ], + ), + ) + ], + ), ), ); } diff --git a/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart b/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart index c893027..dc31b5c 100644 --- a/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart +++ b/lib/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart @@ -32,24 +32,28 @@ class _DialogPickerState extends State> { titlePadding: Dimens.dialogIconTitlePadding, title: Text(widget.title), contentPadding: EdgeInsets.zero, - content: Column( - mainAxisSize: MainAxisSize.min, - children: widget.values - .map( - (e) => RadioListTile( - value: e, - groupValue: _selected, - title: Text(widget.titleAdapter(context, e)), - onChanged: (T? value) { - if (value != null) { - setState(() { - _selected = value; - }); - } - }, - ), - ) - .toList(), + content: SizedBox( + width: double.maxFinite, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: widget.values + .map( + (e) => RadioListTile( + value: e, + groupValue: _selected, + title: Text(widget.titleAdapter(context, e)), + onChanged: (T? value) { + if (value != null) { + setState(() { + _selected = value; + }); + } + }, + ), + ) + .toList(), + ), ), actionsPadding: Dimens.dialogActionsPadding, actions: [ diff --git a/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart b/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart index cc3f4ca..56f7967 100644 --- a/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart +++ b/lib/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart @@ -36,47 +36,50 @@ class _DialogRangePickerState extends State