diff --git a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart index d47b48cf0..d1fca14bb 100644 --- a/lib/pangea/learning_settings/widgets/p_language_dropdown.dart +++ b/lib/pangea/learning_settings/widgets/p_language_dropdown.dart @@ -17,10 +17,8 @@ class PLanguageDropdown extends StatefulWidget { final bool isL2List; final String? decorationText; final String? error; - final String? Function(LanguageModel?)? validator; final Color? backgroundColor; final bool hasError; - final bool enabled; const PLanguageDropdown({ super.key, @@ -30,10 +28,8 @@ class PLanguageDropdown extends StatefulWidget { this.decorationText, this.isL2List = false, this.error, - this.validator, this.backgroundColor, this.hasError = false, - this.enabled = true, }); @override @@ -87,14 +83,12 @@ class PLanguageDropdownState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ DropdownButtonFormField2( - enableFeedback: widget.enabled, customButton: widget.initialLanguage != null && sortedLanguages.contains(widget.initialLanguage) ? LanguageDropDownEntry( languageModel: widget.initialLanguage!, isL2List: widget.isL2List, isDropdown: true, - enabled: widget.enabled, ) : null, menuItemStyleData: const MenuItemStyleData( @@ -144,15 +138,13 @@ class PLanguageDropdownState extends State { child: LanguageDropDownEntry( languageModel: languageModel, isL2List: widget.isL2List, - enabled: widget.enabled, ), ), ), ), ], - onChanged: widget.enabled ? (value) => widget.onChange(value!) : null, + onChanged: (value) => widget.onChange(value!), value: widget.initialLanguage, - validator: (value) => widget.validator?.call(value), dropdownSearchData: DropdownSearchData( searchController: _searchController, searchInnerWidgetHeight: 50, diff --git a/lib/pangea/login/pages/create_pangea_account_page.dart b/lib/pangea/login/pages/create_pangea_account_page.dart index 43e55e4bc..7814ada55 100644 --- a/lib/pangea/login/pages/create_pangea_account_page.dart +++ b/lib/pangea/login/pages/create_pangea_account_page.dart @@ -49,10 +49,14 @@ class CreatePangeaAccountPageState extends State { String? _spaceId; String? _courseLangCode; - Future get _cachedLangCode => LangCodeRepo.get(); + Future get _cachedLangCode => LangCodeRepo.get(); - Future get _langCode async => - _courseLangCode ?? (await _cachedLangCode); + Future get _targetLangCode async => + _courseLangCode ?? (await _cachedLangCode)?.targetLangCode; + + Future get _baseLangCode async => + (await _cachedLangCode)?.baseLangCode ?? + MatrixState.pangeaController.languageController.systemLanguage?.langCode; String? get _cachedSpaceCode => MatrixState.pangeaController.spaceCodeController.cachedSpaceCode; @@ -137,11 +141,15 @@ class CreatePangeaAccountPageState extends State { } } - Future _updateTargetLanguage() async { - final langCode = await _langCode; + Future _updateLanguageSettings() async { + final targetLangCode = await _targetLangCode; + final baseLangCode = await _baseLangCode; await MatrixState.pangeaController.userController.updateProfile( (profile) { - profile.userSettings.targetLanguage = langCode; + profile.userSettings.targetLanguage = targetLangCode; + if (baseLangCode != null) { + profile.userSettings.sourceLanguage = baseLangCode; + } return profile; }, waitForDataInSync: true, @@ -151,33 +159,30 @@ class CreatePangeaAccountPageState extends State { Future _createUserInPangea() async { final l2Set = await MatrixState.pangeaController.userController.isUserL2Set; if (l2Set) { - await _updateTargetLanguage(); + await _updateLanguageSettings(); _onProfileCreated(); return; } try { - final langCode = await _langCode; + final targetLangCode = await _targetLangCode; + final baseLangCode = await _baseLangCode; final updateFuture = [ _setAvatar(), MatrixState.pangeaController.userController.updateProfile( (profile) { - final systemLang = MatrixState - .pangeaController.languageController.systemLanguage?.langCode; - - if (systemLang != null) { - profile.userSettings.sourceLanguage = systemLang; + profile.userSettings.targetLanguage = targetLangCode; + if (baseLangCode != null) { + profile.userSettings.sourceLanguage = baseLangCode; } - - profile.userSettings.targetLanguage = langCode; profile.userSettings.createdAt = DateTime.now(); return profile; }, waitForDataInSync: true, ), - if (langCode != null) + if (targetLangCode != null) MatrixState.pangeaController.userController.updateAnalyticsProfile( - targetLanguage: PLanguageStore.byLangCode(langCode), + targetLanguage: PLanguageStore.byLangCode(targetLangCode), baseLanguage: MatrixState.pangeaController.languageController.systemLanguage, level: 1, diff --git a/lib/pangea/login/pages/language_selection_page.dart b/lib/pangea/login/pages/language_selection_page.dart index 25e45f663..80c7450f1 100644 --- a/lib/pangea/login/pages/language_selection_page.dart +++ b/lib/pangea/login/pages/language_selection_page.dart @@ -2,11 +2,15 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; +import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dropdown.dart'; import 'package:fluffychat/pangea/login/utils/lang_code_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; +class IdenticalLanguageException implements Exception {} + class LanguageSelectionPage extends StatefulWidget { const LanguageSelectionPage({super.key}); @@ -15,21 +19,41 @@ class LanguageSelectionPage extends StatefulWidget { } class LanguageSelectionPageState extends State { + Object? _error; + LanguageModel? _selectedLanguage; + LanguageModel? _baseLanguage; @override void initState() { super.initState(); + _baseLanguage = + MatrixState.pangeaController.languageController.systemLanguage; } void _setSelectedLanguage(LanguageModel? l) { setState(() => _selectedLanguage = l); } - Future _submit() async { - if (_selectedLanguage == null) return; + void _setBaseLanguage(LanguageModel? l) { + setState(() => _baseLanguage = l); + } - await LangCodeRepo.set(_selectedLanguage!.langCode); + Future _submit() async { + setState(() => _error = null); + + if (_selectedLanguage == null) return; + if (_selectedLanguage?.langCodeShort == _baseLanguage?.langCodeShort) { + setState(() => _error = IdenticalLanguageException()); + return; + } + + await LangCodeRepo.set( + LanguageSettings( + targetLangCode: _selectedLanguage!.langCode, + baseLangCode: _baseLanguage?.langCode, + ), + ); context.go( GoRouterState.of(context).fullPath?.contains('home') == true ? '/home/language/signup' @@ -56,7 +80,6 @@ class LanguageSelectionPageState extends State { child: Column( spacing: 24.0, children: [ - const SizedBox(height: 50.0), Expanded( child: Stack( children: [ @@ -119,6 +142,22 @@ class LanguageSelectionPageState extends State { ], ), ), + AnimatedSize( + duration: FluffyThemes.animationDuration, + child: _selectedLanguage != null && + _selectedLanguage?.langCodeShort == + _baseLanguage?.langCodeShort + ? PLanguageDropdown( + languages: languages, + onChange: _setBaseLanguage, + initialLanguage: _baseLanguage, + decorationText: L10n.of(context).myBaseLanguage, + error: _error is IdenticalLanguageException + ? L10n.of(context).noIdenticalLanguages + : null, + ) + : const SizedBox(), + ), Text( L10n.of(context).chooseLanguage, style: theme.textTheme.titleMedium?.copyWith( diff --git a/lib/pangea/login/utils/lang_code_repo.dart b/lib/pangea/login/utils/lang_code_repo.dart index 9cd4bbda6..8e1572ae8 100644 --- a/lib/pangea/login/utils/lang_code_repo.dart +++ b/lib/pangea/login/utils/lang_code_repo.dart @@ -1,24 +1,54 @@ import 'package:get_storage/get_storage.dart'; +class LanguageSettings { + final String targetLangCode; + final String? baseLangCode; + + LanguageSettings({ + required this.targetLangCode, + this.baseLangCode, + }); + + Map toJson() => { + 'targetLangCode': targetLangCode, + 'baseLangCode': baseLangCode, + }; + + factory LanguageSettings.fromJson(Map json) => + LanguageSettings( + targetLangCode: json['targetLangCode'], + baseLangCode: json['baseLangCode'], + ); +} + class LangCodeRepo { + static const String _storageKey = 'lang_settings'; static final GetStorage _storage = GetStorage('lang_code_storage'); static Future _init() async { await GetStorage.init('lang_code_storage'); } - static Future get() async { + static Future get() async { await _init(); - return _storage.read('lang_code'); + final entry = _storage.read(_storageKey); + if (entry == null) return null; + + try { + return LanguageSettings.fromJson(entry); + } catch (e) { + await remove(); + return null; + } } - static Future set(String langcode) async { + static Future set(LanguageSettings langcode) async { await _init(); - await _storage.write('lang_code', langcode); + await _storage.write(_storageKey, langcode.toJson()); } static Future remove() async { await _init(); - await _storage.remove('lang_code'); + await _storage.remove(_storageKey); } }