You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fluffychat/lib/pangea/course_chats/course_chats_view.dart

338 lines
14 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart' as sdk;
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pages/chat_list/chat_list_item.dart';
import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart';
import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/course_chats/course_chats_page.dart';
import 'package:fluffychat/pangea/course_chats/unjoined_chat_list_item.dart';
import 'package:fluffychat/pangea/course_plans/course_plan_builder.dart';
import 'package:fluffychat/pangea/course_plans/course_plan_model.dart';
import 'package:fluffychat/pangea/course_plans/course_plan_room_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/space_analytics/analytics_request_indicator.dart';
import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart';
import 'package:fluffychat/utils/stream_extension.dart';
class CourseChatsView extends StatelessWidget {
final CourseChatsController controller;
const CourseChatsView(
this.controller, {
super.key,
});
@override
Widget build(BuildContext context) {
final room = controller.room;
if (room == null) {
return const Center(
child: Icon(
Icons.search_outlined,
size: 80,
),
);
}
return CoursePlanBuilder(
courseId: room.coursePlan?.uuid,
onFound: (course) {
controller.setCourse(course);
final topic = room.ownCurrentTopic(course);
if (topic != null) controller.setSelectedTopicId(topic.uuid);
},
builder: (context, courseController) {
final Topic? topic = controller.selectedTopic;
final List<String> activityIds = topic?.activityIds ?? [];
return StreamBuilder(
stream: room.client.onSync.stream
.where((s) => s.hasRoomUpdate)
.rateLimit(const Duration(seconds: 1)),
builder: (context, snapshot) {
final childrenIds = room.spaceChildren
.map((c) => c.roomId)
.whereType<String>()
.toSet();
final joinedChats = [];
final joinedSessions = [];
final joinedRooms = room.client.rooms
.where((room) => childrenIds.remove(room.id))
.where((room) => !room.isHiddenRoom)
.toList();
for (final joinedRoom in joinedRooms) {
if (joinedRoom.isActivitySession) {
String? activityId = joinedRoom.activityPlan?.activityId;
if (activityId == null && joinedRoom.isActivityRoomType) {
activityId = joinedRoom.roomType!.split(":").last;
}
if (topic == null || activityIds.contains(activityId)) {
joinedSessions.add(joinedRoom);
}
} else {
joinedChats.add(joinedRoom);
}
}
final discoveredGroupChats = [];
final discoveredSessions = [];
final discoveredChildren =
controller.discoveredChildren ?? <SpaceRoomsChunk>[];
for (final child in discoveredChildren) {
final roomType = child.roomType;
if (roomType?.startsWith(PangeaRoomTypes.activitySession) ==
true) {
if (activityIds.contains(roomType!.split(":").last)) {
discoveredSessions.add(child);
}
} else {
discoveredGroupChats.add(child);
}
}
final isColumnMode = FluffyThemes.isColumnMode(context);
return Padding(
padding: isColumnMode
? const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 8.0,
)
: const EdgeInsets.all(0.0),
child: ListView.builder(
shrinkWrap: true,
itemCount: joinedChats.length +
joinedSessions.length +
discoveredGroupChats.length +
discoveredSessions.length +
6,
itemBuilder: (context, i) {
// courses chats title
if (i == 0) {
if (isColumnMode) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Column(
spacing: 12.0,
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 24.0),
const Icon(
Icons.chat_bubble_outline,
size: 30.0,
),
Text(
L10n.of(context).courseChats,
style: const TextStyle(fontSize: 12.0),
),
const SizedBox(height: 14.0),
],
),
);
}
return const SizedBox();
}
i--;
if (i == 0) {
return KnockingUsersIndicator(room: room);
}
i--;
if (i == 0) {
return AnalyticsRequestIndicator(room: room);
}
i--;
// joined group chats
if (i < joinedChats.length) {
final joinedRoom = joinedChats[i];
return ChatListItem(
joinedRoom,
onTap: () => controller.onChatTap(joinedRoom),
onLongPress: (context) => controller.chatContextAction(
joinedRoom,
context,
),
activeChat: controller.widget.activeChat == joinedRoom.id,
);
}
i -= joinedChats.length;
// unjoined group chats
if (i < discoveredGroupChats.length) {
return UnjoinedChatListItem(
chunk: discoveredGroupChats[i],
onTap: () =>
controller.joinChildRoom(discoveredGroupChats[i]),
);
}
i -= discoveredGroupChats.length;
if (i == 0) {
if (room.coursePlan == null ||
(courseController.course == null &&
!courseController.loading)) {
return const SizedBox();
}
return Padding(
padding: const EdgeInsets.only(
top: 20.0,
bottom: 12.0,
),
child: courseController.loading
? LinearProgressIndicator(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
)
: topic != null
? Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
MouseRegion(
cursor: controller.canMoveLeft
? SystemMouseCursors.click
: SystemMouseCursors.basic,
child: GestureDetector(
onTap: controller.canMoveLeft
? controller.moveLeft
: null,
child: Opacity(
opacity: controller.canMoveLeft
? 1.0
: 0.3,
child: const Icon(
Icons.arrow_left,
size: 24.0,
),
),
),
),
Row(
spacing: 6.0,
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.location_on,
size: 24.0,
),
Text(
topic.location,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
],
),
MouseRegion(
cursor: controller.canMoveRight
? SystemMouseCursors.click
: SystemMouseCursors.basic,
child: GestureDetector(
onTap: controller.canMoveRight
? controller.moveRight
: null,
child: Opacity(
opacity: controller.canMoveRight
? 1.0
: 0.3,
child: const Icon(
Icons.arrow_right,
size: 24.0,
),
),
),
),
],
)
: const SizedBox(),
);
}
i--;
if (i == 0) {
return joinedSessions.isEmpty && discoveredSessions.isEmpty
? ListTile(
leading: const Icon(Icons.map_outlined),
title: Text(L10n.of(context).whatNow),
subtitle: Text(L10n.of(context).chooseNextActivity),
trailing: const Icon(Icons.arrow_forward),
onTap: () => context.go(
"/rooms/spaces/${room.id}/details?tab=course",
),
)
: const SizedBox();
}
i--;
// joined activity sessions
if (i < joinedSessions.length) {
final joinedRoom = joinedSessions[i];
return ChatListItem(
joinedRoom,
onTap: () => controller.onChatTap(joinedRoom),
onLongPress: (context) => controller.chatContextAction(
joinedRoom,
context,
),
activeChat: controller.widget.activeChat == joinedRoom.id,
);
}
i -= joinedSessions.length;
// unjoined activity sessions
if (i < discoveredSessions.length) {
return UnjoinedChatListItem(
chunk: discoveredSessions[i],
onTap: () => controller.joinChildRoom(
discoveredSessions[i],
),
);
}
i -= discoveredSessions.length;
if (controller.noMoreRooms) {
return const SizedBox();
}
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 2.0,
),
child: TextButton(
onPressed: controller.isLoading
? null
: controller.loadHierarchy,
child: controller.isLoading
? LinearProgressIndicator(
borderRadius: BorderRadius.circular(
AppConfig.borderRadius,
),
)
: Text(L10n.of(context).loadMore),
),
);
},
),
);
},
);
},
);
}
}