bharat_erp/lib/shared/widgets/app_dropdown.dart
2026-07-14 12:01:08 +05:30

90 lines
2.1 KiB
Dart

import 'package:flutter/material.dart';
import 'app_searchable_dropdown.dart';
class AppDropdownOption<T> {
const AppDropdownOption({
required this.value,
required this.label,
this.subtitle,
this.searchText,
});
final T value;
final String label;
/// Secondary line under [label] in the picker (e.g. item code).
final String? subtitle;
/// Extra searchable text (defaults to [label] + [subtitle]).
final String? searchText;
String get searchable =>
(searchText ?? [label, if (subtitle != null) subtitle!].join(' '))
.toLowerCase();
bool matchesQuery(String query) {
final q = query.trim().toLowerCase();
if (q.isEmpty) return true;
return searchable.contains(q);
}
}
/// Searchable dropdown — all app dropdowns use [AppSearchableDropdown] under the hood.
class AppDropdown<T> extends StatelessWidget {
const AppDropdown({
super.key,
required this.label,
required this.value,
required this.options,
required this.onChanged,
this.validator,
this.hint,
this.searchHint,
this.enabled = true,
this.isDense = false,
this.addNewLabel,
this.onAddNew,
});
final String label;
final T? value;
final List<AppDropdownOption<T>> options;
final ValueChanged<T?> onChanged;
final String? Function(T?)? validator;
final String? hint;
final String? searchHint;
final bool enabled;
final bool isDense;
final String? addNewLabel;
final Future<void> Function()? onAddNew;
@override
Widget build(BuildContext context) {
return AppSearchableDropdown<T>(
label: label,
value: value,
options: options,
onChanged: onChanged,
validator: validator,
hint: hint,
searchHint: searchHint ?? 'Search ${label.toLowerCase()}...',
enabled: enabled,
isDense: isDense,
addNewLabel: addNewLabel,
onAddNew: onAddNew,
);
}
}
List<AppDropdownOption<String>> stringDropdownOptions(List<String> values) {
return values
.map(
(value) => AppDropdownOption(
value: value,
label: value.replaceAll('_', ' '),
),
)
.toList();
}