You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudsolutions-atoms/lib/common_widgets/autocomplete_generic_field....

145 lines
4.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/views/app_style/sizing.dart';
class AutoCompleteGenericField<T extends Object> extends StatefulWidget {
final String? label;
final String initialValue;
final bool clearAfterPick;
final Future<List<T>> Function(String query) onSearch;
final String Function(T item) displayString;
final Function(T item) onPick;
const AutoCompleteGenericField({
Key? key,
this.label,
required this.initialValue,
required this.onSearch,
required this.displayString,
required this.onPick,
this.clearAfterPick = true,
}) : super(key: key);
@override
State<AutoCompleteGenericField<T>> createState() => _AutoCompleteGenericFieldState<T>();
}
class _AutoCompleteGenericFieldState<T extends Object> extends State<AutoCompleteGenericField<T>> {
late TextEditingController _controller;
List<T> _options = [];
bool _isLoading = false;
@override
void initState() {
_controller = TextEditingController(text: widget.initialValue);
super.initState();
}
@override
void didUpdateWidget(covariant AutoCompleteGenericField<T> oldWidget) {
if (widget.initialValue != oldWidget.initialValue) {
_controller.text = widget.initialValue;
}
super.didUpdateWidget(oldWidget);
}
Future<void> _search(String query) async {
if (query.isEmpty) {
setState(() => _options = []);
return;
}
setState(() => _isLoading = true);
try {
final results = await widget.onSearch(query);
setState(() => _options = results);
} finally {
setState(() => _isLoading = false);
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final border = UnderlineInputBorder(borderSide: BorderSide.none, borderRadius: BorderRadius.circular(10));
return Container(
decoration: BoxDecoration(
color: AppColor.background(context),
borderRadius: BorderRadius.circular(AppStyle.borderRadius * AppStyle.getScaleFactor(context)),
),
child: RawAutocomplete<T>(
// textEditingController: _controller,
optionsBuilder: (TextEditingValue textEditingValue) => _options,
displayStringForOption: widget.displayString,
fieldViewBuilder: (context, fieldTextEditingController, fieldFocusNode, onFieldSubmitted) {
return TextField(
controller: _controller,
focusNode: fieldFocusNode,
style: AppTextStyles.bodyText.copyWith(color: AppColor.black10),
textAlign: TextAlign.start,
decoration: InputDecoration(
border: border,
disabledBorder: border,
focusedBorder: border,
enabledBorder: border,
errorBorder: border,
contentPadding: EdgeInsets.symmetric(vertical: 8.toScreenHeight, horizontal: 16.toScreenWidth),
// suffixIcon: _isLoading
// ? const Padding(
// padding: EdgeInsets.all(8.0),
// child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)),
// )
// : const Icon(Icons.search, size: 18),
filled: true,
fillColor: AppColor.fieldBgColor(context),
labelText: widget.label,
labelStyle: AppTextStyles.tinyFont.copyWith(color: AppColor.textColor(context)),
),
textInputAction: TextInputAction.search,
onChanged: (text) => _search(text),
onSubmitted: (_) => onFieldSubmitted(),
);
},
onSelected: (T selection) {
if (widget.clearAfterPick) {
_controller.clear();
} else {
_controller.text = widget.displayString(selection);
}
widget.onPick(selection);
},
optionsViewBuilder: (context, onSelected, options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
elevation: 4,
borderRadius: BorderRadius.circular(10),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200, minWidth: 200),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: options.length,
itemBuilder: (context, index) {
final option = options.elementAt(index);
return ListTile(
title: Text(widget.displayString(option)),
onTap: () => onSelected(option),
);
},
),
),
),
);
},
),
);
}
}