diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 188b0297e..b6f004fea 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -575,7 +575,9 @@ class ChatListController extends State classStream = MatrixState.pangeaController.classController.stateStream .listen((event) { if (mounted) { - setActiveSpace(event["activeSpaceId"]); + event["activeSpaceId"] != null + ? setActiveSpace(event["activeSpaceId"]) + : clearActiveSpace(); if (event["activeSpaceId"] != null) { context.go("/rooms/${event["activeSpaceId"]}/details"); } diff --git a/lib/pangea/controllers/class_controller.dart b/lib/pangea/controllers/class_controller.dart index df0a699bc..de507b07b 100644 --- a/lib/pangea/controllers/class_controller.dart +++ b/lib/pangea/controllers/class_controller.dart @@ -15,6 +15,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; +import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; import 'base_controller.dart'; @@ -63,7 +64,7 @@ class ClassController extends BaseController { Future joinClasswithCode(BuildContext context, String classCode) async { final client = Matrix.of(context).client; - await showFutureLoadingDialog( + final space = await showFutureLoadingDialog( context: context, future: () async { final knockResponse = await client.httpClient.post( @@ -76,108 +77,79 @@ class ClassController extends BaseController { }, body: jsonEncode({'access_code': classCode}), ); + if (knockResponse.statusCode == 429) { - await showFutureLoadingDialog( - context: context, - future: () async { - throw L10n.of(context)!.tooManyRequest; - }, - ); - return; + throw L10n.of(context)!.tooManyRequest; } if (knockResponse.statusCode != 200) { - await showFutureLoadingDialog( - context: context, - future: () async { - throw L10n.of(context)!.unableToFindClass; - }, - ); - return; + throw L10n.of(context)!.unableToFindClass; } + final knockResult = jsonDecode(knockResponse.body); final foundClasses = List.from(knockResult['rooms']); final alreadyJoined = List.from(knockResult['already_joined']); - if (alreadyJoined.isNotEmpty) { - await showFutureLoadingDialog( - context: context, - future: () async { - throw L10n.of(context)!.alreadyInClass; - }, - ); - return; + + final bool inFoundClass = foundClasses.isNotEmpty && + _pangeaController.matrixState.client.rooms.any( + (room) => room.id == foundClasses.first, + ); + + if (alreadyJoined.isNotEmpty || inFoundClass) { + context.go("/rooms/${alreadyJoined.first}/details"); + throw L10n.of(context)!.alreadyInClass; } + if (foundClasses.isEmpty) { - await showFutureLoadingDialog( - context: context, - future: () async { - throw L10n.of(context)!.unableToFindClass; - }, - ); - return; + throw L10n.of(context)!.unableToFindClass; } + final chosenClassId = foundClasses.first; - if (_pangeaController.matrixState.client.rooms - .any((room) => room.id == chosenClassId)) { - setActiveSpaceIdInChatListController(chosenClassId); - await showFutureLoadingDialog( - context: context, - future: () async { - throw L10n.of(context)!.alreadyInClass; - }, - ); - return; - } else { - await _pangeaController.pStoreService.save( - PLocalKey.justInputtedCode, - classCode, - isAccountData: false, - ); - await client.joinRoomById(chosenClassId); - _pangeaController.pStoreService.delete(PLocalKey.justInputtedCode); - } + await _pangeaController.pStoreService.save( + PLocalKey.justInputtedCode, + classCode, + isAccountData: false, + ); + + await client.joinRoomById(chosenClassId); + _pangeaController.pStoreService.delete(PLocalKey.justInputtedCode); - if (_pangeaController.matrixState.client.getRoomById(chosenClassId) == - null) { + Room? room = client.getRoomById(chosenClassId); + if (room == null) { await _pangeaController.matrixState.client.waitForRoomInSync( chosenClassId, join: true, ); + room = client.getRoomById(chosenClassId); + if (room == null) return null; } + return room; + }, + ); + if (space.isError || space.result == null) return; + final room = space.result!; + await room.join(); + final isFull = await room.leaveIfFull(); + if (isFull) { + await showFutureLoadingDialog( + context: context, + future: () async => throw L10n.of(context)!.roomFull, + ); + return; + } - // If the room is full, leave - final room = - _pangeaController.matrixState.client.getRoomById(chosenClassId); - if (room == null) { - return; - } - final joinResult = await showFutureLoadingDialog( - context: context, - future: () async { - if (await room.leaveIfFull()) { - throw L10n.of(context)!.roomFull; - } - }, - ); - if (joinResult.error != null) { - return; - } - - setActiveSpaceIdInChatListController(chosenClassId); + // when possible, add user's analytics room the to space they joined + room.addAnalyticsRoomsToSpace(); - // add the user's analytics room to this joined space - // so their teachers can join them via the space hierarchy - final Room? joinedSpace = - _pangeaController.matrixState.client.getRoomById(chosenClassId); + // and invite the space's teachers to the user's analytics rooms + room.inviteSpaceTeachersToAnalyticsRooms(); + GoogleAnalytics.joinClass(classCode); - // when possible, add user's analytics room the to space they joined - joinedSpace?.addAnalyticsRoomsToSpace(); + if (room.client.getRoomById(room.id)?.membership != Membership.join) { + await room.client.waitForRoomInSync(room.id, join: true); + } - // and invite the space's teachers to the user's analytics rooms - joinedSpace?.inviteSpaceTeachersToAnalyticsRooms(); - GoogleAnalytics.joinClass(classCode); - return; - }, - ); + context.go("/rooms/${room.id}/details"); + return; // P-EPIC // prereq - server needs ability to invite to private room. how? // does server api have ability with admin token? diff --git a/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart index 6cb8bb962..b5a5976fc 100644 --- a/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/pangea_room_extension.dart @@ -121,12 +121,6 @@ extension PangeaRoom on Room { String nameIncludingParents(BuildContext context) => _nameIncludingParents(context); - List get allSpaceChildRoomIds => _allSpaceChildRoomIds; - - bool canAddAsParentOf(Room? child, {bool spaceMode = false}) { - return _canAddAsParentOf(child, spaceMode: spaceMode); - } - Future pangeaSetSpaceChild( String roomId, { bool? suggested, diff --git a/lib/pangea/extensions/pangea_room_extension/room_children_and_parents_extension.dart b/lib/pangea/extensions/pangea_room_extension/room_children_and_parents_extension.dart index 371af1768..9d5d9e726 100644 --- a/lib/pangea/extensions/pangea_room_extension/room_children_and_parents_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/room_children_and_parents_extension.dart @@ -108,40 +108,6 @@ extension ChildrenAndParentsRoomExtension on Room { return "... > $nameSoFar"; } - // gets all space children of a given space, down the - // space tree. - List get _allSpaceChildRoomIds { - final List childIds = []; - for (final child in spaceChildren) { - if (child.roomId == null) continue; - childIds.add(child.roomId!); - final Room? room = client.getRoomById(child.roomId!); - if (room != null && room.isSpace) { - childIds.addAll(room._allSpaceChildRoomIds); - } - } - return childIds; - } - - // Checks if has permissions to add child chat - // Or whether potential child space is ancestor of this - bool _canAddAsParentOf(Room? child, {bool spaceMode = false}) { - // don't add a room to itself - if (id == child?.id) return false; - spaceMode = child?.isSpace ?? spaceMode; - - // get the bool for adding chats to spaces - final bool canAddChild = - (child?.isRoomAdmin ?? true) && canSendEvent(EventTypes.SpaceChild); - if (!spaceMode) return canAddChild; - - // if adding space to a space, check if the child is an ancestor - // to prevent cycles - final bool isCycle = - child != null ? child._allSpaceChildRoomIds.contains(id) : false; - return canAddChild && !isCycle; - } - /// Wrapper around call to setSpaceChild with added functionality /// to prevent adding one room to multiple spaces Future _pangeaSetSpaceChild( diff --git a/lib/pangea/models/practice_activities.dart/practice_activity_model.dart b/lib/pangea/models/practice_activities.dart/practice_activity_model.dart index 6e0971584..2ae1f667a 100644 --- a/lib/pangea/models/practice_activities.dart/practice_activity_model.dart +++ b/lib/pangea/models/practice_activities.dart/practice_activity_model.dart @@ -228,6 +228,13 @@ class PracticeActivityModel { throw ("content is null in PracticeActivityModel.fromJson"); } + if (json['lang_code'] is! String) { + Sentry.addBreadcrumb( + Breadcrumb(data: {"json": json}), + ); + throw ("lang_code is not a string in PracticeActivityModel.fromJson"); + } + return PracticeActivityModel( tgtConstructs: ((json['tgt_constructs'] ?? json['target_constructs']) as List)