164 lines
4.8 KiB
Dart
164 lines
4.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:country_picker/country_picker.dart';
|
|
|
|
import '../generated/i18n/app_localizations.dart';
|
|
|
|
class CountryField extends StatelessWidget {
|
|
const CountryField({
|
|
super.key,
|
|
required this.value,
|
|
required this.onChanged,
|
|
this.enabled = true,
|
|
});
|
|
|
|
final String value;
|
|
final ValueChanged<String> onChanged;
|
|
final bool enabled;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l = AppLocalizations.of(context)!;
|
|
final country = CountryService().findByCode(value);
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Text(l.kycCountry, style: Theme.of(context).textTheme.labelLarge),
|
|
const SizedBox(height: 8),
|
|
Semantics(
|
|
label: l.kycCountry,
|
|
child: OutlinedButton(
|
|
onPressed: !enabled
|
|
? null
|
|
: () async {
|
|
final code = await showDialog<String>(
|
|
context: context,
|
|
builder: (_) => _CountrySearch(selected: value),
|
|
);
|
|
if (context.mounted && code != null) onChanged(code);
|
|
},
|
|
style: OutlinedButton.styleFrom(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(14),
|
|
),
|
|
),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
country == null
|
|
? l.kycCountrySelect
|
|
: _name(context, country),
|
|
),
|
|
),
|
|
const SizedBox(width: 8),
|
|
const Icon(Icons.expand_more),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
String _name(BuildContext context, Country country) =>
|
|
country.getTranslatedName(context) ?? country.name;
|
|
|
|
class _CountrySearch extends StatefulWidget {
|
|
const _CountrySearch({required this.selected});
|
|
|
|
final String selected;
|
|
|
|
@override
|
|
State<_CountrySearch> createState() => _CountrySearchState();
|
|
}
|
|
|
|
class _CountrySearchState extends State<_CountrySearch> {
|
|
final _query = TextEditingController();
|
|
final _countries = {
|
|
for (final country in CountryService().getAll())
|
|
country.countryCode: country,
|
|
}.values.toList();
|
|
|
|
@override
|
|
void dispose() {
|
|
_query.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l = AppLocalizations.of(context)!;
|
|
return Focus(
|
|
autofocus: true,
|
|
onKeyEvent: (_, event) {
|
|
if (event is KeyDownEvent &&
|
|
event.logicalKey == LogicalKeyboardKey.escape) {
|
|
Navigator.of(context).pop();
|
|
return KeyEventResult.handled;
|
|
}
|
|
return KeyEventResult.ignored;
|
|
},
|
|
child: Dialog.fullscreen(
|
|
child: Scaffold(
|
|
appBar: AppBar(
|
|
leading: BackButton(onPressed: () => Navigator.of(context).pop()),
|
|
title: TextField(
|
|
key: const ValueKey('country-search'),
|
|
controller: _query,
|
|
autofocus: true,
|
|
decoration: InputDecoration(
|
|
labelText: l.kycCountrySearch,
|
|
prefixIcon: const Icon(Icons.search),
|
|
),
|
|
onChanged: (_) => setState(() {}),
|
|
),
|
|
toolbarHeight: 96,
|
|
actions: [
|
|
if (_query.text.isNotEmpty)
|
|
IconButton(
|
|
tooltip: l.kycCountryClearSearch,
|
|
icon: const Icon(Icons.clear),
|
|
onPressed: () => setState(_query.clear),
|
|
),
|
|
],
|
|
),
|
|
body: _list(context),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _list(BuildContext context) {
|
|
final search = _query.text.trim().toLowerCase();
|
|
final countries = _countries.where((country) {
|
|
return _name(context, country).toLowerCase().contains(search) ||
|
|
country.name.toLowerCase().contains(search) ||
|
|
country.countryCode.toLowerCase() == search;
|
|
}).toList()..sort((a, b) => _name(context, a).compareTo(_name(context, b)));
|
|
if (countries.isEmpty) {
|
|
return Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Text(AppLocalizations.of(context)!.kycCountryEmpty),
|
|
),
|
|
);
|
|
}
|
|
return ListView.builder(
|
|
itemCount: countries.length,
|
|
itemBuilder: (context, index) {
|
|
final country = countries[index];
|
|
final isSelected = country.countryCode == widget.selected;
|
|
return ListTile(
|
|
title: Text(_name(context, country)),
|
|
selected: isSelected,
|
|
trailing: isSelected ? const Icon(Icons.check) : null,
|
|
onTap: () => Navigator.of(context).pop(country.countryCode),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|