mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 23:10:40 +00:00
ML-137 Dialogs improvements (#138)
* Force dialogs to have the same width * Fix `DialogPicker` bouncing when the first selected item is near the end
This commit is contained in:
parent
6566108994
commit
19fc039723
3 changed files with 139 additions and 128 deletions
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
|
|
||||||
|
@ -34,18 +35,20 @@ class _DialogFilterState<T> extends State<DialogFilter<T>> {
|
||||||
bool get _hasAnySelected => checkboxValues.contains(true);
|
bool get _hasAnySelected => checkboxValues.contains(true);
|
||||||
bool get _hasAnyUnselected => checkboxValues.contains(false);
|
bool get _hasAnyUnselected => checkboxValues.contains(false);
|
||||||
|
|
||||||
late final ScrollController _scrollController;
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
int i = 0;
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
for (; i < checkboxValues.length; i++) {
|
int i = 0;
|
||||||
if (checkboxValues[i]) {
|
for (; i < checkboxValues.length; i++) {
|
||||||
break;
|
if (checkboxValues[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
_scrollController.jumpTo((Dimens.grid56 * i).clamp(0, _scrollController.position.maxScrollExtent));
|
||||||
_scrollController = ScrollController(initialScrollOffset: Dimens.grid56 * i);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -61,79 +64,80 @@ class _DialogFilterState<T> extends State<DialogFilter<T>> {
|
||||||
titlePadding: Dimens.dialogIconTitlePadding,
|
titlePadding: Dimens.dialogIconTitlePadding,
|
||||||
title: Text(widget.title),
|
title: Text(widget.title),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: Column(
|
content: SizedBox(
|
||||||
children: [
|
width: double.maxFinite,
|
||||||
Padding(
|
child: Column(
|
||||||
padding: Dimens.dialogIconTitlePadding,
|
children: [
|
||||||
child: Text(widget.description),
|
Padding(
|
||||||
),
|
padding: Dimens.dialogIconTitlePadding,
|
||||||
const Divider(),
|
child: Text(widget.description),
|
||||||
Expanded(
|
),
|
||||||
child: SingleChildScrollView(
|
const Divider(),
|
||||||
controller: _scrollController,
|
Expanded(
|
||||||
child: Column(
|
child: SingleChildScrollView(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
controller: _scrollController,
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Column(
|
||||||
children: List.generate(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
widget.values.length,
|
mainAxisSize: MainAxisSize.min,
|
||||||
(index) => CheckboxListTile(
|
children: List.generate(
|
||||||
value: checkboxValues[index],
|
widget.values.length,
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
(index) => CheckboxListTile(
|
||||||
title: Text(
|
value: checkboxValues[index],
|
||||||
widget.titleAdapter(context, widget.values[index]),
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
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(),
|
||||||
const Divider(),
|
Padding(
|
||||||
Padding(
|
padding: Dimens.dialogActionsPadding,
|
||||||
padding: Dimens.dialogActionsPadding,
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
SizedBox(
|
||||||
SizedBox(
|
width: 40,
|
||||||
width: 40,
|
child: IconButton(
|
||||||
child: IconButton(
|
padding: EdgeInsets.zero,
|
||||||
padding: EdgeInsets.zero,
|
icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect),
|
||||||
icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect),
|
onPressed: _toggleAll,
|
||||||
onPressed: _toggleAll,
|
tooltip: _hasAnyUnselected ? S.of(context).tooltipSelectAll : S.of(context).tooltipDesecelectAll,
|
||||||
tooltip: _hasAnyUnselected
|
),
|
||||||
? S.of(context).tooltipSelectAll
|
|
||||||
: S.of(context).tooltipDesecelectAll,
|
|
||||||
),
|
),
|
||||||
),
|
const Spacer(),
|
||||||
const Spacer(),
|
TextButton(
|
||||||
TextButton(
|
onPressed: Navigator.of(context).pop,
|
||||||
onPressed: Navigator.of(context).pop,
|
child: Text(S.of(context).cancel),
|
||||||
child: Text(S.of(context).cancel),
|
),
|
||||||
),
|
TextButton(
|
||||||
TextButton(
|
onPressed: _hasAnySelected
|
||||||
onPressed: _hasAnySelected
|
? () {
|
||||||
? () {
|
final List<T> selectedValues = [];
|
||||||
final List<T> selectedValues = [];
|
for (int i = 0; i < widget.values.length; i++) {
|
||||||
for (int i = 0; i < widget.values.length; i++) {
|
if (checkboxValues[i]) {
|
||||||
if (checkboxValues[i]) {
|
selectedValues.add(widget.values[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),
|
],
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
],
|
||||||
)
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,24 +32,28 @@ class _DialogPickerState<T> extends State<DialogPicker<T>> {
|
||||||
titlePadding: Dimens.dialogIconTitlePadding,
|
titlePadding: Dimens.dialogIconTitlePadding,
|
||||||
title: Text(widget.title),
|
title: Text(widget.title),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: Column(
|
content: SizedBox(
|
||||||
mainAxisSize: MainAxisSize.min,
|
width: double.maxFinite,
|
||||||
children: widget.values
|
child: Column(
|
||||||
.map(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
(e) => RadioListTile(
|
mainAxisSize: MainAxisSize.min,
|
||||||
value: e,
|
children: widget.values
|
||||||
groupValue: _selected,
|
.map(
|
||||||
title: Text(widget.titleAdapter(context, e)),
|
(e) => RadioListTile(
|
||||||
onChanged: (T? value) {
|
value: e,
|
||||||
if (value != null) {
|
groupValue: _selected,
|
||||||
setState(() {
|
title: Text(widget.titleAdapter(context, e)),
|
||||||
_selected = value;
|
onChanged: (T? value) {
|
||||||
});
|
if (value != null) {
|
||||||
}
|
setState(() {
|
||||||
},
|
_selected = value;
|
||||||
),
|
});
|
||||||
)
|
}
|
||||||
.toList(),
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actionsPadding: Dimens.dialogActionsPadding,
|
actionsPadding: Dimens.dialogActionsPadding,
|
||||||
actions: [
|
actions: [
|
||||||
|
|
|
@ -36,47 +36,50 @@ class _DialogRangePickerState<T extends PhotographyValue> extends State<DialogRa
|
||||||
titlePadding: Dimens.dialogIconTitlePadding,
|
titlePadding: Dimens.dialogIconTitlePadding,
|
||||||
title: Text(widget.title),
|
title: Text(widget.title),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: Column(
|
content: SizedBox(
|
||||||
mainAxisSize: MainAxisSize.min,
|
width: double.maxFinite,
|
||||||
children: [
|
child: Column(
|
||||||
Padding(
|
mainAxisSize: MainAxisSize.min,
|
||||||
padding: Dimens.dialogIconTitlePadding,
|
children: [
|
||||||
child: Text(widget.description),
|
Padding(
|
||||||
),
|
padding: Dimens.dialogIconTitlePadding,
|
||||||
Padding(
|
child: Text(widget.description),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
|
|
||||||
child: DefaultTextStyle(
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge!,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(widget.values[_start].toString()),
|
|
||||||
Text(widget.values[_end].toString()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Row(
|
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
|
||||||
children: [
|
child: DefaultTextStyle(
|
||||||
Expanded(
|
style: Theme.of(context).textTheme.bodyLarge!,
|
||||||
child: RangeSlider(
|
child: Row(
|
||||||
values: RangeValues(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
_start.toDouble(),
|
children: [
|
||||||
_end.toDouble(),
|
Text(widget.values[_start].toString()),
|
||||||
),
|
Text(widget.values[_end].toString()),
|
||||||
max: widget.values.length.toDouble() - 1,
|
],
|
||||||
divisions: widget.values.length - 1,
|
|
||||||
onChanged: (value) {
|
|
||||||
setState(() {
|
|
||||||
_start = value.start.round();
|
|
||||||
_end = value.end.round();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
Row(
|
||||||
],
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: RangeSlider(
|
||||||
|
values: RangeValues(
|
||||||
|
_start.toDouble(),
|
||||||
|
_end.toDouble(),
|
||||||
|
),
|
||||||
|
max: widget.values.length.toDouble() - 1,
|
||||||
|
divisions: widget.values.length - 1,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_start = value.start.round();
|
||||||
|
_end = value.end.round();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actionsPadding: Dimens.dialogActionsPadding,
|
actionsPadding: Dimens.dialogActionsPadding,
|
||||||
actions: [
|
actions: [
|
||||||
|
|
Loading…
Reference in a new issue