Files
sendico/frontend/pweb/lib/pages/settings/widgets/pick.dart
2025-11-25 08:20:09 +03:00

122 lines
3.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
import 'package:pweb/pages/settings/widgets/base.dart';
const _kSearchThreshold = 12;
class SelectValueTile<T> extends BaseEditTile<T> {
final double? maxEditorHeight;
final double? maxEditorWidth;
const SelectValueTile({
super.key,
required super.icon,
required super.title,
required super.valueGetter,
required super.valueSetter,
required super.errorSituation,
required this.options,
required this.labelBuilder,
this.filterOptions,
this.maxEditorHeight,
this.maxEditorWidth,
});
final List<T> options;
final String Function(T) labelBuilder;
final List<T> Function(String)? filterOptions;
@override
bool get useDialogEditor => true;
@override
Widget buildView(BuildContext context, T? value) {
return Text(
value == null ? AppLocalizations.of(context)!.notSet : labelBuilder(value),
);
}
@override
Widget buildEditor(
BuildContext context,
T? initial,
void Function(T) onSave,
VoidCallback onCancel,
bool isSaving,
) {
// local state for the current search query
String searchText = '';
return StatefulBuilder(
builder: (context, setState) {
// decide which list to show
final displayedOptions = (options.length > _kSearchThreshold && filterOptions != null && searchText.isNotEmpty)
? filterOptions!(searchText)
: options;
final content = Column(
mainAxisSize: MainAxisSize.min,
children: [
if (options.length > _kSearchThreshold && filterOptions != null)
Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 4),
child: TextField(
decoration: InputDecoration(
hintText: AppLocalizations.of(context)!.search,
prefixIcon: const Icon(Icons.search),
border: const OutlineInputBorder(),
isDense: true,
),
onChanged: (value) {
// update the local searchText and rebuild the list
setState(() {
searchText = value;
});
},
),
),
Flexible(
child: RadioGroup<T>(
groupValue: initial,
onChanged: (value) {
if (value != null && !isSaving) {
onSave(value);
}
},
child: ListView(
shrinkWrap: true,
children: displayedOptions.map((o) => RadioListTile<T>(
value: o,
title: Text(labelBuilder(o)),
enabled: !isSaving,
)).toList(),
),
),
),
const Divider(),
TextButton(
onPressed: onCancel,
child: Text(AppLocalizations.of(context)!.cancel),
),
],
);
// if the caller passed a max size, enforce it:
if (maxEditorHeight != null || maxEditorWidth != null) {
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight: maxEditorHeight ?? double.infinity,
maxWidth: maxEditorWidth ?? double.infinity,
),
child: content,
);
}
return content;
},
);
}
}