ML-20 Dialog pickers content jumps when selected item is out of vie (#21)

* fixed primary color picker overscroll

* dialog cleanup

* fixed photography value picker overscroll

* Update widget_dialog_picker_photography_value.dart
This commit is contained in:
Vadim 2023-02-05 17:20:36 +03:00 committed by GitHub
parent 9436a59094
commit 8d73a7d2e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 120 deletions

View file

@ -208,6 +208,11 @@ class _ThemeDataProvider extends StatelessWidget {
surfaceTintColor: scheme.surfaceTint, surfaceTintColor: scheme.surfaceTint,
elevation: 6, elevation: 6,
), ),
dividerColor: scheme.outlineVariant,
dividerTheme: DividerThemeData(
color: scheme.outlineVariant,
space: 0,
),
listTileTheme: ListTileThemeData( listTileTheme: ListTileThemeData(
style: ListTileStyle.list, style: ListTileStyle.list,
iconColor: scheme.onSurface, iconColor: scheme.onSurface,

View file

@ -37,5 +37,17 @@ class Dimens {
// Dialog // Dialog
// Taken from `Dialog` documentation // Taken from `Dialog` documentation
static const EdgeInsets dialogTitlePadding = EdgeInsets.fromLTRB(
paddingL,
paddingL,
paddingL,
paddingM,
);
static const EdgeInsets dialogActionsPadding = EdgeInsets.fromLTRB(
paddingL,
paddingM,
paddingL,
paddingL,
);
static const EdgeInsets dialogMargin = EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0); static const EdgeInsets dialogMargin = EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0);
} }

View file

@ -36,15 +36,8 @@ class PhotographyValuePickerDialog<T extends PhotographyValue> extends StatefulW
class _PhotographyValuePickerDialogState<T extends PhotographyValue> class _PhotographyValuePickerDialogState<T extends PhotographyValue>
extends State<PhotographyValuePickerDialog<T>> { extends State<PhotographyValuePickerDialog<T>> {
late T _selectedValue = widget.initialValue; late T _selectedValue = widget.initialValue;
final _scrollController = ScrollController(); late final _scrollController =
ScrollController(initialScrollOffset: Dimens.grid56 * widget.values.indexOf(_selectedValue));
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollController.jumpTo(Dimens.grid56 * widget.values.indexOf(_selectedValue));
});
}
@override @override
void dispose() { void dispose() {
@ -57,35 +50,23 @@ class _PhotographyValuePickerDialogState<T extends PhotographyValue>
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Column( Padding(
children: [ padding: Dimens.dialogTitlePadding,
Padding( child: Column(
padding: const EdgeInsets.fromLTRB( children: [
Dimens.paddingL, Text(
Dimens.paddingL, widget.title,
Dimens.paddingL, style: Theme.of(context).textTheme.headlineSmall!,
Dimens.paddingM,
), ),
child: Column( const SizedBox(height: Dimens.grid16),
children: [ Text(
Text( widget.subtitle,
widget.title, style: Theme.of(context).textTheme.bodyMedium!,
style: Theme.of(context).textTheme.headlineSmall!,
),
const SizedBox(height: Dimens.grid16),
Text(
widget.subtitle,
style: Theme.of(context).textTheme.bodyMedium!,
),
],
), ),
), ],
Divider( ),
color: Theme.of(context).colorScheme.onSurface,
height: 0,
),
],
), ),
const Divider(),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController,
@ -114,32 +95,25 @@ class _PhotographyValuePickerDialogState<T extends PhotographyValue>
), ),
), ),
), ),
Column( const Divider(),
children: [ Padding(
Divider( padding: Dimens.dialogActionsPadding,
color: Theme.of(context).colorScheme.onSurface, child: Row(
height: 0, crossAxisAlignment: CrossAxisAlignment.end,
), mainAxisSize: MainAxisSize.max,
Padding( children: [
padding: const EdgeInsets.all(Dimens.paddingL), const Spacer(),
child: Row( TextButton(
crossAxisAlignment: CrossAxisAlignment.end, onPressed: widget.onCancel,
mainAxisSize: MainAxisSize.max, child: Text(S.of(context).cancel),
children: [
const Spacer(),
TextButton(
onPressed: widget.onCancel,
child: Text(S.of(context).cancel),
),
const SizedBox(width: Dimens.grid16),
TextButton(
onPressed: () => widget.onSelect(_selectedValue),
child: Text(S.of(context).select),
),
],
), ),
), const SizedBox(width: Dimens.grid16),
], TextButton(
onPressed: () => widget.onSelect(_selectedValue),
child: Text(S.of(context).select),
),
],
),
), ),
], ],
); );

View file

@ -3,11 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/environment.dart'; import 'package:lightmeter/environment.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';
import 'package:lightmeter/screens/settings/components/calibration/components/calibration_dialog/event_dialog_calibration.dart';
import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart'; import 'package:lightmeter/screens/shared/centered_slider/widget_slider_centered.dart';
import 'package:lightmeter/utils/to_string_signed.dart'; import 'package:lightmeter/utils/to_string_signed.dart';
import 'bloc_dialog_calibration.dart'; import 'bloc_dialog_calibration.dart';
import 'event_dialog_calibration.dart';
import 'state_dialog_calibration.dart'; import 'state_dialog_calibration.dart';
class CalibrationDialog extends StatelessWidget { class CalibrationDialog extends StatelessWidget {
@ -17,12 +17,7 @@ class CalibrationDialog extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final bool hasLightSensor = context.read<Environment>().hasLightSensor; final bool hasLightSensor = context.read<Environment>().hasLightSensor;
return AlertDialog( return AlertDialog(
titlePadding: const EdgeInsets.fromLTRB( titlePadding: Dimens.dialogTitlePadding,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingM,
),
title: Text(S.of(context).calibration), title: Text(S.of(context).calibration),
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
content: SingleChildScrollView( content: SingleChildScrollView(
@ -67,12 +62,7 @@ class CalibrationDialog extends StatelessWidget {
], ],
), ),
), ),
actionsPadding: const EdgeInsets.fromLTRB( actionsPadding: Dimens.dialogActionsPadding,
Dimens.paddingL,
Dimens.paddingM,
Dimens.paddingL,
Dimens.paddingL,
),
actions: [ actions: [
TextButton( TextButton(
onPressed: Navigator.of(context).pop, onPressed: Navigator.of(context).pop,

View file

@ -13,10 +13,7 @@ class PrimaryColorDialogPicker extends StatefulWidget {
class _PrimaryColorDialogPickerState extends State<PrimaryColorDialogPicker> { class _PrimaryColorDialogPickerState extends State<PrimaryColorDialogPicker> {
late Color _selected = Theme.of(context).primaryColor; late Color _selected = Theme.of(context).primaryColor;
late final ScrollController _scrollController = ScrollController( final ScrollController _scrollController = ScrollController();
initialScrollOffset:
ThemeProvider.primaryColorsList.indexOf(_selected) * (Dimens.grid48 + Dimens.grid8),
);
@override @override
void dispose() { void dispose() {
@ -27,42 +24,38 @@ class _PrimaryColorDialogPickerState extends State<PrimaryColorDialogPicker> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
titlePadding: const EdgeInsets.fromLTRB( titlePadding: Dimens.dialogTitlePadding,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingM,
),
title: Text(S.of(context).choosePrimaryColor), title: Text(S.of(context).choosePrimaryColor),
content: SizedBox( content: SizedBox(
height: Dimens.grid48, height: Dimens.grid48,
width: double.maxFinite, width: double.maxFinite,
child: ListView.separated( child: SingleChildScrollView(
controller: _scrollController, controller: _scrollController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
separatorBuilder: (_, __) => const SizedBox(width: Dimens.grid8), child: Row(
itemCount: ThemeProvider.primaryColorsList.length, children: List.generate(
itemBuilder: (_, index) { ThemeProvider.primaryColorsList.length,
final color = ThemeProvider.primaryColorsList[index]; (index) {
return _SelectableColorItem( final color = ThemeProvider.primaryColorsList[index];
color: color, return Padding(
selected: color.value == _selected.value, padding: EdgeInsets.only(left: index == 0 ? 0 : Dimens.paddingS),
onTap: () { child: _SelectableColorItem(
setState(() { color: color,
_selected = color; selected: color.value == _selected.value,
}); onTap: () {
setState(() {
_selected = color;
});
},
),
);
}, },
); ),
}, ),
), ),
), ),
actionsPadding: const EdgeInsets.fromLTRB( actionsPadding: Dimens.dialogActionsPadding,
Dimens.paddingL,
Dimens.paddingM,
Dimens.paddingL,
Dimens.paddingL,
),
actions: [ actions: [
TextButton( TextButton(
onPressed: Navigator.of(context).pop, onPressed: Navigator.of(context).pop,
@ -79,7 +72,7 @@ class _PrimaryColorDialogPickerState extends State<PrimaryColorDialogPicker> {
} }
} }
class _SelectableColorItem extends StatelessWidget { class _SelectableColorItem extends StatefulWidget {
final Color color; final Color color;
final bool selected; final bool selected;
final VoidCallback onTap; final VoidCallback onTap;
@ -90,19 +83,34 @@ class _SelectableColorItem extends StatelessWidget {
required this.onTap, required this.onTap,
}) : super(key: ValueKey(color)); }) : super(key: ValueKey(color));
@override
State<_SelectableColorItem> createState() => _SelectableColorItemState();
}
class _SelectableColorItemState extends State<_SelectableColorItem> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.selected) {
Scrollable.ensureVisible(context);
}
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: widget.onTap,
child: FilledCircle( child: FilledCircle(
size: Dimens.grid48, size: Dimens.grid48,
color: color, color: widget.color,
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: Dimens.durationS, duration: Dimens.durationS,
child: selected child: widget.selected
? Icon( ? Icon(
Icons.check, Icons.check,
color: ThemeData.estimateBrightnessForColor(color) == Brightness.light color: ThemeData.estimateBrightnessForColor(widget.color) == Brightness.light
? Colors.black ? Colors.black
: Colors.white, : Colors.white,
) )

View file

@ -26,12 +26,7 @@ class _DialogPickerState<T> extends State<DialogPicker<T>> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
titlePadding: const EdgeInsets.fromLTRB( titlePadding: Dimens.dialogTitlePadding,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingL,
Dimens.paddingM,
),
title: Text(widget.title), title: Text(widget.title),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
content: Column( content: Column(
@ -53,12 +48,7 @@ class _DialogPickerState<T> extends State<DialogPicker<T>> {
) )
.toList(), .toList(),
), ),
actionsPadding: const EdgeInsets.fromLTRB( actionsPadding: Dimens.dialogActionsPadding,
Dimens.paddingL,
Dimens.paddingM,
Dimens.paddingL,
Dimens.paddingL,
),
actions: [ actions: [
TextButton( TextButton(
onPressed: Navigator.of(context).pop, onPressed: Navigator.of(context).pop,