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 extends BaseEditTile { 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 options; final String Function(T) labelBuilder; final List 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( groupValue: initial, onChanged: (value) { if (value != null && !isSaving) { onSave(value); } }, child: ListView( shrinkWrap: true, children: displayedOptions.map((o) => RadioListTile( 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; }, ); } }