chore: update room summary model (#5502)

This commit is contained in:
ggurdin 2026-01-28 16:13:50 -05:00 committed by GitHub
parent 8c7d64c0cc
commit 597387def4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 74 additions and 39 deletions

View file

@ -14,6 +14,7 @@ import 'package:fluffychat/pangea/activity_sessions/activity_session_start/activ
import 'package:fluffychat/pangea/activity_sessions/activity_session_start/bot_join_error_dialog.dart';
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/chat_settings/utils/room_summary_extension.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/course_plans/course_activities/activity_summaries_provider.dart';
import 'package:fluffychat/pangea/course_plans/course_activities/course_activity_repo.dart';
import 'package:fluffychat/pangea/course_plans/course_activities/course_activity_translation_request.dart';
@ -191,7 +192,7 @@ class ActivitySessionStartController extends State<ActivitySessionStartPage>
final availableRoles = activity!.roles;
final assignedRoles = activityRoom?.assignedRoles ??
roomSummaries?[widget.roomId]?.activityRoles.roles ??
roomSummaries?[widget.roomId]?.activityRoles?.roles ??
{};
final unassignedIds = availableRoles.keys
.where((id) => !assignedRoles.containsKey(id))
@ -293,8 +294,17 @@ class ActivitySessionStartController extends State<ActivitySessionStartPage>
);
}
await Future.wait(futures);
} catch (e) {
} catch (e, s) {
error = e;
ErrorHandler.logError(
e: e,
s: s,
data: {
"activityId": widget.activityId,
"roomId": widget.roomId,
"parentId": widget.parentId,
},
);
} finally {
if (mounted) {
setState(() => loading = false);

View file

@ -518,7 +518,7 @@ class _ActivityStatuses extends StatelessWidget {
// room (like the bot). Otherwise, show only joined users with roles
Map<String, ActivityRoleModel> activityRoles =
status == ActivitySummaryStatus.completed
? e.value.activityRoles.roles
? (e.value.activityRoles?.roles ?? {})
: e.value.joinedUsersWithRoles;
// If the user is in the activity room and it's not completed, use the room's
@ -530,7 +530,7 @@ class _ActivityStatuses extends StatelessWidget {
return ListTile(
title: OpenRolesIndicator(
roles: activityPlan.roles.values
roles: (activityPlan?.roles.values ?? [])
.sorted((a, b) => a.id.compareTo(b.id))
.toList(),
assignedRoles: activityRoles.values.toList(),

View file

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:http/http.dart' hide Client;
import 'package:matrix/matrix.dart';
import 'package:matrix/matrix_api_lite/generated/api.dart';
@ -52,25 +53,21 @@ class RoomSummariesResponse {
});
return RoomSummariesResponse(summaries: summaries);
}
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
summaries.forEach((key, value) {
json[key] = value.toJson();
});
return json;
}
}
class RoomSummaryResponse {
final ActivityPlanModel activityPlan;
final ActivityRolesModel activityRoles;
final ActivityPlanModel? activityPlan;
final ActivityRolesModel? activityRoles;
final JoinRules? joinRule;
final Map<String, int>? powerLevels;
final Map<String, String> membershipSummary;
RoomSummaryResponse({
required this.activityPlan,
required this.activityRoles,
required this.membershipSummary,
this.activityPlan,
this.activityRoles,
this.joinRule,
this.powerLevels,
});
Membership? getMembershipForUserId(String userId) {
@ -83,32 +80,52 @@ class RoomSummaryResponse {
}
Map<String, ActivityRoleModel> get joinedUsersWithRoles {
if (activityRoles == null) return {};
return Map.fromEntries(
activityRoles.roles.entries.where(
activityRoles!.roles.entries.where(
(role) => getMembershipForUserId(role.value.userId) == Membership.join,
),
);
}
factory RoomSummaryResponse.fromJson(Map<String, dynamic> json) {
final planEntry =
json[PangeaEventTypes.activityPlan]?["default"]?["content"];
ActivityPlanModel? plan;
if (planEntry != null && planEntry is Map<String, dynamic>) {
plan = ActivityPlanModel.fromJson(planEntry);
}
final rolesEntry =
json[PangeaEventTypes.activityRole]?["default"]?["content"];
ActivityRolesModel? roles;
if (rolesEntry != null && rolesEntry is Map<String, dynamic>) {
roles = ActivityRolesModel.fromJson(rolesEntry);
}
final powerLevelsEntry =
json[EventTypes.RoomPowerLevels]?['default']?['content']?['users'];
Map<String, int>? powerLevels;
if (powerLevelsEntry != null) {
powerLevels = Map<String, int>.from(powerLevelsEntry);
}
final joinRulesString =
json[EventTypes.RoomJoinRules]?['default']?['content']?['join_rule'];
JoinRules? joinRule;
if (joinRulesString != null && joinRulesString is String) {
joinRule = JoinRules.values
.singleWhereOrNull((element) => element.text == joinRulesString);
}
return RoomSummaryResponse(
activityPlan: ActivityPlanModel.fromJson(
json[PangeaEventTypes.activityPlan]?["default"]?["content"] ?? {},
),
activityRoles: ActivityRolesModel.fromJson(
json[PangeaEventTypes.activityRole]?["default"]?["content"] ?? {},
),
activityPlan: plan,
activityRoles: roles,
powerLevels: powerLevels,
joinRule: joinRule,
membershipSummary: Map<String, String>.from(
json['membership_summary'] ?? {},
),
);
}
Map<String, dynamic> toJson() {
return {
PangeaEventTypes.activityPlan: activityPlan.toJson(),
PangeaEventTypes.activityRole: activityRoles.toJson(),
'membership_summary': membershipSummary,
};
}
}

View file

@ -133,9 +133,13 @@ class CourseChatsController extends State<CourseChats>
}
final activity = summary.activityPlan;
final roles = summary.activityRoles;
final users = summary.joinedUsersWithRoles;
if (users.isEmpty || !validIDs.contains(activity.activityId)) {
if (activity == null ||
roles == null ||
users.isEmpty ||
!validIDs.contains(activity.activityId)) {
continue;
}
@ -148,7 +152,7 @@ class CourseChatsController extends State<CourseChats>
// It's possible for users to finish an activity and then for some of the
// users to leave, but if the activity was archived by anyone, that means
// it was full at some point.
if (summary.activityRoles.roles.values.any((role) => role.isArchived)) {
if (roles.roles.values.any((role) => role.isArchived)) {
continue;
}

View file

@ -48,6 +48,7 @@ mixin ActivitySummariesProvider<T extends StatefulWidget> on State<T> {
final activityPlan = roomSummary.activityPlan;
final assignedRoles = roomSummary.joinedUsersWithRoles;
if (activityPlan == null) return false;
return activityPlan.roles.length - assignedRoles.length <= 0;
}
@ -56,6 +57,7 @@ mixin ActivitySummariesProvider<T extends StatefulWidget> on State<T> {
if (roomSummary == null) return false;
final activityRoles = roomSummary.activityRoles;
if (activityRoles == null) return false;
final roles = activityRoles.roles.values.where(
(r) => r.userId != BotName.byEnvironment,
);
@ -76,7 +78,7 @@ mixin ActivitySummariesProvider<T extends StatefulWidget> on State<T> {
Map<String, RoomSummaryResponse> activitySessions(String activityId) =>
Map.fromEntries(
roomSummaries?.entries
.where((v) => v.value.activityPlan.activityId == activityId) ??
.where((v) => v.value.activityPlan?.activityId == activityId) ??
[],
);
@ -115,7 +117,7 @@ mixin ActivitySummariesProvider<T extends StatefulWidget> on State<T> {
final summary = entry.value;
final roomId = entry.key;
if (summary.activityPlan.activityId != activityId) {
if (summary.activityPlan?.activityId != activityId) {
continue;
}
@ -132,11 +134,13 @@ mixin ActivitySummariesProvider<T extends StatefulWidget> on State<T> {
if (roomSummaries == null || roomSummaries!.isEmpty) return {};
return roomSummaries!.values
.where(
(entry) => entry.activityRoles.roles.values.any(
(v) => v.userId == userID && v.isArchived,
),
(entry) =>
entry.activityRoles != null &&
entry.activityRoles!.roles.values.any(
(v) => v.userId == userID && v.isArchived,
),
)
.map((e) => e.activityPlan.activityId)
.map((e) => e.activityPlan?.activityId)
.whereType<String>()
.toSet();
}