2655 tweaks to spacechat navigation (#2859)
* chore: update parent space navigation * refactor: show space navigation rail on mobile
This commit is contained in:
parent
fe2db3264d
commit
a5539b4bea
17 changed files with 422 additions and 377 deletions
|
|
@ -4943,5 +4943,6 @@
|
|||
"launchActivityToChats": "Launch activity to chats",
|
||||
"searchChats": "Search chats",
|
||||
"selectChats": "Select chats",
|
||||
"selectChatToStart": "Complete! Select a chat to start"
|
||||
"selectChatToStart": "Complete! Select a chat to start",
|
||||
"displayNavigationRail": "Show navigation rail on mobile"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,9 @@ abstract class AppConfig {
|
|||
static bool swipeRightToLeftToReply = true;
|
||||
static bool? sendOnEnter;
|
||||
static bool showPresences = true;
|
||||
// #Pangea
|
||||
static bool displayNavigationRail = true;
|
||||
// Pangea#
|
||||
static bool experimentalVoip = false;
|
||||
static const bool hideTypingUsernames = false;
|
||||
static const bool hideAllStateEvents = false;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import 'package:fluffychat/pangea/activity_generator/activity_generator.dart';
|
|||
import 'package:fluffychat/pangea/activity_planner/activity_planner_page.dart';
|
||||
import 'package:fluffychat/pangea/activity_suggestions/suggestions_page.dart';
|
||||
import 'package:fluffychat/pangea/guard/p_vguard.dart';
|
||||
import 'package:fluffychat/pangea/layouts/bottom_nav_layout.dart';
|
||||
import 'package:fluffychat/pangea/learning_settings/pages/settings_learning.dart';
|
||||
import 'package:fluffychat/pangea/login/pages/login_or_signup_view.dart';
|
||||
import 'package:fluffychat/pangea/login/pages/signup.dart';
|
||||
|
|
@ -210,15 +209,7 @@ abstract class AppRoutes {
|
|||
),
|
||||
sideView: child,
|
||||
)
|
||||
// #Pangea
|
||||
// : child,
|
||||
: FluffyThemes.isColumnMode(context) ||
|
||||
(state.fullPath?.split("/").reversed.elementAt(1) ==
|
||||
'rooms' &&
|
||||
state.pathParameters['roomid'] != null)
|
||||
? child
|
||||
: BottomNavLayout(mainView: child),
|
||||
// Pangea#
|
||||
: child,
|
||||
),
|
||||
routes: [
|
||||
GoRoute(
|
||||
|
|
@ -352,6 +343,39 @@ abstract class AppRoutes {
|
|||
),
|
||||
redirect: loggedOutRedirect,
|
||||
),
|
||||
// #Pangea
|
||||
GoRoute(
|
||||
path: 'homepage',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const SuggestionsPage(),
|
||||
),
|
||||
routes: [
|
||||
...newRoomRoutes,
|
||||
GoRoute(
|
||||
path: '/planner',
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const ActivityPlannerPage(),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/generator',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const ActivityGenerator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// Pangea#
|
||||
ShellRoute(
|
||||
pageBuilder: (context, state, child) => defaultPageBuilder(
|
||||
|
|
@ -365,40 +389,6 @@ abstract class AppRoutes {
|
|||
: child,
|
||||
),
|
||||
routes: [
|
||||
// #Pangea
|
||||
GoRoute(
|
||||
path: '/homepage',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const SuggestionsPage(),
|
||||
),
|
||||
routes: [
|
||||
...newRoomRoutes,
|
||||
GoRoute(
|
||||
path: '/planner',
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const ActivityPlannerPage(),
|
||||
),
|
||||
redirect: loggedOutRedirect,
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/generator',
|
||||
redirect: loggedOutRedirect,
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
context,
|
||||
state,
|
||||
const ActivityGenerator(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// Pangea#
|
||||
GoRoute(
|
||||
path: 'settings',
|
||||
pageBuilder: (context, state) => defaultPageBuilder(
|
||||
|
|
@ -802,21 +792,14 @@ abstract class AppRoutes {
|
|||
? TwoColumnLayout(
|
||||
mainView: ChatList(
|
||||
activeChat: state.pathParameters['roomid'],
|
||||
// #Pangea
|
||||
activeSpaceId: state.uri.queryParameters['spaceId'],
|
||||
activeFilter: state.uri.queryParameters['filter'],
|
||||
// Pangea#
|
||||
displayNavigationRail:
|
||||
state.path?.startsWith('/rooms/settings') != true,
|
||||
),
|
||||
sideView: child,
|
||||
)
|
||||
: FluffyThemes.isColumnMode(context) ||
|
||||
(state.fullPath?.split("/").reversed.elementAt(1) ==
|
||||
'rooms' &&
|
||||
state.pathParameters['roomid'] != null)
|
||||
? child
|
||||
: BottomNavLayout(mainView: child),
|
||||
: child,
|
||||
);
|
||||
// Pangea#
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ abstract class SettingKeys {
|
|||
'chat.fluffy.swipeRightToLeftToReply';
|
||||
static const String experimentalVoip = 'chat.fluffy.experimental_voip';
|
||||
static const String showPresences = 'chat.fluffy.show_presences';
|
||||
// #Pangea
|
||||
static const String displayNavigationRail =
|
||||
'chat.fluffy.display_navigation_rail';
|
||||
// Pangea#
|
||||
}
|
||||
|
||||
enum AppSettings<T> {
|
||||
|
|
|
|||
|
|
@ -201,7 +201,8 @@ class ChatListViewBody extends StatelessWidget {
|
|||
// #Pangea
|
||||
// if (spaceDelegateCandidates.isNotEmpty &&
|
||||
// !controller.widget.displayNavigationRail)
|
||||
if (!controller.widget.displayNavigationRail)
|
||||
if (!AppConfig.displayNavigationRail &&
|
||||
!FluffyThemes.isColumnMode(context))
|
||||
// Pangea#
|
||||
ActiveFilter.spaces,
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:fluffychat/config/app_config.dart';
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/chat_list/chat_list.dart';
|
||||
import 'package:fluffychat/pangea/chat_list/widgets/chat_list_view_body_wrapper.dart';
|
||||
|
|
@ -31,8 +32,12 @@ class ChatListView extends StatelessWidget {
|
|||
},
|
||||
child: Row(
|
||||
children: [
|
||||
if (FluffyThemes.isColumnMode(context) &&
|
||||
controller.widget.displayNavigationRail) ...[
|
||||
// #Pangea
|
||||
// if (FluffyThemes.isColumnMode(context) &&
|
||||
// controller.widget.displayNavigationRail) ...[
|
||||
if (FluffyThemes.isColumnMode(context) ||
|
||||
AppConfig.displayNavigationRail) ...[
|
||||
// Pangea#
|
||||
SpacesNavigationRail(
|
||||
activeSpaceId: controller.activeSpaceId,
|
||||
onGoToChats: controller.clearActiveSpace,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,14 @@ class NaviRailItem extends StatelessWidget {
|
|||
bottom: 8,
|
||||
left: 0,
|
||||
child: AnimatedContainer(
|
||||
width: isSelected ? 8 : 0,
|
||||
// #Pangea
|
||||
// width: isSelected ? 8 : 0,
|
||||
width: isSelected
|
||||
? FluffyThemes.isColumnMode(context)
|
||||
? 8
|
||||
: 4
|
||||
: 0,
|
||||
// Pangea#
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
decoration: BoxDecoration(
|
||||
|
|
|
|||
|
|
@ -527,6 +527,18 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
final room = Matrix.of(context).client.getRoomById(widget.spaceId);
|
||||
final displayname =
|
||||
room?.getLocalizedDisplayname() ?? L10n.of(context).nothingFound;
|
||||
|
||||
// #Pangea
|
||||
final joinedParents = room?.spaceParents
|
||||
.map((parent) {
|
||||
final roomId = parent.roomId;
|
||||
if (roomId == null) return null;
|
||||
return room.client.getRoomById(roomId);
|
||||
})
|
||||
.whereType<Room>()
|
||||
.toList();
|
||||
// Pangea#
|
||||
|
||||
return Scaffold(
|
||||
// #Pangea
|
||||
// appBar: AppBar(
|
||||
|
|
@ -539,14 +551,51 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
_onSpaceAction(SpaceActions.settings);
|
||||
},
|
||||
child: AppBar(
|
||||
// Pangea#
|
||||
leading: FluffyThemes.isColumnMode(context)
|
||||
? null
|
||||
// leading: FluffyThemes.isColumnMode(context)
|
||||
// ? null
|
||||
// : Center(
|
||||
// child: CloseButton(
|
||||
// onPressed: widget.onBack,
|
||||
// ),
|
||||
// ),
|
||||
leading: joinedParents?.isEmpty ?? true
|
||||
? FluffyThemes.isColumnMode(context)
|
||||
? null
|
||||
: Center(
|
||||
child: CloseButton(
|
||||
onPressed: widget.onBack,
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: CloseButton(
|
||||
onPressed: widget.onBack,
|
||||
),
|
||||
child: joinedParents!.length == 1
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.arrow_back_outlined),
|
||||
onPressed: () =>
|
||||
widget.toParentSpace(joinedParents.first.id),
|
||||
)
|
||||
: PopupMenuButton(
|
||||
popUpAnimationStyle: AnimationStyle(
|
||||
duration: const Duration(milliseconds: 0),
|
||||
),
|
||||
tooltip: null,
|
||||
useRootNavigator: true,
|
||||
icon: const Icon(Icons.arrow_back_outlined),
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
...joinedParents.mapIndexed((i, room) {
|
||||
return PopupMenuItem(
|
||||
value: i,
|
||||
child: Text(room.getLocalizedDisplayname()),
|
||||
);
|
||||
}),
|
||||
];
|
||||
},
|
||||
onSelected: (i) {
|
||||
widget.toParentSpace(joinedParents[i].id);
|
||||
},
|
||||
),
|
||||
),
|
||||
// Pangea#
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: FluffyThemes.isColumnMode(context) ? null : 0,
|
||||
title: ListTile(
|
||||
|
|
@ -660,14 +709,16 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
// Pangea#
|
||||
.toList();
|
||||
|
||||
final joinedParents = room.spaceParents
|
||||
.map((parent) {
|
||||
final roomId = parent.roomId;
|
||||
if (roomId == null) return null;
|
||||
return room.client.getRoomById(roomId);
|
||||
})
|
||||
.whereType<Room>()
|
||||
.toList();
|
||||
// #Pangea
|
||||
// final joinedParents = room.spaceParents
|
||||
// .map((parent) {
|
||||
// final roomId = parent.roomId;
|
||||
// if (roomId == null) return null;
|
||||
// return room.client.getRoomById(roomId);
|
||||
// })
|
||||
// .whereType<Room>()
|
||||
// .toList();
|
||||
// Pangea#
|
||||
final filter = _filterController.text.trim().toLowerCase();
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
|
|
@ -715,51 +766,51 @@ class _SpaceViewState extends State<SpaceView> {
|
|||
),
|
||||
),
|
||||
),
|
||||
SliverList.builder(
|
||||
itemCount: joinedParents.length,
|
||||
itemBuilder: (context, i) {
|
||||
final displayname =
|
||||
joinedParents[i].getLocalizedDisplayname();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 1,
|
||||
),
|
||||
child: Material(
|
||||
borderRadius:
|
||||
BorderRadius.circular(AppConfig.borderRadius),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: ListTile(
|
||||
minVerticalPadding: 0,
|
||||
leading: Icon(
|
||||
Icons.adaptive.arrow_back_outlined,
|
||||
size: 16,
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
Avatar(
|
||||
mxContent: joinedParents[i].avatar,
|
||||
name: displayname,
|
||||
// #Pangea
|
||||
userId: joinedParents[i].directChatMatrixID,
|
||||
// Pangea#
|
||||
size: Avatar.defaultSize / 2,
|
||||
borderRadius: BorderRadius.circular(
|
||||
AppConfig.borderRadius / 4,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(child: Text(displayname)),
|
||||
],
|
||||
),
|
||||
onTap: () =>
|
||||
widget.toParentSpace(joinedParents[i].id),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// #Pangea
|
||||
// SliverList.builder(
|
||||
// itemCount: joinedParents.length,
|
||||
// itemBuilder: (context, i) {
|
||||
// final displayname =
|
||||
// joinedParents[i].getLocalizedDisplayname();
|
||||
// return Padding(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 8,
|
||||
// vertical: 1,
|
||||
// ),
|
||||
// child: Material(
|
||||
// borderRadius:
|
||||
// BorderRadius.circular(AppConfig.borderRadius),
|
||||
// clipBehavior: Clip.hardEdge,
|
||||
// child: ListTile(
|
||||
// minVerticalPadding: 0,
|
||||
// leading: Icon(
|
||||
// Icons.adaptive.arrow_back_outlined,
|
||||
// size: 16,
|
||||
// ),
|
||||
// title: Row(
|
||||
// children: [
|
||||
// Avatar(
|
||||
// mxContent: joinedParents[i].avatar,
|
||||
// name: displayname,
|
||||
// // #Pangea
|
||||
// userId: joinedParents[i].directChatMatrixID,
|
||||
// // Pangea#
|
||||
// size: Avatar.defaultSize / 2,
|
||||
// borderRadius: BorderRadius.circular(
|
||||
// AppConfig.borderRadius / 4,
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(width: 8),
|
||||
// Expanded(child: Text(displayname)),
|
||||
// ],
|
||||
// ),
|
||||
// onTap: () =>
|
||||
// widget.toParentSpace(joinedParents[i].id),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
KnockingUsersIndicator(room: room),
|
||||
// Pangea#
|
||||
SliverList.builder(
|
||||
|
|
|
|||
|
|
@ -41,7 +41,11 @@ class SettingsView extends StatelessWidget {
|
|||
// Pangea#
|
||||
return Row(
|
||||
children: [
|
||||
if (FluffyThemes.isColumnMode(context)) ...[
|
||||
// #Pangea
|
||||
// if (FluffyThemes.isColumnMode(context)) ...[
|
||||
if (FluffyThemes.isColumnMode(context) ||
|
||||
AppConfig.displayNavigationRail) ...[
|
||||
// Pangea#
|
||||
SpacesNavigationRail(
|
||||
activeSpaceId: null,
|
||||
onGoToChats: () => context.go('/rooms'),
|
||||
|
|
|
|||
|
|
@ -359,6 +359,14 @@ class SettingsStyleView extends StatelessWidget {
|
|||
storeKey: SettingKeys.separateChatTypes,
|
||||
defaultValue: AppConfig.separateChatTypes,
|
||||
),
|
||||
// #Pangea
|
||||
// SettingsSwitchListTile.adaptive(
|
||||
// title: L10n.of(context).displayNavigationRail,
|
||||
// onChanged: (b) => AppConfig.displayNavigationRail = b,
|
||||
// storeKey: SettingKeys.displayNavigationRail,
|
||||
// defaultValue: AppConfig.displayNavigationRail,
|
||||
// ),
|
||||
// Pangea#
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
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/pangea/activity_suggestions/activity_suggestions_area.dart';
|
||||
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
|
||||
import 'package:fluffychat/pangea/public_spaces/public_spaces_area.dart';
|
||||
import 'package:fluffychat/widgets/navigation_rail.dart';
|
||||
|
||||
class SuggestionsPage extends StatelessWidget {
|
||||
const SuggestionsPage({super.key});
|
||||
|
|
@ -11,24 +15,45 @@ class SuggestionsPage extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isColumnMode = FluffyThemes.isColumnMode(context);
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0,
|
||||
vertical: 16.0,
|
||||
),
|
||||
child: Column(
|
||||
spacing: 24.0,
|
||||
children: [
|
||||
if (!isColumnMode) const LearningProgressIndicators(),
|
||||
const ActivitySuggestionsArea(
|
||||
showTitle: true,
|
||||
scrollDirection: Axis.horizontal,
|
||||
return Material(
|
||||
child: SafeArea(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isColumnMode && AppConfig.displayNavigationRail) ...[
|
||||
SpacesNavigationRail(
|
||||
activeSpaceId: null,
|
||||
onGoToChats: () => context.go('/rooms'),
|
||||
onGoToSpaceId: (spaceId) =>
|
||||
context.go('/rooms?spaceId=$spaceId'),
|
||||
),
|
||||
Container(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1,
|
||||
),
|
||||
const PublicSpacesArea(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0,
|
||||
vertical: 16.0,
|
||||
),
|
||||
child: Column(
|
||||
spacing: 24.0,
|
||||
children: [
|
||||
if (!isColumnMode) const LearningProgressIndicators(),
|
||||
const ActivitySuggestionsArea(
|
||||
showTitle: true,
|
||||
scrollDirection: Axis.horizontal,
|
||||
),
|
||||
const PublicSpacesArea(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -105,147 +105,156 @@ class LearningProgressIndicatorsState
|
|||
final mxid = client.userID ?? L10n.of(context).user;
|
||||
final displayname = _profile?.displayName ?? mxid.localpart ?? mxid;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Tooltip(
|
||||
message: L10n.of(context).settings,
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () => context.go("/rooms/settings"),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 8.0,
|
||||
right: 8.0,
|
||||
),
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none, // Allow overflow
|
||||
children: [
|
||||
FutureBuilder<Profile>(
|
||||
future: client.fetchOwnProfile(),
|
||||
builder: (context, snapshot) => Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(99),
|
||||
child: Avatar(
|
||||
mxContent: snapshot.data?.avatarUrl,
|
||||
name: snapshot.data?.displayName ??
|
||||
client.userID!.localpart,
|
||||
size: 60,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -3,
|
||||
right: -3,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Theme.of(context).colorScheme.surfaceBright,
|
||||
),
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Icon(
|
||||
size: 14,
|
||||
Icons.settings_outlined,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
weight: 1000,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
spacing: 6.0,
|
||||
children: [
|
||||
Text(
|
||||
displayname,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
LearningSettingsButton(
|
||||
onTap: () => showDialog(
|
||||
context: context,
|
||||
builder: (c) => const SettingsLearning(),
|
||||
barrierDismissible: false,
|
||||
),
|
||||
l2: userL2?.langCode.toUpperCase(),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
spacing: 6.0,
|
||||
children: ConstructTypeEnum.values
|
||||
.map(
|
||||
(c) => ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(c.indicator),
|
||||
loading: _loading,
|
||||
onTap: () {
|
||||
showDialog<AnalyticsPopupWrapper>(
|
||||
context: context,
|
||||
builder: (context) => AnalyticsPopupWrapper(
|
||||
view: c,
|
||||
),
|
||||
);
|
||||
},
|
||||
indicator: c.indicator,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
MouseRegion(
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return Row(
|
||||
children: [
|
||||
Tooltip(
|
||||
message: L10n.of(context).settings,
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
showDialog<LevelBarPopup>(
|
||||
context: context,
|
||||
builder: (c) => const LevelBarPopup(),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 26,
|
||||
onTap: () => context.go("/rooms/settings"),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: 8.0,
|
||||
right: 8.0,
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
clipBehavior: Clip.none, // Allow overflow
|
||||
children: [
|
||||
Positioned(
|
||||
left: 16,
|
||||
right: 0,
|
||||
child: LearningProgressBar(
|
||||
level: _constructsModel.level,
|
||||
totalXP: _constructsModel.totalXP,
|
||||
FutureBuilder<Profile>(
|
||||
future: client.fetchOwnProfile(),
|
||||
builder: (context, snapshot) => Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(99),
|
||||
child: Avatar(
|
||||
mxContent: snapshot.data?.avatarUrl,
|
||||
name: snapshot.data?.displayName ??
|
||||
client.userID!.localpart,
|
||||
size: 60,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
child: LevelBadge(level: _constructsModel.level),
|
||||
bottom: -3,
|
||||
right: -3,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color:
|
||||
Theme.of(context).colorScheme.surfaceBright,
|
||||
),
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Icon(
|
||||
size: 14,
|
||||
Icons.settings_outlined,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
weight: 1000,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
spacing: 6.0,
|
||||
children: [
|
||||
Text(
|
||||
displayname,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
LearningSettingsButton(
|
||||
onTap: () => showDialog(
|
||||
context: context,
|
||||
builder: (c) => const SettingsLearning(),
|
||||
barrierDismissible: false,
|
||||
),
|
||||
l2: userL2?.langCode.toUpperCase(),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
spacing: 6.0,
|
||||
children: ConstructTypeEnum.values
|
||||
.map(
|
||||
(c) => ProgressIndicatorBadge(
|
||||
points: uniqueLemmas(c.indicator),
|
||||
loading: _loading,
|
||||
onTap: () {
|
||||
showDialog<AnalyticsPopupWrapper>(
|
||||
context: context,
|
||||
builder: (context) => AnalyticsPopupWrapper(
|
||||
view: c,
|
||||
),
|
||||
);
|
||||
},
|
||||
indicator: c.indicator,
|
||||
mini: constraints.maxWidth < 380,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
showDialog<LevelBarPopup>(
|
||||
context: context,
|
||||
builder: (c) => const LevelBarPopup(),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 26,
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Positioned(
|
||||
left: 16,
|
||||
right: 0,
|
||||
child: LearningProgressBar(
|
||||
level: _constructsModel.level,
|
||||
totalXP: _constructsModel.totalXP,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 0,
|
||||
child: LevelBadge(
|
||||
level: _constructsModel.level,
|
||||
mini: constraints.maxWidth < 380,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,11 @@ import 'package:fluffychat/pangea/common/widgets/pressable_button.dart';
|
|||
|
||||
class LevelBadge extends StatelessWidget {
|
||||
final int level;
|
||||
final bool mini;
|
||||
|
||||
const LevelBadge({
|
||||
required this.level,
|
||||
this.mini = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
|
|
@ -46,7 +49,7 @@ class LevelBadge extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
L10n.of(context).levelShort(level),
|
||||
mini ? "$level" : L10n.of(context).levelShort(level),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ class ProgressIndicatorBadge extends StatelessWidget {
|
|||
final int points;
|
||||
final VoidCallback onTap;
|
||||
final ProgressIndicatorEnum indicator;
|
||||
final bool mini;
|
||||
|
||||
const ProgressIndicatorBadge({
|
||||
super.key,
|
||||
|
|
@ -16,6 +17,7 @@ class ProgressIndicatorBadge extends StatelessWidget {
|
|||
required this.indicator,
|
||||
required this.loading,
|
||||
required this.points,
|
||||
this.mini = false,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -42,15 +44,17 @@ class ProgressIndicatorBadge extends StatelessWidget {
|
|||
color: indicator.color(context),
|
||||
weight: 1000,
|
||||
),
|
||||
const SizedBox(width: 4.0),
|
||||
Text(
|
||||
indicator.tooltip(context),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: indicator.color(context),
|
||||
if (!mini) ...[
|
||||
const SizedBox(width: 4.0),
|
||||
Text(
|
||||
indicator.tooltip(context),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: indicator.color(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 4.0),
|
||||
!loading
|
||||
? Text(
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class BottomNavLayout extends StatelessWidget {
|
||||
final Widget mainView;
|
||||
|
||||
const BottomNavLayout({
|
||||
super.key,
|
||||
required this.mainView,
|
||||
});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: mainView,
|
||||
bottomNavigationBar: const BottomNavBar(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BottomNavBar extends StatefulWidget {
|
||||
const BottomNavBar({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
BottomNavBarState createState() => BottomNavBarState();
|
||||
}
|
||||
|
||||
class BottomNavBarState extends State<BottomNavBar> {
|
||||
int get selectedIndex {
|
||||
final route = GoRouterState.of(context).fullPath.toString();
|
||||
if (route.contains("settings")) {
|
||||
return 2;
|
||||
}
|
||||
if (route.contains('homepage')) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void onItemTapped(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
context.go('/rooms/homepage');
|
||||
break;
|
||||
case 1:
|
||||
context.go('/rooms');
|
||||
break;
|
||||
case 2:
|
||||
context.go('/rooms/settings');
|
||||
break;
|
||||
}
|
||||
|
||||
if (mounted) setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: Theme.of(context).colorScheme.primary.withAlpha(50),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: BottomNavigationBar(
|
||||
iconSize: 16.0,
|
||||
onTap: onItemTapped,
|
||||
selectedItemColor: Theme.of(context).colorScheme.primary,
|
||||
selectedFontSize: 14.0,
|
||||
unselectedFontSize: 14.0,
|
||||
currentIndex: selectedIndex,
|
||||
items: [
|
||||
BottomNavigationBarItem(
|
||||
icon: const Icon(Icons.home_outlined),
|
||||
activeIcon: const Icon(Icons.home),
|
||||
label: L10n.of(context).home,
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: const Icon(Icons.chat_bubble_outline),
|
||||
activeIcon: const Icon(Icons.chat_bubble),
|
||||
label: L10n.of(context).chats,
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
activeIcon: const Icon(Icons.settings),
|
||||
label: L10n.of(context).settings,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -484,6 +484,12 @@ class MatrixState extends State<Matrix> with WidgetsBindingObserver {
|
|||
|
||||
AppConfig.showPresences =
|
||||
store.getBool(SettingKeys.showPresences) ?? AppConfig.showPresences;
|
||||
|
||||
// #Pangea
|
||||
AppConfig.displayNavigationRail =
|
||||
store.getBool(SettingKeys.displayNavigationRail) ??
|
||||
AppConfig.displayNavigationRail;
|
||||
// Pangea#
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ class SpacesNavigationRail extends StatelessWidget {
|
|||
.uri
|
||||
.path
|
||||
.startsWith('/rooms/settings');
|
||||
// #Pangea
|
||||
final isHomepage = GoRouter.of(context)
|
||||
.routeInformationProvider
|
||||
.value
|
||||
.uri
|
||||
.path
|
||||
.contains('homepage');
|
||||
// Pangea#
|
||||
return StreamBuilder(
|
||||
key: ValueKey(
|
||||
client.userID.toString(),
|
||||
|
|
@ -53,7 +61,12 @@ class SpacesNavigationRail extends StatelessWidget {
|
|||
.toList();
|
||||
|
||||
return SizedBox(
|
||||
width: FluffyThemes.navRailWidth,
|
||||
// #Pangea
|
||||
// width: FluffyThemes.navRailWidth,
|
||||
width: FluffyThemes.isColumnMode(context)
|
||||
? FluffyThemes.navRailWidth
|
||||
: FluffyThemes.navRailWidth * 0.75,
|
||||
// Pangea#
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
|
|
@ -61,31 +74,45 @@ class SpacesNavigationRail extends StatelessWidget {
|
|||
scrollDirection: Axis.vertical,
|
||||
// #Pangea
|
||||
// itemCount: rootSpaces.length + 2,
|
||||
itemCount: rootSpaces.length + 3,
|
||||
itemCount: rootSpaces.length + 4,
|
||||
// Pangea#
|
||||
itemBuilder: (context, i) {
|
||||
// #Pangea
|
||||
if (i == 0) {
|
||||
return NaviRailItem(
|
||||
isSelected: activeSpaceId == null && !isSettings,
|
||||
onTap: onGoToChats,
|
||||
isSelected: isHomepage,
|
||||
onTap: () => context.go("/rooms/homepage"),
|
||||
icon: const Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
// #Pangea
|
||||
// child: Icon(Icons.forum_outlined),
|
||||
child: Icon(Icons.home_outlined),
|
||||
// Pangea#
|
||||
),
|
||||
selectedIcon: const Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
// #Pangea
|
||||
// child: Icon(Icons.forum),
|
||||
child: Icon(Icons.home),
|
||||
// Pangea#
|
||||
),
|
||||
// #Pangea
|
||||
// toolTip: L10n.of(context).chats,
|
||||
toolTip: L10n.of(context).home,
|
||||
unreadBadgeFilter: (room) => true,
|
||||
);
|
||||
}
|
||||
i--;
|
||||
// Pangea#
|
||||
if (i == 0) {
|
||||
return NaviRailItem(
|
||||
// #Pangea
|
||||
// isSelected: activeSpaceId == null && !isSettings,
|
||||
isSelected:
|
||||
activeSpaceId == null && !isSettings && !isHomepage,
|
||||
// Pangea#
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue