Merge remote-tracking branch 'ggurdin/display-navigation-rail-setting'

This commit is contained in:
Christian Kußowski 2025-06-05 08:47:19 +02:00
commit 970de1f4b0
No known key found for this signature in database
GPG key ID: E067ECD60F1A0652
9 changed files with 130 additions and 103 deletions

View file

@ -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;

View file

@ -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<T> {

View file

@ -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"
}

View file

@ -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(

View file

@ -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,

View file

@ -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(

View file

@ -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,
),
],
),
),

View file

@ -436,6 +436,10 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
AppConfig.showPresences =
store.getBool(SettingKeys.showPresences) ?? AppConfig.showPresences;
AppConfig.displayNavigationRail =
store.getBool(SettingKeys.displayNavigationRail) ??
AppConfig.displayNavigationRail;
}
@override

View file

@ -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,
),
],
),
);
},
),
),
);
}
}