diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index e0c3740fd..a03e428ec 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4922,5 +4922,15 @@ } } }, - "leaderboard": "Leaderboard" + "leaderboard": "Leaderboard", + "welcomeUser": "Welcome {user}", + "@welcomeUser": { + "placeholders": { + "user": { + "type": "String" + } + } + }, + "joinSpaceOnboardingDesc": "Do you have an invite code or link to a learning community?", + "skipForNow": "Skip for now" } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index b6616227c..7d6653866 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -37,6 +37,7 @@ import 'package:fluffychat/pangea/layouts/bottom_nav_layout.dart'; import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart'; import 'package:fluffychat/pangea/login/pages/login_or_signup_view.dart'; import 'package:fluffychat/pangea/login/pages/signup.dart'; +import 'package:fluffychat/pangea/login/pages/space_code_onboarding.dart'; import 'package:fluffychat/pangea/login/pages/user_settings.dart'; import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; import 'package:fluffychat/pangea/spaces/utils/join_with_alias.dart'; @@ -173,6 +174,19 @@ abstract class AppRoutes { const UserSettingsPage(), ), redirect: loggedOutRedirect, + routes: [ + GoRoute( + path: 'join_space', + pageBuilder: (context, state) { + return defaultPageBuilder( + context, + state, + const SpaceCodeOnboarding(), + ); + }, + redirect: loggedOutRedirect, + ), + ], ), ShellRoute( pageBuilder: chatListShellRouteBuilder, diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 3318c198b..9b7f8162f 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -19,7 +19,6 @@ import 'package:fluffychat/pages/chat_list/chat_list_view.dart'; import 'package:fluffychat/pangea/chat_list/utils/app_version_util.dart'; import 'package:fluffychat/pangea/chat_list/utils/chat_list_handle_space_tap.dart'; import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart'; -import 'package:fluffychat/pangea/common/constants/local.key.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/common/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; @@ -43,6 +42,7 @@ import '../../widgets/matrix.dart'; import 'package:fluffychat/utils/tor_stub.dart' if (dart.library.html) 'package:tor_detector_web/tor_detector_web.dart'; + enum PopupMenuAction { settings, invite, @@ -533,9 +533,7 @@ class ChatListController extends State // #Pangea final String? justInputtedCode = - MatrixState.pangeaController.classController.chatBox.read( - PLocalKey.justInputtedCode, - ); + MatrixState.pangeaController.classController.justInputtedCode(); final newSpaceCode = space?.classCode(context); if (newSpaceCode == justInputtedCode) return; diff --git a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart index 7ee15eb63..4ef8af2b5 100644 --- a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart +++ b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart @@ -5,7 +5,6 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat_list/chat_list.dart'; -import 'package:fluffychat/pangea/common/constants/local.key.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -50,9 +49,8 @@ void chatListHandleSpaceTap( (element) => element.isSpace && element.membership == Membership.join, ); - final justInputtedCode = MatrixState - .pangeaController.classController.chatBox - .read(PLocalKey.justInputtedCode); + final justInputtedCode = + MatrixState.pangeaController.classController.justInputtedCode(); if (rooms.any((s) => s.spaceChildren.any((c) => c.roomId == space.id))) { autoJoin(space); } else if (justInputtedCode != null && diff --git a/lib/pangea/login/pages/pangea_login_scaffold.dart b/lib/pangea/login/pages/pangea_login_scaffold.dart index 74b47e552..ee43ae212 100644 --- a/lib/pangea/login/pages/pangea_login_scaffold.dart +++ b/lib/pangea/login/pages/pangea_login_scaffold.dart @@ -4,10 +4,12 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/widgets/mxc_image.dart'; class PangeaLoginScaffold extends StatelessWidget { final String mainAssetPath; final Uint8List? mainAssetBytes; + final Uri? mainAssetUrl; final List children; final bool showAppName; final AppBar? customAppBar; @@ -16,6 +18,7 @@ class PangeaLoginScaffold extends StatelessWidget { required this.children, this.mainAssetPath = "assets/pangea/PangeaChat_Glow_Logo.png", this.mainAssetBytes, + this.mainAssetUrl, this.showAppName = true, this.customAppBar, super.key, @@ -58,10 +61,22 @@ class PangeaLoginScaffold extends StatelessWidget { mainAssetBytes!, fit: BoxFit.cover, ) - : Image.asset( - mainAssetPath, - fit: BoxFit.cover, - ), + : mainAssetUrl != null + ? mainAssetUrl!.toString().startsWith("mxc") + ? MxcImage( + uri: mainAssetUrl, + fit: BoxFit.cover, + width: isColumnMode ? 175 : 125, + height: isColumnMode ? 175 : 125, + ) + : Image.network( + mainAssetUrl.toString(), + fit: BoxFit.cover, + ) + : Image.asset( + mainAssetPath, + fit: BoxFit.cover, + ), ), ), if (showAppName) diff --git a/lib/pangea/login/pages/space_code_onboarding.dart b/lib/pangea/login/pages/space_code_onboarding.dart new file mode 100644 index 000000000..5d4c732db --- /dev/null +++ b/lib/pangea/login/pages/space_code_onboarding.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; + +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/login/pages/space_code_onboarding_view.dart'; +import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; +import 'package:fluffychat/widgets/matrix.dart'; + +class SpaceCodeOnboarding extends StatefulWidget { + const SpaceCodeOnboarding({super.key}); + + @override + State createState() => SpaceCodeOnboardingState(); +} + +class SpaceCodeOnboardingState extends State { + Profile? profile; + Client get client => Matrix.of(context).client; + + final TextEditingController codeController = TextEditingController(); + + @override + void initState() { + _setProfile(); + codeController.addListener(() { + if (mounted) setState(() {}); + }); + super.initState(); + } + + @override + void dispose() { + codeController.dispose(); + super.dispose(); + } + + Future _setProfile() async { + try { + profile = await client.getProfileFromUserId( + client.userID!, + ); + } catch (e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + 'userId': client.userID, + }, + ); + } finally { + if (mounted) setState(() {}); + } + } + + Future submitCode() async { + String code = codeController.text.trim(); + if (code.isEmpty) return; + + try { + final link = Uri.parse(Uri.parse(code).fragment); + if (link.queryParameters.containsKey(SpaceConstants.classCode)) { + code = link.queryParameters[SpaceConstants.classCode]!; + } + } catch (e) { + debugPrint("Text input is not a URL: $e"); + } + + await MatrixState.pangeaController.classController + .joinClasswithCode(context, code); + } + + @override + Widget build(BuildContext context) => + SpaceCodeOnboardingView(controller: this); +} diff --git a/lib/pangea/login/pages/space_code_onboarding_view.dart b/lib/pangea/login/pages/space_code_onboarding_view.dart new file mode 100644 index 000000000..3a25421ec --- /dev/null +++ b/lib/pangea/login/pages/space_code_onboarding_view.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/login/pages/pangea_login_scaffold.dart'; +import 'package:fluffychat/pangea/login/pages/space_code_onboarding.dart'; +import 'package:fluffychat/pangea/login/widgets/full_width_button.dart'; +import 'package:fluffychat/pangea/user/utils/p_logout.dart'; + +class SpaceCodeOnboardingView extends StatelessWidget { + final SpaceCodeOnboardingState controller; + const SpaceCodeOnboardingView({ + super.key, + required this.controller, + }); + + @override + Widget build(BuildContext context) { + return PangeaLoginScaffold( + customAppBar: AppBar( + leading: BackButton( + onPressed: () => pLogoutAction( + context, + bypassWarning: true, + ), + ), + ), + showAppName: false, + mainAssetUrl: controller.profile?.avatarUrl, + children: [ + Text( + L10n.of(context).welcomeUser( + controller.profile?.displayName ?? + controller.client.userID?.localpart ?? + "", + ), + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 8.0), + Text( + L10n.of(context).joinSpaceOnboardingDesc, + textAlign: TextAlign.center, + ), + const SizedBox(height: 8.0), + FullWidthTextField( + hintText: L10n.of(context).enterCodeToJoin, + controller: controller.codeController, + onSubmitted: (_) => controller.submitCode, + ), + FullWidthButton( + title: L10n.of(context).join, + onPressed: controller.submitCode, + enabled: controller.codeController.text.isNotEmpty, + ), + const SizedBox(height: 8.0), + TextButton( + child: Text(L10n.of(context).skipForNow), + onPressed: () => context.go("/rooms"), + ), + ], + ); + } +} diff --git a/lib/pangea/login/pages/user_settings.dart b/lib/pangea/login/pages/user_settings.dart index f4b9673f3..9056c963d 100644 --- a/lib/pangea/login/pages/user_settings.dart +++ b/lib/pangea/login/pages/user_settings.dart @@ -207,7 +207,11 @@ class UserSettingsState extends State { throw TimeoutException(L10n.of(context).oopsSomethingWentWrong); }, ); - context.go('/rooms'); + context.go( + _pangeaController.classController.cachedClassCode == null + ? '/user_age/join_space' + : '/rooms', + ); } catch (err) { if (err is MatrixException) { profileCreationError = err.errorMessage; diff --git a/lib/pangea/spaces/controllers/space_controller.dart b/lib/pangea/spaces/controllers/space_controller.dart index a38a73011..4689daae4 100644 --- a/lib/pangea/spaces/controllers/space_controller.dart +++ b/lib/pangea/spaces/controllers/space_controller.dart @@ -23,22 +23,35 @@ import '../../common/controllers/base_controller.dart'; class ClassController extends BaseController { late PangeaController _pangeaController; - - // Storage Initialization - final GetStorage chatBox = GetStorage("chat_list_storage"); - final GetStorage linkBox = GetStorage("link_storage"); static final GetStorage _classStorage = GetStorage('class_storage'); ClassController(PangeaController pangeaController) : super() { _pangeaController = pangeaController; } - Future joinCachedSpaceCode(BuildContext context) async { - final String? classCode = linkBox.read( + Future cacheSpaceCode(String code) async { + if (code.isEmpty) return; + await _classStorage.write( PLocalKey.cachedClassCodeToJoin, + code, ); + } - final String? alias = _classStorage.read(PLocalKey.cachedAliasToJoin); + String? justInputtedCode() { + return _classStorage.read(PLocalKey.justInputtedCode); + } + + String? get cachedClassCode { + return _classStorage.read(PLocalKey.cachedClassCodeToJoin); + } + + String? get cachedAlias { + return _classStorage.read(PLocalKey.cachedAliasToJoin); + } + + Future joinCachedSpaceCode(BuildContext context) async { + final String? classCode = cachedClassCode; + final String? alias = cachedAlias; if (classCode != null) { await joinClasswithCode( @@ -46,7 +59,7 @@ class ClassController extends BaseController { classCode, ); - await linkBox.remove( + await _classStorage.remove( PLocalKey.cachedClassCodeToJoin, ); } else if (alias != null) { @@ -141,7 +154,7 @@ class ClassController extends BaseController { } final chosenClassId = foundClasses.first; - await chatBox.write( + await _classStorage.write( PLocalKey.justInputtedCode, classCode, ); diff --git a/lib/pangea/spaces/utils/join_with_link.dart b/lib/pangea/spaces/utils/join_with_link.dart index c4eac340a..e584d24fb 100644 --- a/lib/pangea/spaces/utils/join_with_link.dart +++ b/lib/pangea/spaces/utils/join_with_link.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:fluffychat/pangea/common/constants/local.key.dart'; import 'package:fluffychat/widgets/matrix.dart'; //if on home with classcode in url and not logged in, then save it soemhow and after llogin, join class automatically @@ -32,10 +31,11 @@ class _JoinClassWithLinkState extends State { ); return; } - await MatrixState.pangeaController.classController.linkBox.write( - PLocalKey.cachedClassCodeToJoin, - widget.classCode, - ); + + if (widget.classCode != null) { + await MatrixState.pangeaController.classController + .cacheSpaceCode(widget.classCode!); + } context.go("/home"); }); }