From e69f04f6e7f0e5f63f826999df93ee8533f9eee0 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 26 May 2026 15:31:37 -0400 Subject: [PATCH] Add room details dialog Fixes #20 --- .vscode/settings.json | 1 + assets/reactions.png | Bin 13144 -> 0 bytes lib/widgets/appbar.dart | 9 ++- lib/widgets/composer/composer.dart | 4 +- lib/widgets/linkified_text.dart | 23 ++++++++ lib/widgets/renderers/event.dart | 21 +------ lib/widgets/room_appbar.dart | 88 ++++++++++++++++++++++------- 7 files changed, 105 insertions(+), 41 deletions(-) delete mode 100644 assets/reactions.png create mode 100644 lib/widgets/linkified_text.dart diff --git a/.vscode/settings.json b/.vscode/settings.json index a0d46c9..068916b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "fluttertagger", "Gomuks", "Homeserver", + "Linkified", "localpart", "msgtype", "muks", diff --git a/assets/reactions.png b/assets/reactions.png deleted file mode 100644 index c413051e9398b704519a75b95a126b2a50350e78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13144 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 diff --git a/lib/widgets/appbar.dart b/lib/widgets/appbar.dart index aae6c13..08c717b 100644 --- a/lib/widgets/appbar.dart +++ b/lib/widgets/appbar.dart @@ -9,10 +9,12 @@ class Appbar extends StatelessWidget implements PreferredSizeWidget { final Color? backgroundColor; final double? scrolledUnderElevation; final IList actions; + final VoidCallback? onTap; const Appbar({ super.key, this.title, + this.onTap, this.backgroundColor, this.scrolledUnderElevation, this.leading, @@ -37,11 +39,14 @@ class Appbar extends StatelessWidget implements PreferredSizeWidget { return GestureDetector( onPanStart: (_) => windowManager.startDragging(), child: AppBar( - leading: leading, + leading: InkWell(onTap: onTap, child: leading), backgroundColor: backgroundColor, scrolledUnderElevation: scrolledUnderElevation, actionsPadding: const EdgeInsets.symmetric(horizontal: 8), - title: IgnorePointer(child: title), + title: InkWell( + onTap: onTap, + child: IgnorePointer(child: title), + ), flexibleSpace: GestureDetector(onDoubleTap: maximize), actions: [ ...actions, diff --git a/lib/widgets/composer/composer.dart b/lib/widgets/composer/composer.dart index e5f7319..9f37999 100644 --- a/lib/widgets/composer/composer.dart +++ b/lib/widgets/composer/composer.dart @@ -140,7 +140,7 @@ class Composer extends HookConsumerWidget { query.value = newQuery; }, triggerCharacterAndStyles: {"@": style, "#": style}, - builder: (context, key) => TextFormField( + builder: (context, key) => TextField( maxLines: 12, minLines: 1, autofocus: true, @@ -150,7 +150,7 @@ class Composer extends HookConsumerWidget { ), controller: controller.value, key: key, - onFieldSubmitted: (_) => send(), + onSubmitted: (_) => send(), // Don't defocus on submit onEditingComplete: () {}, textInputAction: TextInputAction.done, diff --git a/lib/widgets/linkified_text.dart b/lib/widgets/linkified_text.dart new file mode 100644 index 0000000..c6f1c11 --- /dev/null +++ b/lib/widgets/linkified_text.dart @@ -0,0 +1,23 @@ +import "package:flutter/material.dart"; +import "package:flutter_linkify/flutter_linkify.dart"; +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:nexus/helpers/launch_helper.dart"; + +class LinkifiedText extends ConsumerWidget { + final String text; + final int? maxLines; + final TextStyle? style; + const LinkifiedText(this.text, {this.maxLines, this.style, super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) => Linkify( + text: text, + maxLines: maxLines, + style: style, + options: LinkifyOptions(humanize: false), + onOpen: (link) => + ref.watch(LaunchHelper.provider).launchUrl(Uri.parse(link.url)), + linkStyle: TextStyle(color: Theme.of(context).colorScheme.primary), + overflow: maxLines == null ? null : TextOverflow.ellipsis, + ); +} diff --git a/lib/widgets/renderers/event.dart b/lib/widgets/renderers/event.dart index 2302156..1ee7806 100644 --- a/lib/widgets/renderers/event.dart +++ b/lib/widgets/renderers/event.dart @@ -11,7 +11,6 @@ import "package:nexus/controllers/event_controller.dart"; import "package:nexus/helpers/extensions/get_headers.dart"; import "package:nexus/helpers/extensions/mxc_to_https.dart"; import "package:nexus/helpers/extensions/show_context_menu.dart"; -import "package:nexus/helpers/launch_helper.dart"; import "package:nexus/models/content/avatar.dart"; import "package:nexus/models/content/content.dart"; import "package:nexus/models/content/encrypted.dart"; @@ -24,6 +23,7 @@ import "package:nexus/widgets/expandable_image.dart"; import "package:nexus/widgets/html/html.dart"; import "package:nexus/widgets/lazy_loading/message_avatar.dart"; import "package:nexus/widgets/lazy_loading/message_displayname.dart"; +import "package:nexus/widgets/linkified_text.dart"; import "package:nexus/widgets/url_preview.dart"; import "package:nexus/widgets/loading.dart"; import "package:nexus/widgets/players/video.dart"; @@ -33,7 +33,6 @@ import "package:nexus/widgets/renderers/membership.dart"; import "package:nexus/widgets/renderers/generic_event.dart"; import "package:nexus/widgets/file_card.dart"; import "package:timeago/timeago.dart"; -import "package:flutter_linkify/flutter_linkify.dart"; class EventRenderer extends ConsumerWidget { final Event event; @@ -232,24 +231,10 @@ class EventRenderer extends ConsumerWidget { }, ), ) - : Linkify( + : LinkifiedText( + body, style: textStyle, - text: body, maxLines: maxLines, - overflow: maxLines == null - ? null - : TextOverflow.ellipsis, - options: LinkifyOptions( - humanize: false, - ), - onOpen: (link) => ref - .watch(LaunchHelper.provider) - .launchUrl(Uri.parse(link.url)), - linkStyle: TextStyle( - color: Theme.of( - context, - ).colorScheme.primary, - ), ), if (!textOnly) ...[ diff --git a/lib/widgets/room_appbar.dart b/lib/widgets/room_appbar.dart index a77e101..02ba69d 100644 --- a/lib/widgets/room_appbar.dart +++ b/lib/widgets/room_appbar.dart @@ -1,12 +1,13 @@ import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter/material.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; -import "package:nexus/controllers/client_state_controller.dart"; import "package:nexus/controllers/rooms_controller.dart"; import "package:nexus/helpers/extensions/mxc_to_https.dart"; import "package:nexus/widgets/appbar.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/expandable_image.dart"; +import "package:nexus/controllers/client_state_controller.dart"; +import "package:nexus/widgets/linkified_text.dart"; import "package:nexus/widgets/room_menu.dart"; class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget { @@ -30,27 +31,75 @@ class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget { final room = roomId == null ? null : ref.watch(RoomsController.provider.select((value) => value[roomId!])); + return Appbar( - leading: isDesktop - ? room == null - ? null - : ExpandableImage( - room.metadata?.avatar - ?.mxcToHttps( - ref.watch( - ClientStateController.provider.select( - (value) => value!.homeserverUrl!, + onTap: room == null + ? null + : () => showDialog( + context: context, + builder: (context) => Dialog( + constraints: BoxConstraints.loose(Size.fromWidth(400)), + child: Padding( + padding: EdgeInsetsGeometry.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, + children: [ + Row( + spacing: 12, + mainAxisSize: MainAxisSize.min, + children: [ + if (room.metadata?.avatar != null) + ExpandableImage( + room.metadata!.avatar! + .mxcToHttps( + ref.watch( + ClientStateController.provider.select( + (value) => value!.homeserverUrl!, + ), + ), + ) + .toString(), + child: AvatarOrHash( + room.metadata?.avatar, + room.metadata?.name ?? "Unnamed Room", + height: 64, + fallback: Icon(Icons.numbers), + ), + ), + Expanded( + child: Text( + room.metadata?.name ?? "Unnamed Room", + overflow: TextOverflow.ellipsis, + maxLines: 3, + style: Theme.of(context).textTheme.headlineSmall, ), ), - ) - .toString(), - child: AvatarOrHash( - room.metadata?.avatar, - room.metadata?.name ?? "Unnamed Rooms", - height: 24, - fallback: Icon(Icons.numbers), - ), - ) + ], + ), + if (room.metadata?.topic?.isNotEmpty == true) + LinkifiedText( + room.metadata!.topic!, + style: Theme.of(context).textTheme.bodyLarge + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ), + ), + leading: isDesktop && room != null + ? AvatarOrHash( + room.metadata?.avatar, + room.metadata?.name ?? "Unnamed Room", + height: 24, + fallback: Icon(Icons.numbers), + ) : DrawerButton(onPressed: () => onOpenDrawer(context)), scrolledUnderElevation: 0, title: room == null @@ -70,6 +119,7 @@ class RoomAppbar extends ConsumerWidget implements PreferredSizeWidget { overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.labelMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, + decoration: TextDecoration.underline, ), ), ],