From 818078339a96bba8eaf3c4fdf4db533288230a48 Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Thu, 15 May 2025 13:39:16 -0400 Subject: [PATCH] Public sheet popup reversion (#2791) * Don't ask for space code of no-code-required space * Fix Join button gap * Reverts to previous public sheet popup design * Make join button work * Copy fixes for subchat join orange box error * revert public room dialog to fluffychat version * fix import error * Keep sheet from taking up whole screen * chore: formatting --------- Co-authored-by: ggurdin <46800240+ggurdin@users.noreply.github.com> Co-authored-by: ggurdin --- lib/pages/chat_list/chat_list_body.dart | 4 +- lib/pages/chat_list/space_view.dart | 4 +- .../public_room_bottom_sheet.dart | 393 ++++++++++++++++++ .../public_spaces/public_space_card.dart | 6 +- lib/utils/url_launcher.dart | 5 +- .../adaptive_dialogs/public_room_dialog.dart | 186 +-------- 6 files changed, 411 insertions(+), 187 deletions(-) create mode 100644 lib/pangea/public_spaces/public_room_bottom_sheet.dart diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index f6a47adf1..39e08dab3 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -12,8 +12,8 @@ import 'package:fluffychat/pages/chat_list/dummy_chat_list_item.dart'; import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pages/chat_list/space_view.dart'; import 'package:fluffychat/pangea/chat_list/widgets/pangea_chat_list_header.dart'; +import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart'; import 'package:fluffychat/utils/stream_extension.dart'; -import 'package:fluffychat/widgets/adaptive_dialogs/public_room_dialog.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/user_dialog.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/unread_rooms_badge.dart'; @@ -384,7 +384,7 @@ class PublicRoomsHorizontalListState extends State { // Pangea# avatar: publicRooms[i].avatarUrl, // #Pangea - onPressed: () => PublicRoomDialog.show( + onPressed: () => PublicRoomBottomSheet.show( context: context, roomAlias: publicRooms[i].canonicalAlias ?? publicRooms[i].roomId, diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 4471a01d8..24533cc31 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -17,12 +17,12 @@ import 'package:fluffychat/pages/chat_list/search_title.dart'; import 'package:fluffychat/pangea/chat_settings/constants/pangea_room_types.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart'; import 'package:fluffychat/pangea/spaces/constants/space_constants.dart'; import 'package:fluffychat/pangea/spaces/widgets/knocking_users_indicator.dart'; import 'package:fluffychat/pangea/spaces/widgets/space_view_leaderboard.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/utils/stream_extension.dart'; -import 'package:fluffychat/widgets/adaptive_dialogs/public_room_dialog.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; @@ -313,7 +313,7 @@ class _SpaceViewState extends State { // ?.via, // ), // ); - final joined = await PublicRoomDialog.show( + final joined = await PublicRoomBottomSheet.show( context: context, chunk: item, via: space?.spaceChildren diff --git a/lib/pangea/public_spaces/public_room_bottom_sheet.dart b/lib/pangea/public_spaces/public_room_bottom_sheet.dart new file mode 100644 index 000000000..6d0ca3ca3 --- /dev/null +++ b/lib/pangea/public_spaces/public_room_bottom_sheet.dart @@ -0,0 +1,393 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:go_router/go_router.dart'; +import 'package:material_symbols_icons/symbols.dart'; +import 'package:matrix/matrix.dart'; + +import 'package:fluffychat/pangea/common/config/environment.dart'; +import 'package:fluffychat/utils/adaptive_bottom_sheet.dart'; +import 'package:fluffychat/utils/fluffy_share.dart'; +import 'package:fluffychat/widgets/avatar.dart'; +import 'package:fluffychat/widgets/future_loading_dialog.dart'; +import 'package:fluffychat/widgets/matrix.dart'; + +class PublicRoomBottomSheet extends StatefulWidget { + final String? roomAlias; + final BuildContext outerContext; + final PublicRoomsChunk? chunk; + final List? via; + + PublicRoomBottomSheet({ + this.roomAlias, + required this.outerContext, + this.chunk, + this.via, + super.key, + }) { + assert(roomAlias != null || chunk != null); + } + + static Future show({ + required BuildContext context, + String? roomAlias, + PublicRoomsChunk? chunk, + List? via, + }) async { + final room = MatrixState.pangeaController.matrixState.client + .getRoomById(chunk!.roomId); + + if (room != null && room.membership == Membership.join) { + context.go("/rooms?spaceId=${room.id}"); + return null; + } + + return showAdaptiveBottomSheet( + context: context, + builder: (context) => PublicRoomBottomSheet( + roomAlias: roomAlias, + chunk: chunk, + via: via, + outerContext: context, + ), + ); + } + + @override + State createState() => PublicRoomBottomSheetState(); +} + +class PublicRoomBottomSheetState extends State { + BuildContext get outerContext => widget.outerContext; + PublicRoomsChunk? get chunk => widget.chunk; + String? get roomAlias => widget.roomAlias; + List? get via => widget.via; + + final TextEditingController _codeController = TextEditingController(); + late Client client; + + @override + void initState() { + super.initState(); + client = Matrix.of(outerContext).client; + } + + @override + void dispose() { + _codeController.dispose(); + super.dispose(); + } + + Room? get room => client.getRoomById(chunk!.roomId); + bool get _isRoomMember => room != null && room!.membership == Membership.join; + bool get _isKnockRoom => widget.chunk?.joinRule == 'knock'; + + Future _joinWithCode() async { + final resp = + await MatrixState.pangeaController.classController.joinClasswithCode( + context, + _codeController.text, + notFoundError: L10n.of(context).notTheCodeError, + ); + if (!resp.isError) { + Navigator.of(context).pop(true); + } + } + + void _goToRoom(String roomID) { + if (chunk?.roomType != 'm.space' && !client.getRoomById(roomID)!.isSpace) { + outerContext.go("/rooms/$roomID"); + } else { + context.go('/rooms?spaceId=$roomID'); + } + } + + Future _joinRoom() async { + if (_isRoomMember) { + _goToRoom(room!.id); + Navigator.of(context).pop(); + return; + } + + final result = await showFutureLoadingDialog( + context: context, + future: () async { + final roomId = await client.joinRoom( + roomAlias ?? chunk!.roomId, + serverName: via, + ); + + final room = client.getRoomById(roomId); + if (room == null || room.membership != Membership.join) { + await client.waitForRoomInSync(roomId, join: true); + } + return roomId; + }, + ); + + if (result.result != null) { + _goToRoom(result.result!); + Navigator.of(context).pop(true); + } + } + + Future _knockRoom() async { + if (_isRoomMember) { + _goToRoom(room!.id); + Navigator.of(context).pop(); + return; + } + + await showFutureLoadingDialog( + context: context, + future: () async => client.knockRoom( + roomAlias ?? chunk!.roomId, + serverName: via, + ), + onSuccess: () => L10n.of(context).knockSpaceSuccess, + delay: false, + ); + } + + bool testRoom(PublicRoomsChunk r) => r.canonicalAlias == roomAlias; + + Future search() async { + final chunk = this.chunk; + if (chunk != null) return chunk; + final query = await Matrix.of(outerContext).client.queryPublicRooms( + server: roomAlias!.domain, + filter: PublicRoomQueryFilter( + genericSearchTerm: roomAlias, + ), + ); + if (!query.chunk.any(testRoom)) { + throw (L10n.of(outerContext).noRoomsFound); + } + return query.chunk.firstWhere(testRoom); + } + + @override + Widget build(BuildContext context) { + final roomAlias = this.roomAlias ?? chunk?.canonicalAlias; + return SafeArea( + child: Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + title: Text( + chunk?.name ?? roomAlias ?? chunk?.roomId ?? 'Unknown', + overflow: TextOverflow.fade, + ), + actions: [ + Center( + child: CloseButton( + onPressed: Navigator.of(context, rootNavigator: false).pop, + ), + ), + ], + ), + body: FutureBuilder( + future: search(), + builder: (context, snapshot) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + spacing: 32.0, + children: [ + Row( + spacing: 16.0, + children: [ + Avatar( + mxContent: chunk?.avatarUrl, + name: chunk?.name, + size: 160.0, + borderRadius: BorderRadius.circular(24.0), + ), + Expanded( + child: SizedBox( + height: 160.0, + child: Column( + spacing: 16.0, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + spacing: 8.0, + children: [ + const Icon(Icons.group), + Text( + L10n.of(context).countParticipants( + chunk?.numJoinedMembers ?? 1, + ), + ), + ], + ), + if (chunk?.topic != null) + Flexible( + child: SingleChildScrollView( + child: Text( + chunk!.topic!, + softWrap: true, + maxLines: null, + ), + ), + ), + ], + ), + ), + ), + ], + ), + Column( + spacing: 8.0, + children: _isKnockRoom + ? [ + Container( + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.outline, + ), + borderRadius: BorderRadius.circular(24), + ), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _codeController, + decoration: InputDecoration( + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + disabledBorder: InputBorder.none, + hintText: + L10n.of(context).enterSpaceCode, + contentPadding: + const EdgeInsets.symmetric( + horizontal: 16.0, + ), + hintStyle: TextStyle( + color: Theme.of(context).hintColor, + ), + ), + ), + ), + Container( + decoration: BoxDecoration( + border: Border( + left: BorderSide( + color: Theme.of(context) + .colorScheme + .outline, + ), + ), + ), + child: ElevatedButton( + onPressed: _joinWithCode, + style: ElevatedButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.zero, + bottomLeft: Radius.zero, + topRight: Radius.circular(24), + bottomRight: Radius.circular(24), + ), + ), + ), + child: Text(L10n.of(context).join), + ), + ), + ], + ), + ), + ElevatedButton( + onPressed: _knockRoom, + child: Row( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Symbols.door_open, + size: 20.0, + ), + Text(L10n.of(context).askToJoin), + ], + ), + ), + if (roomAlias != null) + ElevatedButton( + onPressed: () { + FluffyShare.share( + "${Environment.frontendURL}/#/join_with_alias?alias=${Uri.encodeComponent(roomAlias)}", + context, + ); + Navigator.of(context).pop(); + }, + child: Row( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.share_outlined, + size: 20.0, + ), + Flexible( + child: Text( + L10n.of(context).shareSpaceLink, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ] + : [ + ElevatedButton( + onPressed: _joinRoom, + child: Row( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.join_full_outlined, + size: 20.0, + ), + Text(L10n.of(context).join), + ], + ), + ), + if (roomAlias != null) + ElevatedButton( + onPressed: () { + FluffyShare.share( + "${Environment.frontendURL}/#/join_with_alias?alias=${Uri.encodeComponent(roomAlias)}", + context, + ); + Navigator.of(context).pop(); + }, + child: Row( + spacing: 8.0, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.share_outlined, + size: 20.0, + ), + Flexible( + child: Text( + L10n.of(context).shareSpaceLink, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ], + ), + ], + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pangea/public_spaces/public_space_card.dart b/lib/pangea/public_spaces/public_space_card.dart index 47c55961c..a4873e65d 100644 --- a/lib/pangea/public_spaces/public_space_card.dart +++ b/lib/pangea/public_spaces/public_space_card.dart @@ -4,7 +4,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/pangea/common/widgets/pressable_button.dart'; -import 'package:fluffychat/widgets/adaptive_dialogs/public_room_dialog.dart'; +import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart'; import 'package:fluffychat/widgets/mxc_image.dart'; class PublicSpaceCard extends StatelessWidget { @@ -24,10 +24,10 @@ class PublicSpaceCard extends StatelessWidget { final theme = Theme.of(context); return PressableButton( - onPressed: () => PublicRoomDialog.show( - context: context, + onPressed: () => PublicRoomBottomSheet.show( roomAlias: space.canonicalAlias ?? space.roomId, chunk: space, + context: context, ), borderRadius: BorderRadius.circular(24.0), color: theme.brightness == Brightness.dark diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index 615b6d505..5dff82be7 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -8,11 +8,11 @@ import 'package:punycode/punycode.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/public_spaces/public_room_bottom_sheet.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/user_dialog.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; -import '../widgets/adaptive_dialogs/public_room_dialog.dart'; import 'platform_infos.dart'; class UrlLauncher { @@ -188,9 +188,10 @@ class UrlLauncher { // roomAlias: identityParts.primaryIdentifier, // ), // ); - await PublicRoomDialog.show( + await PublicRoomBottomSheet.show( context: context, roomAlias: identityParts.primaryIdentifier, + // Pangea# ); // Pangea# } diff --git a/lib/widgets/adaptive_dialogs/public_room_dialog.dart b/lib/widgets/adaptive_dialogs/public_room_dialog.dart index 5d1fc64b0..4f0070ffd 100644 --- a/lib/widgets/adaptive_dialogs/public_room_dialog.dart +++ b/lib/widgets/adaptive_dialogs/public_room_dialog.dart @@ -6,7 +6,6 @@ import 'package:flutter_linkify/flutter_linkify.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart'; import '../../config/themes.dart'; import '../../utils/url_launcher.dart'; @@ -17,58 +16,12 @@ import '../matrix.dart'; import '../mxc_image_viewer.dart'; import 'adaptive_dialog_action.dart'; -// #Pangea -// class PublicRoomDialog extends StatelessWidget { -class PublicRoomDialog extends StatefulWidget { - // Pangea# +class PublicRoomDialog extends StatelessWidget { final String? roomAlias; final PublicRoomsChunk? chunk; final List? via; const PublicRoomDialog({super.key, this.roomAlias, this.chunk, this.via}); - // #Pangea - static Future show({ - required BuildContext context, - String? roomAlias, - PublicRoomsChunk? chunk, - List? via, - }) async { - final room = MatrixState.pangeaController.matrixState.client - .getRoomById(chunk!.roomId); - - if (room != null && room.membership == Membership.join) { - context.go("/rooms?spaceId=${room.id}"); - return null; - } - - return showAdaptiveDialog( - context: context, - barrierDismissible: true, - builder: (context) => PublicRoomDialog( - roomAlias: roomAlias, - chunk: chunk, - via: via, - ), - ); - } - - @override - State createState() => PublicRoomDialogState(); -} - -class PublicRoomDialogState extends State { - PublicRoomsChunk? get chunk => widget.chunk; - String? get roomAlias => widget.roomAlias; - List? get via => widget.via; - - final TextEditingController _codeController = TextEditingController(); - - @override - void dispose() { - _codeController.dispose(); - super.dispose(); - } - // Pangea# void _joinRoom(BuildContext context) async { final client = Matrix.of(context).client; @@ -87,16 +40,9 @@ class PublicRoomDialogState extends State { via: via, ); - // #Pangea - // if (!knock && client.getRoomById(roomId) == null) { - // await client.waitForRoomInSync(roomId); - // } - final room = client.getRoomById(roomId); - if (!knock && (room == null || room.membership != Membership.join)) { - await client.waitForRoomInSync(roomId, join: true); + if (!knock && client.getRoomById(roomId) == null) { + await client.waitForRoomInSync(roomId); } - // Pangea# - return roomId; }, ); @@ -119,11 +65,6 @@ class PublicRoomDialogState extends State { !client.getRoomById(result.result!)!.isSpace) { context.go('/rooms/$roomId'); } - // #Pangea - else { - context.go('/rooms?spaceId=$roomId'); - } - // Pangea# return; } @@ -144,31 +85,10 @@ class PublicRoomDialogState extends State { return query.chunk.firstWhere(_testRoom); } - // #Pangea - Future _joinWithCode() async { - final resp = - await MatrixState.pangeaController.classController.joinClasswithCode( - context, - _codeController.text, - notFoundError: L10n.of(context).notTheCodeError, - ); - if (!resp.isError) { - Navigator.of(context).pop(true); - } - } - // Pangea# - @override Widget build(BuildContext context) { final roomAlias = this.roomAlias ?? chunk?.canonicalAlias; - // #Pangea - // final roomLink = roomAlias ?? chunk?.roomId; - String? roomLink = roomAlias ?? chunk?.roomId; - if (roomLink != null) { - roomLink = - "${Environment.frontendURL}/#/join_with_alias?alias=${Uri.encodeComponent(roomLink)}"; - } - // Pangea# + final roomLink = roomAlias ?? chunk?.roomId; var copied = false; return AlertDialog.adaptive( title: ConstrainedBox( @@ -179,13 +99,7 @@ class PublicRoomDialogState extends State { ), ), content: ConstrainedBox( - // #Pangea - // constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), - constraints: const BoxConstraints( - maxWidth: 256, - maxHeight: 300, - ), - // Pangea# + constraints: const BoxConstraints(maxWidth: 256, maxHeight: 256), child: FutureBuilder( future: _search(context), builder: (context, snapshot) { @@ -208,10 +122,7 @@ class PublicRoomDialogState extends State { child: GestureDetector( onTap: () { Clipboard.setData( - // #Pangea - // ClipboardData(text: roomLink), - ClipboardData(text: roomLink!), - // Pangea# + ClipboardData(text: roomLink), ); setState(() { copied = true; @@ -243,12 +154,7 @@ class PublicRoomDialogState extends State { ), ), ), - // #Pangea - // TextSpan(text: roomLink), - TextSpan( - text: L10n.of(context).shareSpaceLink, - ), - // Pangea# + TextSpan(text: roomLink), ], style: theme.textTheme.bodyMedium ?.copyWith(fontSize: 10), @@ -280,79 +186,6 @@ class PublicRoomDialogState extends State { style: const TextStyle(fontSize: 10), textAlign: TextAlign.center, ), - // #Pangea - Material( - type: MaterialType.transparency, - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context).colorScheme.outline, - ), - borderRadius: BorderRadius.circular(24), - ), - child: Row( - children: [ - Expanded( - child: TextField( - style: const TextStyle( - fontSize: 12, - ), - controller: _codeController, - decoration: InputDecoration( - border: InputBorder.none, - focusedBorder: InputBorder.none, - enabledBorder: InputBorder.none, - errorBorder: InputBorder.none, - disabledBorder: InputBorder.none, - hintText: L10n.of(context).enterSpaceCode, - contentPadding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), - labelStyle: const TextStyle( - fontSize: 12, - ), - hintStyle: TextStyle( - color: Theme.of(context).hintColor, - fontSize: 12, - ), - isDense: true, - ), - ), - ), - Container( - decoration: BoxDecoration( - border: Border( - left: BorderSide( - color: Theme.of(context).colorScheme.outline, - ), - ), - ), - child: ElevatedButton( - onPressed: _joinWithCode, - style: ElevatedButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.zero, - bottomLeft: Radius.zero, - topRight: Radius.circular(24), - bottomRight: Radius.circular(24), - ), - ), - padding: EdgeInsets.zero, - ), - child: Text( - L10n.of(context).join, - style: const TextStyle( - fontSize: 12, - ), - ), - ), - ), - ], - ), - ), - ), - // Pangea# if (topic != null && topic.isNotEmpty) SelectableLinkify( text: topic, @@ -381,10 +214,7 @@ class PublicRoomDialogState extends State { child: Text( chunk?.joinRule == 'knock' && Matrix.of(context).client.getRoomById(chunk!.roomId) == null - // #Pangea - // ? L10n.of(context).knock - ? L10n.of(context).askToJoin - // Pangea# + ? L10n.of(context).knock : chunk?.roomType == 'm.space' ? L10n.of(context).joinSpace : L10n.of(context).joinRoom,