From 715e615e3a6945b58b8bb43387c59ef1a227bdf3 Mon Sep 17 00:00:00 2001 From: krille-chan Date: Sat, 23 Dec 2023 12:14:51 +0100 Subject: [PATCH] feat: Search for public spaces --- assets/l10n/intl_en.arb | 5 +- lib/pages/chat_details/chat_details_view.dart | 6 +- lib/pages/chat_list/chat_list_body.dart | 86 ++++++++++++------- .../user_bottom_sheet_view.dart | 5 +- lib/widgets/public_room_bottom_sheet.dart | 67 ++++++++++----- 5 files changed, 110 insertions(+), 59 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 34b6b093..bf238306 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2385,5 +2385,8 @@ "newPassword": "New password", "pleaseChooseAStrongPassword": "Please choose a strong password", "passwordsDoNotMatch": "Passwords do not match", - "passwordIsWrong": "Your entered password is wrong" + "passwordIsWrong": "Your entered password is wrong", + "publicLink": "Public link", + "joinSpace": "Join space", + "publicSpaces": "Public spaces" } \ No newline at end of file diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 1dc92366..f7de39ce 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -235,8 +235,10 @@ class ChatDetailsView extends StatelessWidget { ? L10n.of(context)!.noChatDescriptionYet : room.topic, options: const LinkifyOptions(humanize: false), - linkStyle: - const TextStyle(color: Colors.blueAccent), + linkStyle: const TextStyle( + color: Colors.blueAccent, + decorationColor: Colors.blueAccent, + ), style: TextStyle( fontSize: 14, fontStyle: room.topic.isEmpty diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index 211542f4..82034a78 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -28,7 +28,12 @@ class ChatListViewBody extends StatelessWidget { @override Widget build(BuildContext context) { - final roomSearchResult = controller.roomSearchResult; + final publicRooms = controller.roomSearchResult?.chunk + .where((room) => room.roomType != 'm.space') + .toList(); + final publicSpaces = controller.roomSearchResult?.chunk + .where((room) => room.roomType == 'm.space') + .toList(); final userSearchResult = controller.userSearchResult; final client = Matrix.of(context).client; const dummyChatCount = 4; @@ -83,39 +88,12 @@ class ChatListViewBody extends StatelessWidget { title: L10n.of(context)!.publicRooms, icon: const Icon(Icons.explore_outlined), ), - AnimatedContainer( - clipBehavior: Clip.hardEdge, - decoration: const BoxDecoration(), - height: roomSearchResult == null || - roomSearchResult.chunk.isEmpty - ? 0 - : 106, - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - child: roomSearchResult == null - ? null - : ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: roomSearchResult.chunk.length, - itemBuilder: (context, i) => _SearchItem( - title: roomSearchResult.chunk[i].name ?? - roomSearchResult.chunk[i].canonicalAlias - ?.localpart ?? - L10n.of(context)!.group, - avatar: roomSearchResult.chunk[i].avatarUrl, - onPressed: () => showAdaptiveBottomSheet( - context: context, - builder: (c) => PublicRoomBottomSheet( - roomAlias: roomSearchResult - .chunk[i].canonicalAlias ?? - roomSearchResult.chunk[i].roomId, - outerContext: context, - chunk: roomSearchResult.chunk[i], - ), - ), - ), - ), + PublicRoomsHorizontalList(publicRooms: publicRooms), + SearchTitle( + title: L10n.of(context)!.publicSpaces, + icon: const Icon(Icons.workspaces_outlined), ), + PublicRoomsHorizontalList(publicRooms: publicSpaces), SearchTitle( title: L10n.of(context)!.users, icon: const Icon(Icons.group_outlined), @@ -294,6 +272,48 @@ class ChatListViewBody extends StatelessWidget { } } +class PublicRoomsHorizontalList extends StatelessWidget { + const PublicRoomsHorizontalList({ + super.key, + required this.publicRooms, + }); + + final List? publicRooms; + + @override + Widget build(BuildContext context) { + final publicRooms = this.publicRooms; + return AnimatedContainer( + clipBehavior: Clip.hardEdge, + decoration: const BoxDecoration(), + height: publicRooms == null || publicRooms.isEmpty ? 0 : 106, + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + child: publicRooms == null + ? null + : ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: publicRooms.length, + itemBuilder: (context, i) => _SearchItem( + title: publicRooms[i].name ?? + publicRooms[i].canonicalAlias?.localpart ?? + L10n.of(context)!.group, + avatar: publicRooms[i].avatarUrl, + onPressed: () => showAdaptiveBottomSheet( + context: context, + builder: (c) => PublicRoomBottomSheet( + roomAlias: + publicRooms[i].canonicalAlias ?? publicRooms[i].roomId, + outerContext: context, + chunk: publicRooms[i], + ), + ), + ), + ), + ); + } +} + class _SearchItem extends StatelessWidget { final String title; final Uri? avatar; diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart index 56d1b00f..93774a8c 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart @@ -211,7 +211,10 @@ class UserBottomSheetView extends StatelessWidget { text: status, style: const TextStyle(fontSize: 16), options: const LinkifyOptions(humanize: false), - linkStyle: const TextStyle(color: Colors.blueAccent), + linkStyle: const TextStyle( + color: Colors.blueAccent, + decorationColor: Colors.blueAccent, + ), onOpen: (url) => UrlLauncher(context, url.url).launchUrl(), ), ); diff --git a/lib/widgets/public_room_bottom_sheet.dart b/lib/widgets/public_room_bottom_sheet.dart index ddb22f56..baf59a03 100644 --- a/lib/widgets/public_room_bottom_sheet.dart +++ b/lib/widgets/public_room_bottom_sheet.dart @@ -6,6 +6,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; +import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/url_launcher.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -41,9 +42,7 @@ class PublicRoomBottomSheet extends StatelessWidget { : await client.joinRoom(roomAlias ?? chunk!.roomId); if (client.getRoomById(roomId) == null) { - await client.onSync.stream.firstWhere( - (sync) => sync.rooms?.join?.containsKey(roomId) ?? false, - ); + await client.waitForRoomInSync(roomId); } return roomId; }, @@ -51,7 +50,8 @@ class PublicRoomBottomSheet extends StatelessWidget { if (result.error == null) { Navigator.of(context).pop(); // don't open the room if the joined room is a space - if (!client.getRoomById(result.result!)!.isSpace) { + if (chunk?.roomType != 'm.space' && + !client.getRoomById(result.result!)!.isSpace) { outerContext.go('/rooms/${result.result!}'); } return; @@ -77,12 +77,12 @@ class PublicRoomBottomSheet extends StatelessWidget { @override Widget build(BuildContext context) { - final roomAlias = this.roomAlias; + final roomAlias = this.roomAlias ?? chunk?.canonicalAlias; return SafeArea( child: Scaffold( appBar: AppBar( title: Text( - roomAlias ?? chunk!.name ?? chunk!.roomId, + chunk!.name ?? roomAlias ?? chunk!.roomId, overflow: TextOverflow.fade, ), leading: IconButton( @@ -92,11 +92,13 @@ class PublicRoomBottomSheet extends StatelessWidget { ), actions: [ Padding( - padding: const EdgeInsets.all(8.0), - child: OutlinedButton.icon( - onPressed: () => _joinRoom(context), - label: Text(L10n.of(context)!.joinRoom), - icon: const Icon(Icons.login_outlined), + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: IconButton( + icon: Icon(Icons.adaptive.share_outlined), + onPressed: () => FluffyShare.share( + 'https://matrix.to/#/${roomAlias ?? chunk?.roomId}', + context, + ), ), ), ], @@ -131,29 +133,50 @@ class PublicRoomBottomSheet extends StatelessWidget { ), ), ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: ElevatedButton.icon( + onPressed: () => _joinRoom(context), + label: Text( + chunk?.roomType == 'm.space' + ? L10n.of(context)!.joinSpace + : L10n.of(context)!.joinRoom, + ), + icon: const Icon(Icons.login_outlined), + ), + ), + const SizedBox(height: 16), ListTile( title: Text( - profile?.name ?? - roomAlias?.localpart ?? - chunk!.roomId.localpart ?? - '', + profile?.name ?? chunk!.roomId.localpart ?? '', ), subtitle: Text( '${L10n.of(context)!.participant}: ${profile?.numJoinedMembers ?? 0}', ), trailing: const Icon(Icons.account_box_outlined), ), - if (profile?.topic?.isNotEmpty ?? false) + if (roomAlias != null) ListTile( - title: Text( - L10n.of(context)!.chatDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, + title: Text(L10n.of(context)!.publicLink), + subtitle: SelectableText(roomAlias), + contentPadding: + const EdgeInsets.symmetric(horizontal: 16.0), + trailing: IconButton( + icon: const Icon(Icons.copy_outlined), + onPressed: () => FluffyShare.share( + roomAlias, + context, ), ), - subtitle: Linkify( + ), + if (profile?.topic?.isNotEmpty ?? false) + ListTile( + subtitle: SelectableLinkify( text: profile!.topic!, - linkStyle: const TextStyle(color: Colors.blueAccent), + linkStyle: const TextStyle( + color: Colors.blueAccent, + decorationColor: Colors.blueAccent, + ), style: TextStyle( fontSize: 14, color: Theme.of(context).textTheme.bodyMedium!.color,