diff --git a/lib/pangea/learning_settings/pages/settings_learning.dart b/lib/pangea/learning_settings/pages/settings_learning.dart index 9deab5590..8cac708eb 100644 --- a/lib/pangea/learning_settings/pages/settings_learning.dart +++ b/lib/pangea/learning_settings/pages/settings_learning.dart @@ -4,11 +4,14 @@ import 'package:country_picker/country_picker.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/learning_settings/enums/language_level_type_enum.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; import 'package:fluffychat/pangea/learning_settings/pages/settings_learning_view.dart'; +import 'package:fluffychat/pangea/learning_settings/utils/language_list_util.dart'; import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dialog.dart'; import 'package:fluffychat/pangea/spaces/models/space_model.dart'; import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart'; import 'package:fluffychat/pangea/user/models/user_model.dart'; +import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; class SettingsLearning extends StatefulWidget { @@ -22,6 +25,22 @@ class SettingsLearningController extends State { PangeaController pangeaController = MatrixState.pangeaController; final tts = TtsController(); + LanguageModel? get selectedSourceLanguage { + return userL1 ?? pangeaController.languageController.systemLanguage; + } + + LanguageModel? get selectedTargetLanguage { + return userL2 ?? + ((selectedSourceLanguage?.langCode != 'en') + ? PangeaLanguage.byLangCode('en')! + : PangeaLanguage.byLangCode('es')!); + } + + LanguageModel? get userL1 => pangeaController.languageController.userL1; + LanguageModel? get userL2 => pangeaController.languageController.userL2; + + final GlobalKey formKey = GlobalKey(); + @override void initState() { super.initState(); @@ -34,6 +53,33 @@ class SettingsLearningController extends State { super.dispose(); } + Future setSelectedLanguage({ + LanguageModel? sourceLanguage, + LanguageModel? targetLanguage, + }) async { + if (targetLanguage == null && sourceLanguage == null) return; + if (!formKey.currentState!.validate()) return; + + await showFutureLoadingDialog( + context: context, + future: () async { + pangeaController.userController.updateProfile( + (profile) { + if (sourceLanguage != null) { + profile.userSettings.sourceLanguage = sourceLanguage.langCode; + } + if (targetLanguage != null) { + profile.userSettings.targetLanguage = targetLanguage.langCode; + } + return profile; + }, + waitForDataInSync: true, + ); + }, + ); + if (mounted) setState(() {}); + } + void setPublicProfile(bool isPublic) { pangeaController.userController.updateProfile( (profile) { diff --git a/lib/pangea/learning_settings/pages/settings_learning_view.dart b/lib/pangea/learning_settings/pages/settings_learning_view.dart index 82d228d09..a30ac7ec5 100644 --- a/lib/pangea/learning_settings/pages/settings_learning_view.dart +++ b/lib/pangea/learning_settings/pages/settings_learning_view.dart @@ -8,9 +8,10 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart'; import 'package:fluffychat/pangea/common/constants/model_keys.dart'; import 'package:fluffychat/pangea/common/widgets/full_width_dialog.dart'; +import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart'; import 'package:fluffychat/pangea/learning_settings/widgets/country_picker_tile.dart'; -import 'package:fluffychat/pangea/learning_settings/widgets/language_tile.dart'; +import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dropdown.dart'; import 'package:fluffychat/pangea/learning_settings/widgets/p_settings_switch_list_tile.dart'; import 'package:fluffychat/pangea/spaces/models/space_model.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -46,88 +47,126 @@ class SettingsLearningView extends StatelessWidget { iconColor: Theme.of(context).textTheme.bodyLarge!.color, child: MaxWidthBody( withScrolling: true, - child: Column( - children: [ - LanguageTile(controller), - CountryPickerTile(controller), - Padding( - padding: const EdgeInsets.only(top: 16.0, bottom: 24.0), - child: LanguageLevelDropdown( - initialLevel: controller.cefrLevel, - onChanged: controller.setCefrLevel, + child: Form( + key: controller.formKey, + child: Column( + children: [ + const SizedBox(height: 8.0), + PLanguageDropdown( + onChange: (lang) => + controller.setSelectedLanguage(sourceLanguage: lang), + initialLanguage: controller.selectedSourceLanguage ?? + LanguageModel.unknown, + languages: MatrixState + .pangeaController.pLanguageStore.baseOptions, + isL2List: false, + decorationText: L10n.of(context).myBaseLanguage, + validator: (lang) { + if (lang == controller.selectedTargetLanguage) { + return L10n.of(context).noIdenticalLanguages; + } + return null; + }, ), - ), - const Divider(height: 1), - ListTile( - title: Text(L10n.of(context).toggleToolSettingsDescription), - ), - for (final toolSetting in ToolSetting.values - .where((tool) => tool.isAvailableSetting)) - Column( - children: [ - ProfileSettingsSwitchListTile.adaptive( - defaultValue: controller.getToolSetting(toolSetting), - title: toolSetting.toolName(context), - subtitle: toolSetting == ToolSetting.enableTTS && - !controller.tts.isLanguageFullySupported - ? null - : toolSetting.toolDescription(context), - onChange: (bool value) => - controller.updateToolSetting( - toolSetting, - value, - ), - enabled: toolSetting == ToolSetting.enableTTS - ? controller.tts.isLanguageFullySupported - : true, - ), - if (toolSetting == ToolSetting.enableTTS && - !controller.tts.isLanguageFullySupported) - ListTile( - trailing: const Padding( - padding: EdgeInsets.symmetric(horizontal: 16.0), - child: Icon(Icons.info_outlined), + const SizedBox(height: 24.0), + PLanguageDropdown( + onChange: (lang) => + controller.setSelectedLanguage(targetLanguage: lang), + initialLanguage: controller.selectedTargetLanguage, + languages: MatrixState + .pangeaController.pLanguageStore.targetOptions, + isL2List: true, + decorationText: L10n.of(context).iWantToLearn, + validator: (lang) { + if (lang == controller.selectedSourceLanguage) { + return L10n.of(context).noIdenticalLanguages; + } + return null; + }, + ), + const SizedBox(height: 16.0), + CountryPickerTile(controller), + Padding( + padding: const EdgeInsets.only(top: 16.0, bottom: 24.0), + child: LanguageLevelDropdown( + initialLevel: controller.cefrLevel, + onChanged: controller.setCefrLevel, + ), + ), + const Divider(height: 1), + ListTile( + title: + Text(L10n.of(context).toggleToolSettingsDescription), + ), + for (final toolSetting in ToolSetting.values + .where((tool) => tool.isAvailableSetting)) + Column( + children: [ + ProfileSettingsSwitchListTile.adaptive( + defaultValue: + controller.getToolSetting(toolSetting), + title: toolSetting.toolName(context), + subtitle: toolSetting == ToolSetting.enableTTS && + !controller.tts.isLanguageFullySupported + ? null + : toolSetting.toolDescription(context), + onChange: (bool value) => + controller.updateToolSetting( + toolSetting, + value, ), - subtitle: RichText( - text: TextSpan( - text: L10n.of(context).couldNotFindTTS, - style: DefaultTextStyle.of(context).style, - children: [ - if (PlatformInfos.isWindows || - PlatformInfos.isAndroid) - TextSpan( - text: L10n.of(context) - .ttsInstructionsHyperlink, - style: const TextStyle( - color: Colors.blue, - fontWeight: FontWeight.bold, - decoration: TextDecoration.underline, + enabled: toolSetting == ToolSetting.enableTTS + ? controller.tts.isLanguageFullySupported + : true, + ), + if (toolSetting == ToolSetting.enableTTS && + !controller.tts.isLanguageFullySupported) + ListTile( + trailing: const Padding( + padding: EdgeInsets.symmetric(horizontal: 16.0), + child: Icon(Icons.info_outlined), + ), + subtitle: RichText( + text: TextSpan( + text: L10n.of(context).couldNotFindTTS, + style: DefaultTextStyle.of(context).style, + children: [ + if (PlatformInfos.isWindows || + PlatformInfos.isAndroid) + TextSpan( + text: L10n.of(context) + .ttsInstructionsHyperlink, + style: const TextStyle( + color: Colors.blue, + fontWeight: FontWeight.bold, + decoration: TextDecoration.underline, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrlString( + PlatformInfos.isWindows + ? AppConfig + .windowsTTSDownloadInstructions + : AppConfig + .androidTTSDownloadInstructions, + ); + }, ), - recognizer: TapGestureRecognizer() - ..onTap = () { - launchUrlString( - PlatformInfos.isWindows - ? AppConfig - .windowsTTSDownloadInstructions - : AppConfig - .androidTTSDownloadInstructions, - ); - }, - ), - ], + ], + ), ), ), - ), - ], + ], + ), + SwitchListTile.adaptive( + value: controller.publicProfile, + onChanged: controller.setPublicProfile, + title: Text(L10n.of(context).publicProfileTitle), + subtitle: Text(L10n.of(context).publicProfileDesc), + activeColor: AppConfig.activeToggleColor, ), - SwitchListTile.adaptive( - value: controller.publicProfile, - onChanged: controller.setPublicProfile, - title: Text(L10n.of(context).publicProfileTitle), - subtitle: Text(L10n.of(context).publicProfileDesc), - activeColor: AppConfig.activeToggleColor, - ), - ], + ], + ), ), ), ), diff --git a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart index d21c40232..4d00f16c4 100644 --- a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart +++ b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart @@ -2,14 +2,12 @@ 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 StatefulWidget { +class PLanguageDropdown extends StatelessWidget { final List languages; final LanguageModel? initialLanguage; final Function(LanguageModel) onChange; @@ -17,6 +15,7 @@ class PLanguageDropdown extends StatefulWidget { final bool isL2List; final String decorationText; final String? error; + final String? Function(LanguageModel?)? validator; const PLanguageDropdown({ super.key, @@ -27,16 +26,12 @@ class PLanguageDropdown extends StatefulWidget { required this.decorationText, this.isL2List = false, this.error, + this.validator, }); - @override - State createState() => _PLanguageDropdownState(); -} - -class _PLanguageDropdownState extends State { @override Widget build(BuildContext context) { - final List sortedLanguages = widget.languages; + final List sortedLanguages = languages; final String systemLang = Localizations.localeOf(context).languageCode; final List languagePriority = [systemLang, 'en', 'es']; @@ -65,16 +60,16 @@ class _PLanguageDropdownState extends State { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - DropdownButtonFormField2( - decoration: InputDecoration(labelText: widget.decorationText), + DropdownButtonFormField( + decoration: InputDecoration(labelText: decorationText), isExpanded: true, items: [ - if (widget.showMultilingual) + if (showMultilingual) DropdownMenuItem( value: LanguageModel.multiLingual(context), child: LanguageDropDownEntry( languageModel: LanguageModel.multiLingual(context), - isL2List: widget.isL2List, + isL2List: isL2List, ), ), ...sortedLanguages.map( @@ -82,17 +77,18 @@ class _PLanguageDropdownState extends State { value: languageModel, child: LanguageDropDownEntry( languageModel: languageModel, - isL2List: widget.isL2List, + isL2List: isL2List, ), ), ), ], - onChanged: (value) => widget.onChange(value!), - value: widget.initialLanguage, + onChanged: (value) => onChange(value!), + value: initialLanguage, + validator: (value) => validator?.call(value), ), AnimatedSize( duration: FluffyThemes.animationDuration, - child: widget.error == null + child: error == null ? const SizedBox.shrink() : Padding( padding: const EdgeInsets.symmetric( @@ -100,7 +96,7 @@ class _PLanguageDropdownState extends State { vertical: 5, ), child: Text( - widget.error!, + error!, style: TextStyle( color: Theme.of(context).colorScheme.error, fontSize: 12,