Skip to content

Commit

Permalink
feat: implemented go_route shell/nested route
Browse files Browse the repository at this point in the history
BRIEF DESCRIPTION:
- Nested Routes like React-Router/Spotify Web/desktop
- Except Login routes everything is nested and wrapped by a Shell
- PlayerOverlay is no more a overlay
A really simple Sidebar now
  • Loading branch information
KRTirtho committed Oct 10, 2022
1 parent 25e6b23 commit 3e498a4
Show file tree
Hide file tree
Showing 24 changed files with 691 additions and 567 deletions.
4 changes: 2 additions & 2 deletions lib/components/Album/AlbumCard.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Shared/PlaybuttonCard.dart';
import 'package:spotube/hooks/useBreakpointValue.dart';
import 'package:spotube/models/CurrentPlaylist.dart';
import 'package:spotube/provider/Playback.dart';
import 'package:spotube/provider/SpotifyDI.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

class AlbumCard extends HookConsumerWidget {
Expand All @@ -33,7 +33,7 @@ class AlbumCard extends HookConsumerWidget {
description:
"Album • ${TypeConversionUtils.artists_X_String<ArtistSimple>(album.artists ?? [])}",
onTap: () {
GoRouter.of(context).push("/album/${album.id}", extra: album);
ServiceUtils.navigate(context, "/album/${album.id}", extra: album);
},
onPlaybuttonPressed: () async {
SpotifyApi spotify = ref.read(spotifyProvider);
Expand Down
4 changes: 2 additions & 2 deletions lib/components/Artist/ArtistCard.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Shared/HoverBuilder.dart';
import 'package:spotube/components/Shared/UniversalImage.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

class ArtistCard extends StatelessWidget {
Expand All @@ -23,7 +23,7 @@ class ArtistCard extends StatelessWidget {
width: 200,
child: InkWell(
onTap: () {
GoRouter.of(context).push("/artist/${artist.id}");
ServiceUtils.navigate(context, "/artist/${artist.id}");
},
borderRadius: BorderRadius.circular(10),
child: HoverBuilder(builder: (context, isHovering) {
Expand Down
64 changes: 64 additions & 0 deletions lib/components/Home/Genres.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import 'package:fl_query_hooks/fl_query_hooks.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/components/Category/CategoryCard.dart';
import 'package:spotube/components/LoaderShimmers/ShimmerCategories.dart';
import 'package:spotube/components/Shared/Waypoint.dart';
import 'package:spotube/provider/SpotifyDI.dart';
import 'package:spotube/provider/SpotifyRequests.dart';
import 'package:spotube/provider/UserPreferences.dart';

class Genres extends HookConsumerWidget {
const Genres({Key? key}) : super(key: key);

@override
Widget build(BuildContext context, ref) {
final spotify = ref.watch(spotifyProvider);
final recommendationMarket = ref.watch(
userPreferencesProvider.select((s) => s.recommendationMarket),
);
final categoriesQuery = useInfiniteQuery(
job: categoriesQueryJob,
externalData: {
"spotify": spotify,
"recommendationMarket": recommendationMarket,
},
);
final categories = [
useMemoized(
() => Category()
..id = "user-featured-playlists"
..name = "Featured",
[],
),
...categoriesQuery.pages
.expand<Category?>(
(page) => page?.items ?? const Iterable.empty(),
)
.toList()
];

return Scaffold(
body: ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
final category = categories[index];
if (category == null) return Container();
if (index == categories.length - 1) {
return Waypoint(
onEnter: () {
if (categoriesQuery.hasNextPage) {
categoriesQuery.fetchNextPage();
}
},
child: const ShimmerCategories(),
);
}
return CategoryCard(category);
},
),
);
}
}
106 changes: 106 additions & 0 deletions lib/components/Home/Shell.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/Home/Sidebar.dart';
import 'package:spotube/components/Home/SpotubeNavigationBar.dart';
import 'package:spotube/components/Player/Player.dart';
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
import 'package:spotube/components/Shared/ReplaceDownloadedFileDialog.dart';
import 'package:spotube/hooks/useUpdateChecker.dart';
import 'package:spotube/provider/Downloader.dart';

const _path = {
0: "/",
1: "/search",
2: "/library",
3: "/lyrics",
};

class Shell extends HookConsumerWidget {
final Widget child;
const Shell({
required this.child,
Key? key,
}) : super(key: key);

@override
Widget build(BuildContext context, ref) {
final index = useState(0);
final isMounted = useIsMounted();

final downloader = ref.watch(downloaderProvider);
useEffect(() {
downloader.onFileExists = (track) async {
if (!isMounted()) return false;
return await showDialog<bool>(
context: context,
builder: (context) => ReplaceDownloadedFileDialog(
track: track,
),
) ??
false;
};
return null;
}, [downloader]);

// checks for latest version of the application
useUpdateChecker(ref);

final backgroundColor = Theme.of(context).backgroundColor;

useEffect(() {
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: backgroundColor, // status bar color
statusBarIconBrightness: backgroundColor.computeLuminance() > 0.179
? Brightness.dark
: Brightness.light,
),
);
return null;
}, [backgroundColor]);

const pageWindowTitleBar = PageWindowTitleBar();
return Scaffold(
primary: true,
appBar: _path.values.contains(GoRouter.of(context).location)
? pageWindowTitleBar
: null,
extendBodyBehindAppBar: true,
body: Row(
children: [
Sidebar(
selectedIndex: index.value,
onSelectedIndexChanged: (selectedIndex) {
index.value = selectedIndex;
GoRouter.of(context).go(_path[selectedIndex]!);
},
),
Expanded(
child: Column(
children: [
Expanded(child: child),
],
),
),
],
),
extendBody: true,
bottomNavigationBar: Column(
mainAxisSize: MainAxisSize.min,
children: [
Player(),
SpotubeNavigationBar(
selectedIndex: index.value,
onSelectedIndexChanged: (selectedIndex) {
index.value = selectedIndex;
GoRouter.of(context).go(_path[selectedIndex]!);
},
),
],
),
);
}
}
76 changes: 41 additions & 35 deletions lib/components/Home/Sidebar.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:badges/badges.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:flutter/material.dart';
import 'package:spotube/components/Shared/UniversalImage.dart';
Expand All @@ -12,6 +11,7 @@ import 'package:spotube/provider/Downloader.dart';
import 'package:spotube/provider/SpotifyRequests.dart';
import 'package:spotube/provider/UserPreferences.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/service_utils.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

final sidebarExtendedStateProvider = StateProvider<bool?>((ref) => null);
Expand All @@ -35,7 +35,7 @@ class Sidebar extends HookConsumerWidget {
}

static void goToSettings(BuildContext context) {
GoRouter.of(context).push("/settings");
ServiceUtils.navigate(context, "/settings");
}

@override
Expand Down Expand Up @@ -78,46 +78,52 @@ class Sidebar extends HookConsumerWidget {
!(forceExtended ?? extended.value);

return SafeArea(
top: false,
child: Material(
color: Theme.of(context).navigationRailTheme.backgroundColor,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (selectedIndex == 3 && kIsDesktop)
if (kIsDesktop)
SizedBox(
height: appWindow.titleBarHeight,
width: extended.value ? 256 : 80,
child: MoveWindow(),
child: MoveWindow(
child: !extended.value
? Center(
child: IconButton(
icon: const Icon(Icons.menu_rounded),
onPressed: toggleExtended,
),
)
: null,
),
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: (extended.value)
? Row(
children: [
_buildSmallLogo(),
const SizedBox(
width: 10,
),
Text(
"Spotube",
style: Theme.of(context).textTheme.headline4,
),
IconButton(
icon: const Icon(Icons.menu_rounded),
onPressed: toggleExtended,
),
],
)
: Column(
children: [
IconButton(
icon: const Icon(Icons.menu_rounded),
onPressed: toggleExtended,
),
_buildSmallLogo(),
],
),
),
if (!kIsDesktop && !extended.value)
Center(
child: IconButton(
icon: const Icon(Icons.menu_rounded),
onPressed: toggleExtended,
),
),
(extended.value)
? Row(
children: [
_buildSmallLogo(),
const SizedBox(
width: 10,
),
Text(
"Spotube",
style: Theme.of(context).textTheme.headline4,
),
IconButton(
icon: const Icon(Icons.menu_rounded),
onPressed: toggleExtended,
),
],
)
: _buildSmallLogo(),
Expanded(
child: NavigationRail(
destinations: sidebarTileList.map(
Expand Down Expand Up @@ -166,7 +172,7 @@ class Sidebar extends HookConsumerWidget {
);
if (extended.value) {
return Padding(
padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16).copyWith(left: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expand Down
46 changes: 22 additions & 24 deletions lib/components/Library/UserLibrary.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,30 @@ class UserLibrary extends ConsumerWidget {
const UserLibrary({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, ref) {
return Expanded(
child: DefaultTabController(
length: 5,
child: SafeArea(
child: Scaffold(
appBar: ColoredTabBar(
color: Theme.of(context).backgroundColor,
child: const TabBar(
isScrollable: true,
tabs: [
Tab(text: "Playlist"),
Tab(text: "Downloads"),
Tab(text: "Local"),
Tab(text: "Artists"),
Tab(text: "Album"),
],
),
return DefaultTabController(
length: 5,
child: SafeArea(
child: Scaffold(
appBar: ColoredTabBar(
color: Theme.of(context).backgroundColor,
child: const TabBar(
isScrollable: true,
tabs: [
Tab(text: "Playlist"),
Tab(text: "Downloads"),
Tab(text: "Local"),
Tab(text: "Artists"),
Tab(text: "Album"),
],
),
body: const TabBarView(children: [
AnonymousFallback(child: UserPlaylists()),
UserDownloads(),
UserLocalTracks(),
AnonymousFallback(child: UserArtists()),
AnonymousFallback(child: UserAlbums()),
]),
),
body: const TabBarView(children: [
AnonymousFallback(child: UserPlaylists()),
UserDownloads(),
UserLocalTracks(),
AnonymousFallback(child: UserArtists()),
AnonymousFallback(child: UserAlbums()),
]),
),
),
);
Expand Down
Loading

0 comments on commit 3e498a4

Please sign in to comment.