From f0a397f5762c64f7af23d60ef165e73eb76b35f1 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 14 Nov 2025 17:27:43 -0500 Subject: [PATCH] conditionally show room avatar in header --- lib/helpers/extension_helper.dart | 7 +++ lib/main.dart | 23 ++++----- lib/widgets/avatar_or_hash.dart | 1 + lib/widgets/member_list.dart | 83 ++++++++++++++++++------------- lib/widgets/room_appbar.dart | 54 ++++++++++---------- lib/widgets/room_chat.dart | 12 +++-- lib/widgets/sidebar.dart | 25 ++++------ 7 files changed, 110 insertions(+), 95 deletions(-) diff --git a/lib/helpers/extension_helper.dart b/lib/helpers/extension_helper.dart index 22a65fd..70265a5 100644 --- a/lib/helpers/extension_helper.dart +++ b/lib/helpers/extension_helper.dart @@ -1,3 +1,4 @@ +import "package:flutter/material.dart"; import "package:flutter/widgets.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; @@ -118,3 +119,9 @@ extension ToMessage on Event { }; } } + +extension ToTheme on ColorScheme { + ThemeData get theme => ThemeData.from( + colorScheme: this, + ).copyWith(appBarTheme: AppBarTheme(titleSpacing: 0)); +} diff --git a/lib/main.dart b/lib/main.dart index 6fb7d11..cfbf23a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:nexus/helpers/extension_helper.dart"; import "package:nexus/widgets/room_chat.dart"; import "package:nexus/widgets/sidebar.dart"; import "package:scaled_app/scaled_app.dart"; @@ -31,18 +32,16 @@ class App extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, - theme: ThemeData.from( - colorScheme: - lightDynamic ?? ColorScheme.fromSeed(seedColor: Colors.indigo), - ), - darkTheme: ThemeData.from( - colorScheme: - darkDynamic ?? - ColorScheme.fromSeed( - seedColor: Colors.indigo, - brightness: Brightness.dark, - ), - ), + theme: + (lightDynamic ?? ColorScheme.fromSeed(seedColor: Colors.indigo)) + .theme, + darkTheme: + (darkDynamic ?? + ColorScheme.fromSeed( + seedColor: Colors.indigo, + brightness: Brightness.dark, + )) + .theme, home: Scaffold( body: Builder( builder: (context) => Row( diff --git a/lib/widgets/avatar_or_hash.dart b/lib/widgets/avatar_or_hash.dart index a349921..accae27 100644 --- a/lib/widgets/avatar_or_hash.dart +++ b/lib/widgets/avatar_or_hash.dart @@ -26,6 +26,7 @@ class AvatarOrHash extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(4)), child: SizedBox( height: height, + width: height, child: avatar == null ? fallback ?? box : Image.network( diff --git a/lib/widgets/member_list.dart b/lib/widgets/member_list.dart index 9b47cc0..164c312 100644 --- a/lib/widgets/member_list.dart +++ b/lib/widgets/member_list.dart @@ -11,43 +11,56 @@ class MemberList extends ConsumerWidget { const MemberList(this.room, {super.key}); @override - Widget build(BuildContext context, WidgetRef ref) => ColoredBox( - color: Theme.of(context).colorScheme.surfaceContainerLow, - child: SizedBox( - width: 240, - child: ref - .watch(MembersController.provider(room)) - .betterWhen( - data: (members) => ListView( - children: [ - ...members - .where( - (membership) => - membership.content["membership"] == - Membership.join.name, - ) - .map( - (member) => ListTile( - leading: AvatarOrHash( - ref - .watch( - AvatarController.provider( - member.content["avatar_url"].toString(), - ), - ) - .whenOrNull(data: (data) => data), - member.content["displayname"].toString(), - headers: room.client.headers, - ), - title: Text( - member.content["displayname"].toString(), - overflow: TextOverflow.ellipsis, - ), + Widget build(BuildContext context, WidgetRef ref) => Drawer( + shape: Border(), + child: ref + .watch(MembersController.provider(room)) + .betterWhen( + data: (members) => ListView( + children: [ + AppBar( + scrolledUnderElevation: 0, + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerLow, + leading: Icon(Icons.people), + title: Text("Members"), + actionsPadding: EdgeInsets.only(right: 4), + actions: [ + if (Scaffold.of(context).hasEndDrawer) + IconButton( + onPressed: Scaffold.of(context).closeEndDrawer, + icon: Icon(Icons.close), + ), + ], + ), + ...members + .where( + (membership) => + membership.content["membership"] == + Membership.join.name, + ) + .map( + (member) => ListTile( + leading: AvatarOrHash( + ref + .watch( + AvatarController.provider( + member.content["avatar_url"].toString(), + ), + ) + .whenOrNull(data: (data) => data), + member.content["displayname"].toString(), + headers: room.client.headers, + ), + title: Text( + member.content["displayname"].toString(), + overflow: TextOverflow.ellipsis, ), ), - ], - ), + ), + ], ), - ), + ), ); } diff --git a/lib/widgets/room_appbar.dart b/lib/widgets/room_appbar.dart index 5a13774..c000a4a 100644 --- a/lib/widgets/room_appbar.dart +++ b/lib/widgets/room_appbar.dart @@ -8,8 +8,8 @@ import "package:nexus/widgets/avatar_or_hash.dart"; class RoomAppbar extends StatelessWidget implements PreferredSizeWidget { final bool isDesktop; final FullRoom room; - final VoidCallback onOpenMemberList; - final VoidCallback onOpenDrawer; + final void Function(BuildContext context) onOpenMemberList; + final void Function(BuildContext context) onOpenDrawer; const RoomAppbar( this.room, { required this.isDesktop, @@ -23,39 +23,37 @@ class RoomAppbar extends StatelessWidget implements PreferredSizeWidget { @override AppBar build(BuildContext context) => AppBar( - leading: isDesktop ? null : DrawerButton(onPressed: onOpenDrawer), + leading: isDesktop + ? AvatarOrHash( + room.avatar, + room.title, + height: 32, + fallback: Icon(Icons.numbers), + headers: room.roomData.client.headers, + ) + : DrawerButton(onPressed: () => onOpenDrawer(context)), + scrolledUnderElevation: 0, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, actionsPadding: EdgeInsets.symmetric(horizontal: 8), - title: Row( + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - AvatarOrHash( - room.avatar, - room.title, - height: 32, - fallback: Icon(Icons.numbers), - headers: room.roomData.client.headers, - ), - SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(room.title, overflow: TextOverflow.ellipsis), - - Text( - room.roomData.topic, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.labelMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ], + Text(room.title, overflow: TextOverflow.ellipsis), + Text( + room.roomData.topic, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.labelMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ], ), actions: [ - IconButton(onPressed: onOpenMemberList, icon: Icon(Icons.people)), + IconButton( + onPressed: () => onOpenMemberList(context), + icon: Icon(Icons.people), + ), if (!(Platform.isAndroid || Platform.isIOS)) IconButton(onPressed: () => exit(0), icon: Icon(Icons.close)), ], diff --git a/lib/widgets/room_chat.dart b/lib/widgets/room_chat.dart index cd3ab7f..4744a0b 100644 --- a/lib/widgets/room_chat.dart +++ b/lib/widgets/room_chat.dart @@ -58,9 +58,11 @@ class RoomChat extends HookConsumerWidget { appBar: RoomAppbar( room, isDesktop: isDesktop, - onOpenDrawer: Scaffold.of(context).openDrawer, - onOpenMemberList: () => - memberListOpened.value = !memberListOpened.value, + onOpenDrawer: (_) => Scaffold.of(context).openDrawer(), + onOpenMemberList: (thisContext) { + memberListOpened.value = !memberListOpened.value; + Scaffold.of(thisContext).openEndDrawer(); + }, ), body: Row( children: [ @@ -245,9 +247,11 @@ class RoomChat extends HookConsumerWidget { ), ), - if (memberListOpened.value == true) MemberList(room.roomData), + if (memberListOpened.value == true && isDesktop) + MemberList(room.roomData), ], ), + endDrawer: isDesktop ? null : MemberList(room.roomData), ); }, ); diff --git a/lib/widgets/sidebar.dart b/lib/widgets/sidebar.dart index 4f98092..da84406 100644 --- a/lib/widgets/sidebar.dart +++ b/lib/widgets/sidebar.dart @@ -61,22 +61,15 @@ class Sidebar extends HookConsumerWidget { return Scaffold( backgroundColor: Colors.transparent, appBar: AppBar( - title: Row( - children: [ - AvatarOrHash( - space.avatar, - fallback: space.icon, - space.title, - headers: space.client.headers, - ), - SizedBox(width: 12), - Expanded( - child: Text( - space.title, - overflow: TextOverflow.ellipsis, - ), - ), - ], + leading: AvatarOrHash( + space.avatar, + fallback: space.icon, + space.title, + headers: space.client.headers, + ), + title: Text( + space.title, + overflow: TextOverflow.ellipsis, ), backgroundColor: Colors.transparent, ),