diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index e59c19fd9..0ed012b60 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -604,7 +604,7 @@ class ChatListController extends State ).client.rooms.where((r) => r.isSpace && r.membership == Membership.invite); for (final space in invitedSpaces) { - await showInviteDialog(space, context); + await SpaceTapUtil.onTap(context, space); } } @@ -641,9 +641,7 @@ class ChatListController extends State final roomCode = room.classCode?.toLowerCase(); final cachedCode = SpaceCodeRepo.recentCode?.toLowerCase(); if (cachedCode == roomCode) continue; - - // Show invite popup - chatListHandleSpaceTap(context, room); + await SpaceTapUtil.onTap(context, room); } } } diff --git a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart index c54d1fffb..082e7ee4e 100644 --- a/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart +++ b/lib/pangea/chat_list/utils/chat_list_handle_space_tap.dart @@ -3,142 +3,63 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/chat_list/widgets/room_invite_dialog.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; import 'package:fluffychat/pangea/join_codes/knock_room_extension.dart'; import 'package:fluffychat/pangea/join_codes/space_code_repo.dart'; -import 'package:fluffychat/utils/localized_exception_extension.dart'; -import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; import '../../common/utils/error_handler.dart'; -Future showInviteDialog(Room room, BuildContext context) async { - if (room.membership != Membership.invite) return; - - final theme = Theme.of(context); - final action = await showAdaptiveDialog( - barrierDismissible: true, - context: context, - builder: (context) => AlertDialog.adaptive( - title: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256), - child: Center( - child: Text( - L10n.of(context).youreInvited, - textAlign: TextAlign.center, - ), - ), - ), - content: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), - child: Text( - room.isSpace - ? L10n.of( - context, - ).invitedToSpace(room.name, room.creatorId ?? "???") - : L10n.of( - context, - ).invitedToChat(room.name, room.creatorId ?? "???"), - textAlign: TextAlign.center, - ), - ), - actions: [ - AdaptiveDialogAction( - onPressed: () => - Navigator.of(context).pop(CourseInviteAction.decline), - bigButtons: true, - child: Text( - L10n.of(context).decline, - style: TextStyle(color: theme.colorScheme.error), - ), - ), - AdaptiveDialogAction( - onPressed: () => Navigator.of(context).pop(CourseInviteAction.accept), - bigButtons: true, - child: Text(L10n.of(context).accept), - ), - ], - ), - ); - switch (action) { - case null: - return; - case CourseInviteAction.accept: - break; - case CourseInviteAction.decline: - await room.leave(); - return; +class SpaceTapUtil { + static Future onTap(BuildContext context, Room space) async { + switch (space.membership) { + case Membership.join: + context.go("/rooms/spaces/${space.id}/details"); + return; + case Membership.leave: + await _autoJoin(context, space); + return; + case Membership.invite: + await _onInviteTap(context, space); + return; + case Membership.ban: + case Membership.knock: + context.go("/rooms/spaces/${space.id}/details"); + ErrorHandler.logError( + m: 'should not show space with membership ${space.membership}', + data: space.toJson(), + ); + } } - final joinResult = await showFutureLoadingDialog( - context: context, - future: () async { - await room.joinKnockedRoom(); - }, - exceptionContext: ExceptionContext.joinRoom, - ); - if (joinResult.error != null) return; + static Future _autoJoin(BuildContext context, Room space) async { + final resp = await showFutureLoadingDialog( + context: context, + future: space.joinKnockedRoom, + ); - if (room.membership != Membership.join) { - await room.client.waitForRoomInSync(room.id, join: true); - } - - context.go( - room.isSpace ? "/rooms/spaces/${room.id}/details" : "/rooms/${room.id}", - ); -} - -// ignore: curly_braces_in_flow_control_structures -void chatListHandleSpaceTap(BuildContext context, Room space) { - void setActiveSpaceAndCloseChat() { + if (resp.isError) return; context.go("/rooms/spaces/${space.id}/details"); } - void autoJoin(Room space) { - showFutureLoadingDialog( - context: context, - future: () async { - await space.joinKnockedRoom(); - setActiveSpaceAndCloseChat(); - }, - ); - } + static Future _onInviteTap(BuildContext context, Room space) async { + final justInputtedCode = SpaceCodeRepo.recentCode; + final spaceCode = space.classCode; + if (spaceCode != null && justInputtedCode == spaceCode) { + return; + } - switch (space.membership) { - case Membership.join: - setActiveSpaceAndCloseChat(); - break; - case Membership.invite: - //if space is a child of a space you're in, automatically join - //else confirm you want to join - //can we tell whether space or chat? - final rooms = Matrix.of(context).client.rooms.where( - (element) => element.isSpace && element.membership == Membership.join, - ); - final justInputtedCode = SpaceCodeRepo.recentCode; - if (rooms.any((s) => s.spaceChildren.any((c) => c.roomId == space.id))) { - autoJoin(space); - } else if (justInputtedCode != null && - justInputtedCode == space.classCode) { - // do nothing - } else if (space.hasKnocked) { - autoJoin(space); - } else { - showInviteDialog(space, context); - } - break; - case Membership.leave: - autoJoin(space); - break; - default: - setActiveSpaceAndCloseChat(); - ErrorHandler.logError( - m: 'should not show space with membership ${space.membership}', - data: space.toJson(), - ); - break; + final rooms = Matrix.of(context).client.rooms.where( + (element) => element.isSpace && element.membership == Membership.join, + ); + + final isSpaceChild = rooms.any( + (s) => s.spaceChildren.any((c) => c.roomId == space.id), + ); + + isSpaceChild || space.hasKnocked + ? await _autoJoin(context, space) + : await RoomInviteDialog.show(context, space); } } - -enum CourseInviteAction { accept, decline } diff --git a/lib/pangea/chat_list/widgets/room_invite_dialog.dart b/lib/pangea/chat_list/widgets/room_invite_dialog.dart new file mode 100644 index 000000000..46a3c01b0 --- /dev/null +++ b/lib/pangea/chat_list/widgets/room_invite_dialog.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; + +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/l10n/l10n.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/join_codes/knock_room_extension.dart'; +import 'package:fluffychat/utils/localized_exception_extension.dart'; +import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart'; +import 'package:fluffychat/widgets/future_loading_dialog.dart'; + +enum CourseInviteAction { accept, decline } + +class RoomInviteDialog extends StatelessWidget { + final Room room; + const RoomInviteDialog({super.key, required this.room}); + + static Future show(BuildContext context, Room room) async { + final resp = await showDialog( + context: context, + builder: (context) => RoomInviteDialog(room: room), + ); + + switch (resp) { + case CourseInviteAction.accept: + final joinResult = await showFutureLoadingDialog( + context: context, + future: room.joinKnockedRoom, + exceptionContext: ExceptionContext.joinRoom, + ); + + if (joinResult.isError) return; + if (room.membership != Membership.join) { + await room.client.waitForRoomInSync(room.id, join: true); + } + + context.go( + room.isSpace + ? "/rooms/spaces/${room.id}/details" + : "/rooms/${room.id}", + ); + return; + case CourseInviteAction.decline: + await room.leave(); + return; + case null: + return; + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog.adaptive( + title: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256), + child: Center( + child: Text( + L10n.of(context).youreInvited, + textAlign: TextAlign.center, + ), + ), + ), + content: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), + child: Text( + room.isSpace + ? L10n.of( + context, + ).invitedToSpace(room.name, room.creatorId ?? "???") + : L10n.of( + context, + ).invitedToChat(room.name, room.creatorId ?? "???"), + textAlign: TextAlign.center, + ), + ), + actions: [ + AdaptiveDialogAction( + onPressed: () => + Navigator.of(context).pop(CourseInviteAction.decline), + bigButtons: true, + child: Text( + L10n.of(context).decline, + style: TextStyle(color: Theme.of(context).colorScheme.error), + ), + ), + AdaptiveDialogAction( + onPressed: () => Navigator.of(context).pop(CourseInviteAction.accept), + bigButtons: true, + child: Text(L10n.of(context).accept), + ), + ], + ); + } +} diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index 4b891123b..d57c37638 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -233,11 +233,11 @@ class SpacesNavigationRail extends StatelessWidget { backgroundColor: Colors.transparent, borderRadius: BorderRadius.circular(0), // onTap: () => onGoToSpaceId(allSpaces[i].id), - onTap: () { + onTap: () async { collapse(); final room = client.getRoomById(allSpaces[i].id); if (room != null) { - chatListHandleSpaceTap(context, room); + await SpaceTapUtil.onTap(context, room); } else { context.go( "/rooms/spaces/${allSpaces[i].id}/details",