diff --git a/lib/helpers/extensions/show_leave_room_sheet.dart b/lib/helpers/extensions/show_leave_room_sheet.dart index a981d4b..7dd8d3a 100644 --- a/lib/helpers/extensions/show_leave_room_sheet.dart +++ b/lib/helpers/extensions/show_leave_room_sheet.dart @@ -18,9 +18,8 @@ extension ShowLeaveRoomSheet on BuildContext { ), TextButton( onPressed: () { - final client = ProviderScope.containerOf( - context, - ).read(ClientController.provider.notifier); + final client = ProviderScope.containerOf(context) + .read(ClientController.provider.notifier); context.withProgressSnackbar( "Leaving $name...", () => client.leaveRoom(roomId), diff --git a/lib/models/room_summary.dart b/lib/models/room_summary.dart index f2c8852..6d22f6c 100644 --- a/lib/models/room_summary.dart +++ b/lib/models/room_summary.dart @@ -3,6 +3,7 @@ import "package:nexus/models/content/create.dart"; import "package:nexus/models/content/membership.dart"; import "package:nexus/models/join_rule.dart"; import "package:nexus/models/membership_status.dart"; +import "package:nexus/models/room_metadata.dart"; part "room_summary.freezed.dart"; part "room_summary.g.dart"; @@ -40,6 +41,16 @@ class const RoomSummary({ /// Whether this is an invite to a direct message. @JsonKey(includeFromJson: false) final bool isDirect = false, }) with _$RoomSummary { + /// A summary of a room the user is in, from its synced metadata. + factory RoomSummary.fromMetadata(RoomMetadata metadata) => .new( + roomId: metadata.id, + joinedMembers: metadata.lazyLoadSummary?.joinedMemberCount, + avatarUrl: metadata.avatar, + canonicalAlias: metadata.canonicalAlias, + name: metadata.name, + topic: metadata.topic, + ); + factory RoomSummary.fromJson(Map json) => _$RoomSummaryFromJson(json); } diff --git a/lib/widgets/appbar.dart b/lib/widgets/appbar.dart index a6489a2..226da68 100644 --- a/lib/widgets/appbar.dart +++ b/lib/widgets/appbar.dart @@ -13,6 +13,9 @@ final class const Appbar({ final double? scrolledUnderElevation, final IList actions = const .empty(), final VoidCallback? onTap, + + /// Whether to show the minimize, maximize and close buttons on desktop. + final bool windowControls = true, super.key, }) extends ConsumerWidget implements PreferredSizeWidget { @override @@ -50,7 +53,7 @@ final class const Appbar({ flexibleSpace: GestureDetector(onDoubleTap: maximize), actions: [ ...actions, - if (!(Platform.isAndroid || Platform.isIOS)) ...[ + if (windowControls && !(Platform.isAndroid || Platform.isIOS)) ...[ if (ref .watch(SettingsController.provider) .whenOrNull( diff --git a/lib/widgets/room_appbar.dart b/lib/widgets/room_appbar.dart index bcd4108..e284bc5 100644 --- a/lib/widgets/room_appbar.dart +++ b/lib/widgets/room_appbar.dart @@ -7,6 +7,7 @@ import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/count_badge.dart"; import "package:nexus/widgets/room_menu_button.dart"; import "package:nexus/widgets/room_summary_sheet.dart"; +import "package:nexus/widgets/room_title.dart"; import "package:nexus/widgets/sidebar.dart"; final class const RoomAppbar({ @@ -30,17 +31,7 @@ final class const RoomAppbar({ onTap: room?.metadata == null ? null : () => context.showAdaptiveSheet( - (context) => RoomSummarySheet( - .new( - roomId: room!.metadata!.id, - joinedMembers: - room.metadata!.lazyLoadSummary?.joinedMemberCount, - avatarUrl: room.metadata?.avatar, - canonicalAlias: room.metadata?.canonicalAlias, - name: room.metadata?.name, - topic: room.metadata?.topic, - ), - ), + (context) => RoomSummarySheet(.fromMetadata(room!.metadata!)), ), leading: isDesktop ? room == null @@ -62,24 +53,9 @@ final class const RoomAppbar({ scrolledUnderElevation: 0, title: room == null ? null - : Column( - crossAxisAlignment: .start, - children: [ - Text( - room.metadata?.name ?? "Unnamed Room", - overflow: .ellipsis, - maxLines: 1, - ), - if (room.metadata?.topic?.isNotEmpty == true) - Text( - room.metadata!.topic!, - maxLines: 1, - overflow: .ellipsis, - style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ], + : RoomTitle( + room.metadata?.name ?? "Unnamed Room", + topic: room.metadata?.topic, ), actions: .new( room == null diff --git a/lib/widgets/room_list.dart b/lib/widgets/room_list.dart index bd109f7..0864a47 100644 --- a/lib/widgets/room_list.dart +++ b/lib/widgets/room_list.dart @@ -9,6 +9,8 @@ import "package:nexus/helpers/extensions/room_destinations.dart"; import "package:nexus/helpers/extensions/show_adaptive_sheet.dart"; import "package:nexus/widgets/adaptive_menu_button.dart"; import "package:nexus/models/nav_page.dart"; +import "package:nexus/widgets/appbar.dart"; +import "package:nexus/widgets/room_title.dart"; import "package:nexus/widgets/avatar_or_hash.dart"; import "package:nexus/widgets/create_room_sheet.dart"; import "package:nexus/widgets/start_dm_sheet.dart"; @@ -16,6 +18,7 @@ import "package:nexus/widgets/divider_widget.dart"; import "package:nexus/widgets/error_dialog.dart"; import "package:nexus/widgets/pages/settings.dart"; import "package:nexus/widgets/join_sheet.dart"; +import "package:nexus/widgets/room_summary_sheet.dart"; import "package:nexus/widgets/room_menu_button.dart"; import "package:nexus/widgets/space_hierarchy_sheet.dart"; import "package:nexus/controllers/key.dart"; @@ -232,25 +235,33 @@ class const RoomsPane({super.key}) extends ConsumerWidget { }), ); final isDm = selectedSpace.id == "dms"; + final spaceMetadata = selectedSpace.room?.metadata; return Scaffold( backgroundColor: Colors.transparent, - appBar: AppBar( + appBar: Appbar( + // Home and DMs aren't real spaces, so they don't have a summary. + onTap: spaceMetadata == null + ? null + : () => context.showAdaptiveSheet( + (_) => RoomSummarySheet(.fromMetadata(spaceMetadata)), + ), + windowControls: false, leading: AvatarOrHash( - selectedSpace.room?.metadata?.avatar, + spaceMetadata?.avatar, fallback: selectedSpace.icon == null ? null : Icon(selectedSpace.icon), selectedSpace.title, ), - title: Text(selectedSpace.title, overflow: .ellipsis), + title: RoomTitle(selectedSpace.title, topic: spaceMetadata?.topic), backgroundColor: Colors.transparent, - actions: [ + actions: .new([ RoomMenuButton( selectedSpace.room, children: selectedSpace.allChildRooms, ), - ], + ]), ), body: MaterialUiCompatibilityBridge( child: Builder( diff --git a/lib/widgets/room_title.dart b/lib/widgets/room_title.dart new file mode 100644 index 0000000..94eacc8 --- /dev/null +++ b/lib/widgets/room_title.dart @@ -0,0 +1,22 @@ +import "package:material_ui/material_ui.dart"; + +/// A room or space's name, with its topic underneath if it has one, for app +/// bars. +class const RoomTitle(final String name, {final String? topic, super.key}) + extends StatelessWidget { + @override + Widget build(BuildContext context) => Column( + crossAxisAlignment: .start, + children: [ + Text(name, overflow: .ellipsis, maxLines: 1), + if (topic?.isNotEmpty == true) + Text( + topic!, + maxLines: 1, + overflow: .ellipsis, + style: Theme.of(context).textTheme.labelMedium + ?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant), + ), + ], + ); +}