3671 dont show join wrap up state events instead in activity plan state event show taken untaken roles and below that show users who havent picked a role (#3675)
* chore: add role IDs * chore: add row of unjoined users to activity plan state event display
This commit is contained in:
parent
d87f86bee1
commit
194c25be25
11 changed files with 251 additions and 140 deletions
|
|
@ -13,7 +13,7 @@ class ActivityPlanModel {
|
|||
final String? imageURL;
|
||||
final DateTime? endAt;
|
||||
final Duration? duration;
|
||||
final List<Role> roles;
|
||||
final Map<String, ActivityRole> roles;
|
||||
|
||||
ActivityPlanModel({
|
||||
required this.req,
|
||||
|
|
@ -36,7 +36,7 @@ class ActivityPlanModel {
|
|||
String? imageURL,
|
||||
DateTime? endAt,
|
||||
Duration? duration,
|
||||
List<Role>? roles,
|
||||
Map<String, ActivityRole>? roles,
|
||||
}) {
|
||||
return ActivityPlanModel(
|
||||
req: req,
|
||||
|
|
@ -55,6 +55,28 @@ class ActivityPlanModel {
|
|||
final req =
|
||||
ActivityPlanRequest.fromJson(json[ModelKey.activityPlanRequest]);
|
||||
|
||||
Map<String, ActivityRole> roles;
|
||||
final roleContent = json['roles'];
|
||||
if (roleContent is Map<String, dynamic>) {
|
||||
roles = Map<String, ActivityRole>.from(
|
||||
json['roles'].map(
|
||||
(key, value) => MapEntry(
|
||||
key,
|
||||
ActivityRole.fromJson(value),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
roles = {};
|
||||
for (int i = 0; i < req.numberOfParticipants; i++) {
|
||||
roles['role_$i'] = ActivityRole(
|
||||
id: 'role_$i',
|
||||
name: 'Participant',
|
||||
avatarUrl: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return ActivityPlanModel(
|
||||
imageURL: json[ModelKey.activityPlanImageURL],
|
||||
instructions: json[ModelKey.activityPlanInstructions],
|
||||
|
|
@ -74,15 +96,7 @@ class ActivityPlanModel {
|
|||
minutes: json[ModelKey.activityPlanDuration]['minutes'] ?? 0,
|
||||
)
|
||||
: null,
|
||||
roles: List<Role>.from(
|
||||
json['roles']?.map((role) => Role.fromJson(role)) ??
|
||||
req.numberOfParticipants > 1
|
||||
? List.generate(
|
||||
req.numberOfParticipants,
|
||||
(index) => Role(name: 'Participant'),
|
||||
)
|
||||
: [Role(name: 'Participant')],
|
||||
),
|
||||
roles: roles,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +115,9 @@ class ActivityPlanModel {
|
|||
'hours': duration?.inHours.remainder(24) ?? 0,
|
||||
'minutes': duration?.inMinutes.remainder(60) ?? 0,
|
||||
},
|
||||
'roles': roles.map((role) => role.toJson()).toList(),
|
||||
'roles': roles.map(
|
||||
(key, value) => MapEntry(key, value.toJson()),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -180,17 +196,20 @@ class Vocab {
|
|||
int get hashCode => lemma.hashCode ^ pos.hashCode;
|
||||
}
|
||||
|
||||
class Role {
|
||||
class ActivityRole {
|
||||
final String id;
|
||||
final String name;
|
||||
final String? avatarUrl;
|
||||
|
||||
Role({
|
||||
ActivityRole({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.avatarUrl,
|
||||
});
|
||||
|
||||
factory Role.fromJson(Map<String, dynamic> json) {
|
||||
return Role(
|
||||
factory ActivityRole.fromJson(Map<String, dynamic> json) {
|
||||
return ActivityRole(
|
||||
id: json['id'],
|
||||
name: json['name'],
|
||||
avatarUrl: json['avatar_url'],
|
||||
);
|
||||
|
|
@ -198,6 +217,7 @@ class Role {
|
|||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'avatar_url': avatarUrl,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,7 +36,15 @@ class BookmarkedActivitiesRepo {
|
|||
for (final key in keys) {
|
||||
final json = _bookStorage.read(key);
|
||||
if (json == null) continue;
|
||||
final activity = ActivityPlanModel.fromJson(json);
|
||||
|
||||
ActivityPlanModel? activity;
|
||||
try {
|
||||
activity = ActivityPlanModel.fromJson(json);
|
||||
} catch (e) {
|
||||
_bookStorage.remove(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key != activity.bookmarkId) {
|
||||
_bookStorage.remove(key);
|
||||
_bookStorage.write(activity.bookmarkId, activity.toJson());
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:matrix/matrix.dart';
|
|||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_participant_indicator.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_results_carousel.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart';
|
||||
|
|
@ -49,6 +50,8 @@ class ActivityFinishedStatusMessageState
|
|||
_setDefaultHighlightedRole();
|
||||
}
|
||||
|
||||
Map<String, ActivityRole> get _roles => widget.room.activityPlan?.roles ?? {};
|
||||
|
||||
void _setExpanded(bool expanded) {
|
||||
if (mounted) setState(() => _expanded = expanded);
|
||||
}
|
||||
|
|
@ -110,7 +113,7 @@ class ActivityFinishedStatusMessageState
|
|||
}
|
||||
|
||||
final roles = widget.room.activityRoles;
|
||||
return roles?.roles.where((role) {
|
||||
return roles?.roles.values.where((role) {
|
||||
return widget.room.activitySummary!.summary!.participants.any(
|
||||
(p) => p.participantId == role.userId,
|
||||
);
|
||||
|
|
@ -202,20 +205,28 @@ class ActivityFinishedStatusMessageState
|
|||
),
|
||||
const SizedBox(height: 8.0),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12.0,
|
||||
runSpacing: 12.0,
|
||||
children: rolesWithSummaries
|
||||
.map(
|
||||
(role) => ActivityParticipantIndicator(
|
||||
onTap: _highlightedRole == role
|
||||
? null
|
||||
: () => _highlightRole(role),
|
||||
role: role,
|
||||
displayname: role.userId.localpart,
|
||||
selected: _highlightedRole == role,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
children: rolesWithSummaries.map(
|
||||
(role) {
|
||||
final user =
|
||||
widget.room.getParticipants().firstWhereOrNull(
|
||||
(u) => u.id == role.userId,
|
||||
);
|
||||
|
||||
return ActivityParticipantIndicator(
|
||||
availableRole: _roles[role.id]!,
|
||||
avatarUrl: _roles[role.id]?.avatarUrl ??
|
||||
user?.avatarUrl?.toString(),
|
||||
onTap: _highlightedRole == role
|
||||
? null
|
||||
: () => _highlightRole(role),
|
||||
assignedRole: role,
|
||||
selected: _highlightedRole == role,
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
const SizedBox(height: 20.0),
|
||||
] else if (summary?.isLoading ?? false)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart';
|
||||
import 'package:fluffychat/utils/string_color.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
import 'package:fluffychat/widgets/hover_builder.dart';
|
||||
|
||||
class ActivityParticipantIndicator extends StatelessWidget {
|
||||
final bool selected;
|
||||
final ActivityRole availableRole;
|
||||
final ActivityRoleModel? assignedRole;
|
||||
|
||||
final ActivityRoleModel? role;
|
||||
final String? displayname;
|
||||
final String? avatarUrl;
|
||||
|
||||
final VoidCallback? onTap;
|
||||
final bool selected;
|
||||
final double opacity;
|
||||
|
||||
const ActivityParticipantIndicator({
|
||||
super.key,
|
||||
required this.availableRole,
|
||||
this.avatarUrl,
|
||||
this.assignedRole,
|
||||
this.selected = false,
|
||||
this.role,
|
||||
this.displayname,
|
||||
this.onTap,
|
||||
this.opacity = 1.0,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -33,7 +42,7 @@ class ActivityParticipantIndicator extends StatelessWidget {
|
|||
child: HoverBuilder(
|
||||
builder: (context, hovered) {
|
||||
return Opacity(
|
||||
opacity: onTap == null ? 0.7 : 1.0,
|
||||
opacity: opacity,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
|
|
@ -50,22 +59,43 @@ class ActivityParticipantIndicator extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 30.0,
|
||||
backgroundColor: theme.colorScheme.primaryContainer,
|
||||
),
|
||||
assignedRole != null
|
||||
? avatarUrl == null || avatarUrl!.startsWith("mxc")
|
||||
? Avatar(
|
||||
mxContent: avatarUrl != null
|
||||
? Uri.parse(avatarUrl!)
|
||||
: null,
|
||||
name: assignedRole?.userId.localpart,
|
||||
size: 60.0,
|
||||
)
|
||||
: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: avatarUrl!,
|
||||
width: 60.0,
|
||||
height: 60.0,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
)
|
||||
: CircleAvatar(
|
||||
radius: 30.0,
|
||||
backgroundColor:
|
||||
theme.colorScheme.primaryContainer,
|
||||
),
|
||||
Text(
|
||||
role?.role ?? L10n.of(context).participant,
|
||||
availableRole.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 12.0,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
displayname ?? L10n.of(context).openRoleLabel,
|
||||
assignedRole?.userId.localpart ??
|
||||
L10n.of(context).openRoleLabel,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: displayname?.lightColorAvatar ??
|
||||
role?.role?.lightColorAvatar,
|
||||
color: assignedRole
|
||||
?.userId.localpart?.lightColorAvatar ??
|
||||
assignedRole?.role?.lightColorAvatar,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
class ActivityRoleModel {
|
||||
final String id;
|
||||
final String userId;
|
||||
final String? role;
|
||||
DateTime? finishedAt;
|
||||
DateTime? archivedAt;
|
||||
|
||||
ActivityRoleModel({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
this.role,
|
||||
this.finishedAt,
|
||||
|
|
@ -17,6 +19,7 @@ class ActivityRoleModel {
|
|||
|
||||
factory ActivityRoleModel.fromJson(Map<String, dynamic> json) {
|
||||
return ActivityRoleModel(
|
||||
id: json['id'],
|
||||
userId: json['userId'],
|
||||
role: json['role'],
|
||||
finishedAt: json['finishedAt'] != null
|
||||
|
|
@ -30,6 +33,7 @@ class ActivityRoleModel {
|
|||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'userId': userId,
|
||||
'role': role,
|
||||
'finishedAt': finishedAt?.toIso8601String(),
|
||||
|
|
@ -45,7 +49,8 @@ class ActivityRoleModel {
|
|||
other.userId == userId &&
|
||||
other.role == role &&
|
||||
other.finishedAt == finishedAt &&
|
||||
other.archivedAt == archivedAt;
|
||||
other.archivedAt == archivedAt &&
|
||||
other.id == id;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -53,5 +58,6 @@ class ActivityRoleModel {
|
|||
userId.hashCode ^
|
||||
role.hashCode ^
|
||||
(finishedAt?.hashCode ?? 0) ^
|
||||
(archivedAt?.hashCode ?? 0);
|
||||
(archivedAt?.hashCode ?? 0) ^
|
||||
id.hashCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,67 +1,41 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_role_model.dart';
|
||||
|
||||
class ActivityRolesModel {
|
||||
final Event? event;
|
||||
late List<ActivityRoleModel> _roles;
|
||||
final Map<String, ActivityRoleModel> roles;
|
||||
|
||||
ActivityRolesModel({this.event, List<ActivityRoleModel>? roles}) {
|
||||
assert(
|
||||
event != null || roles != null,
|
||||
"Either event or roles must be provided",
|
||||
);
|
||||
|
||||
if (roles != null) {
|
||||
_roles = roles;
|
||||
} else {
|
||||
final rolesList = event!.content["roles"] as List<dynamic>? ?? [];
|
||||
try {
|
||||
_roles = rolesList
|
||||
.map<ActivityRoleModel>((e) => ActivityRoleModel.fromJson(e))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
_roles = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ActivityRoleModel> get roles => _roles;
|
||||
const ActivityRolesModel(this.roles);
|
||||
|
||||
ActivityRoleModel? role(String userId) {
|
||||
return _roles.firstWhereOrNull((r) => r.userId == userId);
|
||||
return roles.values.firstWhereOrNull((r) => r.userId == userId);
|
||||
}
|
||||
|
||||
/// If this user already has a role, replace it with the new one.
|
||||
/// Otherwise, add the new role.
|
||||
void updateRole(ActivityRoleModel role) {
|
||||
final index = _roles.indexWhere((r) => r.userId == role.userId);
|
||||
index != -1 ? _roles[index] = role : _roles.add(role);
|
||||
roles[role.id] = role;
|
||||
}
|
||||
|
||||
void finishAll() {
|
||||
for (final role in _roles) {
|
||||
if (role.isFinished) continue;
|
||||
role.finishedAt = DateTime.now();
|
||||
for (final id in roles.keys) {
|
||||
if (roles[id]!.isFinished) continue;
|
||||
roles[id]!.finishedAt = DateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
static ActivityRolesModel get empty => ActivityRolesModel(
|
||||
roles: [],
|
||||
);
|
||||
static ActivityRolesModel get empty {
|
||||
final roles = <String, ActivityRoleModel>{};
|
||||
return ActivityRolesModel(roles);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
"roles": _roles.map((role) => role.toJson()).toList(),
|
||||
"roles": roles.map((id, role) => MapEntry(id, role.toJson())),
|
||||
};
|
||||
}
|
||||
|
||||
static ActivityRolesModel fromJson(Map<String, dynamic> json) {
|
||||
final roles = (json["roles"] as List<dynamic>?)
|
||||
?.map<ActivityRoleModel>((e) => ActivityRoleModel.fromJson(e))
|
||||
.toList();
|
||||
|
||||
return ActivityRolesModel(roles: roles);
|
||||
final roles = (json['roles'] as Map<String, dynamic>)
|
||||
.map((id, value) => MapEntry(id, ActivityRoleModel.fromJson(value)));
|
||||
return ActivityRolesModel(roles);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
|
@ -36,13 +35,12 @@ extension ActivityRoomExtension on Room {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> joinActivity({
|
||||
String? role,
|
||||
}) async {
|
||||
Future<void> joinActivity(ActivityRole role) async {
|
||||
final currentRoles = activityRoles ?? ActivityRolesModel.empty;
|
||||
final activityRole = ActivityRoleModel(
|
||||
id: role.id,
|
||||
userId: client.userID!,
|
||||
role: role,
|
||||
role: role.name,
|
||||
);
|
||||
|
||||
currentRoles.updateRole(activityRole);
|
||||
|
|
@ -277,7 +275,7 @@ extension ActivityRoomExtension on Room {
|
|||
activityRoles?.role(client.userID!)?.isFinished ?? false;
|
||||
|
||||
bool get activityIsFinished {
|
||||
final roles = activityRoles?.roles.where(
|
||||
final roles = activityRoles?.roles.values.where(
|
||||
(r) => r.userId != BotName.byEnvironment,
|
||||
);
|
||||
|
||||
|
|
@ -294,14 +292,6 @@ extension ActivityRoomExtension on Room {
|
|||
});
|
||||
}
|
||||
|
||||
int get remainingRoles {
|
||||
if (activityPlan == null) return 0;
|
||||
return max(
|
||||
0,
|
||||
activityPlan!.roles.length - (activityRoles?.roles.length ?? 0),
|
||||
);
|
||||
}
|
||||
|
||||
bool get isHiddenActivityRoom =>
|
||||
activityRoles?.role(client.userID!)?.isArchived ?? false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
|
|
@ -7,6 +8,7 @@ import 'package:fluffychat/pages/chat/events/state_message.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/activity_plan_model.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_participant_indicator.dart';
|
||||
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
|
||||
import 'package:fluffychat/widgets/avatar.dart';
|
||||
|
||||
class ActivityStateEvent extends StatelessWidget {
|
||||
final Event event;
|
||||
|
|
@ -14,9 +16,20 @@ class ActivityStateEvent extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (event.room.activityPlan == null) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
try {
|
||||
final activity = ActivityPlanModel.fromJson(event.content);
|
||||
final roles = event.room.activityRoles?.roles ?? [];
|
||||
final availableRoles = event.room.activityPlan!.roles;
|
||||
final assignedRoles = event.room.activityRoles?.roles ?? {};
|
||||
|
||||
final remainingMembers = event.room.getParticipants().where(
|
||||
(p) => !assignedRoles.values.any((r) => r.userId == p.id),
|
||||
);
|
||||
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
|
@ -33,17 +46,70 @@ class ActivityStateEvent extends StatelessWidget {
|
|||
activity.markdown,
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
if (roles.isNotEmpty)
|
||||
Wrap(
|
||||
spacing: 12.0,
|
||||
runSpacing: 12.0,
|
||||
children: roles.map((role) {
|
||||
return ActivityParticipantIndicator(
|
||||
role: role,
|
||||
displayname: role.userId.localpart,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12.0,
|
||||
runSpacing: 12.0,
|
||||
children: availableRoles.values.map((availableRole) {
|
||||
final assignedRole = assignedRoles[availableRole.id];
|
||||
final user = event.room.getParticipants().firstWhereOrNull(
|
||||
(u) => u.id == assignedRole?.userId,
|
||||
);
|
||||
|
||||
return ActivityParticipantIndicator(
|
||||
availableRole: availableRole,
|
||||
assignedRole: assignedRole,
|
||||
opacity: assignedRole == null || assignedRole.isFinished
|
||||
? 0.5
|
||||
: 1.0,
|
||||
avatarUrl:
|
||||
availableRole.avatarUrl ?? user?.avatarUrl.toString(),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12.0,
|
||||
runSpacing: 12.0,
|
||||
children: remainingMembers.map((member) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(18.0),
|
||||
),
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Opacity(
|
||||
opacity: 0.5,
|
||||
child: Row(
|
||||
spacing: 4.0,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Avatar(
|
||||
size: 18.0,
|
||||
mxContent: member.avatarUrl,
|
||||
name: member.calcDisplayname(),
|
||||
userId: member.id,
|
||||
),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 80.0,
|
||||
),
|
||||
child: Text(
|
||||
member.calcDisplayname(),
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
color: theme.colorScheme.onPrimaryContainer,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -22,34 +22,43 @@ class ActivityUnfinishedStatusMessage extends StatefulWidget {
|
|||
|
||||
class ActivityUnfinishedStatusMessageState
|
||||
extends State<ActivityUnfinishedStatusMessage> {
|
||||
int? _selectedRole;
|
||||
String? _selectedRoleId;
|
||||
|
||||
void _selectRole(int role) {
|
||||
if (_selectedRole == role) return;
|
||||
if (mounted) setState(() => _selectedRole = role);
|
||||
void _selectRole(String id) {
|
||||
if (_selectedRoleId == id) return;
|
||||
if (mounted) setState(() => _selectedRoleId = id);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
|
||||
final remainingRoles = widget.room.remainingRoles;
|
||||
final completed = widget.room.hasCompletedActivity;
|
||||
|
||||
final availableRoles = widget.room.activityPlan!.roles;
|
||||
final assignedRoles = widget.room.activityRoles?.roles ?? {};
|
||||
final remainingRoles = availableRoles.length - assignedRoles.length;
|
||||
|
||||
final unassignedIds = availableRoles.keys
|
||||
.where((id) => !assignedRoles.containsKey(id))
|
||||
.toList();
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
if (!completed) ...[
|
||||
if (remainingRoles > 0)
|
||||
if (unassignedIds.isNotEmpty)
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 12.0,
|
||||
runSpacing: 12.0,
|
||||
children: List.generate(remainingRoles, (index) {
|
||||
children: unassignedIds.map((id) {
|
||||
return ActivityParticipantIndicator(
|
||||
selected: _selectedRole == index,
|
||||
onTap: () => _selectRole(index),
|
||||
availableRole: availableRoles[id]!,
|
||||
selected: _selectedRoleId == id,
|
||||
onTap: () => _selectRole(id),
|
||||
avatarUrl: availableRoles[id]?.avatarUrl,
|
||||
);
|
||||
}),
|
||||
}).toList(),
|
||||
),
|
||||
const SizedBox(height: 16.0),
|
||||
Text(
|
||||
|
|
@ -79,11 +88,13 @@ class ActivityUnfinishedStatusMessageState
|
|||
future: widget.room.continueActivity,
|
||||
);
|
||||
}
|
||||
: _selectedRole != null
|
||||
: _selectedRoleId != null
|
||||
? () {
|
||||
showFutureLoadingDialog(
|
||||
context: context,
|
||||
future: widget.room.joinActivity,
|
||||
future: () => widget.room.joinActivity(
|
||||
availableRoles[_selectedRoleId!]!,
|
||||
),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
|
|
|
|||
|
|
@ -22,9 +22,16 @@ class ActivitySearchRepo {
|
|||
final cachedJson = _activityPlanStorage.read(request.storageKey);
|
||||
if (cachedJson != null &&
|
||||
(cachedJson['activity_plans'] as List).isNotEmpty) {
|
||||
final cached = ActivityPlanResponse.fromJson(cachedJson);
|
||||
ActivityPlanResponse? cached;
|
||||
try {
|
||||
cached = ActivityPlanResponse.fromJson(cachedJson);
|
||||
} catch (e) {
|
||||
_activityPlanStorage.remove(request.storageKey);
|
||||
}
|
||||
|
||||
return cached;
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
final Requests req = Requests(
|
||||
|
|
|
|||
|
|
@ -81,16 +81,4 @@ class ActivitySummaryRequestModel {
|
|||
'content_feedback': contentFeedback.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
factory ActivitySummaryRequestModel.fromJson(Map<String, dynamic> json) {
|
||||
return ActivitySummaryRequestModel(
|
||||
activity: ActivityPlanModel.fromJson(json['activity']),
|
||||
activityResults: (json['activity_results'] as List)
|
||||
.map((e) => ActivitySummaryResultsMessage.fromJson(e))
|
||||
.toList(),
|
||||
contentFeedback: (json['content_feedback'] as List)
|
||||
.map((e) => ContentFeedbackModel.fromJson(e))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue