mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-11-15 12:17:25 +01:00
feat: space navigation enhancements
- add ravigation rail on large screens - refactor space hierarchy dummy code - add material 3 like radius to spaces drawer - rename column router to catch the application-specific code inside Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
parent
3e80e3f67e
commit
77661f1ead
@ -113,7 +113,7 @@ class AppRoutes {
|
|||||||
List<VRouteElement> get _tabletRoutes => [
|
List<VRouteElement> get _tabletRoutes => [
|
||||||
VNester(
|
VNester(
|
||||||
path: '/rooms',
|
path: '/rooms',
|
||||||
widgetBuilder: (child) => TwoColumnLayout(
|
widgetBuilder: (child) => FluffyChatTwoColumnLayout(
|
||||||
mainView: const ChatList(),
|
mainView: const ChatList(),
|
||||||
sideView: child,
|
sideView: child,
|
||||||
),
|
),
|
||||||
@ -198,7 +198,7 @@ class AppRoutes {
|
|||||||
),
|
),
|
||||||
VWidget(
|
VWidget(
|
||||||
path: '/rooms',
|
path: '/rooms',
|
||||||
widget: const TwoColumnLayout(
|
widget: const FluffyChatTwoColumnLayout(
|
||||||
mainView: ChatList(),
|
mainView: ChatList(),
|
||||||
sideView: EmptyPage(),
|
sideView: EmptyPage(),
|
||||||
),
|
),
|
||||||
@ -206,7 +206,7 @@ class AppRoutes {
|
|||||||
stackedRoutes: [
|
stackedRoutes: [
|
||||||
VNester(
|
VNester(
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
widgetBuilder: (child) => TwoColumnLayout(
|
widgetBuilder: (child) => FluffyChatTwoColumnLayout(
|
||||||
mainView: const Settings(),
|
mainView: const Settings(),
|
||||||
sideView: child,
|
sideView: child,
|
||||||
),
|
),
|
||||||
@ -222,7 +222,7 @@ class AppRoutes {
|
|||||||
),
|
),
|
||||||
VWidget(
|
VWidget(
|
||||||
path: '/archive',
|
path: '/archive',
|
||||||
widget: const TwoColumnLayout(
|
widget: const FluffyChatTwoColumnLayout(
|
||||||
mainView: Archive(),
|
mainView: Archive(),
|
||||||
sideView: EmptyPage(),
|
sideView: EmptyPage(),
|
||||||
),
|
),
|
||||||
|
|||||||
37
lib/pages/chat_list/chat_list_body_container.dart
Normal file
37
lib/pages/chat_list/chat_list_body_container.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||||
|
import 'chat_list_body.dart';
|
||||||
|
import 'chat_list_navigation_rail.dart';
|
||||||
|
|
||||||
|
class ChatListBodyContainer extends StatelessWidget {
|
||||||
|
final ChatListController controller;
|
||||||
|
|
||||||
|
const ChatListBodyContainer(this.controller, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
|
if (MediaQuery.of(context).size.width > 1024) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 72.0,
|
||||||
|
height: constraints.maxHeight,
|
||||||
|
child: ChatListNavigationRail(controller),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1.0,
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
),
|
||||||
|
Expanded(child: ChatListViewBody(controller)),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ChatListViewBody(controller);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,10 +12,14 @@ import '../../config/app_config.dart';
|
|||||||
|
|
||||||
class ChatListDrawer extends StatelessWidget {
|
class ChatListDrawer extends StatelessWidget {
|
||||||
final ChatListController controller;
|
final ChatListController controller;
|
||||||
|
|
||||||
const ChatListDrawer(this.controller, {Key? key}) : super(key: key);
|
const ChatListDrawer(this.controller, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Drawer(
|
Widget build(BuildContext context) => Drawer(
|
||||||
|
// TODO(TheOneWithTheBraid): remove once migrated to MD3
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.horizontal(right: Radius.circular(32))),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
76
lib/pages/chat_list/chat_list_navigation_rail.dart
Normal file
76
lib/pages/chat_list/chat_list_navigation_rail.dart
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||||
|
import 'package:vrouter/vrouter.dart';
|
||||||
|
|
||||||
|
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||||
|
import 'package:fluffychat/pages/chat_list/spaces_drawer.dart';
|
||||||
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
|
|
||||||
|
class ChatListNavigationRail extends StatelessWidget {
|
||||||
|
final ChatListController controller;
|
||||||
|
|
||||||
|
const ChatListNavigationRail(this.controller, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final spaceHierarchy = SpacesDrawer.getSpaceHierarchy(controller);
|
||||||
|
|
||||||
|
final currentIndex = controller.spacesEntries.indexWhere((space) =>
|
||||||
|
controller.activeSpacesEntry.runtimeType == space.runtimeType &&
|
||||||
|
(controller.activeSpaceId == space.getSpace(context)?.id));
|
||||||
|
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: SizedBox(
|
||||||
|
// wasted 1.5 h for finding out the proper sizing mechanism...
|
||||||
|
height: spaceHierarchy.length * 44 + 64 + 8,
|
||||||
|
child: NavigationRail(
|
||||||
|
destinations: List.generate(spaceHierarchy.length + 1, (i) {
|
||||||
|
if (i == spaceHierarchy.length) {
|
||||||
|
return NavigationRailDestination(
|
||||||
|
icon: Tooltip(
|
||||||
|
message: L10n.of(context)!.archive,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.archive_outlined,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
label: Text(L10n.of(context)!.archive),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final space = spaceHierarchy.keys.toList()[i];
|
||||||
|
final room = space.getSpace(context);
|
||||||
|
final active = currentIndex == i;
|
||||||
|
return NavigationRailDestination(
|
||||||
|
icon: Tooltip(
|
||||||
|
message: space.getName(context),
|
||||||
|
child: room == null
|
||||||
|
? space.getIcon(active)
|
||||||
|
: Avatar(
|
||||||
|
size: Avatar.defaultSize / 2,
|
||||||
|
mxContent: room.avatar,
|
||||||
|
name: space.getName(context),
|
||||||
|
)),
|
||||||
|
label: Text(
|
||||||
|
space.getName(context),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
selectedIndex: currentIndex,
|
||||||
|
onDestinationSelected: (index) {
|
||||||
|
if (index == spaceHierarchy.length) {
|
||||||
|
VRouter.of(context).to('/archive');
|
||||||
|
} else {
|
||||||
|
controller.setActiveSpacesEntry(
|
||||||
|
context,
|
||||||
|
spaceHierarchy.keys.toList()[index],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelType: NavigationRailLabelType.selected,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,9 +7,9 @@ import 'package:keyboard_shortcuts/keyboard_shortcuts.dart';
|
|||||||
import 'package:vrouter/vrouter.dart';
|
import 'package:vrouter/vrouter.dart';
|
||||||
|
|
||||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||||
|
import 'package:fluffychat/pages/chat_list/chat_list_body_container.dart';
|
||||||
import 'package:fluffychat/pages/chat_list/chat_list_drawer.dart';
|
import 'package:fluffychat/pages/chat_list/chat_list_drawer.dart';
|
||||||
import '../../widgets/matrix.dart';
|
import 'package:fluffychat/widgets/matrix.dart';
|
||||||
import 'chat_list_body.dart';
|
|
||||||
import 'chat_list_header.dart';
|
import 'chat_list_header.dart';
|
||||||
|
|
||||||
class ChatListView extends StatelessWidget {
|
class ChatListView extends StatelessWidget {
|
||||||
@ -31,7 +31,7 @@ class ChatListView extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: ChatListHeader(controller: controller),
|
appBar: ChatListHeader(controller: controller),
|
||||||
body: ChatListViewBody(controller),
|
body: ChatListBodyContainer(controller),
|
||||||
drawer: ChatListDrawer(controller),
|
drawer: ChatListDrawer(controller),
|
||||||
floatingActionButton: selectMode == SelectMode.normal
|
floatingActionButton: selectMode == SelectMode.normal
|
||||||
? KeyBoardShortcuts(
|
? KeyBoardShortcuts(
|
||||||
|
|||||||
@ -12,16 +12,24 @@ class SpacesDrawer extends StatelessWidget {
|
|||||||
|
|
||||||
const SpacesDrawer({Key? key, required this.controller}) : super(key: key);
|
const SpacesDrawer({Key? key, required this.controller}) : super(key: key);
|
||||||
|
|
||||||
|
/// PLACEHOLDER for later computation of space hierarchy mapping
|
||||||
|
///
|
||||||
|
/// TODO(TheOeWithTheBraid): implement space hierarchy
|
||||||
|
static Map<SpacesEntry, dynamic> getSpaceHierarchy(
|
||||||
|
ChatListController controller) {
|
||||||
|
return Map.fromEntries(
|
||||||
|
controller.spacesEntries.map((e) => MapEntry(e, null)));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
/// keep this implementation in sync with [ChatListBodyContainer]
|
||||||
final currentIndex = controller.spacesEntries.indexWhere((space) =>
|
final currentIndex = controller.spacesEntries.indexWhere((space) =>
|
||||||
controller.activeSpacesEntry.runtimeType == space.runtimeType &&
|
controller.activeSpacesEntry.runtimeType == space.runtimeType &&
|
||||||
(controller.activeSpaceId == space.getSpace(context)?.id));
|
(controller.activeSpaceId == space.getSpace(context)?.id));
|
||||||
|
|
||||||
final Map<SpacesEntry, dynamic> spaceHierarchy =
|
final Map<SpacesEntry, dynamic> spaceHierarchy =
|
||||||
Map.fromEntries(controller.spacesEntries.map((e) => MapEntry(e, null)));
|
SpacesDrawer.getSpaceHierarchy(controller);
|
||||||
|
|
||||||
// TODO(TheOeWithTheBraid): wait for space hierarchy https://gitlab.com/famedly/company/frontend/libraries/matrix_api_lite/-/merge_requests/58
|
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: spaceHierarchy.length + 1,
|
itemCount: spaceHierarchy.length + 1,
|
||||||
|
|||||||
@ -1,24 +1,37 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class TwoColumnLayout extends StatelessWidget {
|
import 'package:vrouter/vrouter.dart';
|
||||||
|
|
||||||
|
/// displays a two-column layout with some FluffyChat specific patches
|
||||||
|
///
|
||||||
|
/// On huge screens width > 1024, the navigation rail for quick navigation is
|
||||||
|
/// rendered surround
|
||||||
|
class FluffyChatTwoColumnLayout extends StatelessWidget {
|
||||||
final Widget mainView;
|
final Widget mainView;
|
||||||
final Widget sideView;
|
final Widget sideView;
|
||||||
|
|
||||||
const TwoColumnLayout({
|
const FluffyChatTwoColumnLayout({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.mainView,
|
required this.mainView,
|
||||||
required this.sideView,
|
required this.sideView,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: Row(
|
body: LayoutBuilder(builder: (context, constraints) {
|
||||||
|
final columnWidth = context.vRouter.path.startsWith('/rooms') &&
|
||||||
|
constraints.maxWidth > 1024
|
||||||
|
? 360.0 + 64
|
||||||
|
: 360.0;
|
||||||
|
|
||||||
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
decoration: const BoxDecoration(),
|
decoration: const BoxDecoration(),
|
||||||
width: 360.0,
|
width: columnWidth,
|
||||||
child: mainView,
|
child: mainView,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@ -31,7 +44,8 @@ class TwoColumnLayout extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user