feat: adaptive navigation bar (#739)

This commit is contained in:
Noo6
2025-04-22 11:19:19 +08:00
committed by GitHub
parent 6e7fee20b8
commit ede238c647
3 changed files with 132 additions and 55 deletions

View File

@@ -56,7 +56,41 @@ enum AppTab {
}; };
} }
NavigationRailDestination get navRailDestination {
return switch (this) {
server => NavigationRailDestination(
icon: const Icon(BoxIcons.bx_server),
label: Text(l10n.server),
selectedIcon: const Icon(BoxIcons.bxs_server),
),
// settings => NavigationRailDestination(
// icon: const Icon(Icons.settings),
// label: libL10n.setting,
// selectedIcon: const Icon(Icons.settings),
// ),
ssh => const NavigationRailDestination(
icon: Icon(Icons.terminal_outlined),
label: Text('SSH'),
selectedIcon: Icon(Icons.terminal),
),
snippet => NavigationRailDestination(
icon: const Icon(Icons.code),
label: Text(l10n.snippet),
selectedIcon: const Icon(Icons.code),
),
file => NavigationRailDestination(
icon: const Icon(Icons.folder_open),
label: Text(libL10n.file),
selectedIcon: const Icon(Icons.folder),
),
};
}
static List<NavigationDestination> get navDestinations { static List<NavigationDestination> get navDestinations {
return AppTab.values.map((e) => e.navDestination).toList(); return AppTab.values.map((e) => e.navDestination).toList();
} }
static List<NavigationRailDestination> get navRailDestinations {
return AppTab.values.map((e) => e.navRailDestination).toList();
}
} }

View File

@@ -1,5 +1,6 @@
import 'package:fl_lib/fl_lib.dart'; import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
import 'package:server_box/core/chan.dart'; import 'package:server_box/core/chan.dart';
import 'package:server_box/data/model/app/tab.dart'; import 'package:server_box/data/model/app/tab.dart';
import 'package:server_box/data/provider/app.dart'; import 'package:server_box/data/provider/app.dart';
@@ -26,7 +27,6 @@ class _HomePageState extends State<HomePage>
late final PageController _pageController; late final PageController _pageController;
final _selectIndex = ValueNotifier(0); final _selectIndex = ValueNotifier(0);
final _isLandscape = ValueNotifier(false);
bool _switchingPage = false; bool _switchingPage = false;
bool _shouldAuth = false; bool _shouldAuth = false;
@@ -40,7 +40,6 @@ class _HomePageState extends State<HomePage>
WakelockPlus.disable(); WakelockPlus.disable();
_selectIndex.dispose(); _selectIndex.dispose();
_isLandscape.dispose();
} }
@override @override
@@ -58,13 +57,6 @@ class _HomePageState extends State<HomePage>
} }
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_isLandscape.value =
MediaQuery.of(context).orientation == Orientation.landscape;
}
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state); super.didChangeAppLifecycleState(state);
@@ -102,7 +94,35 @@ class _HomePageState extends State<HomePage>
AppProvider.ctx = context; AppProvider.ctx = context;
final sysPadding = MediaQuery.of(context).padding; final sysPadding = MediaQuery.of(context).padding;
return Scaffold( return ColoredBox(
color: context.theme.colorScheme.surface,
child: AdaptiveLayout(
transitionDuration: const Duration(milliseconds: 250),
primaryNavigation: SlotLayout(
config: {
Breakpoints.medium: SlotLayout.from(
key: const Key('primaryNavigation'),
builder: (context) => _buildRailBar(),
),
Breakpoints.mediumLarge: SlotLayout.from(
key: const Key('MediumLarge primaryNavigation'),
builder: (context) => _buildRailBar(extended: true),
),
Breakpoints.large: SlotLayout.from(
key: const Key('Large primaryNavigation'),
builder: (context) => _buildRailBar(extended: true),
),
Breakpoints.extraLarge: SlotLayout.from(
key: const Key('ExtraLarge primaryNavigation'),
builder: (context) => _buildRailBar(extended: true),
),
},
),
body: SlotLayout(
config: {
Breakpoint.standard(): SlotLayout.from(
key: const Key('body'),
builder: (context) => Scaffold(
appBar: _AppBar(sysPadding.top), appBar: _AppBar(sysPadding.top),
body: PageView.builder( body: PageView.builder(
controller: _pageController, controller: _pageController,
@@ -116,42 +136,50 @@ class _HomePageState extends State<HomePage>
} }
}, },
), ),
bottomNavigationBar: ValBuilder( ),
listenable: _isLandscape, ),
builder: (ls) {
return Stores.setting.fullScreen.fetch()
? UIs.placeholder
: ListenableBuilder(
listenable: _selectIndex,
builder: (_, __) => _buildBottomBar(ls),
);
}, },
), ),
bottomNavigation: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(
key: const Key('bottomNavigation'),
builder: (context) => ListenableBuilder(
listenable: _selectIndex,
builder: (context, child) => _buildBottomBar(),
),
),
},
),
),
); );
} }
Widget _buildBottomBar(bool ls) { Widget _buildBottomBar() {
return NavigationBar( return ListenableBuilder(
listenable: _selectIndex,
builder: (context, child) => NavigationBar(
selectedIndex: _selectIndex.value, selectedIndex: _selectIndex.value,
height: kBottomNavigationBarHeight * (ls ? 0.75 : 1.1), height: kBottomNavigationBarHeight * 1.1,
animationDuration: const Duration(milliseconds: 250), animationDuration: const Duration(milliseconds: 250),
onDestinationSelected: (int index) { onDestinationSelected: _onDestinationSelected,
if (_selectIndex.value == index) return; labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
_selectIndex.value = index;
_switchingPage = true;
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 677),
curve: Curves.fastLinearToSlowEaseIn,
);
Future.delayed(const Duration(milliseconds: 677), () {
_switchingPage = false;
});
},
labelBehavior: ls
? NavigationDestinationLabelBehavior.alwaysHide
: NavigationDestinationLabelBehavior.onlyShowSelected,
destinations: AppTab.navDestinations, destinations: AppTab.navDestinations,
),
);
}
Widget _buildRailBar({bool extended = false}) {
return ListenableBuilder(
listenable: _selectIndex,
builder: (context, child) => AdaptiveScaffold.standardNavigationRail(
extended: extended,
padding: EdgeInsets.zero,
selectedIndex: _selectIndex.value,
destinations: AppTab.navRailDestinations,
onDestinationSelected: _onDestinationSelected,
labelType: extended ? null : NavigationRailLabelType.selected,
),
); );
} }
@@ -207,4 +235,18 @@ class _HomePageState extends State<HomePage>
); );
} }
} }
void _onDestinationSelected(int index) {
if (_selectIndex.value == index) return;
_selectIndex.value = index;
_switchingPage = true;
_pageController.animateToPage(
index,
duration: const Duration(milliseconds: 677),
curve: Curves.fastLinearToSlowEaseIn,
);
Future.delayed(const Duration(milliseconds: 677), () {
_switchingPage = false;
});
}
} }

View File

@@ -59,6 +59,7 @@ dependencies:
git: git:
url: https://github.com/lppcg/fl_lib url: https://github.com/lppcg/fl_lib
ref: v1.0.263 ref: v1.0.263
flutter_adaptive_scaffold: ^0.3.2
dependency_overrides: dependency_overrides:
# webdav_client_plus: # webdav_client_plus: