aves_mio/lib/widgets/dialogs/selection_dialogs/single_selection.dart
Fabio Micheluz 2c988f959b
Some checks are pending
Quality check / Flutter analysis (push) Waiting to run
Quality check / CodeQL analysis (java-kotlin) (push) Waiting to run
first commit
2026-02-19 13:25:23 +01:00

99 lines
3.2 KiB
Dart

import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:aves/widgets/dialogs/selection_dialogs/common.dart';
import 'package:aves/widgets/dialogs/selection_dialogs/radio_list_tile.dart';
import 'package:flutter/material.dart';
// do not use as `T` a record containing a collection
// because radio value comparison will fail without deep equality
class AvesSingleSelectionDialog<T> extends StatefulWidget {
static const routeName = '/dialog/selection';
final T initialValue;
final Map<T, String> options;
final TextBuilder<T>? optionSubtitleBuilder;
final String? title, message, confirmationButtonLabel;
final bool? dense;
const AvesSingleSelectionDialog({
super.key,
required this.initialValue,
required this.options,
this.optionSubtitleBuilder,
this.title,
this.message,
this.confirmationButtonLabel,
this.dense,
});
@override
State<AvesSingleSelectionDialog<T>> createState() => _AvesSingleSelectionDialogState<T>();
}
class _AvesSingleSelectionDialogState<T> extends State<AvesSingleSelectionDialog<T>> {
late T _selectedValue;
@override
void initState() {
super.initState();
_selectedValue = widget.initialValue;
}
@override
Widget build(BuildContext context) {
final title = widget.title;
final message = widget.message;
final verticalPadding = (title == null && message == null) ? AvesDialog.cornerRadius.y / 2 : .0;
final confirmationButtonLabel = widget.confirmationButtonLabel;
final needConfirmation = confirmationButtonLabel != null;
return AvesDialog(
title: title,
scrollableContent: [
RadioGroup<T>(
groupValue: _selectedValue,
onChanged: (v) {
// always update the group value even when popping afterwards,
// so that the group value can be used in pop handlers
// as well as the regular return value from navigation
_selectedValue = v as T;
if (!needConfirmation) {
// validate without confirmation
Navigator.maybeOf(context)?.pop(v);
} else {
setState(() {});
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (verticalPadding != 0) SizedBox(height: verticalPadding),
if (message != null)
Padding(
padding: const EdgeInsets.all(16),
child: Text(message),
),
...widget.options.entries.map((kv) {
final radioValue = kv.key;
final radioTitle = kv.value;
return SelectionRadioListTile(
value: radioValue,
title: radioTitle,
optionSubtitleBuilder: widget.optionSubtitleBuilder,
dense: widget.dense,
);
}),
if (verticalPadding != 0) SizedBox(height: verticalPadding),
],
),
),
],
actions: [
const CancelButton(),
if (needConfirmation)
TextButton(
onPressed: () => Navigator.maybeOf(context)?.pop(_selectedValue),
child: Text(confirmationButtonLabel),
),
],
);
}
}