diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 3e0413230..d6f75f360 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -21,6 +21,7 @@ import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dar import 'package:fluffychat/pangea/models/choreo_record.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; +import 'package:fluffychat/pangea/pages/games/story_game/round_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/utils/report_message.dart'; @@ -112,9 +113,10 @@ class ChatController extends State with WidgetsBindingObserver { // #Pangea final PangeaController pangeaController = MatrixState.pangeaController; - late Choreographer choreographer = Choreographer(pangeaController, this); + final List gameRounds = []; // Pangea# + Room get room => sendingClient.getRoomById(roomId) ?? widget.room; late Client sendingClient; @@ -309,6 +311,7 @@ class ChatController extends State sendingClient = Matrix.of(context).client; WidgetsBinding.instance.addObserver(this); // #Pangea + gameRounds.add(GameRoundModel(controller: this)); if (!mounted) return; Future.delayed(const Duration(seconds: 1), () async { if (!mounted) return; @@ -533,6 +536,9 @@ class ChatController extends State //#Pangea choreographer.stateListener.close(); choreographer.dispose(); + for (final round in gameRounds) { + round.timer?.cancel(); + } //Pangea# super.dispose(); } diff --git a/lib/pangea/extensions/sync_update_extension.dart b/lib/pangea/extensions/sync_update_extension.dart index 6adb55c69..227e88c25 100644 --- a/lib/pangea/extensions/sync_update_extension.dart +++ b/lib/pangea/extensions/sync_update_extension.dart @@ -1,85 +1,26 @@ +import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:matrix/matrix.dart'; extension MembershipUpdate on SyncUpdate { - bool isMembershipUpdate(String userId) { - return isMembershipUpdateByType(Membership.join, userId) || - isMembershipUpdateByType(Membership.leave, userId) || - isMembershipUpdateByType(Membership.invite, userId); - } - - bool isMembershipUpdateByType(Membership type, String userId) { - final List? updates = getRoomUpdates(type); - if (updates?.isEmpty ?? true) { - return false; + List botMessages(String roomID) { + if (rooms?.join == null || + !rooms!.join!.containsKey(roomID) || + rooms!.join![roomID]!.timeline?.events == null) { + return []; } - for (final SyncRoomUpdate update in updates!) { - final List? events = getRoomUpdateEvents(type, update); - if (hasMembershipUpdate( - events, - type.name, - userId, - )) { - return true; - } + final messageEvents = rooms!.join![roomID]!.timeline!.events! + .where( + (event) => event.type == EventTypes.Message, + ) + .toList(); + if (messageEvents.isEmpty) { + return []; } - return false; - } - List? getRoomUpdates(Membership type) { - switch (type) { - case Membership.join: - return rooms?.join?.values.toList(); - case Membership.leave: - return rooms?.leave?.values.toList(); - case Membership.invite: - return rooms?.invite?.values.toList(); - default: - return null; - } - } - - bool isSpaceChildUpdate(String activeSpaceId) { - if (rooms?.join?.isEmpty ?? true) { - return false; - } - for (final update in rooms!.join!.entries) { - final String spaceId = update.key; - final List? timelineEvents = update.value.timeline?.events; - final bool isUpdate = timelineEvents != null && - spaceId == activeSpaceId && - timelineEvents.any((event) => event.type == EventTypes.SpaceChild); - if (isUpdate) return true; - } - return false; + return messageEvents + .where((event) => event.senderId == BotName.byEnvironment) + .map((event) => event.eventId) + .toList(); } } - -List? getRoomUpdateEvents(Membership type, SyncRoomUpdate update) { - switch (type) { - case Membership.join: - return (update as JoinedRoomUpdate).timeline?.events; - case Membership.leave: - return (update as LeftRoomUpdate).timeline?.events; - case Membership.invite: - return (update as InvitedRoomUpdate).inviteState; - default: - return null; - } -} - -bool hasMembershipUpdate( - List? events, - String membershipType, - String userId, -) { - if (events == null) { - return false; - } - return events.any( - (event) => - event.type == EventTypes.RoomMember && - event.stateKey == userId && - event.content['membership'] == membershipType, - ); -} diff --git a/lib/pangea/pages/games/story_game/round_model.dart b/lib/pangea/pages/games/story_game/round_model.dart index e3ad65d89..6177fe1fe 100644 --- a/lib/pangea/pages/games/story_game/round_model.dart +++ b/lib/pangea/pages/games/story_game/round_model.dart @@ -1,28 +1,47 @@ import 'dart:async'; +import 'package:fluffychat/pages/chat/chat.dart'; +import 'package:fluffychat/pangea/extensions/sync_update_extension.dart'; +import 'package:flutter/material.dart'; +import 'package:matrix/matrix.dart'; + enum RoundState { notStarted, inProgress, completed } class GameRoundModel { static const Duration roundLength = Duration(minutes: 3); + final ChatController controller; Timer? timer; DateTime? startTime; DateTime? endTime; RoundState state = RoundState.notStarted; - GameRoundModel() { - timer = Timer(roundLength, () => endRound()); - startTime = DateTime.now(); + final Set messageIDs = {}; + + GameRoundModel({ + required this.controller, + }) { + client.onSync.stream.firstWhere((update) { + final botEventIDs = update.botMessages(controller.roomId); + return botEventIDs.isNotEmpty; + }).then((_) => startRound()); } + Client get client => controller.pangeaController.matrixState.client; + void startRound() { + debugPrint("starting round"); state = RoundState.inProgress; startTime = DateTime.now(); timer = Timer(roundLength, () => endRound()); } void endRound() { + debugPrint("ending round"); endTime = DateTime.now(); state = RoundState.completed; + timer?.cancel(); } + + void dispose() {} }