diff --git a/lib/pages/chat/chat_event_list.dart b/lib/pages/chat/chat_event_list.dart index 30f733d1d..c32e23934 100644 --- a/lib/pages/chat/chat_event_list.dart +++ b/lib/pages/chat/chat_event_list.dart @@ -78,8 +78,7 @@ class ChatEventList extends StatelessWidget { // #Pangea if (i == 1) { - return (controller.room.locked ?? false) && - !controller.room.isRoomAdmin + return (controller.room.locked) && !controller.room.isRoomAdmin ? const LockedChatMessage() : const SizedBox.shrink(); } diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index a095d49fd..ca4816da0 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -461,6 +461,7 @@ class ChatDetailsView extends StatelessWidget { ), // #Pangea if (room.canInvite && + !room.isDirectChat && (!room.isSpace || room.isRoomAdmin)) ListTile( title: Text( @@ -491,13 +492,15 @@ class ChatDetailsView extends StatelessWidget { room.showClassEditOptions) ClassInvitationButtons(roomId: controller.roomId!), const Divider(height: 1), - if (!room.isSpace && room.canInvite) + if (!room.isSpace && + !room.isDirectChat && + room.canInvite) ConversationBotSettings( key: controller.addConversationBotKey, room: room, ), const Divider(height: 1), - if (!room.isPangeaClass) + if (!room.isPangeaClass && !room.isDirectChat) AddToSpaceToggles( roomId: room.id, key: controller.addToSpaceKey, @@ -507,7 +510,9 @@ class ChatDetailsView extends StatelessWidget { : AddToClassMode.chat, ), const Divider(height: 1), - if (!room.isSpace || (room.isSpace && room.isRoomAdmin)) + if (!room.isDirectChat && + (!room.isSpace || + (room.isSpace && room.isRoomAdmin))) ListTile( title: Text( room.isSpace @@ -539,7 +544,7 @@ class ChatDetailsView extends StatelessWidget { }, ), ), - if (room.isRoomAdmin) + if (room.isRoomAdmin && !room.isDirectChat) SwitchListTile.adaptive( activeColor: AppConfig.activeToggleColor, title: Text( @@ -556,12 +561,12 @@ class ChatDetailsView extends StatelessWidget { Theme.of(context).scaffoldBackgroundColor, foregroundColor: iconColor, child: Icon( - room.locked ?? false + room.locked ? Icons.lock_outlined : Icons.no_encryption_outlined, ), ), - value: room.locked ?? false, + value: room.locked, onChanged: (value) => showFutureLoadingDialog( context: context, future: () => value diff --git a/lib/pages/chat_list/chat_list_item.dart b/lib/pages/chat_list/chat_list_item.dart index 949b18112..a24fcd8fd 100644 --- a/lib/pages/chat_list/chat_list_item.dart +++ b/lib/pages/chat_list/chat_list_item.dart @@ -111,7 +111,15 @@ class ChatListItem extends StatelessWidget { if (room.membership == Membership.join) { // Share content into this room - final shareContent = Matrix.of(context).shareContent; + // #Pangea + // final shareContent = Matrix.of(context).shareContent; + Map? shareContent; + try { + shareContent = Matrix.of(context).shareContent; + } catch (e) { + shareContent = null; + } + // Pangea# if (shareContent != null) { final shareFile = shareContent.tryGet('file'); if (shareContent.tryGet('msgtype') == @@ -365,7 +373,7 @@ class ChatListItem extends StatelessWidget { ), const SizedBox(width: 8), // #Pangea - if (room.locked ?? false) + if (room.locked) const Padding( padding: EdgeInsets.only(right: 4.0), child: Icon( diff --git a/lib/pages/invitation_selection/invitation_selection.dart b/lib/pages/invitation_selection/invitation_selection.dart index 4811934eb..a762d398c 100644 --- a/lib/pages/invitation_selection/invitation_selection.dart +++ b/lib/pages/invitation_selection/invitation_selection.dart @@ -75,7 +75,9 @@ class InvitationSelectionController extends State { } final eligibleStudents = []; - final spaceParents = room.pangeaSpaceParents; + final spaceParents = room?.pangeaSpaceParents; + if (spaceParents == null) return eligibleStudents; + final userId = Matrix.of(context).client.userID; for (final Room space in spaceParents) { eligibleStudents.addAll( @@ -115,15 +117,25 @@ class InvitationSelectionController extends State { ); } - List studentsInRoom(BuildContext context) => room - .getParticipants() - .where( - (u) => [Membership.join, Membership.invite].contains(u.membership), - ) - .toList(); + List studentsInRoom(BuildContext context) => + room + ?.getParticipants() + .where( + (u) => [Membership.join, Membership.invite].contains(u.membership), + ) + .toList() ?? + []; //Pangea# - void inviteAction(BuildContext context, String id, String displayname) async { + // #Pangea + // void inviteAction(BuildContext context, String id, String displayname) async { + void inviteAction( + BuildContext context, + String id, + String displayname, { + InvitationSelectionMode? mode, + }) async { + // Pangea# final room = Matrix.of(context).client.getRoomById(roomId!)!; if (OkCancelResult.ok != await showOkCancelAlertDialog( @@ -144,25 +156,12 @@ class InvitationSelectionController extends State { context: context, //#Pangea // future: () => room.invite(id), - future: () => Future.wait([ - room.invite(id), - room.setPower(id, ClassDefaultValues.powerLevelOfAdmin), - if (room.isSpace) - ...room.spaceChildren - .map( - (e) => roomId != null - ? Matrix.of(context).client.getRoomById(e.roomId!) - : null, - ) - .where((element) => element != null) - .cast() - .map( - (e) => Future.wait([ - e.invite(id), - e.setPower(id, ClassDefaultValues.powerLevelOfAdmin), - ]), - ), - ]), + future: () async { + await room.invite(id); + if (mode == InvitationSelectionMode.admin) { + await inviteTeacherAction(room, id); + } + }, // Pangea# ); if (success.error == null) { @@ -174,6 +173,26 @@ class InvitationSelectionController extends State { } } + // #Pangea + Future inviteTeacherAction(Room room, String id) async { + room.setPower(id, ClassDefaultValues.powerLevelOfAdmin); + if (room.isSpace) { + for (final spaceChild in room.spaceChildren) { + if (spaceChild.roomId == null) continue; + final spaceChildRoom = + Matrix.of(context).client.getRoomById(spaceChild.roomId!); + if (spaceChildRoom != null) { + await spaceChildRoom.invite(id); + await spaceChildRoom.setPower( + id, + ClassDefaultValues.powerLevelOfAdmin, + ); + } + } + } + } + // Pangea# + void searchUserWithCoolDown(String text) async { coolDown?.cancel(); coolDown = Timer( @@ -224,8 +243,8 @@ class InvitationSelectionController extends State { //#Pangea final participants = Matrix.of(context) .client - .getRoomById(roomId!)! - .getParticipants() + .getRoomById(roomId!) + ?.getParticipants() .where( (user) => [Membership.join, Membership.invite].contains(user.membership), @@ -233,7 +252,7 @@ class InvitationSelectionController extends State { .toList(); foundProfiles.removeWhere( (profile) => - participants.indexWhere((u) => u.id == profile.userId) != -1 && + participants?.indexWhere((u) => u.id == profile.userId) != -1 && BotName.byEnvironment != profile.userId, ); //Pangea# @@ -242,17 +261,19 @@ class InvitationSelectionController extends State { //#Pangea Room? _room; - Room get room => _room ??= Matrix.of(context).client.getRoomById(roomId!)!; + Room? get room => _room ??= Matrix.of(context).client.getRoomById(roomId!); // request participants for all parent spaces Future requestParentSpaceParticipants() async { - final spaceParents = room.pangeaSpaceParents; - await Future.wait([ - ...spaceParents.map((r) async { - await r.requestParticipants(); - }), - room.requestParticipants(), - ]); + final spaceParents = room?.pangeaSpaceParents; + if (spaceParents != null) { + await Future.wait([ + ...spaceParents.map((r) async { + await r.requestParticipants(); + }), + room!.requestParticipants(), + ]); + } } InvitationSelectionMode mode = InvitationSelectionMode.member; @@ -263,7 +284,7 @@ class InvitationSelectionController extends State { Future.delayed( Duration.zero, () => setState( - () => mode = room.isSpace + () => mode = room?.isSpace ?? false ? InvitationSelectionMode.admin : InvitationSelectionMode.member, ), @@ -275,9 +296,11 @@ class InvitationSelectionController extends State { .where( (event) => event.rooms?.join?.keys.any( - (ithRoomId) => room.pangeaSpaceParents - .map((e) => e.id) - .contains(ithRoomId), + (ithRoomId) => + room?.pangeaSpaceParents + .map((e) => e.id) + .contains(ithRoomId) ?? + false, ) ?? false, ) diff --git a/lib/pages/invitation_selection/invitation_selection_view.dart b/lib/pages/invitation_selection/invitation_selection_view.dart index 5a2621046..cafa5fec7 100644 --- a/lib/pages/invitation_selection/invitation_selection_view.dart +++ b/lib/pages/invitation_selection/invitation_selection_view.dart @@ -106,6 +106,9 @@ class InvitationSelectionView extends StatelessWidget { controller.foundProfiles[i].displayName ?? controller.foundProfiles[i].userId.localpart ?? L10n.of(context)!.user, + // #Pangea + mode: controller.mode, + // Pangea# ), ), ) @@ -143,6 +146,9 @@ class InvitationSelectionView extends StatelessWidget { contacts[i].displayName ?? contacts[i].id.localpart ?? L10n.of(context)!.user, + // #Pangea + mode: controller.mode, + // Pangea# ), ), ); diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet.dart index c6802ae86..06a652495 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet.dart @@ -239,9 +239,12 @@ class UserBottomSheetController extends State { final roomIdResult = await showFutureLoadingDialog( context: widget.outerContext, - future: () => Matrix.of(widget.outerContext) - .client - .startDirectChat(user?.id ?? widget.profile!.userId), + future: () => Matrix.of(widget.outerContext).client.startDirectChat( + user?.id ?? widget.profile!.userId, + // #Pangea + enableEncryption: false, + // Pangea# + ), ); final roomId = roomIdResult.result; if (roomId == null) return; diff --git a/lib/pangea/controllers/pangea_controller.dart b/lib/pangea/controllers/pangea_controller.dart index 79006aa9d..86946f314 100644 --- a/lib/pangea/controllers/pangea_controller.dart +++ b/lib/pangea/controllers/pangea_controller.dart @@ -14,6 +14,7 @@ import 'package:fluffychat/pangea/controllers/subscription_controller.dart'; import 'package:fluffychat/pangea/controllers/text_to_speech_controller.dart'; import 'package:fluffychat/pangea/controllers/user_controller.dart'; import 'package:fluffychat/pangea/controllers/word_net_controller.dart'; +import 'package:fluffychat/pangea/extensions/client_extension.dart'; import 'package:fluffychat/pangea/guard/p_vguard.dart'; import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; @@ -164,7 +165,11 @@ class PangeaController { void startChatWithBotIfNotPresent() { Future.delayed(const Duration(milliseconds: 10000), () async { // check if user is logged in - if (!matrixState.client.isLogged()) return; + if (!matrixState.client.isLogged() || + (await matrixState.client.hasBotDM)) { + return; + } + try { await matrixState.client.startDirectChat( BotName.byEnvironment, diff --git a/lib/pangea/extensions/client_extension.dart b/lib/pangea/extensions/client_extension.dart index 98353d29b..ea0c709d7 100644 --- a/lib/pangea/extensions/client_extension.dart +++ b/lib/pangea/extensions/client_extension.dart @@ -168,4 +168,15 @@ extension PangeaClient on Client { ) .firstOrNull ?.classSettings; + + Future get hasBotDM async { + final List chats = rooms + .where((room) => !room.isSpace && room.membership == Membership.join) + .toList(); + + for (final Room chat in chats) { + if (await chat.isBotDM) return true; + } + return false; + } } diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index 1b6370ce1..b45f7bf66 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -923,17 +923,17 @@ extension PangeaRoom on Room { ?.content .tryGet('events_default'); - bool? get locked { + bool get locked { if (isDirectChat) return false; if (!isSpace) { - if (eventsDefaultPowerLevel == null) return null; + if (eventsDefaultPowerLevel == null) return false; return (eventsDefaultPowerLevel ?? 0) >= ClassDefaultValues.powerLevelOfAdmin; } for (final child in spaceChildren) { if (child.roomId == null) continue; final Room? room = client.getRoomById(child.roomId!); - if (room?.locked == false && (room?.canChangePowerLevel ?? false)) { + if (room?.locked == false) { return false; } } @@ -995,6 +995,9 @@ extension PangeaRoom on Room { ); } + Future get isBotDM async => + (await isBotRoom) && getParticipants().length == 2; + BotOptionsModel? get botOptions { if (isSpace) return null; return BotOptionsModel.fromJson( diff --git a/lib/pangea/pages/p_user_age/p_user_age.dart b/lib/pangea/pages/p_user_age/p_user_age.dart index 9d59e84b5..3cb1fccc5 100644 --- a/lib/pangea/pages/p_user_age/p_user_age.dart +++ b/lib/pangea/pages/p_user_age/p_user_age.dart @@ -2,6 +2,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/constants/age_limits.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; +import 'package:fluffychat/pangea/extensions/client_extension.dart'; import 'package:fluffychat/pangea/pages/p_user_age/p_user_age_view.dart'; import 'package:fluffychat/pangea/utils/p_extension.dart'; import 'package:fluffychat/widgets/fluffy_chat_app.dart'; @@ -34,19 +35,20 @@ class PUserAgeController extends State { @override void initState() { super.initState(); - Future.delayed( - Duration.zero, - () => Matrix.of(context) - .client - .startDirectChat( - BotName.byEnvironment, - enableEncryption: false, - ) - .onError( - (error, stackTrace) => - ErrorHandler.logError(e: error, s: stackTrace), - ), - ); + Future.delayed(Duration.zero, () async { + if (!(await Matrix.of(context).client.hasBotDM)) { + Matrix.of(context) + .client + .startDirectChat( + BotName.byEnvironment, + enableEncryption: false, + ) + .onError( + (error, stackTrace) => + ErrorHandler.logError(e: error, s: stackTrace), + ); + } + }); } String? dobValidator() { diff --git a/lib/pangea/utils/lock_room.dart b/lib/pangea/utils/lock_room.dart index e21ec8aba..ba11872f5 100644 --- a/lib/pangea/utils/lock_room.dart +++ b/lib/pangea/utils/lock_room.dart @@ -17,7 +17,11 @@ Future lockChat(Room room, Client client) async { final Map powerLevelsContent = Map.from( room.getState(EventTypes.RoomPowerLevels)!.content, ); + powerLevelsContent['events_default'] = 100; + if (!powerLevelsContent.containsKey('events')) { + powerLevelsContent['events'] = Map.from({}); + } powerLevelsContent['events'][EventTypes.spaceChild] = 100; await room.client.setRoomStateWithKey(