add navigation rail for laptop
This commit is contained in:
parent
5ba7e932e3
commit
6aa596177f
410
lib/main.dart
410
lib/main.dart
|
|
@ -298,20 +298,17 @@ class _LoginMainWrapperState extends State<LoginMainWrapper> {
|
||||||
class MainScreen extends StatefulWidget {
|
class MainScreen extends StatefulWidget {
|
||||||
const MainScreen({super.key});
|
const MainScreen({super.key});
|
||||||
|
|
||||||
|
static MainScreenState of(BuildContext context) =>
|
||||||
|
context.findAncestorStateOfType<MainScreenState>()!;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MainScreen> createState() => _MainScreenState();
|
MainScreenState createState() => MainScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MainScreenState extends State<MainScreen>
|
class MainScreenState extends State<MainScreen>
|
||||||
with SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
with SingleTickerProviderStateMixin, WidgetsBindingObserver {
|
||||||
final _logger = Logger('_MainScreenState');
|
final _logger = Logger('_MainScreenState');
|
||||||
final _selected = ValueNotifier<int>(0);
|
final _selected = ValueNotifier<int>(0);
|
||||||
final _destinations = <int, String>{
|
|
||||||
0: '/',
|
|
||||||
1: '/podcasts',
|
|
||||||
2: '/library',
|
|
||||||
3: '/search',
|
|
||||||
};
|
|
||||||
StreamSubscription? _urlLinkStream;
|
StreamSubscription? _urlLinkStream;
|
||||||
int _keyPressed = 0;
|
int _keyPressed = 0;
|
||||||
bool textFieldVisited = false;
|
bool textFieldVisited = false;
|
||||||
|
|
@ -320,6 +317,9 @@ class _MainScreenState extends State<MainScreen>
|
||||||
final playerScreenFocusNode = FocusScopeNode();
|
final playerScreenFocusNode = FocusScopeNode();
|
||||||
final playerBarFocusNode = FocusNode();
|
final playerBarFocusNode = FocusNode();
|
||||||
final _fancyScaffoldKey = GlobalKey<FancyScaffoldState>();
|
final _fancyScaffoldKey = GlobalKey<FancyScaffoldState>();
|
||||||
|
final routeObserver = RouteObserver();
|
||||||
|
|
||||||
|
late bool _isDesktop;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -445,7 +445,7 @@ class _MainScreenState extends State<MainScreen>
|
||||||
// Movement to navigation bar and back
|
// Movement to navigation bar and back
|
||||||
if ((event is RawKeyUpEvent && textFieldVisited) ||
|
if ((event is RawKeyUpEvent && textFieldVisited) ||
|
||||||
event is RawKeyDownEvent) {
|
event is RawKeyDownEvent) {
|
||||||
// only handl if we're running on android
|
// only handle if we're running on android
|
||||||
if (event.data is! RawKeyEventDataAndroid) return;
|
if (event.data is! RawKeyEventDataAndroid) return;
|
||||||
int keyCode = (event.data as RawKeyEventDataAndroid).keyCode;
|
int keyCode = (event.data as RawKeyEventDataAndroid).keyCode;
|
||||||
_logger.fine('KEY PRESSED: $keyCode');
|
_logger.fine('KEY PRESSED: $keyCode');
|
||||||
|
|
@ -518,108 +518,203 @@ class _MainScreenState extends State<MainScreen>
|
||||||
return playerBarFocusNode.requestFocus();
|
return playerBarFocusNode.requestFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final _destinationRoutes = <int, String>{
|
||||||
|
0: '/',
|
||||||
|
1: '/podcasts',
|
||||||
|
2: '/library',
|
||||||
|
3: '/search',
|
||||||
|
};
|
||||||
|
final _destinations = <NavigationDestination>[
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Icons.home_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.home),
|
||||||
|
label: 'Home'.i18n),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Icons.podcasts), label: 'Podcasts'.i18n),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: const Icon(Icons.library_music_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.library_music),
|
||||||
|
label: 'Library'.i18n),
|
||||||
|
NavigationDestination(icon: const Icon(Icons.search), label: 'Search'.i18n),
|
||||||
|
];
|
||||||
|
|
||||||
|
final _navigationRailDestinationRoutes = <int, String>{
|
||||||
|
0: '/',
|
||||||
|
1: '/podcasts',
|
||||||
|
2: '/library/tracks',
|
||||||
|
3: '/library/albums',
|
||||||
|
4: '/library/artists',
|
||||||
|
5: '/library/playlists',
|
||||||
|
6: '/library/history',
|
||||||
|
7: '/downloads',
|
||||||
|
8: '/settings',
|
||||||
|
};
|
||||||
|
final _navigationRailDestinations = <NavigationRailDestination>[
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.home_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.home),
|
||||||
|
label: Text('Home'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.podcasts),
|
||||||
|
label: Text('Podcasts'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.audiotrack_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.audiotrack),
|
||||||
|
label: Text('Tracks'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.album_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.album),
|
||||||
|
label: Text('Albums'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.recent_actors_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.recent_actors),
|
||||||
|
label: Text('Artists'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.playlist_play),
|
||||||
|
label: Text('Playlists'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.history),
|
||||||
|
label: Text('History'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.download_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.download),
|
||||||
|
label: Text('Downloads'.i18n),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
icon: const Icon(Icons.settings_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.settings),
|
||||||
|
label: Text('Settings'.i18n),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
void _onDestinationSelected(int s,
|
||||||
|
{bool useNavigationRailDestinations = false}) {
|
||||||
|
//Pop all routes until home screen
|
||||||
|
navigatorKey.currentState!.popUntil((route) => route.isFirst);
|
||||||
|
navigatorKey.currentState!.pushReplacementNamed(
|
||||||
|
useNavigationRailDestinations
|
||||||
|
? _navigationRailDestinationRoutes[s]!
|
||||||
|
: _destinationRoutes[s]!,
|
||||||
|
arguments: true);
|
||||||
|
|
||||||
|
if (_selected.value != s) _selected.value = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? buildBottomBar(bool isDesktop) {
|
||||||
|
if (isDesktop) return null;
|
||||||
|
if (_selected.value > _destinations.length - 1) _selected.value = 3;
|
||||||
|
return FocusScope(
|
||||||
|
node: navigationBarFocusNode,
|
||||||
|
child: ValueListenableBuilder<int>(
|
||||||
|
valueListenable: _selected,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return NavigationBar(
|
||||||
|
selectedIndex: value,
|
||||||
|
onDestinationSelected: _onDestinationSelected,
|
||||||
|
destinations: _destinations,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? _buildNavigationRail(bool isDesktop) {
|
||||||
|
if (!isDesktop) return null;
|
||||||
|
|
||||||
|
return ValueListenableBuilder(
|
||||||
|
valueListenable: _selected,
|
||||||
|
builder: (context, selected, _) {
|
||||||
|
return ExtensibleNavigationRail(
|
||||||
|
destinations: _navigationRailDestinations,
|
||||||
|
selectedIndex: selected,
|
||||||
|
onDestinationSelected: (int s) =>
|
||||||
|
_onDestinationSelected(s, useNavigationRailDestinations: true),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RawKeyboardListener(
|
return RawKeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
onKey: _handleKey,
|
onKey: _handleKey,
|
||||||
child: FancyScaffold(
|
child: LayoutBuilder(builder: (context, constraints) {
|
||||||
key: _fancyScaffoldKey,
|
// check if we're running on a desktop platform
|
||||||
bottomNavigationBar: FocusScope(
|
final isLandscape = constraints.maxWidth > constraints.maxHeight;
|
||||||
node: navigationBarFocusNode,
|
_isDesktop = isLandscape && constraints.maxWidth > 1024;
|
||||||
child: ValueListenableBuilder<int>(
|
return FancyScaffold(
|
||||||
valueListenable: _selected,
|
key: _fancyScaffoldKey,
|
||||||
builder: (context, value, _) {
|
bodyDrawer: _buildNavigationRail(_isDesktop),
|
||||||
return NavigationBar(
|
bottomNavigationBar: buildBottomBar(_isDesktop),
|
||||||
selectedIndex: value,
|
bottomPanel: PlayerBar(
|
||||||
onDestinationSelected: (int s) async {
|
focusNode: playerBarFocusNode,
|
||||||
//Pop all routes until home screen
|
onTap: () =>
|
||||||
navigatorKey.currentState!
|
_fancyScaffoldKey.currentState!.dragController.fling(),
|
||||||
.popUntil((route) => route.isFirst);
|
shouldHaveHero: false,
|
||||||
navigatorKey.currentState!.pushReplacementNamed(
|
),
|
||||||
_destinations[s]!,
|
bottomPanelHeight: 68.0,
|
||||||
arguments: true);
|
expandedPanel: FocusScope(
|
||||||
|
node: playerScreenFocusNode,
|
||||||
if (_selected.value != s) _selected.value = s;
|
|
||||||
},
|
|
||||||
destinations: <NavigationDestination>[
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.home_outlined),
|
|
||||||
selectedIcon: const Icon(Icons.home),
|
|
||||||
label: 'Home'.i18n),
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.podcasts),
|
|
||||||
label: 'Podcasts'.i18n),
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.library_music_outlined),
|
|
||||||
selectedIcon: const Icon(Icons.library_music),
|
|
||||||
label: 'Library'.i18n),
|
|
||||||
NavigationDestination(
|
|
||||||
icon: const Icon(Icons.search),
|
|
||||||
label: 'Search'.i18n),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
bottomPanel: PlayerBar(
|
|
||||||
focusNode: playerBarFocusNode,
|
|
||||||
onTap: () =>
|
|
||||||
_fancyScaffoldKey.currentState!.dragController.fling(),
|
|
||||||
shouldHaveHero: false,
|
|
||||||
),
|
|
||||||
bottomPanelHeight: 68.0,
|
|
||||||
expandedPanel: FocusScope(
|
|
||||||
node: playerScreenFocusNode,
|
|
||||||
skipTraversal: true,
|
|
||||||
canRequestFocus: true,
|
|
||||||
child: const PlayerScreen(),
|
|
||||||
),
|
|
||||||
onAnimationStatusChange: (status) {
|
|
||||||
if (status == AnimationStatus.dismissed) {
|
|
||||||
return playerBarFocusNode.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.fine('requesting focus to playerScreen');
|
|
||||||
playerScreenFocusNode.requestFocus();
|
|
||||||
},
|
|
||||||
body: Focus(
|
|
||||||
focusNode: screenFocusNode,
|
|
||||||
skipTraversal: true,
|
skipTraversal: true,
|
||||||
canRequestFocus: false,
|
canRequestFocus: true,
|
||||||
child: _MainRouteNavigator(
|
child: const PlayerScreen(),
|
||||||
navigatorKey: navigatorKey,
|
),
|
||||||
routes: {
|
onAnimationStatusChange: (status) {
|
||||||
Navigator.defaultRouteName: (context) => const HomeScreen(),
|
if (status == AnimationStatus.dismissed) {
|
||||||
'/podcasts': (context) => HomePageScreen(
|
return playerBarFocusNode.requestFocus();
|
||||||
cacheable: true,
|
}
|
||||||
channel:
|
|
||||||
const DeezerChannel(target: 'channels/podcasts'),
|
_logger.fine('requesting focus to playerScreen');
|
||||||
title: 'Podcasts'.i18n,
|
playerScreenFocusNode.requestFocus();
|
||||||
),
|
},
|
||||||
'/library': (context) => const LibraryScreen(),
|
body: Focus(
|
||||||
'/library/tracks': (context) => const LibraryTracks(),
|
focusNode: screenFocusNode,
|
||||||
'/library/albums': (context) => const LibraryAlbums(),
|
skipTraversal: true,
|
||||||
'/library/artists': (context) => const LibraryArtists(),
|
canRequestFocus: false,
|
||||||
'/library/playlists': (context) => const LibraryPlaylists(),
|
child: _MainRouteNavigator(
|
||||||
'/library/history': (context) => const HistoryScreen(),
|
observers: [routeObserver],
|
||||||
'/search': (context) => const SearchScreen(),
|
navigatorKey: navigatorKey,
|
||||||
'/settings': (context) => const SettingsScreen(),
|
routes: {
|
||||||
'/downloads': (context) => const DownloadsScreen(),
|
Navigator.defaultRouteName: (context) =>
|
||||||
},
|
const HomeScreen(),
|
||||||
))));
|
'/podcasts': (context) => HomePageScreen(
|
||||||
|
cacheable: true,
|
||||||
|
channel: const DeezerChannel(
|
||||||
|
target: 'channels/podcasts'),
|
||||||
|
title: 'Podcasts'.i18n,
|
||||||
|
),
|
||||||
|
'/library': (context) => const LibraryScreen(),
|
||||||
|
'/library/tracks': (context) => const LibraryTracks(),
|
||||||
|
'/library/albums': (context) => const LibraryAlbums(),
|
||||||
|
'/library/artists': (context) => const LibraryArtists(),
|
||||||
|
'/library/playlists': (context) =>
|
||||||
|
const LibraryPlaylists(),
|
||||||
|
'/library/history': (context) => const HistoryScreen(),
|
||||||
|
'/search': (context) => const SearchScreen(),
|
||||||
|
'/settings': (context) => const SettingsScreen(),
|
||||||
|
'/downloads': (context) => const DownloadsScreen(),
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hella simple null-safe reimplementation of custom_navigator, which is NOT null-safe
|
// hella simple null-safe reimplementation of custom_navigator, which is NOT null-safe
|
||||||
class _MainRouteNavigator extends StatefulWidget {
|
class _MainRouteNavigator extends StatefulWidget {
|
||||||
final Map<String, WidgetBuilder> routes;
|
final Map<String, WidgetBuilder> routes;
|
||||||
final Map<String, RouteFactory>? customRoutes;
|
|
||||||
final GlobalKey<NavigatorState> navigatorKey;
|
final GlobalKey<NavigatorState> navigatorKey;
|
||||||
|
final List<NavigatorObserver> observers;
|
||||||
const _MainRouteNavigator({
|
const _MainRouteNavigator({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.routes,
|
required this.routes,
|
||||||
this.customRoutes,
|
|
||||||
required this.navigatorKey,
|
required this.navigatorKey,
|
||||||
|
this.observers = const <NavigatorObserver>[],
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -630,6 +725,7 @@ class _MainRouteNavigatorState extends State<_MainRouteNavigator>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -658,6 +754,7 @@ class _MainRouteNavigatorState extends State<_MainRouteNavigator>
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Navigator(
|
return Navigator(
|
||||||
|
observers: widget.observers,
|
||||||
key: widget.navigatorKey,
|
key: widget.navigatorKey,
|
||||||
initialRoute: Navigator.defaultRouteName,
|
initialRoute: Navigator.defaultRouteName,
|
||||||
onGenerateRoute: _onGenerateRoute,
|
onGenerateRoute: _onGenerateRoute,
|
||||||
|
|
@ -687,80 +784,155 @@ class _MainRouteNavigatorState extends State<_MainRouteNavigator>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ExtensibleNavigationRail extends StatefulWidget {
|
||||||
|
final List<NavigationRailDestination> destinations;
|
||||||
|
final int selectedIndex;
|
||||||
|
final void Function(int)? onDestinationSelected;
|
||||||
|
const ExtensibleNavigationRail({
|
||||||
|
super.key,
|
||||||
|
required this.destinations,
|
||||||
|
required this.selectedIndex,
|
||||||
|
this.onDestinationSelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ExtensibleNavigationRail> createState() =>
|
||||||
|
_ExtensibleNavigationRailState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExtensibleNavigationRailState extends State<ExtensibleNavigationRail> {
|
||||||
|
bool _extended = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
onEnter: (_) => setState(() => _extended = true),
|
||||||
|
onExit: (_) => setState(() => _extended = false),
|
||||||
|
child: NavigationRail(
|
||||||
|
extended: _extended,
|
||||||
|
destinations: widget.destinations,
|
||||||
|
selectedIndex: widget.selectedIndex,
|
||||||
|
onDestinationSelected: widget.onDestinationSelected,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// class FreezerDrawer extends StatelessWidget {
|
// class FreezerDrawer extends StatelessWidget {
|
||||||
// const FreezerDrawer({Key? key}) : super(key: key);
|
// final double? width;
|
||||||
//
|
// const FreezerDrawer({super.key, this.width});
|
||||||
|
//
|
||||||
// @override
|
// @override
|
||||||
// Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
// return Drawer(
|
// return NavigationDrawer(
|
||||||
// child: ListView(children: [
|
// onDestinationSelected: print,
|
||||||
|
// children: [
|
||||||
// const DrawerHeader(child: FreezerTitle()),
|
// const DrawerHeader(child: FreezerTitle()),
|
||||||
|
// NavigationDrawerDestination(
|
||||||
|
// icon: const Icon(Icons.home_outlined),
|
||||||
|
// selectedIcon: const Icon(Icons.home),
|
||||||
|
// label: Text('Home'.i18n)),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Home'.i18n, icon: Icon(Icons.home), route: '/'),
|
// title: 'Home'.i18n,
|
||||||
// Divider(),
|
// icon: const Icon(Icons.home),
|
||||||
|
// route: Navigator.defaultRouteName),
|
||||||
|
// const Divider(),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Tracks'.i18n,
|
// title: 'Tracks'.i18n,
|
||||||
// icon: Icon(Icons.audiotrack),
|
// icon: const Icon(Icons.audiotrack),
|
||||||
// route: '/library/tracks'),
|
// route: '/library/tracks'),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Albums'.i18n,
|
// title: 'Albums'.i18n,
|
||||||
// icon: Icon(Icons.album),
|
// icon: const Icon(Icons.album),
|
||||||
// route: '/library/albums'),
|
// route: '/library/albums'),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Artists'.i18n,
|
// title: 'Artists'.i18n,
|
||||||
// icon: Icon(Icons.recent_actors),
|
// icon: const Icon(Icons.recent_actors),
|
||||||
// route: '/library/artists'),
|
// route: '/library/artists'),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Playlists'.i18n,
|
// title: 'Playlists'.i18n,
|
||||||
// icon: Icon(Icons.playlist_play),
|
// icon: const Icon(Icons.playlist_play),
|
||||||
// route: '/library/playlists'),
|
// route: '/library/playlists'),
|
||||||
// Divider(),
|
// const Divider(),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Downloads'.i18n,
|
// title: 'Downloads'.i18n,
|
||||||
// icon: Icon(Icons.download),
|
// icon: const Icon(Icons.download),
|
||||||
// route: '/downloads'),
|
// route: '/downloads'),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'History'.i18n,
|
// title: 'History'.i18n,
|
||||||
// icon: Icon(Icons.history),
|
// icon: const Icon(Icons.history),
|
||||||
// route: '/library/history'),
|
// route: '/library/history'),
|
||||||
// FreezerDrawerTile(
|
// FreezerDrawerTile(
|
||||||
// title: 'Settings'.i18n,
|
// title: 'Settings'.i18n,
|
||||||
// icon: Icon(Icons.settings),
|
// icon: const Icon(Icons.settings),
|
||||||
// route: '/settings'),
|
// route: '/settings'),
|
||||||
// ]),
|
// ],
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// class FreezerDrawerTile extends StatelessWidget {
|
// class FreezerDrawerTile extends StatefulWidget {
|
||||||
// final Widget? icon;
|
// final Widget? icon;
|
||||||
// final String title;
|
// final String title;
|
||||||
// final String route;
|
// final String route;
|
||||||
// const FreezerDrawerTile(
|
// const FreezerDrawerTile(
|
||||||
// {Key? key, this.icon, required this.title, required this.route})
|
// {Key? key, this.icon, required this.title, required this.route})
|
||||||
// : super(key: key);
|
// : super(key: key);
|
||||||
//
|
//
|
||||||
|
// @override
|
||||||
|
// State<FreezerDrawerTile> createState() => _FreezerDrawerTileState();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// class _FreezerDrawerTileState extends State<FreezerDrawerTile> with RouteAware {
|
||||||
|
// bool _isHighlighted = false;
|
||||||
|
// late final RouteObserver _routeObserver;
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// void didChangeDependencies() {
|
||||||
|
// _routeObserver = MainScreen.of(context).routeObserver;
|
||||||
|
// _routeObserver.subscribe(this, ModalRoute.of(context)!);
|
||||||
|
// super.didChangeDependencies();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// void dispose() {
|
||||||
|
// _routeObserver.unsubscribe(this);
|
||||||
|
// super.dispose();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// void didPushNext() => _update();
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// void didPopNext() => _update();
|
||||||
|
//
|
||||||
|
// void _update() {
|
||||||
|
// final highlighted = ModalRoute.of(context)?.settings.name == widget.route;
|
||||||
|
//
|
||||||
|
// if (highlighted != _isHighlighted) {
|
||||||
|
// setState(() => _isHighlighted = highlighted);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
// @override
|
// @override
|
||||||
// Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
// print(route);
|
|
||||||
// return Padding(
|
// return Padding(
|
||||||
// padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
// padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
// child: Material(
|
// child: Material(
|
||||||
// borderRadius: BorderRadius.circular(8.0),
|
// borderRadius: BorderRadius.circular(8.0),
|
||||||
// clipBehavior: Clip.antiAlias,
|
// clipBehavior: Clip.antiAlias,
|
||||||
// color: ModalRoute.of(context)?.settings.name == route
|
// color: _isHighlighted
|
||||||
// ? Theme.of(context).brightness == Brightness.dark
|
// ? Theme.of(context).brightness == Brightness.dark
|
||||||
// ? Colors.white12
|
// ? Colors.white12
|
||||||
// : Colors.black12
|
// : Colors.black12
|
||||||
// : null,
|
// : null,
|
||||||
// child: ListTile(
|
// child: ListTile(
|
||||||
// selected: ModalRoute.of(context)?.settings.name == route,
|
// selected: _isHighlighted,
|
||||||
// leading: icon,
|
// leading: widget.icon,
|
||||||
// visualDensity: VisualDensity.compact,
|
// visualDensity: VisualDensity.compact,
|
||||||
// title: Text(title),
|
// title: Text(widget.title),
|
||||||
// onTap: () {
|
// onTap: () {
|
||||||
// Navigator.of(context).pop();
|
// navigatorKey.currentState!.pushReplacementNamed(widget.route);
|
||||||
// navigatorKey.currentState!.pushReplacementNamed(route);
|
|
||||||
// }),
|
// }),
|
||||||
// ),
|
// ),
|
||||||
// );
|
// );
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ class FancyScaffold extends StatefulWidget {
|
||||||
final Widget bottomPanel;
|
final Widget bottomPanel;
|
||||||
final double bottomPanelHeight;
|
final double bottomPanelHeight;
|
||||||
final Widget expandedPanel;
|
final Widget expandedPanel;
|
||||||
final Widget bottomNavigationBar;
|
final Widget? bottomNavigationBar;
|
||||||
|
final Widget? drawer;
|
||||||
|
final Widget? bodyDrawer;
|
||||||
final Widget body;
|
final Widget body;
|
||||||
final void Function(AnimationStatus)? onAnimationStatusChange;
|
final void Function(AnimationStatus)? onAnimationStatusChange;
|
||||||
|
|
||||||
|
|
@ -21,9 +23,11 @@ class FancyScaffold extends StatefulWidget {
|
||||||
required this.bottomPanel,
|
required this.bottomPanel,
|
||||||
required this.bottomPanelHeight,
|
required this.bottomPanelHeight,
|
||||||
required this.expandedPanel,
|
required this.expandedPanel,
|
||||||
required this.bottomNavigationBar,
|
|
||||||
required this.body,
|
required this.body,
|
||||||
this.onAnimationStatusChange,
|
this.onAnimationStatusChange,
|
||||||
|
this.bottomNavigationBar,
|
||||||
|
this.bodyDrawer,
|
||||||
|
this.drawer,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -61,7 +65,8 @@ class FancyScaffoldState extends State<FancyScaffold>
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final systemPadding = MediaQuery.of(context).viewPadding;
|
final systemPadding = MediaQuery.of(context).viewPadding;
|
||||||
final defaultBottomPadding = 80.0 + systemPadding.bottom;
|
final defaultBottomPadding =
|
||||||
|
(widget.bottomNavigationBar == null ? 0 : 80.0) + systemPadding.bottom;
|
||||||
final screenHeight = MediaQuery.of(context).size.height;
|
final screenHeight = MediaQuery.of(context).size.height;
|
||||||
final sizeAnimation = Tween<double>(
|
final sizeAnimation = Tween<double>(
|
||||||
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
|
begin: widget.bottomPanelHeight / MediaQuery.of(context).size.height,
|
||||||
|
|
@ -81,17 +86,24 @@ class FancyScaffoldState extends State<FancyScaffold>
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
body: widget.body,
|
body: widget.bodyDrawer != null
|
||||||
|
? Row(children: [
|
||||||
|
widget.bodyDrawer!,
|
||||||
|
Expanded(child: widget.body)
|
||||||
|
])
|
||||||
|
: widget.body,
|
||||||
|
drawer: widget.drawer,
|
||||||
bottomNavigationBar: Column(
|
bottomNavigationBar: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: widget.bottomPanelHeight),
|
SizedBox(height: widget.bottomPanelHeight),
|
||||||
SizeTransition(
|
if (widget.bottomNavigationBar != null)
|
||||||
axisAlignment: -1.0,
|
SizeTransition(
|
||||||
sizeFactor:
|
axisAlignment: -1.0,
|
||||||
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
|
sizeFactor:
|
||||||
child: widget.bottomNavigationBar,
|
Tween(begin: 1.0, end: 0.0).animate(sizeAnimation),
|
||||||
),
|
child: widget.bottomNavigationBar,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -754,9 +754,11 @@ packages:
|
||||||
just_audio_media_kit:
|
just_audio_media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "../just_audio_media_kit"
|
path: "."
|
||||||
relative: true
|
ref: HEAD
|
||||||
source: path
|
resolved-ref: "8ccec63c67c0c206c6df3570e46f60b2a45dbb24"
|
||||||
|
url: "https://github.com/Pato05/just_audio_media_kit.git"
|
||||||
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
just_audio_platform_interface:
|
just_audio_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,8 @@ dependencies:
|
||||||
isar: ^3.1.0+1
|
isar: ^3.1.0+1
|
||||||
isar_flutter_libs: ^3.1.0+1
|
isar_flutter_libs: ^3.1.0+1
|
||||||
flutter_background_service: ^5.0.1
|
flutter_background_service: ^5.0.1
|
||||||
|
#deezcryptor:
|
||||||
|
#path: deezcryptor/
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue