diff --git a/lib/config/routes.dart b/lib/config/routes.dart index df0d64d6e..bc4b0eaa6 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -253,29 +253,39 @@ abstract class AppRoutes { // redirect: loggedOutRedirect, redirect: (context, state) async { final resp = await loggedOutRedirect(context, state); - final spaceId = state.uri.queryParameters['spaceId']; + if (resp != null) return resp; + final isColumnMode = FluffyThemes.isColumnMode(context); final roomId = state.pathParameters['roomid']; final room = roomId != null ? Matrix.of(context).client.getRoomById(roomId) : null; - if (room != null && - room.isSpace && - !FluffyThemes.isColumnMode(context) && - (state.fullPath?.endsWith(':roomid') ?? false)) { - return '/rooms?spaceId=${room.id}'; + if (room != null && room.isSpace) { + // If a user is on mobile and they end up on the space + // page, redirect them and set the activeSpaceId + if (!isColumnMode && + (state.fullPath?.endsWith(':roomid') ?? false)) { + return '/rooms?spaceId=${room.id}'; + } } - if (resp != null || - !state.uri.queryParameters.containsKey('spaceId') || - spaceId == 'clear' || - !FluffyThemes.isColumnMode(context) || - state.path == ':roomid') { - return resp; + if (state.uri.queryParameters.containsKey('spaceId')) { + final spaceId = state.uri.queryParameters['spaceId']; + if (spaceId == null || spaceId == 'clear') { + // Have to load chat list to clear the spaceId, so don't redirect + return null; + } + + // If spaceId is not null, and on web, and not on the space page, + // redirect to the space page + if (isColumnMode && + !(state.fullPath?.endsWith(':roomid') ?? false)) { + return '/rooms/$spaceId?spaceId=$spaceId'; + } } - return '/rooms/$spaceId?spaceId=${spaceId ?? 'clear'}'; + return null; }, // Pangea# pageBuilder: (context, state) => defaultPageBuilder( diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index f75979fe4..127ae2c40 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -406,7 +406,9 @@ class ChatView extends StatelessWidget { ), // #Pangea ChatViewBackground(controller.choreographer), - if (!controller.room.isAbandonedDMRoom) + if (!controller.room.isAbandonedDMRoom && + controller.room.canSendDefaultMessages && + controller.room.membership == Membership.join) Positioned( left: 0, right: 0, diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 24adcd1f4..dcf16676b 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -534,7 +534,9 @@ class ChatListController extends State final String? justInputtedCode = MatrixState.pangeaController.classController.justInputtedCode(); final newSpaceCode = space?.classCode(context); - if (newSpaceCode == justInputtedCode) return; + if (newSpaceCode?.toLowerCase() == justInputtedCode?.toLowerCase()) { + return; + } if (space != null) { chatListHandleSpaceTap( diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index 2bbff9d52..f6a47adf1 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -383,15 +383,21 @@ class PublicRoomsHorizontalListState extends State { L10n.of(context).chat, // Pangea# avatar: publicRooms[i].avatarUrl, - onPressed: () => showAdaptiveDialog( - context: context, - builder: (c) => PublicRoomDialog( - roomAlias: publicRooms[i].canonicalAlias ?? - publicRooms[i].roomId, - chunk: publicRooms[i], - ), - ), // #Pangea + onPressed: () => PublicRoomDialog.show( + context: context, + roomAlias: + publicRooms[i].canonicalAlias ?? publicRooms[i].roomId, + chunk: publicRooms[i], + ), + // onPressed: () => showAdaptiveDialog( + // context: context, + // builder: (c) => PublicRoomDialog( + // roomAlias: publicRooms[i].canonicalAlias ?? + // publicRooms[i].roomId, + // chunk: publicRooms[i], + // ), + // ), radius: BorderRadius.circular( AppConfig.borderRadius / 2, ), diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 1500da23e..4471a01d8 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -15,7 +15,9 @@ import 'package:fluffychat/pages/chat_list/chat_list.dart'; import 'package:fluffychat/pages/chat_list/chat_list_item.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart'; import 'package:fluffychat/pangea/spaces/widgets/space_view_leaderboard.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; @@ -89,7 +91,7 @@ class _SpaceViewState extends State { // and reload the hierarchy when they come through final client = Matrix.of(context).client; _roomSubscription ??= client.onSync.stream - .where(hasHierarchyUpdate) + .where(_hasHierarchyUpdate) .listen((update) => loadHierarchy(hasUpdate: true)); // Pangea# super.initState(); @@ -124,6 +126,44 @@ class _SpaceViewState extends State { super.dispose(); } + Future _joinDefaultChats() async { + if (_discoveredChildren == null) return; + final found = List.from(_discoveredChildren!); + + final List joinFutures = []; + for (final chunk in found) { + if (chunk.canonicalAlias == null) continue; + final alias = chunk.canonicalAlias!; + + final isDefaultChat = (alias.localpart ?? '') + .startsWith(SpaceConstants.announcementsChatAlias) || + (alias.localpart ?? '') + .startsWith(SpaceConstants.introductionChatAlias); + + if (!isDefaultChat) continue; + + joinFutures.add( + Matrix.of(context).client.joinRoom(alias).then((_) { + _discoveredChildren?.remove(chunk); + }).catchError((e, s) { + ErrorHandler.logError( + e: e, + s: s, + data: { + 'alias': alias, + 'spaceId': widget.spaceId, + }, + ); + return null; + }), + ); + } + + if (joinFutures.isNotEmpty) { + await Future.wait(joinFutures); + } + } + Future loadHierarchy({hasUpdate = false}) async { final room = Matrix.of(context).client.getRoomById(widget.spaceId); if (room == null) return; @@ -134,6 +174,7 @@ class _SpaceViewState extends State { try { await _loadHierarchy(activeSpace: room, hasUpdate: hasUpdate); + await _joinDefaultChats(); } catch (e, s) { Logs().w('Unable to load hierarchy', e, s); if (!mounted) return; @@ -208,12 +249,12 @@ class _SpaceViewState extends State { // finally, set the response to the last response for this space // and set the current next batch token - currentHierarchy = filterHierarchyResponse(activeSpace, response.rooms); + currentHierarchy = _filterHierarchyResponse(activeSpace, response.rooms); currentNextBatch = response.nextBatch; } _discoveredChildren = currentHierarchy; - _discoveredChildren?.sort(sortSpaceChildren); + _discoveredChildren?.sort(_sortSpaceChildren); _nextBatch = currentNextBatch; } @@ -260,17 +301,28 @@ class _SpaceViewState extends State { final client = Matrix.of(context).client; final space = client.getRoomById(widget.spaceId); - final joined = await showAdaptiveDialog( + // #Pangea + // final joined = await showAdaptiveDialog( + // context: context, + // builder: (_) => PublicRoomDialog( + // chunk: item, + // via: space?.spaceChildren + // .firstWhereOrNull( + // (child) => child.roomId == item.roomId, + // ) + // ?.via, + // ), + // ); + final joined = await PublicRoomDialog.show( context: context, - builder: (_) => PublicRoomDialog( - chunk: item, - via: space?.spaceChildren - .firstWhereOrNull( - (child) => child.roomId == item.roomId, - ) - ?.via, - ), + chunk: item, + via: space?.spaceChildren + .firstWhereOrNull( + (child) => child.roomId == item.roomId, + ) + ?.via, ); + // Pangea# if (mounted && joined == true) { setState(() { // #Pangea @@ -394,7 +446,7 @@ class _SpaceViewState extends State { // Pangea# // #Pangea - bool includeSpaceChild( + bool _includeSpaceChild( Room space, SpaceRoomsChunk hierarchyMember, ) { @@ -412,7 +464,7 @@ class _SpaceViewState extends State { return !isAnalyticsRoom && (isMember || isSuggested); } - List filterHierarchyResponse( + List _filterHierarchyResponse( Room space, List hierarchyResponse, ) { @@ -428,7 +480,7 @@ class _SpaceViewState extends State { ); if (isDuplicate) continue; - if (includeSpaceChild(space, child)) { + if (_includeSpaceChild(space, child)) { filteredChildren.add(child); } } @@ -437,7 +489,7 @@ class _SpaceViewState extends State { /// Used to filter out sync updates with hierarchy updates for the active /// space so that the view can be auto-reloaded in the room subscription - bool hasHierarchyUpdate(SyncUpdate update) { + bool _hasHierarchyUpdate(SyncUpdate update) { final joinTimeline = update.rooms?.join?[widget.spaceId]?.timeline; final leaveTimeline = update.rooms?.leave?[widget.spaceId]?.timeline; if (joinTimeline == null && leaveTimeline == null) return false; @@ -452,7 +504,7 @@ class _SpaceViewState extends State { return hasJoinUpdate || hasLeaveUpdate; } - int sortSpaceChildren( + int _sortSpaceChildren( SpaceRoomsChunk a, SpaceRoomsChunk b, ) { @@ -466,19 +518,6 @@ class _SpaceViewState extends State { } return 0; } - - List? get joinedRooms { - final room = Matrix.of(context).client.getRoomById(widget.spaceId); - if (room == null) return null; - - final spaceChildIds = - room.spaceChildren.map((c) => c.roomId).whereType().toSet(); - - return room.client.rooms - .where((room) => spaceChildIds.contains(room.id)) - .where((room) => !room.isAnalyticsRoom) - .toList(); - } // Pangea# @override diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 33fbe0d99..4e9d4cc57 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -11,12 +11,10 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/new_group/new_group_view.dart'; import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart'; import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; -import 'package:fluffychat/pangea/common/constants/model_keys.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'; -import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; -import 'package:fluffychat/pangea/spaces/utils/space_code.dart'; +import 'package:fluffychat/pangea/spaces/utils/client_spaces_extension.dart'; import 'package:fluffychat/utils/file_selector.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -197,44 +195,40 @@ class NewGroupController extends State { Future _createSpace() async { if (!mounted) return; // #Pangea - final client = Matrix.of(context).client; - final joinCode = await SpaceCodeUtil.generateSpaceCode(client); - // Pangea# - final spaceId = await Matrix.of(context).client.createRoom( - // #Pangea - // preset: publicGroup - // ? sdk.CreateRoomPreset.publicChat - // : sdk.CreateRoomPreset.privateChat, - // Pangea# - creationContent: {'type': RoomCreationTypes.mSpace}, - // #Pangea - // visibility: publicGroup ? sdk.Visibility.public : null, + // final spaceId = await Matrix.of(context).client.createRoom( + // preset: publicGroup + // ? sdk.CreateRoomPreset.publicChat + // : sdk.CreateRoomPreset.privateChat, + // creationContent: {'type': RoomCreationTypes.mSpace}, + // visibility: publicGroup ? sdk.Visibility.public : null, + // roomAliasName: publicGroup + // ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') + // : null, + // name: nameController.text.trim(), + // powerLevelContentOverride: {'events_default': 100}, + // initialState: [ + // if (avatar != null) + // sdk.StateEvent( + // type: sdk.EventTypes.RoomAvatar, + // content: {'url': avatarUrl.toString()}, + // ), + // ], + // ); + // if (!mounted) return; + // context.pop(spaceId); + final spaceId = await Matrix.of(context).client.createPangeaSpace( + name: nameController.text, visibility: groupCanBeFound ? sdk.Visibility.public : sdk.Visibility.private, - // roomAliasName: publicGroup - // ? nameController.text.trim().toLowerCase().replaceAll(' ', '_') - // : null, - // Pangea# - name: nameController.text.trim(), - powerLevelContentOverride: {'events_default': 100}, - initialState: [ - // #Pangea - ..._spaceInitialState(joinCode), - // Pangea# - if (avatar != null) - sdk.StateEvent( - type: sdk.EventTypes.RoomAvatar, - content: {'url': avatarUrl.toString()}, - ), - ], + joinRules: + requiredCodeToJoin ? sdk.JoinRules.knock : sdk.JoinRules.public, + avatar: avatar, + avatarUrl: avatarUrl, ); + if (!mounted) return; - // #Pangea - Room? room = client.getRoomById(spaceId); - if (room == null) { - await Matrix.of(context).client.waitForRoomInSync(spaceId); - room = client.getRoomById(spaceId); - } + + final room = Matrix.of(context).client.getRoomById(spaceId); if (room == null) return; final spaceCode = room.classCode(context); if (spaceCode != null) { @@ -245,38 +239,8 @@ class NewGroupController extends State { if (error != null) return; context.go("/rooms?spaceId=$spaceId"); // Pangea# - context.pop(spaceId); } - // #Pangea - List _spaceInitialState(String joinCode) { - return [ - StateEvent( - type: EventTypes.RoomPowerLevels, - stateKey: '', - content: { - 'events': { - EventTypes.SpaceChild: 50, - }, - 'users_default': 0, - 'users': { - Matrix.of(context).client.userID: SpaceConstants.powerLevelOfAdmin, - }, - }, - ), - StateEvent( - type: sdk.EventTypes.RoomJoinRules, - content: { - ModelKey.joinRule: requiredCodeToJoin - ? sdk.JoinRules.knock.toString().replaceAll('JoinRules.', '') - : sdk.JoinRules.public.toString().replaceAll('JoinRules.', ''), - ModelKey.accessCode: joinCode, - }, - ), - ]; - } - //Pangea# - void submitAction([_]) async { final client = Matrix.of(context).client; diff --git a/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart b/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart index d1c6f8f5b..7d5ccde38 100644 --- a/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart +++ b/lib/pangea/analytics_details_popup/morph_analytics_list_view.dart @@ -6,6 +6,7 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart'; +import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/constructs/construct_level_enum.dart'; import 'package:fluffychat/pangea/instructions/instructions_enum.dart'; @@ -13,7 +14,6 @@ import 'package:fluffychat/pangea/instructions/instructions_inline_tooltip.dart' import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/morphs/morph_icon.dart'; -import 'package:fluffychat/pangea/user/client_extension.dart'; import 'package:fluffychat/widgets/matrix.dart'; class MorphAnalyticsListView extends StatelessWidget { @@ -183,7 +183,8 @@ class MorphTagChip extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final unlocked = constructAnalytics.points > 0; + final unlocked = constructAnalytics.points > 0 || + Matrix.of(context).client.userID == Environment.supportUserId; return InkWell( borderRadius: BorderRadius.circular(AppConfig.borderRadius), @@ -216,7 +217,7 @@ class MorphTagChip extends StatelessWidget { SizedBox( width: 28.0, height: 28.0, - child: unlocked || Matrix.of(context).client.isSupportAccount + child: unlocked ? MorphIcon( morphFeature: feature, morphTag: morphTag, diff --git a/lib/pangea/chat/constants/default_power_level.dart b/lib/pangea/chat/constants/default_power_level.dart index c200720f8..4bb21ef1b 100644 --- a/lib/pangea/chat/constants/default_power_level.dart +++ b/lib/pangea/chat/constants/default_power_level.dart @@ -1,16 +1,21 @@ Map defaultPowerLevels(String userID) => { - "defaults": { - "ban": 50, - "events_default": 0, - "invite": 50, - "kick": 50, - "notifications": { - "room": 50, - }, - "redact": 50, - "state_default": 50, - "users_default": 0, - }, + "events": { + "m.room.avatar": 50, + "m.room.canonical_alias": 50, + "m.room.encryption": 100, + "m.room.history_visibility": 100, + "m.room.name": 50, + "m.room.power_levels": 100, + "m.room.server_acl": 100, + "m.room.tombstone": 100, + }, + "users": { + userID: 100, + }, + }; + +Map restrictedPowerLevels(String userID) => { + "events_default": 50, "events": { "m.room.avatar": 50, "m.room.canonical_alias": 50, diff --git a/lib/pangea/common/controllers/pangea_controller.dart b/lib/pangea/common/controllers/pangea_controller.dart index f150d49b5..7d67a074f 100644 --- a/lib/pangea/common/controllers/pangea_controller.dart +++ b/lib/pangea/common/controllers/pangea_controller.dart @@ -172,11 +172,13 @@ class PangeaController { getAnalytics.dispose(); userController.clear(); _languageStream?.cancel(); + _languageStream = null; break; case LoginState.loggedIn: // Initialize analytics data putAnalytics.initialize(); getAnalytics.initialize(); + _setLanguageStream(); break; } if (state != LoginState.loggedIn) { @@ -352,9 +354,12 @@ class PangeaController { void _subscribeToStreams() { matrixState.client.onLoginStateChanged.stream .listen(_handleLoginStateChange); + _setLanguageStream(); + } - // Listen for changes to the user's language settings - _languageStream ??= userController.stateStream.listen((update) { + void _setLanguageStream() { + _languageStream?.cancel(); + _languageStream = userController.stateStream.listen((update) { if (update is Map && update['prev_target_lang'] != null) { clearCache(); diff --git a/lib/pangea/extensions/room_children_and_parents_extension.dart b/lib/pangea/extensions/room_children_and_parents_extension.dart index 02750f063..16c2d0f43 100644 --- a/lib/pangea/extensions/room_children_and_parents_extension.dart +++ b/lib/pangea/extensions/room_children_and_parents_extension.dart @@ -25,9 +25,7 @@ extension ChildrenAndParentsRoomExtension on Room { throw NestedSpaceError(); } - final List spaceParents = - ChildrenAndParentsRoomExtension(child).pangeaSpaceParents; - for (final Room parent in spaceParents) { + for (final Room parent in pangeaSpaceParents) { try { await parent.removeSpaceChild(roomId); } catch (e) { diff --git a/lib/pangea/public_spaces/public_space_card.dart b/lib/pangea/public_spaces/public_space_card.dart index 0797b89c6..47c55961c 100644 --- a/lib/pangea/public_spaces/public_space_card.dart +++ b/lib/pangea/public_spaces/public_space_card.dart @@ -24,12 +24,10 @@ class PublicSpaceCard extends StatelessWidget { final theme = Theme.of(context); return PressableButton( - onPressed: () => showAdaptiveDialog( + onPressed: () => PublicRoomDialog.show( context: context, - builder: (c) => PublicRoomDialog( - roomAlias: space.canonicalAlias ?? space.roomId, - chunk: space, - ), + roomAlias: space.canonicalAlias ?? space.roomId, + chunk: space, ), borderRadius: BorderRadius.circular(24.0), color: theme.brightness == Brightness.dark diff --git a/lib/pangea/spaces/constants/space_constants.dart b/lib/pangea/spaces/constants/space_constants.dart index adcdda1ee..7a40bfca3 100644 --- a/lib/pangea/spaces/constants/space_constants.dart +++ b/lib/pangea/spaces/constants/space_constants.dart @@ -4,4 +4,6 @@ class SpaceConstants { static const defaultDominantLanguage = "en"; static const defaultTargetLanguage = "es"; static const String classCode = 'classcode'; + static const String introductionChatAlias = 'introductionChat'; + static const String announcementsChatAlias = 'announcementsChat'; } diff --git a/lib/pangea/spaces/controllers/space_controller.dart b/lib/pangea/spaces/controllers/space_controller.dart index 4689daae4..1fa6eef94 100644 --- a/lib/pangea/spaces/controllers/space_controller.dart +++ b/lib/pangea/spaces/controllers/space_controller.dart @@ -117,6 +117,11 @@ class ClassController extends BaseController { final spaceID = await showFutureLoadingDialog( context: context, future: () async { + await _classStorage.write( + PLocalKey.justInputtedCode, + classCode, + ); + final knockResponse = await client.httpClient.post( Uri.parse( '${client.homeserver}/_synapse/client/pangea/v1/knock_with_code', @@ -154,10 +159,6 @@ class ClassController extends BaseController { } final chosenClassId = foundClasses.first; - await _classStorage.write( - PLocalKey.justInputtedCode, - classCode, - ); return chosenClassId; }, ); diff --git a/lib/pangea/spaces/utils/client_spaces_extension.dart b/lib/pangea/spaces/utils/client_spaces_extension.dart new file mode 100644 index 000000000..8f6f6e759 --- /dev/null +++ b/lib/pangea/spaces/utils/client_spaces_extension.dart @@ -0,0 +1,152 @@ +import 'dart:typed_data'; + +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/chat/constants/default_power_level.dart'; +import 'package:fluffychat/pangea/common/constants/model_keys.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; +import 'package:fluffychat/pangea/spaces/utils/space_code.dart'; + +extension SpacesClientExtension on Client { + Future createPangeaSpace({ + required String name, + Visibility visibility = Visibility.private, + JoinRules joinRules = JoinRules.public, + Uint8List? avatar, + Uri? avatarUrl, + }) async { + final joinCode = await SpaceCodeUtil.generateSpaceCode(this); + final roomId = await createRoom( + creationContent: {'type': RoomCreationTypes.mSpace}, + visibility: visibility, + name: name.trim(), + powerLevelContentOverride: {'events_default': 100}, + initialState: [ + ..._spaceInitialState( + joinCode, + joinRules: joinRules, + ), + if (avatar != null) + StateEvent( + type: EventTypes.RoomAvatar, + content: {'url': avatarUrl.toString()}, + ), + ], + ); + + final space = await _waitForRoom(roomId); + if (space == null) return roomId; + + await _addDefaultSpaceChats(space: space); + return roomId; + } + + Future _waitForRoom(String roomId) async { + final room = getRoomById(roomId); + if (room != null) return room; + await waitForRoomInSync(roomId, join: true).timeout( + const Duration(seconds: 15), + onTimeout: () { + throw Exception('Timeout fetching room after creation'); + }, + ); + return getRoomById(roomId); + } + + Future _addDefaultSpaceChats({ + required Room space, + String introductionsName = "Introductions", + String announcementsName = "Announcements", + }) async { + final introChatFuture = createRoom( + preset: CreateRoomPreset.publicChat, + visibility: Visibility.private, + name: introductionsName, + roomAliasName: + "${SpaceConstants.introductionChatAlias}_${space.id.localpart}", + initialState: [ + // if (avatar != null) + // StateEvent( + // type: EventTypes.RoomAvatar, + // content: {'url': avatarUrl.toString()}, + // ), + StateEvent( + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: defaultPowerLevels(userID!), + ), + ], + ); + + final announcementsChatFuture = createRoom( + preset: CreateRoomPreset.publicChat, + visibility: Visibility.private, + name: announcementsName, + roomAliasName: + "${SpaceConstants.announcementsChatAlias}_${space.id.localpart}", + initialState: [ + // if (avatar != null) + // StateEvent( + // type: EventTypes.RoomAvatar, + // content: {'url': avatarUrl.toString()}, + // ), + StateEvent( + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: restrictedPowerLevels(userID!), + ), + ], + ); + + final List roomIds = await Future.wait([ + introChatFuture, + announcementsChatFuture, + ]); + + if (roomIds.length != 2) { + throw Exception('Failed to create default space chats'); + } + + final addIntroChatFuture = space.pangeaSetSpaceChild( + roomIds[0], + ); + + final addAnnouncementsChatFuture = space.pangeaSetSpaceChild( + roomIds[1], + ); + + await Future.wait([ + addIntroChatFuture, + addAnnouncementsChatFuture, + ]); + } + + List _spaceInitialState( + String joinCode, { + required JoinRules joinRules, + }) { + return [ + StateEvent( + type: EventTypes.RoomPowerLevels, + stateKey: '', + content: { + 'events': { + EventTypes.SpaceChild: 50, + }, + 'users_default': 0, + 'users': { + userID: SpaceConstants.powerLevelOfAdmin, + }, + }, + ), + StateEvent( + type: EventTypes.RoomJoinRules, + content: { + ModelKey.joinRule: joinRules.toString().replaceAll('JoinRules.', ''), + ModelKey.accessCode: joinCode, + }, + ), + ]; + } +} diff --git a/lib/pangea/user/client_extension.dart b/lib/pangea/user/client_extension.dart deleted file mode 100644 index bb4e8edb7..000000000 --- a/lib/pangea/user/client_extension.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:matrix/matrix.dart'; - -import 'package:fluffychat/pangea/common/config/environment.dart'; - -extension AccountIdentiferExt on Client { - bool get isSupportAccount => userID == Environment.supportUserId; -} diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 56a0076db..523f9c416 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -163,7 +163,9 @@ abstract class ClientManager { return event.content.tryGet(ModelKey.transcription) == null && !event.type.startsWith("p.") && !event.type.startsWith("pangea.") && - event.type != EventTypes.RoomPinnedEvents; + event.type != EventTypes.RoomPinnedEvents && + event.type != EventTypes.SpaceChild && + event.type != EventTypes.SpaceParent; }, // Pangea# ); diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index 3dec6aeea..615b6d505 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -181,12 +181,18 @@ class UrlLauncher { } return; } else { - await showAdaptiveDialog( + // #Pangea + // await showAdaptiveDialog( + // context: context, + // builder: (c) => PublicRoomDialog( + // roomAlias: identityParts.primaryIdentifier, + // ), + // ); + await PublicRoomDialog.show( context: context, - builder: (c) => PublicRoomDialog( - roomAlias: identityParts.primaryIdentifier, - ), + roomAlias: identityParts.primaryIdentifier, ); + // Pangea# } if (roomIdOrAlias.sigil == '!') { if (await showOkCancelAlertDialog( diff --git a/lib/widgets/adaptive_dialogs/public_room_dialog.dart b/lib/widgets/adaptive_dialogs/public_room_dialog.dart index 64c382644..5d1fc64b0 100644 --- a/lib/widgets/adaptive_dialogs/public_room_dialog.dart +++ b/lib/widgets/adaptive_dialogs/public_room_dialog.dart @@ -27,6 +27,31 @@ class PublicRoomDialog extends StatefulWidget { const PublicRoomDialog({super.key, this.roomAlias, this.chunk, this.via}); // #Pangea + static Future show({ + required BuildContext context, + String? roomAlias, + PublicRoomsChunk? chunk, + List? via, + }) async { + final room = MatrixState.pangeaController.matrixState.client + .getRoomById(chunk!.roomId); + + if (room != null && room.membership == Membership.join) { + context.go("/rooms?spaceId=${room.id}"); + return null; + } + + return showAdaptiveDialog( + context: context, + barrierDismissible: true, + builder: (context) => PublicRoomDialog( + roomAlias: roomAlias, + chunk: chunk, + via: via, + ), + ); + } + @override State createState() => PublicRoomDialogState(); } @@ -38,20 +63,6 @@ class PublicRoomDialogState extends State { final TextEditingController _codeController = TextEditingController(); - @override - void didChangeDependencies() { - super.didChangeDependencies(); - if (chunk != null) { - final room = MatrixState.pangeaController.matrixState.client - .getRoomById(chunk!.roomId); - - if (room != null && room.membership == Membership.join) { - context.go("/rooms?spaceId=${room.id}"); - Navigator.of(context).maybePop(); - } - } - } - @override void dispose() { _codeController.dispose();