feat: set initial L2 via cached space code course target language if available (#4264)

This commit is contained in:
ggurdin 2025-10-07 11:25:46 -04:00 committed by GitHub
parent 9790d2e56d
commit a44e378f4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 160 additions and 561 deletions

View file

@ -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(

View file

@ -27,12 +27,7 @@ class PAuthGaurd {
// If user hasn't set their L2,
// and their URL doesnt 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 doesnt 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

View file

@ -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<CreatePangeaAccountPage> {
bool _loadingProfile = true;
bool _loading = true;
Object? _profileError;
Object? _courseError;
final List<String> avatarPaths = const [
"assets/pangea/Avatar_1.png",
@ -39,7 +42,69 @@ class CreatePangeaAccountPageState extends State<CreatePangeaAccountPage> {
@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<void> _createProfile() async {
setState(() {
_loading = true;
_profileError = null;
_courseError = null;
});
await _joinCachedCourse();
if (mounted) {
await _createUserInPangea();
}
if (mounted) {
setState(() => _loading = false);
}
}
Future<void> _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<void> _setAvatar() async {
@ -68,7 +133,7 @@ class CreatePangeaAccountPageState extends State<CreatePangeaAccountPage> {
Future<void> _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<CreatePangeaAccountPage> {
}
Future<void> _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<CreatePangeaAccountPage> {
}
try {
if (_langCode == null) {
throw Exception('No language selected');
}
final updateFuture = [
_setAvatar(),
MatrixState.pangeaController.userController.updateProfile(
@ -100,14 +164,14 @@ class CreatePangeaAccountPageState extends State<CreatePangeaAccountPage> {
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<CreatePangeaAccountPage> {
} else {
_profileError = err;
}
} finally {
if (mounted) {
setState(() => _loadingProfile = false);
}
}
}
Future<void> _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<CreatePangeaAccountPage> {
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),
),
],
),
],
)

View file

@ -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<LanguageSelectionPage> {
setState(() => _selectedLanguage = l);
}
Future<void> _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<LanguageSelectionPage> {
),
),
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,

View file

@ -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<LoginOrSignupView> {
_loadOverrides();
}
String? get _cachedSpaceCode =>
MatrixState.pangeaController.spaceCodeController.cachedSpaceCode;
Future<void> _loadOverrides() async {
final overrides = await Environment.getAppConfigOverrides();
if (mounted) {
@ -93,7 +97,11 @@ class LoginOrSignupViewState extends State<LoginOrSignupView> {
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,

View file

@ -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<SignupPage> {
},
);
if (!resp.isError) context.go('/registration/${widget.langCode}');
if (!resp.isError) context.go('/registration/create');
}
Future<void> _signupFuture() async {

View file

@ -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,

View file

@ -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<UserSettingsPage> {
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<String> 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<FormState> formKey = GlobalKey<FormState>();
@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<void> _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<void> _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<void> 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<LanguageModel> get targetOptions =>
_pangeaController.pLanguageStore.targetOptions;
List<LanguageModel> get baseOptions =>
MatrixState.pangeaController.pLanguageStore.baseOptions;
bool get _hasIdenticalLanguages =>
selectedBaseLanguage != null &&
selectedTargetLanguage?.langCodeShort ==
selectedBaseLanguage?.langCodeShort;
@override
Widget build(BuildContext context) => UserSettingsView(controller: this);
}

View file

@ -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<Widget> 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<Widget>()
.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
),
),
),
);
}
}

View file

@ -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<void> set(String langcode) async {
await _storage.write('lang_code', langcode);
}
static Future<void> remove() async {
await _storage.remove('lang_code');
}
}

View file

@ -54,9 +54,6 @@ Future<void> 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<void> 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<void> 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;

View file

@ -21,8 +21,13 @@ class SpaceCodeController extends BaseController {
late PangeaController _pangeaController;
static final GetStorage _spaceStorage = GetStorage('class_storage');
Completer<void> initCompleter = Completer<void>();
SpaceCodeController(PangeaController pangeaController) : super() {
_pangeaController = pangeaController;
GetStorage.init('class_storage').then(
(_) => initCompleter.complete(),
);
}
Future<void> cacheSpaceCode(String code) async {

View file

@ -380,14 +380,11 @@ class MatrixState extends State<Matrix> 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