diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 955f0eb61..32268f90a 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -569,6 +569,7 @@ abstract class AppRoutes { state, ChatDetails( roomId: state.pathParameters['spaceid']!, + activeTab: state.uri.queryParameters['tab'], ), ), redirect: loggedOutRedirect, @@ -581,9 +582,16 @@ abstract class AppRoutes { const EmptyPage(), ), redirect: (context, state) { - final subroute = + String subroute = state.fullPath?.split(":spaceid/details").last ?? ""; + + if (state.uri.queryParameters.isNotEmpty) { + final queryString = state.uri.queryParameters.entries + .map((e) => '${e.key}=${e.value}') + .join('&'); + subroute = '$subroute?$queryString'; + } return "/rooms/spaces/${state.pathParameters['spaceid']}$subroute"; }, routes: roomDetailsRoutes('spaceid'), @@ -683,7 +691,14 @@ abstract class AppRoutes { // #Pangea // redirect: loggedOutRedirect, redirect: (context, state) { - final subroute = state.fullPath!.split('roomid').last; + String subroute = state.fullPath!.split('roomid').last; + if (state.uri.queryParameters.isNotEmpty) { + final queryString = state.uri.queryParameters.entries + .map((e) => '${e.key}=${e.value}') + .join('&'); + subroute = '$subroute?$queryString'; + } + final roomId = state.pathParameters['roomid']!; final room = Matrix.of(context).client.getRoomById(roomId); if (room != null && room.isSpace) { diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 21375a08c..3f7e5fa45 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -33,11 +33,17 @@ enum AliasActions { copy, delete, setCanonical } class ChatDetails extends StatefulWidget { final String roomId; final Widget? embeddedCloseButton; + // #Pangea + final String? activeTab; + // Pangea# const ChatDetails({ super.key, required this.roomId, this.embeddedCloseButton, + // #Pangea + this.activeTab, + // Pangea# }); @override diff --git a/lib/pangea/chat_settings/pages/space_details_content.dart b/lib/pangea/chat_settings/pages/space_details_content.dart index 7488d1a86..0d13558e3 100644 --- a/lib/pangea/chat_settings/pages/space_details_content.dart +++ b/lib/pangea/chat_settings/pages/space_details_content.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; import 'package:go_router/go_router.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:matrix/matrix.dart'; @@ -30,79 +31,71 @@ enum SpaceSettingsTabs { course, participants, analytics, - more, + more; + + static SpaceSettingsTabs? fromString(String value) { + return SpaceSettingsTabs.values.firstWhereOrNull( + (e) => e.name == value, + ); + } } -class SpaceDetailsContent extends StatefulWidget { +class SpaceDetailsContent extends StatelessWidget { final ChatDetailsController controller; final Room room; - const SpaceDetailsContent(this.controller, this.room, {super.key}); + const SpaceDetailsContent( + this.controller, + this.room, { + super.key, + }); - @override - State createState() => SpaceDetailsContentState(); -} - -class SpaceDetailsContentState extends State { - SpaceSettingsTabs? _selectedTab; + SpaceSettingsTabs tab(BuildContext context) { + final defaultTab = FluffyThemes.isColumnMode(context) + ? SpaceSettingsTabs.course + : SpaceSettingsTabs.chat; - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - setState( - () => _selectedTab = FluffyThemes.isColumnMode(context) - ? SpaceSettingsTabs.course - : SpaceSettingsTabs.chat, - ); - }); - } - - @override - void didUpdateWidget(covariant SpaceDetailsContent oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.room.id != widget.room.id) { - setState(() { - _selectedTab = FluffyThemes.isColumnMode(context) - ? SpaceSettingsTabs.course - : SpaceSettingsTabs.chat; - }); + final activeTab = controller.widget.activeTab; + if (activeTab != null) { + final selectedTab = SpaceSettingsTabs.fromString(activeTab); + return selectedTab ?? defaultTab; } + + return defaultTab; } - void setSelectedTab(SpaceSettingsTabs tab) { - setState(() { - _selectedTab = tab; - }); + void setSelectedTab(SpaceSettingsTabs tab, BuildContext context) { + context.go('/rooms/spaces/${room.id}/details?tab=${tab.name}'); } - List get _buttons { + List _buttons(BuildContext context) { final L10n l10n = L10n.of(context); return [ ButtonDetails( title: l10n.chats, icon: const Icon(Icons.chat_bubble_outline, size: 30.0), - onPressed: () => setSelectedTab(SpaceSettingsTabs.chat), + onPressed: () => setSelectedTab(SpaceSettingsTabs.chat, context), visible: !FluffyThemes.isColumnMode(context), tab: SpaceSettingsTabs.chat, ), ButtonDetails( title: l10n.coursePlan, icon: const Icon(Icons.map_outlined, size: 30.0), - onPressed: () => setSelectedTab(SpaceSettingsTabs.course), + onPressed: () => setSelectedTab(SpaceSettingsTabs.course, context), tab: SpaceSettingsTabs.course, ), ButtonDetails( title: l10n.participants, icon: const Icon(Icons.group_outlined, size: 30.0), - onPressed: () => setSelectedTab(SpaceSettingsTabs.participants), + onPressed: () => + setSelectedTab(SpaceSettingsTabs.participants, context), tab: SpaceSettingsTabs.participants, ), ButtonDetails( title: l10n.stats, icon: const Icon(Symbols.bar_chart_4_bars, size: 30.0), - onPressed: () => setSelectedTab(SpaceSettingsTabs.analytics), - enabled: widget.room.isRoomAdmin, + onPressed: () => setSelectedTab(SpaceSettingsTabs.analytics, context), + enabled: room.isRoomAdmin, tab: SpaceSettingsTabs.analytics, ), ButtonDetails( @@ -111,16 +104,14 @@ class SpaceDetailsContentState extends State { icon: const Icon(Icons.person_add_outlined, size: 30.0), onPressed: () { String filter = 'knocking'; - if (widget.room.getParticipants([Membership.knock]).isEmpty) { - filter = widget.room.pangeaSpaceParents.isNotEmpty - ? 'space' - : 'contacts'; + if (room.getParticipants([Membership.knock]).isEmpty) { + filter = room.pangeaSpaceParents.isNotEmpty ? 'space' : 'contacts'; } context.go( - '/rooms/spaces/${widget.room.id}/details/invite?filter=$filter', + '/rooms/spaces/${room.id}/details/invite?filter=$filter', ); }, - enabled: widget.room.canInvite && !widget.room.isDirectChat, + enabled: room.canInvite && !room.isDirectChat, showInMainView: false, ), ButtonDetails( @@ -129,33 +120,32 @@ class SpaceDetailsContentState extends State { icon: const Icon(Icons.edit_outlined, size: 30.0), onPressed: () {}, visible: false, - enabled: widget.room.canChangeStateEvent(PangeaEventTypes.coursePlan), + enabled: room.canChangeStateEvent(PangeaEventTypes.coursePlan), showInMainView: false, ), ButtonDetails( title: l10n.permissions, description: l10n.permissionsDesc, icon: const Icon(Icons.edit_attributes_outlined, size: 30.0), - onPressed: () => - context.go('/rooms/${widget.room.id}/details/permissions'), - enabled: widget.room.isRoomAdmin && !widget.room.isDirectChat, + onPressed: () => context.go('/rooms/${room.id}/details/permissions'), + enabled: room.isRoomAdmin && !room.isDirectChat, showInMainView: false, ), ButtonDetails( title: l10n.access, description: l10n.accessDesc, icon: const Icon(Icons.shield_outlined, size: 30.0), - onPressed: () => context.go('/rooms/${widget.room.id}/details/access'), - enabled: widget.room.isRoomAdmin && widget.room.spaceParents.isEmpty, + onPressed: () => context.go('/rooms/${room.id}/details/access'), + enabled: room.isRoomAdmin && room.spaceParents.isEmpty, showInMainView: false, ), ButtonDetails( title: l10n.createGroupChat, description: l10n.createGroupChatDesc, icon: const Icon(Symbols.chat_add_on, size: 30.0), - onPressed: widget.controller.addGroupChat, - enabled: widget.room.isRoomAdmin && - widget.room.canChangeStateEvent( + onPressed: controller.addGroupChat, + enabled: room.isRoomAdmin && + room.canChangeStateEvent( EventTypes.SpaceChild, ), showInMainView: false, @@ -176,13 +166,13 @@ class SpaceDetailsContentState extends State { if (confirmed != OkCancelResult.ok) return; final resp = await showFutureLoadingDialog( context: context, - future: widget.room.leaveSpace, + future: room.leaveSpace, ); if (!resp.isError) { context.go("/rooms"); } }, - enabled: widget.room.membership == Membership.join, + enabled: room.membership == Membership.join, showInMainView: false, ), ButtonDetails( @@ -195,14 +185,14 @@ class SpaceDetailsContentState extends State { onPressed: () async { final resp = await showDialog( context: context, - builder: (_) => DeleteSpaceDialog(space: widget.room), + builder: (_) => DeleteSpaceDialog(space: room), ); if (resp == true) { context.go("/rooms"); } }, - enabled: widget.room.isRoomAdmin && !widget.room.isDirectChat, + enabled: room.isRoomAdmin && !room.isDirectChat, showInMainView: false, ), ]; @@ -211,11 +201,11 @@ class SpaceDetailsContentState extends State { @override Widget build(BuildContext context) { final isColumnMode = FluffyThemes.isColumnMode(context); - final displayname = widget.room.getLocalizedDisplayname( + final displayname = room.getLocalizedDisplayname( MatrixLocals(L10n.of(context)), ); return CoursePlanBuilder( - courseId: widget.room.coursePlan?.uuid, + courseId: room.coursePlan?.uuid, builder: (context, courseController) { return Column( mainAxisSize: MainAxisSize.min, @@ -232,13 +222,12 @@ class SpaceDetailsContentState extends State { children: [ if (isColumnMode) ...[ Avatar( - mxContent: widget.room.avatar, + mxContent: room.avatar, name: displayname, - userId: widget.room.directChatMatrixID, + userId: room.directChatMatrixID, size: 80.0, - borderRadius: widget.room.isSpace - ? BorderRadius.circular(24.0) - : null, + borderRadius: + room.isSpace ? BorderRadius.circular(24.0) : null, ), const SizedBox(width: 16.0), ], @@ -271,51 +260,51 @@ class SpaceDetailsContentState extends State { ], ), ), - if (widget.room.classCode != null) + if (room.classCode != null) Padding( padding: const EdgeInsets.only(left: 16.0), - child: ShareRoomButton(room: widget.room), + child: ShareRoomButton(room: room), ), ], ), SizedBox(height: isColumnMode ? 24.0 : 12.0), SpaceDetailsButtonRow( - controller: widget.controller, - room: widget.room, - selectedTab: _selectedTab, - onTabSelected: setSelectedTab, - buttons: _buttons, + controller: controller, + room: room, + selectedTab: tab(context), + onTabSelected: (tab) => setSelectedTab(tab, context), + buttons: _buttons(context), ), SizedBox(height: isColumnMode ? 30.0 : 14.0), Expanded( child: Builder( builder: (context) { - switch (_selectedTab) { + switch (tab(context)) { case SpaceSettingsTabs.chat: return CourseChats( - widget.room.id, + room.id, activeChat: null, - client: widget.room.client, + client: room.client, ); case SpaceSettingsTabs.course: return SingleChildScrollView( child: CourseSettings( courseController, - room: widget.room, + room: room, ), ); case SpaceSettingsTabs.participants: return SingleChildScrollView( - child: RoomParticipantsSection(room: widget.room), + child: RoomParticipantsSection(room: room), ); case SpaceSettingsTabs.analytics: return SingleChildScrollView( child: Center( - child: SpaceAnalytics(roomId: widget.room.id), + child: SpaceAnalytics(roomId: room.id), ), ); case SpaceSettingsTabs.more: - final buttons = _buttons + final buttons = _buttons(context) .where( (b) => !b.showInMainView && b.visible, ) @@ -355,8 +344,6 @@ class SpaceDetailsContentState extends State { ], ), ); - case null: - return const SizedBox(); } }, ), diff --git a/lib/pangea/course_chats/course_chats_view.dart b/lib/pangea/course_chats/course_chats_view.dart index dcbc1c773..c0582aa71 100644 --- a/lib/pangea/course_chats/course_chats_view.dart +++ b/lib/pangea/course_chats/course_chats_view.dart @@ -270,8 +270,9 @@ class CourseChatsView extends StatelessWidget { title: Text(L10n.of(context).whatNow), subtitle: Text(L10n.of(context).chooseNextActivity), trailing: const Icon(Icons.arrow_forward), - onTap: () => - context.go("/rooms/spaces/${room.id}/details"), + onTap: () => context.go( + "/rooms/spaces/${room.id}/details?tab=course", + ), ) : const SizedBox(); }