💄 New navigation draft (skip ci)

This commit is contained in:
LittleSheep 2025-03-22 12:48:55 +08:00
parent 152872db65
commit f356e08f79
5 changed files with 108 additions and 55 deletions

@ -322,6 +322,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
if (!mounted) return; if (!mounted) return;
final ud = context.read<UserDirectoryProvider>(); final ud = context.read<UserDirectoryProvider>();
final userCacheSize = await ud.loadAccountCache(); final userCacheSize = await ud.loadAccountCache();
if (!mounted) return;
final rm = context.read<SnRealmProvider>();
await rm.refreshAvailableRealms();
logging.info('[Users] Loaded local user cache, size: $userCacheSize'); logging.info('[Users] Loaded local user cache, size: $userCacheSize');
logging.info('[Bootstrap] Everything initialized!'); logging.info('[Bootstrap] Everything initialized!');
} catch (err) { } catch (err) {

@ -88,7 +88,7 @@ class NavigationProvider extends ChangeNotifier {
'home', 'home',
'explore', 'explore',
'chat', 'chat',
'account', 'realm',
]; ];
List<AppNavDestination> destinations = []; List<AppNavDestination> destinations = [];

@ -11,6 +11,13 @@ class SnRealmProvider {
} }
final Map<String, SnRealm> _cache = {}; final Map<String, SnRealm> _cache = {};
List<SnRealm> _availableRealms = List.empty(growable: true);
Future<void> refreshAvailableRealms() async {
_availableRealms = await listAvailableRealms();
}
List<SnRealm> get availableRealms => _availableRealms;
Future<List<SnRealm>> listAvailableRealms() async { Future<List<SnRealm>> listAvailableRealms() async {
final resp = await _sn.client.get('/cgi/id/realms/me/available'); final resp = await _sn.client.get('/cgi/id/realms/me/available');

@ -4,11 +4,15 @@ import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/config.dart'; import 'package:surface/providers/config.dart';
import 'package:surface/providers/navigation.dart'; import 'package:surface/providers/navigation.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/version_label.dart'; import 'package:surface/widgets/version_label.dart';
class AppNavigationDrawer extends StatefulWidget { class AppNavigationDrawer extends StatefulWidget {
@ -25,12 +29,15 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context)); context
.read<NavigationProvider>()
.autoDetectIndex(GoRouter.maybeOf(context));
}); });
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ua = context.read<UserProvider>();
final nav = context.watch<NavigationProvider>(); final nav = context.watch<NavigationProvider>();
final cfg = context.watch<ConfigProvider>(); final cfg = context.watch<ConfigProvider>();
@ -39,58 +46,101 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
return ListenableBuilder( return ListenableBuilder(
listenable: nav, listenable: nav,
builder: (context, _) { builder: (context, _) {
final destinations = [ return Drawer(
...nav.destinations.where((ele) => ele.isPinned),
...nav.destinations.where((ele) => !ele.isPinned),
];
return NavigationDrawer(
elevation: widget.elevation, elevation: widget.elevation,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
selectedIndex: nav.currentIndex, child: Column(
children: [ mainAxisSize: MainAxisSize.max,
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && !cfg.drawerIsExpanded) crossAxisAlignment: CrossAxisAlignment.start,
Container( children: [
decoration: BoxDecoration( if (!kIsWeb &&
border: Border( (Platform.isWindows ||
bottom: BorderSide( Platform.isLinux ||
color: Theme.of(context).dividerColor, Platform.isMacOS) &&
width: 1 / MediaQuery.of(context).devicePixelRatio, !cfg.drawerIsExpanded)
Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / MediaQuery.of(context).devicePixelRatio,
),
), ),
), ),
child: WindowTitleBarBox(),
), ),
child: WindowTitleBarBox(), Gap(MediaQuery.of(context).padding.top),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Solar Network').bold(),
AppVersionLabel(),
],
).padding(
horizontal: 32,
vertical: 12,
), ),
Column( Expanded(
mainAxisSize: MainAxisSize.min, child: ListView(),
crossAxisAlignment: CrossAxisAlignment.start, ),
children: [ Row(
Text('Solar Network').bold(), spacing: 8,
AppVersionLabel(), children: nav.destinations.where((ele) => ele.isPinned).map(
], (ele) {
).padding( return Expanded(
horizontal: 32, child: IconButton.filledTonal(
vertical: 12, icon: ele.icon,
), color: Theme.of(context).colorScheme.onPrimaryContainer,
...destinations.where((ele) => ele.isPinned).map((ele) { onPressed: () {
return NavigationDrawerDestination( GoRouter.of(context).goNamed(ele.screen);
icon: ele.icon, Scaffold.of(context).closeDrawer();
label: Text(ele.label).tr(), },
); ),
}), );
const Divider(), },
...destinations.where((ele) => !ele.isPinned).map((ele) { ).toList(),
return NavigationDrawerDestination( ).padding(horizontal: 16),
icon: ele.icon, Align(
label: Text(ele.label).tr(), alignment: Alignment.bottomCenter,
); child: ListTile(
}), contentPadding: EdgeInsets.symmetric(horizontal: 24),
], leading: AccountImage(content: ua.user?.avatar),
onDestinationSelected: (idx) { title: Text(ua.user?.nick ?? 'unknown').tr().fontSize(15),
nav.setIndex(idx); subtitle:
GoRouter.of(context).goNamed(destinations[idx].screen); Text('@${ua.user?.name ?? 'unknown'.tr()}').fontSize(13),
Scaffold.of(context).closeDrawer(); trailing: Row(
}, mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Symbols.notifications, fill: 1),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
GoRouter.of(context).pushNamed('notification');
Scaffold.of(context).closeDrawer();
},
),
IconButton(
icon: const Icon(Symbols.settings, fill: 1),
padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact,
onPressed: () {
GoRouter.of(context).pushNamed('settings');
Scaffold.of(context).closeDrawer();
},
),
],
),
onTap: () {
GoRouter.of(context).pushNamed('account');
Scaffold.of(context).closeDrawer();
},
),
),
Gap(MediaQuery.of(context).padding.bottom),
],
),
); );
}, },
); );

@ -12,7 +12,6 @@ import 'package:surface/providers/config.dart';
import 'package:surface/providers/navigation.dart'; import 'package:surface/providers/navigation.dart';
import 'package:surface/widgets/connection_indicator.dart'; import 'package:surface/widgets/connection_indicator.dart';
import 'package:surface/widgets/navigation/app_background.dart'; import 'package:surface/widgets/navigation/app_background.dart';
import 'package:surface/widgets/navigation/app_bottom_navigation.dart';
import 'package:surface/widgets/navigation/app_drawer_navigation.dart'; import 'package:surface/widgets/navigation/app_drawer_navigation.dart';
import 'package:surface/widgets/navigation/app_rail_navigation.dart'; import 'package:surface/widgets/navigation/app_rail_navigation.dart';
import 'package:surface/widgets/notify_indicator.dart'; import 'package:surface/widgets/notify_indicator.dart';
@ -118,10 +117,6 @@ class AppRootScaffold extends StatelessWidget {
.last .last
.route .route
.name; .name;
final isShowBottomNavigation =
NavigationProvider.kShowBottomNavScreen.contains(routeName)
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false;
final isPopable = !NavigationProvider.kAllDestination final isPopable = !NavigationProvider.kAllDestination
.map((ele) => ele.screen) .map((ele) => ele.screen)
.contains(routeName); .contains(routeName);
@ -232,8 +227,6 @@ class AppRootScaffold extends StatelessWidget {
), ),
drawer: !isExpandedDrawer ? AppNavigationDrawer() : null, drawer: !isExpandedDrawer ? AppNavigationDrawer() : null,
drawerEdgeDragWidth: isPopable ? 0 : null, drawerEdgeDragWidth: isPopable ? 0 : null,
bottomNavigationBar:
isShowBottomNavigation ? AppBottomNavigationBar() : null,
); );
} }
} }