add build step for flutter web, add persistent pagination in the traction list
Some checks failed
Release / meta (push) Successful in 14s
Release / web-build (push) Has been cancelled
Release / release-dev (push) Has been cancelled
Release / release-master (push) Has been cancelled
Release / linux-build (push) Has been cancelled
Release / android-build (push) Has been cancelled
Some checks failed
Release / meta (push) Successful in 14s
Release / web-build (push) Has been cancelled
Release / release-dev (push) Has been cancelled
Release / release-master (push) Has been cancelled
Release / linux-build (push) Has been cancelled
Release / android-build (push) Has been cancelled
This commit is contained in:
@@ -84,6 +84,13 @@ class _NewTractionPageState extends State<NewTractionPage> {
|
||||
'traction_motors': TextEditingController(),
|
||||
'build_date': TextEditingController(),
|
||||
};
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
final data = context.read<DataService>();
|
||||
if (data.locoClasses.isEmpty) {
|
||||
data.fetchClassList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -254,6 +261,10 @@ class _NewTractionPageState extends State<NewTractionPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isActive = _statusIsActive;
|
||||
final data = context.watch<DataService>();
|
||||
final classOptions = [...data.locoClasses]..sort(
|
||||
(a, b) => a.toLowerCase().compareTo(b.toLowerCase()),
|
||||
);
|
||||
final size = MediaQuery.of(context).size;
|
||||
final isNarrow = size.width < 720;
|
||||
final fieldWidth = isNarrow ? double.infinity : 340.0;
|
||||
@@ -269,6 +280,89 @@ class _NewTractionPageState extends State<NewTractionPage> {
|
||||
double? widthOverride,
|
||||
String? Function(String?)? validator,
|
||||
}) {
|
||||
// Special autocomplete for class field using existing loco classes.
|
||||
if (key == 'class' && classOptions.isNotEmpty) {
|
||||
return SizedBox(
|
||||
width: widthOverride ?? fieldWidth,
|
||||
child: Autocomplete<String>(
|
||||
optionsBuilder: (TextEditingValue value) {
|
||||
final query = value.text.trim().toLowerCase();
|
||||
if (query.isEmpty) return classOptions;
|
||||
return classOptions.where(
|
||||
(c) => c.toLowerCase().contains(query),
|
||||
);
|
||||
},
|
||||
onSelected: (selection) {
|
||||
_controllers[key]?.text = selection;
|
||||
_formKey.currentState?.validate();
|
||||
},
|
||||
fieldViewBuilder:
|
||||
(context, textEditingController, focusNode, onFieldSubmitted) {
|
||||
if (textEditingController.text != _controllers[key]?.text) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
if (textEditingController.text != _controllers[key]?.text) {
|
||||
textEditingController.value =
|
||||
_controllers[key]?.value ?? textEditingController.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return TextFormField(
|
||||
controller: textEditingController,
|
||||
focusNode: focusNode,
|
||||
decoration: InputDecoration(
|
||||
labelText: required ? '$label *' : label,
|
||||
helperText: helper,
|
||||
suffixText: suffixText,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
keyboardType: keyboardType,
|
||||
maxLines: maxLines,
|
||||
validator: (val) {
|
||||
if (required && (val == null || val.trim().isEmpty)) {
|
||||
return 'Required';
|
||||
}
|
||||
return validator?.call(val);
|
||||
},
|
||||
onChanged: (_) {
|
||||
_controllers[key]?.text = textEditingController.text;
|
||||
_formKey.currentState?.validate();
|
||||
},
|
||||
onFieldSubmitted: (_) => onFieldSubmitted(),
|
||||
);
|
||||
},
|
||||
optionsViewBuilder: (context, onSelected, options) {
|
||||
final opts = options.toList();
|
||||
if (opts.isEmpty) return const SizedBox.shrink();
|
||||
return Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: Material(
|
||||
elevation: 4,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: 280,
|
||||
maxWidth: widthOverride ?? fieldWidth,
|
||||
),
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
itemCount: opts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final option = opts[index];
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Text(option),
|
||||
onTap: () => onSelected(option),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
width: widthOverride ?? fieldWidth,
|
||||
child: TextFormField(
|
||||
|
||||
Reference in New Issue
Block a user