diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 472e633b2..b5e10985d 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -59,6 +59,7 @@ abstract class AppConfig { static bool swipeRightToLeftToReply = true; static bool? sendOnEnter; static bool showPresences = true; + static bool displayNavigationRail = false; static bool experimentalVoip = false; static const bool hideTypingUsernames = false; static const bool hideAllStateEvents = false; diff --git a/lib/config/setting_keys.dart b/lib/config/setting_keys.dart index 21eacb778..9fa58efd8 100644 --- a/lib/config/setting_keys.dart +++ b/lib/config/setting_keys.dart @@ -32,6 +32,8 @@ abstract class SettingKeys { 'chat.fluffy.swipeRightToLeftToReply'; static const String experimentalVoip = 'chat.fluffy.experimental_voip'; static const String showPresences = 'chat.fluffy.show_presences'; + static const String displayNavigationRail = + 'chat.fluffy.display_navigation_rail'; } enum AppSettings { diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index b7e61178c..82c45c1ba 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -3238,5 +3238,6 @@ "youHaveKnocked": "You have knocked", "pleaseWaitUntilInvited": "Please wait now, until someone from the room invites you.", "commandHint_logout": "Logout your current device", - "commandHint_logoutall": "Logout all active devices" + "commandHint_logoutall": "Logout all active devices", + "displayNavigationRail": "Show navigation rail on mobile" } \ No newline at end of file diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index b75bf8902..d5ec1c096 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -165,7 +165,8 @@ class ChatListViewBody extends StatelessWidget { ActiveFilter.groups, ActiveFilter.unread, if (spaceDelegateCandidates.isNotEmpty && - !controller.widget.displayNavigationRail) + !AppConfig.displayNavigationRail && + !FluffyThemes.isColumnMode(context)) ActiveFilter.spaces, ] .map( diff --git a/lib/pages/chat_list/chat_list_view.dart b/lib/pages/chat_list/chat_list_view.dart index 9a5736024..35f763983 100644 --- a/lib/pages/chat_list/chat_list_view.dart +++ b/lib/pages/chat_list/chat_list_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/chat_list/chat_list.dart'; @@ -30,8 +31,8 @@ class ChatListView extends StatelessWidget { }, child: Row( children: [ - if (FluffyThemes.isColumnMode(context) && - controller.widget.displayNavigationRail) ...[ + if (FluffyThemes.isColumnMode(context) || + AppConfig.displayNavigationRail) ...[ SpacesNavigationRail( activeSpaceId: controller.activeSpaceId, onGoToChats: controller.clearActiveSpace, diff --git a/lib/pages/chat_list/navi_rail_item.dart b/lib/pages/chat_list/navi_rail_item.dart index 0e844e05d..f29a16b5d 100644 --- a/lib/pages/chat_list/navi_rail_item.dart +++ b/lib/pages/chat_list/navi_rail_item.dart @@ -44,7 +44,11 @@ class NaviRailItem extends StatelessWidget { bottom: 8, left: 0, child: AnimatedContainer( - width: isSelected ? 8 : 0, + width: isSelected + ? FluffyThemes.isColumnMode(context) + ? 8 + : 4 + : 0, duration: FluffyThemes.animationDuration, curve: FluffyThemes.animationCurve, decoration: BoxDecoration( diff --git a/lib/pages/settings_style/settings_style_view.dart b/lib/pages/settings_style/settings_style_view.dart index d2d20190f..f4bbd7285 100644 --- a/lib/pages/settings_style/settings_style_view.dart +++ b/lib/pages/settings_style/settings_style_view.dart @@ -359,6 +359,12 @@ class SettingsStyleView extends StatelessWidget { storeKey: SettingKeys.separateChatTypes, defaultValue: AppConfig.separateChatTypes, ), + SettingsSwitchListTile.adaptive( + title: L10n.of(context).displayNavigationRail, + onChanged: (b) => AppConfig.displayNavigationRail = b, + storeKey: SettingKeys.displayNavigationRail, + defaultValue: AppConfig.displayNavigationRail, + ), ], ), ), diff --git a/lib/widgets/matrix.dart b/lib/widgets/matrix.dart index aa79fc7b1..18f35efc5 100644 --- a/lib/widgets/matrix.dart +++ b/lib/widgets/matrix.dart @@ -436,6 +436,10 @@ class MatrixState extends State with WidgetsBindingObserver { AppConfig.showPresences = store.getBool(SettingKeys.showPresences) ?? AppConfig.showPresences; + + AppConfig.displayNavigationRail = + store.getBool(SettingKeys.displayNavigationRail) ?? + AppConfig.displayNavigationRail; } @override diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index 81e8fa744..d27d84912 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -33,105 +33,112 @@ class SpacesNavigationRail extends StatelessWidget { .uri .path .startsWith('/rooms/settings'); - return StreamBuilder( - key: ValueKey( - client.userID.toString(), - ), - stream: client.onSync.stream - .where((s) => s.hasRoomUpdate) - .rateLimit(const Duration(seconds: 1)), - builder: (context, _) { - final allSpaces = client.rooms.where((room) => room.isSpace); - final rootSpaces = allSpaces - .where( - (space) => !allSpaces.any( - (parentSpace) => parentSpace.spaceChildren - .any((child) => child.roomId == space.id), - ), - ) - .toList(); - - return SizedBox( - width: FluffyThemes.navRailWidth, - child: Column( - children: [ - Expanded( - child: ListView.builder( - scrollDirection: Axis.vertical, - itemCount: rootSpaces.length + 2, - itemBuilder: (context, i) { - if (i == 0) { - return NaviRailItem( - isSelected: activeSpaceId == null && !isSettings, - onTap: onGoToChats, - icon: const Padding( - padding: EdgeInsets.all(10.0), - child: Icon(Icons.forum_outlined), - ), - selectedIcon: const Padding( - padding: EdgeInsets.all(10.0), - child: Icon(Icons.forum), - ), - toolTip: L10n.of(context).chats, - unreadBadgeFilter: (room) => true, - ); - } - i--; - if (i == rootSpaces.length) { - return NaviRailItem( - isSelected: false, - onTap: () => context.go('/rooms/newspace'), - icon: const Padding( - padding: EdgeInsets.all(8.0), - child: Icon(Icons.add), - ), - toolTip: L10n.of(context).createNewSpace, - ); - } - final space = rootSpaces[i]; - final displayname = rootSpaces[i].getLocalizedDisplayname( - MatrixLocals(L10n.of(context)), - ); - final spaceChildrenIds = - space.spaceChildren.map((c) => c.roomId).toSet(); - return NaviRailItem( - toolTip: displayname, - isSelected: activeSpaceId == space.id, - onTap: () => onGoToSpaceId(rootSpaces[i].id), - unreadBadgeFilter: (room) => - spaceChildrenIds.contains(room.id), - icon: Avatar( - mxContent: rootSpaces[i].avatar, - name: displayname, - border: BorderSide( - width: 1, - color: Theme.of(context).dividerColor, - ), - borderRadius: BorderRadius.circular( - AppConfig.borderRadius / 2, - ), - ), - ); - }, - ), - ), - NaviRailItem( - isSelected: isSettings, - onTap: () => context.go('/rooms/settings'), - icon: const Padding( - padding: EdgeInsets.all(10.0), - child: Icon(Icons.settings_outlined), - ), - selectedIcon: const Padding( - padding: EdgeInsets.all(10.0), - child: Icon(Icons.settings), - ), - toolTip: L10n.of(context).settings, - ), - ], + return Material( + child: SafeArea( + child: StreamBuilder( + key: ValueKey( + client.userID.toString(), ), - ); - }, + stream: client.onSync.stream + .where((s) => s.hasRoomUpdate) + .rateLimit(const Duration(seconds: 1)), + builder: (context, _) { + final allSpaces = client.rooms.where((room) => room.isSpace); + final rootSpaces = allSpaces + .where( + (space) => !allSpaces.any( + (parentSpace) => parentSpace.spaceChildren + .any((child) => child.roomId == space.id), + ), + ) + .toList(); + + return SizedBox( + width: FluffyThemes.isColumnMode(context) + ? FluffyThemes.navRailWidth + : FluffyThemes.navRailWidth * 0.75, + child: Column( + children: [ + Expanded( + child: ListView.builder( + scrollDirection: Axis.vertical, + itemCount: rootSpaces.length + 2, + itemBuilder: (context, i) { + if (i == 0) { + return NaviRailItem( + isSelected: activeSpaceId == null && !isSettings, + onTap: onGoToChats, + icon: const Padding( + padding: EdgeInsets.all(10.0), + child: Icon(Icons.forum_outlined), + ), + selectedIcon: const Padding( + padding: EdgeInsets.all(10.0), + child: Icon(Icons.forum), + ), + toolTip: L10n.of(context).chats, + unreadBadgeFilter: (room) => true, + ); + } + i--; + if (i == rootSpaces.length) { + return NaviRailItem( + isSelected: false, + onTap: () => context.go('/rooms/newspace'), + icon: const Padding( + padding: EdgeInsets.all(8.0), + child: Icon(Icons.add), + ), + toolTip: L10n.of(context).createNewSpace, + ); + } + final space = rootSpaces[i]; + final displayname = + rootSpaces[i].getLocalizedDisplayname( + MatrixLocals(L10n.of(context)), + ); + final spaceChildrenIds = + space.spaceChildren.map((c) => c.roomId).toSet(); + return NaviRailItem( + toolTip: displayname, + isSelected: activeSpaceId == space.id, + onTap: () => onGoToSpaceId(rootSpaces[i].id), + unreadBadgeFilter: (room) => + spaceChildrenIds.contains(room.id), + icon: Avatar( + mxContent: rootSpaces[i].avatar, + name: displayname, + border: BorderSide( + width: 1, + color: Theme.of(context).dividerColor, + ), + borderRadius: BorderRadius.circular( + AppConfig.borderRadius / 2, + ), + ), + ); + }, + ), + ), + NaviRailItem( + isSelected: isSettings, + onTap: () => context.go('/rooms/settings'), + icon: const Padding( + padding: EdgeInsets.all(10.0), + child: Icon(Icons.settings_outlined), + ), + selectedIcon: const Padding( + padding: EdgeInsets.all(10.0), + child: Icon(Icons.settings), + ), + toolTip: L10n.of(context).settings, + ), + ], + ), + ); + }, + ), + ), ); } }