From a44e378f4fcbe41023620d7d05527e783d3cbaf9 Mon Sep 17 00:00:00 2001 From: ggurdin <46800240+ggurdin@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:25:46 -0400 Subject: [PATCH] feat: set initial L2 via cached space code course target language if available (#4264) --- lib/config/routes.dart | 29 +- lib/pangea/guard/p_vguard.dart | 15 +- .../pages/create_pangea_account_page.dart | 126 ++++++-- .../login/pages/language_selection_page.dart | 25 +- .../login/pages/login_or_signup_view.dart | 10 +- lib/pangea/login/pages/signup.dart | 4 +- lib/pangea/login/pages/signup_view.dart | 2 +- lib/pangea/login/pages/user_settings.dart | 278 ------------------ .../login/pages/user_settings_view.dart | 198 ------------- lib/pangea/login/utils/lang_code_repo.dart | 17 ++ lib/pangea/login/utils/sso_login_action.dart | 7 +- .../controllers/space_code_controller.dart | 5 + lib/widgets/matrix.dart | 5 +- 13 files changed, 160 insertions(+), 561 deletions(-) delete mode 100644 lib/pangea/login/pages/user_settings.dart delete mode 100644 lib/pangea/login/pages/user_settings_view.dart create mode 100644 lib/pangea/login/utils/lang_code_repo.dart diff --git a/lib/config/routes.dart b/lib/config/routes.dart index df5736814..b3b2d9292 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -135,7 +135,7 @@ abstract class AppRoutes { ), // #Pangea GoRoute( - path: 'signup', + path: 'language', pageBuilder: (context, state) => defaultPageBuilder( context, state, @@ -143,13 +143,11 @@ abstract class AppRoutes { ), routes: [ GoRoute( - path: ':langcode', + path: 'signup', pageBuilder: (context, state) => defaultPageBuilder( context, state, - SignupPage( - langCode: state.pathParameters['langcode']!, - ), + const SignupPage(), ), routes: [ GoRoute( @@ -157,9 +155,8 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - SignupPage( + const SignupPage( withEmail: true, - langCode: state.pathParameters['langcode']!, ), ), ), @@ -196,6 +193,14 @@ abstract class AppRoutes { ), redirect: PAuthGaurd.onboardingRedirect, routes: [ + GoRoute( + path: 'create', + pageBuilder: (context, state) => defaultPageBuilder( + context, + state, + const CreatePangeaAccountPage(), + ), + ), GoRoute( path: 'course', pageBuilder: (context, state) => defaultPageBuilder( @@ -271,16 +276,6 @@ abstract class AppRoutes { ), ], ), - GoRoute( - path: ':langcode', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - CreatePangeaAccountPage( - langCode: state.pathParameters['langcode']!, - ), - ), - ), ], ), GoRoute( diff --git a/lib/pangea/guard/p_vguard.dart b/lib/pangea/guard/p_vguard.dart index 2e2291f5a..42ec76e87 100644 --- a/lib/pangea/guard/p_vguard.dart +++ b/lib/pangea/guard/p_vguard.dart @@ -27,12 +27,7 @@ class PAuthGaurd { // If user hasn't set their L2, // and their URL doesn’t include ‘course,’ redirect final bool hasSetL2 = await pController!.userController.isUserL2Set; - final langCode = state.pathParameters['langcode']; - return !hasSetL2 - ? langCode != null - ? '/registration/$langCode' - : '/registration' - : '/rooms'; + return !hasSetL2 ? '/registration/create' : '/rooms'; } /// Redirect for /rooms routes @@ -53,13 +48,7 @@ class PAuthGaurd { // If user hasn't set their L2, // and their URL doesn’t include ‘course,’ redirect final bool hasSetL2 = await pController!.userController.isUserL2Set; - - final langCode = state.pathParameters['langcode']; - return !hasSetL2 - ? langCode != null - ? '/registration/$langCode' - : '/registration' - : null; + return !hasSetL2 ? '/registration/create' : null; } /// Redirect for onboarding routes diff --git a/lib/pangea/login/pages/create_pangea_account_page.dart b/lib/pangea/login/pages/create_pangea_account_page.dart index b52f33efd..cc9e418ce 100644 --- a/lib/pangea/login/pages/create_pangea_account_page.dart +++ b/lib/pangea/login/pages/create_pangea_account_page.dart @@ -10,14 +10,15 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/widgets/error_indicator.dart'; +import 'package:fluffychat/pangea/course_plans/course_plan_room_extension.dart'; +import 'package:fluffychat/pangea/course_plans/course_plans_repo.dart'; import 'package:fluffychat/pangea/learning_settings/utils/p_language_store.dart'; +import 'package:fluffychat/pangea/login/utils/lang_code_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; class CreatePangeaAccountPage extends StatefulWidget { - final String langCode; const CreatePangeaAccountPage({ super.key, - required this.langCode, }); @override @@ -25,8 +26,10 @@ class CreatePangeaAccountPage extends StatefulWidget { } class CreatePangeaAccountPageState extends State { - bool _loadingProfile = true; + bool _loading = true; + Object? _profileError; + Object? _courseError; final List avatarPaths = const [ "assets/pangea/Avatar_1.png", @@ -39,7 +42,69 @@ class CreatePangeaAccountPageState extends State { @override void initState() { super.initState(); - _createUserInPangea(); + _createProfile(); + } + + String? _spaceId; + String? _courseLangCode; + + String? get _cachedLangCode => LangCodeRepo.get(); + + String? get _langCode => _courseLangCode ?? _cachedLangCode; + + String? get _cachedSpaceCode => + MatrixState.pangeaController.spaceCodeController.cachedSpaceCode; + + Future _createProfile() async { + setState(() { + _loading = true; + _profileError = null; + _courseError = null; + }); + + await _joinCachedCourse(); + if (mounted) { + await _createUserInPangea(); + } + if (mounted) { + setState(() => _loading = false); + } + } + + Future _joinCachedCourse() async { + await MatrixState.pangeaController.spaceCodeController.initCompleter.future; + if (_cachedSpaceCode == null) return; + + try { + final spaceId = await MatrixState.pangeaController.spaceCodeController + .joinCachedSpaceCode(context); + + if (spaceId == null) { + throw Exception('Failed to join space with code $_cachedSpaceCode'); + } + + final client = Matrix.of(context).client; + Room? room = client.getRoomById(spaceId); + if (room == null || room.membership != Membership.join) { + await client.waitForRoomInSync(spaceId, join: true); + room = client.getRoomById(spaceId); + if (room == null || room.membership != Membership.join) { + throw Exception('Failed to join space with code $_cachedSpaceCode'); + } + } + + final courseId = room.coursePlan?.uuid; + if (courseId == null) { + throw Exception('No course plan associated with space $spaceId'); + } + + final course = await CoursePlansRepo.get(courseId); + + _spaceId = spaceId; + _courseLangCode = course.targetLanguage; + } catch (err) { + _courseError = err; + } } Future _setAvatar() async { @@ -68,7 +133,7 @@ class CreatePangeaAccountPageState extends State { Future _updateTargetLanguage() async { await MatrixState.pangeaController.userController.updateProfile( (profile) { - profile.userSettings.targetLanguage = widget.langCode; + profile.userSettings.targetLanguage = _langCode; return profile; }, waitForDataInSync: true, @@ -76,11 +141,6 @@ class CreatePangeaAccountPageState extends State { } Future _createUserInPangea() async { - setState(() { - _loadingProfile = true; - _profileError = null; - }); - final l2Set = await MatrixState.pangeaController.userController.isUserL2Set; if (l2Set) { await _updateTargetLanguage(); @@ -89,6 +149,10 @@ class CreatePangeaAccountPageState extends State { } try { + if (_langCode == null) { + throw Exception('No language selected'); + } + final updateFuture = [ _setAvatar(), MatrixState.pangeaController.userController.updateProfile( @@ -100,14 +164,14 @@ class CreatePangeaAccountPageState extends State { profile.userSettings.sourceLanguage = systemLang; } - profile.userSettings.targetLanguage = widget.langCode; + profile.userSettings.targetLanguage = _langCode; profile.userSettings.createdAt = DateTime.now(); return profile; }, waitForDataInSync: true, ), MatrixState.pangeaController.userController.updateAnalyticsProfile( - targetLanguage: PLanguageStore.byLangCode(widget.langCode), + targetLanguage: PLanguageStore.byLangCode(_langCode!), baseLanguage: MatrixState.pangeaController.languageController.systemLanguage, level: 1, @@ -129,32 +193,26 @@ class CreatePangeaAccountPageState extends State { } else { _profileError = err; } - } finally { - if (mounted) { - setState(() => _loadingProfile = false); - } } } Future _onProfileCreated() async { - final joinedSpaceId = await MatrixState.pangeaController.spaceCodeController - .joinCachedSpaceCode(context); - if (joinedSpaceId != null) return; - context.go('/registration/course'); + await LangCodeRepo.remove(); + context.go( + _spaceId != null + ? '/rooms/spaces/$_spaceId/details' + : '/registration/course', + ); } @override Widget build(BuildContext context) { - if (_loadingProfile && _profileError != null) { - _onProfileCreated(); - } - return Scaffold( body: SafeArea( child: Center( - child: _loadingProfile + child: _loading ? const CircularProgressIndicator.adaptive() - : _profileError != null + : _profileError != null || _courseError != null ? Column( spacing: 8.0, mainAxisSize: MainAxisSize.min, @@ -162,9 +220,19 @@ class CreatePangeaAccountPageState extends State { ErrorIndicator( message: L10n.of(context).oopsSomethingWentWrong, ), - TextButton( - onPressed: _createUserInPangea, - child: Text(L10n.of(context).tryAgain), + Row( + spacing: 8.0, + mainAxisSize: MainAxisSize.min, + children: [ + TextButton( + onPressed: _createUserInPangea, + child: Text(L10n.of(context).tryAgain), + ), + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(L10n.of(context).cancel), + ), + ], ), ], ) diff --git a/lib/pangea/login/pages/language_selection_page.dart b/lib/pangea/login/pages/language_selection_page.dart index 64f66cbe0..25e45f663 100644 --- a/lib/pangea/login/pages/language_selection_page.dart +++ b/lib/pangea/login/pages/language_selection_page.dart @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/learning_settings/models/language_model.dart'; +import 'package:fluffychat/pangea/login/utils/lang_code_repo.dart'; import 'package:fluffychat/widgets/matrix.dart'; class LanguageSelectionPage extends StatefulWidget { @@ -25,6 +26,17 @@ class LanguageSelectionPageState extends State { setState(() => _selectedLanguage = l); } + Future _submit() async { + if (_selectedLanguage == null) return; + + await LangCodeRepo.set(_selectedLanguage!.langCode); + context.go( + GoRouterState.of(context).fullPath?.contains('home') == true + ? '/home/language/signup' + : '/registration/create', + ); + } + @override Widget build(BuildContext context) { final theme = Theme.of(context); @@ -114,18 +126,7 @@ class LanguageSelectionPageState extends State { ), ), ElevatedButton( - onPressed: _selectedLanguage != null - ? () { - context.go( - GoRouterState.of(context) - .fullPath - ?.contains('home') == - true - ? '/home/signup/${_selectedLanguage!.langCode}' - : '/registration/${_selectedLanguage!.langCode}', - ); - } - : null, + onPressed: _selectedLanguage != null ? _submit : null, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, diff --git a/lib/pangea/login/pages/login_or_signup_view.dart b/lib/pangea/login/pages/login_or_signup_view.dart index f187984d9..26e123351 100644 --- a/lib/pangea/login/pages/login_or_signup_view.dart +++ b/lib/pangea/login/pages/login_or_signup_view.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/common/widgets/pangea_logo_svg.dart'; import 'package:fluffychat/pangea/login/widgets/app_config_dialog.dart'; +import 'package:fluffychat/widgets/matrix.dart'; class LoginOrSignupView extends StatefulWidget { const LoginOrSignupView({super.key}); @@ -24,6 +25,9 @@ class LoginOrSignupViewState extends State { _loadOverrides(); } + String? get _cachedSpaceCode => + MatrixState.pangeaController.spaceCodeController.cachedSpaceCode; + Future _loadOverrides() async { final overrides = await Environment.getAppConfigOverrides(); if (mounted) { @@ -93,7 +97,11 @@ class LoginOrSignupViewState extends State { mainAxisSize: MainAxisSize.min, children: [ ElevatedButton( - onPressed: () => context.go('/home/signup'), + onPressed: () => context.go( + _cachedSpaceCode != null + ? '/home/language/signup' + : '/home/language', + ), style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.onPrimaryContainer, diff --git a/lib/pangea/login/pages/signup.dart b/lib/pangea/login/pages/signup.dart index 8062c91cf..3028cc26e 100644 --- a/lib/pangea/login/pages/signup.dart +++ b/lib/pangea/login/pages/signup.dart @@ -14,10 +14,8 @@ import 'package:fluffychat/widgets/matrix.dart'; class SignupPage extends StatefulWidget { final bool withEmail; - final String langCode; const SignupPage({ - required this.langCode, this.withEmail = false, super.key, }); @@ -178,7 +176,7 @@ class SignupPageController extends State { }, ); - if (!resp.isError) context.go('/registration/${widget.langCode}'); + if (!resp.isError) context.go('/registration/create'); } Future _signupFuture() async { diff --git a/lib/pangea/login/pages/signup_view.dart b/lib/pangea/login/pages/signup_view.dart index 4ec01ad9a..caa985e98 100644 --- a/lib/pangea/login/pages/signup_view.dart +++ b/lib/pangea/login/pages/signup_view.dart @@ -59,7 +59,7 @@ class SignupPageView extends StatelessWidget { ), ElevatedButton( onPressed: () => context.go( - '/home/signup/${controller.widget.langCode}/email', + '/home/language/signup/email', ), style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, diff --git a/lib/pangea/login/pages/user_settings.dart b/lib/pangea/login/pages/user_settings.dart deleted file mode 100644 index fac051685..000000000 --- a/lib/pangea/login/pages/user_settings.dart +++ /dev/null @@ -1,278 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -import 'package:go_router/go_router.dart'; -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; -import 'package:fluffychat/pangea/common/utils/error_handler.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/utils/p_language_store.dart'; -import 'package:fluffychat/pangea/login/pages/user_settings_view.dart'; -import 'package:fluffychat/utils/file_selector.dart'; -import 'package:fluffychat/utils/localized_exception_extension.dart'; -import 'package:fluffychat/widgets/future_loading_dialog.dart'; -import 'package:fluffychat/widgets/matrix.dart'; - -class UserSettingsPage extends StatefulWidget { - const UserSettingsPage({super.key}); - - @override - UserSettingsState createState() => UserSettingsState(); -} - -class UserSettingsState extends State { - PangeaController get _pangeaController => MatrixState.pangeaController; - - LanguageModel? selectedTargetLanguage; - LanguageModel? selectedBaseLanguage; - bool showBaseLanguageDropdown = false; - - LanguageLevelTypeEnum selectedCefrLevel = LanguageLevelTypeEnum.a1; - - String? selectedLanguageError; - String? profileCreationError; - String? tncError; - - bool loading = false; - - Uint8List? avatar; - String? _selectedFilePath; - - List avatarPaths = const [ - "assets/pangea/Avatar_1.png", - "assets/pangea/Avatar_2.png", - "assets/pangea/Avatar_3.png", - "assets/pangea/Avatar_4.png", - "assets/pangea/Avatar_5.png", - ]; - String? selectedAvatarPath; - - LanguageModel? get _systemLanguage { - final systemLangCode = - _pangeaController.languageController.systemLanguage?.langCode; - return systemLangCode == null - ? null - : PLanguageStore.byLangCode(systemLangCode); - } - - TextEditingController displayNameController = TextEditingController(); - final GlobalKey formKey = GlobalKey(); - - @override - void initState() { - super.initState(); - selectedBaseLanguage = - _pangeaController.languageController.userL1 ?? _systemLanguage; - selectedTargetLanguage = _pangeaController.languageController.userL2; - - displayNameController.text = Matrix.of(context).client.userID?.localpart ?? - Matrix.of(context).client.userID ?? - ""; - - final random = Random(); - selectedAvatarPath = avatarPaths[random.nextInt(avatarPaths.length)]; - } - - @override - void dispose() { - displayNameController.dispose(); - loading = false; - selectedLanguageError = null; - profileCreationError = null; - tncError = null; - super.dispose(); - } - - void setSelectedBaseLanguage(LanguageModel? language) { - setState(() { - selectedBaseLanguage = language; - selectedLanguageError = null; - }); - } - - void setSelectedTargetLanguage(LanguageModel? language) { - setState(() { - selectedTargetLanguage = language; - selectedLanguageError = null; - if (!showBaseLanguageDropdown && _hasIdenticalLanguages) { - showBaseLanguageDropdown = true; - } - }); - } - - void setSelectedCefrLevel(LanguageLevelTypeEnum? cefrLevel) { - setState(() { - selectedCefrLevel = cefrLevel ?? LanguageLevelTypeEnum.a1; - }); - } - - void setSelectedAvatarPath(int index) { - if (index < 0 || index >= avatarPaths.length) return; - setState(() { - avatar = null; - selectedAvatarPath = avatarPaths[index]; - }); - } - - int get selectedAvatarIndex { - if (selectedAvatarPath == null) return -1; - return avatarPaths.indexOf(selectedAvatarPath!); - } - - void uploadAvatar() async { - final photo = await selectFiles( - context, - type: FileSelectorType.images, - allowMultiple: false, - ); - final selectedFile = photo.singleOrNull; - final bytes = await selectedFile?.readAsBytes(); - final path = selectedFile?.path; - - if (bytes == null || path == null) { - return; - } - - setState(() { - selectedAvatarPath = null; - avatar = bytes; - _selectedFilePath = path; - }); - } - - Future _setAvatar() async { - final client = Matrix.of(context).client; - try { - MatrixFile? file; - if (avatar != null && _selectedFilePath != null) { - file = MatrixFile( - bytes: avatar!, - name: _selectedFilePath!, - ); - } else if (selectedAvatarPath != null) { - final ByteData byteData = await rootBundle.load(selectedAvatarPath!); - final Uint8List bytes = byteData.buffer.asUint8List(); - file = MatrixFile( - bytes: bytes, - name: selectedAvatarPath!, - ); - } - if (file != null) await client.setAvatar(file); - } catch (err, s) { - ErrorHandler.logError( - e: err, - s: s, - data: { - "avatar": avatar.toString(), - }, - ); - } - } - - Future _setDisplayName() async { - final displayName = displayNameController.text.trim(); - if (displayName.isEmpty) return; - - final client = Matrix.of(context).client; - if (client.userID == null) return; - await client.setDisplayName(client.userID!, displayName); - } - - Future createUserInPangea() async { - setState(() { - profileCreationError = null; - selectedLanguageError = null; - tncError = null; - }); - - if (selectedTargetLanguage == null) { - setState(() { - selectedLanguageError = L10n.of(context).pleaseSelectALanguage; - }); - return; - } - - if (_hasIdenticalLanguages) { - setState(() { - selectedLanguageError = L10n.of(context).noIdenticalLanguages; - }); - return; - } - - if (!formKey.currentState!.validate()) return; - setState(() => loading = true); - - try { - final updateFuture = [ - _setDisplayName(), - _setAvatar(), - _pangeaController.subscriptionController.reinitialize(), - _pangeaController.userController.updateProfile( - (profile) { - profile.userSettings.sourceLanguage = - selectedBaseLanguage?.langCode ?? _systemLanguage?.langCode; - profile.userSettings.targetLanguage = - selectedTargetLanguage!.langCode; - profile.userSettings.cefrLevel = selectedCefrLevel; - profile.userSettings.createdAt = DateTime.now(); - return profile; - }, - waitForDataInSync: true, - ), - _pangeaController.userController.updateAnalyticsProfile( - targetLanguage: selectedTargetLanguage, - baseLanguage: _systemLanguage, - level: 1, - ), - ]; - - await showFutureLoadingDialog( - context: context, - future: () => Future.wait(updateFuture).timeout( - const Duration(seconds: 30), - onTimeout: () { - throw TimeoutException(L10n.of(context).oopsSomethingWentWrong); - }, - ), - ); - - await _pangeaController.subscriptionController.reinitialize(); - context.go( - _pangeaController.spaceCodeController.cachedSpaceCode == null - ? '/user_age/join_space' - : '/rooms', - ); - } catch (err) { - if (err is MatrixException) { - profileCreationError = err.errorMessage; - } else { - profileCreationError = err.toLocalizedString(context); - } - if (mounted) setState(() {}); - } finally { - if (mounted) { - setState(() => loading = false); - } - } - } - - List get targetOptions => - _pangeaController.pLanguageStore.targetOptions; - - List get baseOptions => - MatrixState.pangeaController.pLanguageStore.baseOptions; - - bool get _hasIdenticalLanguages => - selectedBaseLanguage != null && - selectedTargetLanguage?.langCodeShort == - selectedBaseLanguage?.langCodeShort; - - @override - Widget build(BuildContext context) => UserSettingsView(controller: this); -} diff --git a/lib/pangea/login/pages/user_settings_view.dart b/lib/pangea/login/pages/user_settings_view.dart deleted file mode 100644 index 995573527..000000000 --- a/lib/pangea/login/pages/user_settings_view.dart +++ /dev/null @@ -1,198 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:collection/collection.dart'; - -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/themes.dart'; -import 'package:fluffychat/l10n/l10n.dart'; -import 'package:fluffychat/pangea/chat_settings/widgets/language_level_dropdown.dart'; -import 'package:fluffychat/pangea/learning_settings/widgets/p_language_dropdown.dart'; -import 'package:fluffychat/pangea/login/pages/pangea_login_scaffold.dart'; -import 'package:fluffychat/pangea/login/pages/user_settings.dart'; -import 'package:fluffychat/pangea/login/widgets/full_width_button.dart'; -import 'package:fluffychat/pangea/user/utils/p_logout.dart'; - -class UserSettingsView extends StatelessWidget { - final UserSettingsState controller; - - const UserSettingsView({ - required this.controller, - super.key, - }); - - final double avatarSize = 55.0; - - @override - Widget build(BuildContext context) { - final List avatarOptions = controller.avatarPaths - .mapIndexed((index, path) { - return Padding( - padding: const EdgeInsets.all(5), - child: AvatarOption( - onTap: () => controller.setSelectedAvatarPath(index), - path: path, - selected: controller.selectedAvatarIndex == index, - size: avatarSize, - ), - ); - }) - .cast() - .toList(); - - avatarOptions.add( - Padding( - padding: const EdgeInsets.all(5), - child: InkWell( - onTap: controller.uploadAvatar, - child: Container( - width: avatarSize, - height: avatarSize, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - border: Border.all( - color: controller.avatar != null - ? AppConfig.activeToggleColor - : Theme.of(context).colorScheme.primary, - width: 2, - ), - ), - child: Icon( - Icons.upload, - color: Theme.of(context).colorScheme.primary, - size: 30, - ), - ), - ), - ), - ); - - return Form( - key: controller.formKey, - child: PangeaLoginScaffold( - customAppBar: AppBar( - leading: BackButton( - onPressed: () => pLogoutAction( - context, - bypassWarning: true, - ), - ), - ), - showAppName: false, - mainAssetPath: controller.selectedAvatarPath ?? "", - mainAssetBytes: controller.avatar, - children: [ - Opacity( - opacity: 0.9, - child: Text( - L10n.of(context).chooseYourAvatar, - style: const TextStyle( - fontWeight: FontWeight.w100, - fontStyle: FontStyle.italic, - ), - ), - ), - Wrap( - alignment: WrapAlignment.center, - children: avatarOptions, - ), - FullWidthTextField( - labelText: L10n.of(context).displayName, - hintText: L10n.of(context).username, - validator: (username) { - if (username == null || username.isEmpty) { - return L10n.of(context).pleaseChooseAUsername; - } - return null; - }, - controller: controller.displayNameController, - ), - AnimatedSize( - duration: FluffyThemes.animationDuration, - child: controller.showBaseLanguageDropdown - ? Padding( - padding: const EdgeInsets.all(8), - child: PLanguageDropdown( - languages: controller.baseOptions, - onChange: controller.setSelectedBaseLanguage, - initialLanguage: controller.selectedBaseLanguage, - hasError: controller.selectedLanguageError != null, - decorationText: L10n.of(context).myBaseLanguage, - ), - ) - : const SizedBox(), - ), - Padding( - padding: const EdgeInsets.all(8), - child: PLanguageDropdown( - languages: controller.targetOptions, - onChange: controller.setSelectedTargetLanguage, - initialLanguage: controller.selectedTargetLanguage, - isL2List: true, - error: controller.selectedLanguageError, - decorationText: L10n.of(context).iWantToLearn, - ), - ), - Padding( - padding: const EdgeInsets.all(8), - child: LanguageLevelDropdown( - onChanged: controller.setSelectedCefrLevel, - initialLevel: controller.selectedCefrLevel, - ), - ), - FullWidthButton( - title: L10n.of(context).letsStart, - onPressed: controller.selectedTargetLanguage != null - ? controller.createUserInPangea - : null, - error: controller.profileCreationError, - loading: controller.loading, - enabled: controller.selectedTargetLanguage != null, - ), - ], - ), - ); - } -} - -class AvatarOption extends StatelessWidget { - final VoidCallback onTap; - final String path; // Path or URL of the SVG file - final double size; // Diameter of the circle - final bool selected; - - const AvatarOption({ - super.key, - required this.onTap, - required this.path, - this.size = 40.0, - this.selected = false, - }); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Container( - width: size, - height: size, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - border: Border.all( - color: selected - ? AppConfig.activeToggleColor - : Theme.of(context).colorScheme.primary, - width: 2, - ), - ), - child: ClipOval( - child: Image.asset( - path, - fit: BoxFit.cover, // scale properly without warping - ), - ), - ), - ); - } -} diff --git a/lib/pangea/login/utils/lang_code_repo.dart b/lib/pangea/login/utils/lang_code_repo.dart new file mode 100644 index 000000000..c2647b81a --- /dev/null +++ b/lib/pangea/login/utils/lang_code_repo.dart @@ -0,0 +1,17 @@ +import 'package:get_storage/get_storage.dart'; + +class LangCodeRepo { + static final GetStorage _storage = GetStorage('lang_code_storage'); + + static String? get() { + return _storage.read('lang_code'); + } + + static Future set(String langcode) async { + await _storage.write('lang_code', langcode); + } + + static Future remove() async { + await _storage.remove('lang_code'); + } +} diff --git a/lib/pangea/login/utils/sso_login_action.dart b/lib/pangea/login/utils/sso_login_action.dart index fe7c78163..c552d9008 100644 --- a/lib/pangea/login/utils/sso_login_action.dart +++ b/lib/pangea/login/utils/sso_login_action.dart @@ -54,9 +54,6 @@ Future pangeaSSOLoginAction( final token = Uri.parse(result).queryParameters['loginToken']; if (token?.isEmpty ?? false) return; - final langCode = FluffyChatApp.router.state.pathParameters['langcode']; - final path = langCode != null ? '/registration/$langCode' : '/registration'; - final redirect = client.onLoginStateChanged.stream .where((state) => state == LoginState.loggedIn) .first @@ -65,7 +62,7 @@ Future pangeaSSOLoginAction( final route = FluffyChatApp.router.state.fullPath; if (route == null || (!route.contains("/rooms") && !route.contains('registration'))) { - context.go(path); + context.go('/registration/create'); } }, ).timeout(const Duration(seconds: 30)); @@ -80,7 +77,7 @@ Future pangeaSSOLoginAction( final route = FluffyChatApp.router.state.fullPath; if (route == null || (!route.contains("/rooms") && !route.contains('registration'))) { - context.go(path); + context.go('/registration/create'); } } else { await redirect; diff --git a/lib/pangea/spaces/controllers/space_code_controller.dart b/lib/pangea/spaces/controllers/space_code_controller.dart index d20129f1a..1ab87d826 100644 --- a/lib/pangea/spaces/controllers/space_code_controller.dart +++ b/lib/pangea/spaces/controllers/space_code_controller.dart @@ -21,8 +21,13 @@ class SpaceCodeController extends BaseController { late PangeaController _pangeaController; static final GetStorage _spaceStorage = GetStorage('class_storage'); + Completer initCompleter = Completer(); + SpaceCodeController(PangeaController pangeaController) : super() { _pangeaController = pangeaController; + GetStorage.init('class_storage').then( + (_) => initCompleter.complete(), + ); } Future cacheSpaceCode(String code) async { diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index 7641ff9d7..33d9d4385 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -380,14 +380,11 @@ class MatrixState extends State with WidgetsBindingObserver { } else { // #Pangea final isL2Set = await pangeaController.userController.isUserL2Set; - final langCode = FluffyChatApp.router.state.pathParameters['langcode']; - final registrationRedirect = - langCode != null ? '/registration/$langCode' : '/registration'; FluffyChatApp.router.go( state == LoginState.loggedIn ? isL2Set ? '/rooms' - : registrationRedirect + : '/registration/create' : '/home', ); // FluffyChatApp.router