diff --git a/lib/pangea/learning_settings/pages/settings_learning.dart b/lib/pangea/learning_settings/pages/settings_learning.dart index 62707da5e..be99b28a7 100644 --- a/lib/pangea/learning_settings/pages/settings_learning.dart +++ b/lib/pangea/learning_settings/pages/settings_learning.dart @@ -77,8 +77,8 @@ class SettingsLearningController extends State { if (mounted) setState(() {}); } - void changeCountry(Country country) { - _profile.userSettings.country = country.displayNameNoCountryCode; + void changeCountry(Country? country) { + _profile.userSettings.country = country?.name; if (mounted) setState(() {}); } @@ -146,7 +146,8 @@ class SettingsLearningController extends State { LanguageLevelTypeEnum get cefrLevel => _profile.userSettings.cefrLevel; - String? get country => _profile.userSettings.country; + Country? get country => + CountryService().findByName(_profile.userSettings.country); @override Widget build(BuildContext context) { diff --git a/lib/pangea/learning_settings/pages/settings_learning_view.dart b/lib/pangea/learning_settings/pages/settings_learning_view.dart index b2d63a82c..afc2f660a 100644 --- a/lib/pangea/learning_settings/pages/settings_learning_view.dart +++ b/lib/pangea/learning_settings/pages/settings_learning_view.dart @@ -98,7 +98,7 @@ class SettingsLearningView extends StatelessWidget { return null; }, ), - CountryPickerTile(controller), + CountryPickerDropdown(controller), LanguageLevelDropdown( initialLevel: controller.cefrLevel, onChanged: controller.setCefrLevel, diff --git a/lib/pangea/learning_settings/widgets/country_picker_tile.dart b/lib/pangea/learning_settings/widgets/country_picker_tile.dart index 8c67e294e..b02827638 100644 --- a/lib/pangea/learning_settings/widgets/country_picker_tile.dart +++ b/lib/pangea/learning_settings/widgets/country_picker_tile.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:country_picker/country_picker.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; @@ -8,34 +9,117 @@ import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart import 'package:fluffychat/pangea/learning_settings/utils/country_display.dart'; import 'package:fluffychat/widgets/matrix.dart'; -class CountryPickerTile extends StatelessWidget { +class CountryPickerDropdown extends StatefulWidget { final SettingsLearningController learningController; final PangeaController pangeaController = MatrixState.pangeaController; - CountryPickerTile(this.learningController, {super.key}); + CountryPickerDropdown(this.learningController, {super.key}); @override - Widget build(BuildContext context) { - final String displayName = CountryDisplayUtil.countryDisplayName( - learningController.country, - context, - ) ?? - ''; - - final String flag = CountryDisplayUtil.flagEmoji( - learningController.country, - ); + CountryPickerDropdownState createState() => CountryPickerDropdownState(); +} + +class CountryPickerDropdownState extends State { + final TextEditingController _searchController = TextEditingController(); - return ListTile( - title: Text( - "${L10n.of(context).countryInformation}: $displayName $flag", + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return DropdownButtonFormField2( + customButton: widget.learningController.country != null + ? CountryPickerTile( + widget.learningController.country!, + isDropdown: true, + ) + : null, + decoration: InputDecoration( + labelText: L10n.of(context).countryInformation, ), - trailing: const Icon(Icons.edit_outlined), - onTap: () => showCountryPicker( - context: context, - showPhoneCode: false, - onSelect: learningController.changeCountry, + dropdownStyleData: const DropdownStyleData( + maxHeight: 300, ), + items: [ + ...CountryService().getAll().map( + (country) => DropdownMenuItem( + value: country, + child: CountryPickerTile(country), + ), + ), + ], + onChanged: widget.learningController.changeCountry, + value: widget.learningController.country, + dropdownSearchData: DropdownSearchData( + searchController: _searchController, + searchInnerWidgetHeight: 50, + searchInnerWidget: Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), + child: TextField( + autofocus: true, + controller: _searchController, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.search), + ), + ), + ), + searchMatchFn: (item, searchValue) { + final countryName = item.value?.name.toLowerCase(); + if (countryName == null) return false; + + final search = searchValue.toLowerCase(); + return countryName.startsWith(search); + }, + ), + onMenuStateChange: (isOpen) { + if (!isOpen) _searchController.clear(); + }, + ); + } +} + +class CountryPickerTile extends StatelessWidget { + final Country country; + final bool isDropdown; + + const CountryPickerTile( + this.country, { + super.key, + this.isDropdown = false, + }); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + CountryDisplayUtil.flagEmoji(country.name), + style: const TextStyle(fontSize: 25), + ), + const SizedBox(width: 10), + Expanded( + child: Text( + CountryDisplayUtil.countryDisplayName( + country.name, + context, + ) ?? + '', + style: const TextStyle().copyWith( + color: Theme.of(context).textTheme.bodyLarge!.color, + fontSize: 14, + ), + overflow: TextOverflow.ellipsis, + ), + ), + if (isDropdown) + Icon( + Icons.arrow_drop_down, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ], ); } } diff --git a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart index 4d00f16c4..747a509d8 100644 --- a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart +++ b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart @@ -2,12 +2,14 @@ import 'package:flutter/material.dart'; +import 'package:dropdown_button2/dropdown_button2.dart'; + import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pangea/learning_settings/enums/l2_support_enum.dart'; import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; import 'flag.dart'; -class PLanguageDropdown extends StatelessWidget { +class PLanguageDropdown extends StatefulWidget { final List languages; final LanguageModel? initialLanguage; final Function(LanguageModel) onChange; @@ -29,9 +31,22 @@ class PLanguageDropdown extends StatelessWidget { this.validator, }); + @override + PLanguageDropdownState createState() => PLanguageDropdownState(); +} + +class PLanguageDropdownState extends State { + final TextEditingController _searchController = TextEditingController(); + + @override + void dispose() { + _searchController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - final List sortedLanguages = languages; + final List sortedLanguages = widget.languages; final String systemLang = Localizations.localeOf(context).languageCode; final List languagePriority = [systemLang, 'en', 'es']; @@ -60,16 +75,26 @@ class PLanguageDropdown extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - DropdownButtonFormField( - decoration: InputDecoration(labelText: decorationText), + DropdownButtonFormField2( + customButton: widget.initialLanguage != null + ? LanguageDropDownEntry( + languageModel: widget.initialLanguage!, + isL2List: widget.isL2List, + isDropdown: true, + ) + : null, + decoration: InputDecoration(labelText: widget.decorationText), isExpanded: true, + dropdownStyleData: const DropdownStyleData( + maxHeight: 400, + ), items: [ - if (showMultilingual) + if (widget.showMultilingual) DropdownMenuItem( value: LanguageModel.multiLingual(context), child: LanguageDropDownEntry( languageModel: LanguageModel.multiLingual(context), - isL2List: isL2List, + isL2List: widget.isL2List, ), ), ...sortedLanguages.map( @@ -77,18 +102,42 @@ class PLanguageDropdown extends StatelessWidget { value: languageModel, child: LanguageDropDownEntry( languageModel: languageModel, - isL2List: isL2List, + isL2List: widget.isL2List, ), ), ), ], - onChanged: (value) => onChange(value!), - value: initialLanguage, - validator: (value) => validator?.call(value), + onChanged: (value) => widget.onChange(value!), + value: widget.initialLanguage, + validator: (value) => widget.validator?.call(value), + dropdownSearchData: DropdownSearchData( + searchController: _searchController, + searchInnerWidgetHeight: 50, + searchInnerWidget: Padding( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), + child: TextField( + autofocus: true, + controller: _searchController, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.search), + ), + ), + ), + searchMatchFn: (item, searchValue) { + final displayName = item.value?.displayName.toLowerCase(); + if (displayName == null) return false; + + final search = searchValue.toLowerCase(); + return displayName.startsWith(search); + }, + ), + onMenuStateChange: (isOpen) { + if (!isOpen) _searchController.clear(); + }, ), AnimatedSize( duration: FluffyThemes.animationDuration, - child: error == null + child: widget.error == null ? const SizedBox.shrink() : Padding( padding: const EdgeInsets.symmetric( @@ -96,7 +145,7 @@ class PLanguageDropdown extends StatelessWidget { vertical: 5, ), child: Text( - error!, + widget.error!, style: TextStyle( color: Theme.of(context).colorScheme.error, fontSize: 12, @@ -112,40 +161,46 @@ class PLanguageDropdown extends StatelessWidget { class LanguageDropDownEntry extends StatelessWidget { final LanguageModel languageModel; final bool isL2List; + final bool isDropdown; + const LanguageDropDownEntry({ super.key, required this.languageModel, required this.isL2List, + this.isDropdown = false, }); @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.only(left: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - LanguageFlag( - language: languageModel, - ), - const SizedBox(width: 10), - Flexible( - child: Text( - languageModel.getDisplayName(context) ?? "", - style: const TextStyle().copyWith( - color: Theme.of(context).textTheme.bodyLarge!.color, - fontSize: 14, + return Row( + children: [ + LanguageFlag( + language: languageModel, + ), + const SizedBox(width: 10), + Expanded( + child: Row( + children: [ + Text( + languageModel.getDisplayName(context) ?? "", + style: const TextStyle().copyWith( + color: Theme.of(context).textTheme.bodyLarge!.color, + fontSize: 14, + ), + overflow: TextOverflow.ellipsis, ), - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - ), + const SizedBox(width: 10), + if (isL2List && languageModel.l2Support != L2SupportEnum.full) + languageModel.l2Support.toBadge(context), + ], ), - const SizedBox(width: 10), - if (isL2List && languageModel.l2Support != L2SupportEnum.full) - languageModel.l2Support.toBadge(context), - ], - ), + ), + if (isDropdown) + Icon( + Icons.arrow_drop_down, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ], ); } }