💄 New navigation draft (skip ci)
This commit is contained in:
		@@ -322,6 +322,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
 | 
			
		||||
      if (!mounted) return;
 | 
			
		||||
      final ud = context.read<UserDirectoryProvider>();
 | 
			
		||||
      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('[Bootstrap] Everything initialized!');
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ class NavigationProvider extends ChangeNotifier {
 | 
			
		||||
    'home',
 | 
			
		||||
    'explore',
 | 
			
		||||
    'chat',
 | 
			
		||||
    'account',
 | 
			
		||||
    'realm',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  List<AppNavDestination> destinations = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,13 @@ class SnRealmProvider {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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 {
 | 
			
		||||
    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:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:gap/gap.dart';
 | 
			
		||||
import 'package:go_router/go_router.dart';
 | 
			
		||||
import 'package:material_symbols_icons/symbols.dart';
 | 
			
		||||
import 'package:provider/provider.dart';
 | 
			
		||||
import 'package:styled_widget/styled_widget.dart';
 | 
			
		||||
import 'package:surface/providers/config.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';
 | 
			
		||||
 | 
			
		||||
class AppNavigationDrawer extends StatefulWidget {
 | 
			
		||||
@@ -25,12 +29,15 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    WidgetsBinding.instance.addPostFrameCallback((_) {
 | 
			
		||||
      context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context));
 | 
			
		||||
      context
 | 
			
		||||
          .read<NavigationProvider>()
 | 
			
		||||
          .autoDetectIndex(GoRouter.maybeOf(context));
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final ua = context.read<UserProvider>();
 | 
			
		||||
    final nav = context.watch<NavigationProvider>();
 | 
			
		||||
    final cfg = context.watch<ConfigProvider>();
 | 
			
		||||
 | 
			
		||||
@@ -39,58 +46,101 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
 | 
			
		||||
    return ListenableBuilder(
 | 
			
		||||
      listenable: nav,
 | 
			
		||||
      builder: (context, _) {
 | 
			
		||||
        final destinations = [
 | 
			
		||||
          ...nav.destinations.where((ele) => ele.isPinned),
 | 
			
		||||
          ...nav.destinations.where((ele) => !ele.isPinned),
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return NavigationDrawer(
 | 
			
		||||
        return Drawer(
 | 
			
		||||
          elevation: widget.elevation,
 | 
			
		||||
          backgroundColor: backgroundColor,
 | 
			
		||||
          selectedIndex: nav.currentIndex,
 | 
			
		||||
          children: [
 | 
			
		||||
            if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && !cfg.drawerIsExpanded)
 | 
			
		||||
              Container(
 | 
			
		||||
                decoration: BoxDecoration(
 | 
			
		||||
                  border: Border(
 | 
			
		||||
                    bottom: BorderSide(
 | 
			
		||||
                      color: Theme.of(context).dividerColor,
 | 
			
		||||
                      width: 1 / MediaQuery.of(context).devicePixelRatio,
 | 
			
		||||
          child: Column(
 | 
			
		||||
            mainAxisSize: MainAxisSize.max,
 | 
			
		||||
            crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
            children: [
 | 
			
		||||
              if (!kIsWeb &&
 | 
			
		||||
                  (Platform.isWindows ||
 | 
			
		||||
                      Platform.isLinux ||
 | 
			
		||||
                      Platform.isMacOS) &&
 | 
			
		||||
                  !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(
 | 
			
		||||
              mainAxisSize: MainAxisSize.min,
 | 
			
		||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
              children: [
 | 
			
		||||
                Text('Solar Network').bold(),
 | 
			
		||||
                AppVersionLabel(),
 | 
			
		||||
              ],
 | 
			
		||||
            ).padding(
 | 
			
		||||
              horizontal: 32,
 | 
			
		||||
              vertical: 12,
 | 
			
		||||
            ),
 | 
			
		||||
            ...destinations.where((ele) => ele.isPinned).map((ele) {
 | 
			
		||||
              return NavigationDrawerDestination(
 | 
			
		||||
                icon: ele.icon,
 | 
			
		||||
                label: Text(ele.label).tr(),
 | 
			
		||||
              );
 | 
			
		||||
            }),
 | 
			
		||||
            const Divider(),
 | 
			
		||||
            ...destinations.where((ele) => !ele.isPinned).map((ele) {
 | 
			
		||||
              return NavigationDrawerDestination(
 | 
			
		||||
                icon: ele.icon,
 | 
			
		||||
                label: Text(ele.label).tr(),
 | 
			
		||||
              );
 | 
			
		||||
            }),
 | 
			
		||||
          ],
 | 
			
		||||
          onDestinationSelected: (idx) {
 | 
			
		||||
            nav.setIndex(idx);
 | 
			
		||||
            GoRouter.of(context).goNamed(destinations[idx].screen);
 | 
			
		||||
            Scaffold.of(context).closeDrawer();
 | 
			
		||||
          },
 | 
			
		||||
              Expanded(
 | 
			
		||||
                child: ListView(),
 | 
			
		||||
              ),
 | 
			
		||||
              Row(
 | 
			
		||||
                spacing: 8,
 | 
			
		||||
                children: nav.destinations.where((ele) => ele.isPinned).map(
 | 
			
		||||
                  (ele) {
 | 
			
		||||
                    return Expanded(
 | 
			
		||||
                      child: IconButton.filledTonal(
 | 
			
		||||
                        icon: ele.icon,
 | 
			
		||||
                        color: Theme.of(context).colorScheme.onPrimaryContainer,
 | 
			
		||||
                        onPressed: () {
 | 
			
		||||
                          GoRouter.of(context).goNamed(ele.screen);
 | 
			
		||||
                          Scaffold.of(context).closeDrawer();
 | 
			
		||||
                        },
 | 
			
		||||
                      ),
 | 
			
		||||
                    );
 | 
			
		||||
                  },
 | 
			
		||||
                ).toList(),
 | 
			
		||||
              ).padding(horizontal: 16),
 | 
			
		||||
              Align(
 | 
			
		||||
                alignment: Alignment.bottomCenter,
 | 
			
		||||
                child: ListTile(
 | 
			
		||||
                  contentPadding: EdgeInsets.symmetric(horizontal: 24),
 | 
			
		||||
                  leading: AccountImage(content: ua.user?.avatar),
 | 
			
		||||
                  title: Text(ua.user?.nick ?? 'unknown').tr().fontSize(15),
 | 
			
		||||
                  subtitle:
 | 
			
		||||
                      Text('@${ua.user?.name ?? 'unknown'.tr()}').fontSize(13),
 | 
			
		||||
                  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/widgets/connection_indicator.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_rail_navigation.dart';
 | 
			
		||||
import 'package:surface/widgets/notify_indicator.dart';
 | 
			
		||||
@@ -118,10 +117,6 @@ class AppRootScaffold extends StatelessWidget {
 | 
			
		||||
        .last
 | 
			
		||||
        .route
 | 
			
		||||
        .name;
 | 
			
		||||
    final isShowBottomNavigation =
 | 
			
		||||
        NavigationProvider.kShowBottomNavScreen.contains(routeName)
 | 
			
		||||
            ? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
 | 
			
		||||
            : false;
 | 
			
		||||
    final isPopable = !NavigationProvider.kAllDestination
 | 
			
		||||
        .map((ele) => ele.screen)
 | 
			
		||||
        .contains(routeName);
 | 
			
		||||
@@ -232,8 +227,6 @@ class AppRootScaffold extends StatelessWidget {
 | 
			
		||||
      ),
 | 
			
		||||
      drawer: !isExpandedDrawer ? AppNavigationDrawer() : null,
 | 
			
		||||
      drawerEdgeDragWidth: isPopable ? 0 : null,
 | 
			
		||||
      bottomNavigationBar:
 | 
			
		||||
          isShowBottomNavigation ? AppBottomNavigationBar() : null,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user