mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
feat: adaptive navigation bar (#739)
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user