diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index 92a55da9..96cedb52 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -1,10 +1,10 @@ import 'dart:async'; +import 'package:fluffychat/widgets/public_room_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; import 'package:vrouter/vrouter.dart'; @@ -38,45 +38,15 @@ class SearchController extends State { ); } - Future _joinRoomAndWait( - BuildContext context, - String roomId, - String alias, - ) async { - if (Matrix.of(context).client.getRoomById(roomId) != null) { - return roomId; - } - final newRoomId = await Matrix.of(context) - .client - .joinRoom(alias?.isNotEmpty ?? false ? alias : roomId); - await Matrix.of(context).client.onSync.stream.firstWhere( - (update) => update.rooms?.join?.containsKey(newRoomId) ?? false); - return newRoomId; - } - - void joinGroupAction(PublicRoomsChunk room) async { - if (await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - okLabel: L10n.of(context).joinRoom, - title: '${room.name} (${room.numJoinedMembers ?? 0})', - message: room.topic ?? L10n.of(context).noDescription, - cancelLabel: L10n.of(context).cancel, - ) == - OkCancelResult.cancel) { - return; - } - final success = await showFutureLoadingDialog( + void joinGroupAction(PublicRoomsChunk room) { + showModalBottomSheet( context: context, - future: () => _joinRoomAndWait( - context, - room.roomId, - room.canonicalAlias ?? room.aliases?.first, + builder: (c) => PublicRoomBottomSheet( + roomAlias: room.canonicalAlias, + outerContext: context, + chunk: room, ), ); - if (success.error == null) { - VRouter.of(context).toSegments(['rooms', success.result]); - } } String server; diff --git a/lib/utils/localized_exception_extension.dart b/lib/utils/localized_exception_extension.dart index ac767611..52d194ca 100644 --- a/lib/utils/localized_exception_extension.dart +++ b/lib/utils/localized_exception_extension.dart @@ -50,6 +50,7 @@ extension LocalizedExceptionExtension on Object { if (this is MatrixConnectionException || this is SocketException) { return L10n.of(context).noConnectionToTheServer; } + if (this is String) return toString(); if (this is UiaException) return toString(); Logs().w('Something went wrong: ', this); return L10n.of(context).oopsSomethingWentWrong; diff --git a/lib/utils/url_launcher.dart b/lib/utils/url_launcher.dart index 65b22f4c..6b54096c 100644 --- a/lib/utils/url_launcher.dart +++ b/lib/utils/url_launcher.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/widgets/public_room_bottom_sheet.dart'; import 'package:flutter/material.dart'; import 'package:adaptive_dialog/adaptive_dialog.dart'; @@ -162,9 +163,13 @@ class UrlLauncher { } } } else { - VRouter.of(context).to('/search', queryParameters: { - if (roomIdOrAlias != null) 'query': roomIdOrAlias - }); + await showModalBottomSheet( + context: context, + builder: (c) => PublicRoomBottomSheet( + roomAlias: identityParts.primaryIdentifier, + outerContext: context, + ), + ); } } else if (identityParts.primaryIdentifier.sigil == '@') { await showModalBottomSheet( diff --git a/lib/widgets/public_room_bottom_sheet.dart b/lib/widgets/public_room_bottom_sheet.dart new file mode 100644 index 00000000..38ca8235 --- /dev/null +++ b/lib/widgets/public_room_bottom_sheet.dart @@ -0,0 +1,138 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:flutter_matrix_html/flutter_html.dart'; +import 'package:future_loading_dialog/future_loading_dialog.dart'; +import 'package:matrix/matrix.dart'; +import 'package:vrouter/vrouter.dart'; + +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/widgets/content_banner.dart'; +import 'package:fluffychat/widgets/matrix.dart'; +import '../utils/localized_exception_extension.dart'; + +class PublicRoomBottomSheet extends StatelessWidget { + final String roomAlias; + final BuildContext outerContext; + final PublicRoomsChunk chunk; + const PublicRoomBottomSheet({ + @required this.roomAlias, + @required this.outerContext, + this.chunk, + Key key, + }) : super(key: key); + + void _joinRoom(BuildContext context) async { + final client = Matrix.of(context).client; + final result = await showFutureLoadingDialog( + context: context, + future: () => client.joinRoom(roomAlias), + ); + if (result.error == null) { + if (client.getRoomById(result.result) == null) { + await client.onSync.stream.firstWhere( + (sync) => sync.rooms?.join?.containsKey(result.result) ?? false); + } + VRouter.of(context).toSegments(['rooms', result.result]); + Navigator.of(context, rootNavigator: false).pop(); + return; + } + } + + bool _testRoom(PublicRoomsChunk r) => + r.canonicalAlias == roomAlias || + (r.aliases?.contains(roomAlias) ?? false); + + Future _search(BuildContext context) async { + if (chunk != null) return chunk; + final query = await Matrix.of(context).client.queryPublicRooms( + server: roomAlias.domain, + filter: PublicRoomQueryFilter( + genericSearchTerm: roomAlias, + ), + ); + if (!query.chunk.any(_testRoom) ?? true) { + throw (L10n.of(context).noRoomsFound); + } + return query.chunk.firstWhere(_testRoom); + } + + @override + Widget build(BuildContext context) { + final roomAlias = + this.roomAlias ?? chunk.canonicalAlias ?? chunk.aliases?.first ?? ''; + return Center( + child: SizedBox( + width: min( + MediaQuery.of(context).size.width, FluffyThemes.columnWidth * 1.5), + child: Material( + elevation: 4, + child: SafeArea( + child: Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + elevation: 0, + backgroundColor: + Theme.of(context).scaffoldBackgroundColor.withOpacity(0.5), + title: Text(roomAlias), + leading: IconButton( + icon: const Icon(Icons.arrow_downward_outlined), + onPressed: Navigator.of(context, rootNavigator: false).pop, + tooltip: L10n.of(context).close, + ), + ), + body: FutureBuilder( + future: _search(context), + builder: (context, snapshot) { + final profile = snapshot.data; + return Column( + children: [ + Expanded( + child: profile == null + ? Container( + alignment: Alignment.center, + color: Theme.of(context).secondaryHeaderColor, + child: snapshot.hasError + ? Text(snapshot.error + .toLocalizedString(context)) + : const CircularProgressIndicator + .adaptive(strokeWidth: 2), + ) + : ContentBanner( + profile.avatarUrl, + defaultIcon: Icons.person_outline, + client: Matrix.of(context).client, + ), + ), + ListTile( + title: Text(profile?.name ?? roomAlias.localpart), + subtitle: Text( + '${L10n.of(context).participant}: ${profile?.numJoinedMembers ?? 0}'), + trailing: const Icon(Icons.account_box_outlined), + ), + if (profile?.topic != null && profile.topic.isNotEmpty) + ListTile( + subtitle: Html(data: profile.topic), + ), + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + child: ElevatedButton.icon( + onPressed: () => _joinRoom(context), + label: Text(L10n.of(context).joinRoom), + icon: const Icon(Icons.login_outlined), + ), + ), + const SizedBox(height: 8), + ], + ); + }), + ), + ), + ), + ), + ); + } +}