mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
v2 Roadmap: Responsive navigation added
for three different breakpoints
This commit is contained in:
parent
a86b6bc40b
commit
5b389564c1
@ -1,26 +1,24 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart' hide Page;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:oauth2/oauth2.dart' show AuthorizationException;
|
||||
import 'package:spotify/spotify.dart' hide Image, Player, Search;
|
||||
|
||||
import 'package:spotube/components/Category/CategoryCard.dart';
|
||||
import 'package:spotube/components/Home/Sidebar.dart';
|
||||
import 'package:spotube/components/Home/SpotubeNavigationBar.dart';
|
||||
import 'package:spotube/components/Login.dart';
|
||||
import 'package:spotube/components/Lyrics.dart';
|
||||
import 'package:spotube/components/Search/Search.dart';
|
||||
import 'package:spotube/components/Shared/PageWindowTitleBar.dart';
|
||||
import 'package:spotube/components/Player/Player.dart';
|
||||
import 'package:spotube/components/Settings.dart';
|
||||
import 'package:spotube/components/Library/UserLibrary.dart';
|
||||
import 'package:spotube/components/Shared/SpotubePageRoute.dart';
|
||||
import 'package:spotube/helpers/image-to-url-string.dart';
|
||||
import 'package:spotube/helpers/oauth-login.dart';
|
||||
import 'package:spotube/models/LocalStorageKeys.dart';
|
||||
import 'package:spotube/models/sideBarTiles.dart';
|
||||
import 'package:spotube/provider/Auth.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
@ -135,10 +133,14 @@ class _HomeState extends ConsumerState<Home> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
_onSelectedIndexChanged(int index) => setState(() {
|
||||
_selectedIndex = index;
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Auth auth = ref.watch(authProvider);
|
||||
SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
if (!auth.isLoggedIn) {
|
||||
return const Login();
|
||||
}
|
||||
@ -153,7 +155,12 @@ class _HomeState extends ConsumerState<Home> {
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
constraints: const BoxConstraints(maxWidth: 256),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: width > 400 && width <= 700
|
||||
? 72
|
||||
: width > 700
|
||||
? 256
|
||||
: 0),
|
||||
color:
|
||||
Theme.of(context).navigationRailTheme.backgroundColor,
|
||||
child: MoveWindow(),
|
||||
@ -168,76 +175,9 @@ class _HomeState extends ConsumerState<Home> {
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
NavigationRail(
|
||||
destinations: sidebarTileList
|
||||
.map((e) => NavigationRailDestination(
|
||||
icon: Icon(e.icon),
|
||||
label: Text(
|
||||
e.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
Sidebar(
|
||||
selectedIndex: _selectedIndex,
|
||||
onDestinationSelected: (value) => setState(() {
|
||||
_selectedIndex = value;
|
||||
}),
|
||||
extended: true,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Row(children: [
|
||||
Image.asset(
|
||||
"assets/spotube-logo.png",
|
||||
height: 50,
|
||||
width: 50,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text("Spotube",
|
||||
style: Theme.of(context).textTheme.headline4),
|
||||
]),
|
||||
),
|
||||
trailing: FutureBuilder<User>(
|
||||
future: spotify.me.get(),
|
||||
builder: (context, snapshot) {
|
||||
var avatarImg = imageToUrlString(snapshot.data?.images,
|
||||
index: (snapshot.data?.images?.length ?? 1) - 1);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundImage:
|
||||
CachedNetworkImageProvider(avatarImg),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
snapshot.data?.displayName ?? "User's name",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(SpotubePageRoute(
|
||||
child: const Settings(),
|
||||
));
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
onSelectedIndexChanged: _onSelectedIndexChanged,
|
||||
),
|
||||
// contents of the spotify
|
||||
if (_selectedIndex == 0)
|
||||
@ -261,7 +201,11 @@ class _HomeState extends ConsumerState<Home> {
|
||||
),
|
||||
),
|
||||
// player itself
|
||||
const Player()
|
||||
const Player(),
|
||||
SpotubeNavigationBar(
|
||||
selectedIndex: _selectedIndex,
|
||||
onSelectedIndexChanged: _onSelectedIndexChanged,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
120
lib/components/Home/Sidebar.dart
Normal file
120
lib/components/Home/Sidebar.dart
Normal file
@ -0,0 +1,120 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotify/spotify.dart' hide Image;
|
||||
import 'package:spotube/components/Settings.dart';
|
||||
import 'package:spotube/components/Shared/SpotubePageRoute.dart';
|
||||
import 'package:spotube/helpers/image-to-url-string.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
import '../../models/sideBarTiles.dart';
|
||||
|
||||
class Sidebar extends HookConsumerWidget {
|
||||
final int selectedIndex;
|
||||
final void Function(int) onSelectedIndexChanged;
|
||||
|
||||
const Sidebar({
|
||||
required this.selectedIndex,
|
||||
required this.onSelectedIndexChanged,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
Widget _buildSmallLogo() {
|
||||
return Image.asset(
|
||||
"assets/spotube-logo.png",
|
||||
height: 50,
|
||||
width: 50,
|
||||
);
|
||||
}
|
||||
|
||||
void _goToSettings(BuildContext context) {
|
||||
Navigator.of(context).push(SpotubePageRoute(
|
||||
child: const Settings(),
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
if (width <= 400) return Container();
|
||||
final extended = useState(false);
|
||||
final SpotifyApi spotify = ref.watch(spotifyProvider);
|
||||
useEffect(() {
|
||||
if (width <= 700 && extended.value) {
|
||||
extended.value = false;
|
||||
} else if (width > 700 && !extended.value) {
|
||||
extended.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
return NavigationRail(
|
||||
destinations: sidebarTileList
|
||||
.map((e) => NavigationRailDestination(
|
||||
icon: Icon(e.icon),
|
||||
label: Text(
|
||||
e.title,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
selectedIndex: selectedIndex,
|
||||
onDestinationSelected: onSelectedIndexChanged,
|
||||
extended: extended.value,
|
||||
leading: extended.value
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Row(children: [
|
||||
_buildSmallLogo(),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text("Spotube", style: Theme.of(context).textTheme.headline4),
|
||||
]),
|
||||
)
|
||||
: _buildSmallLogo(),
|
||||
trailing: FutureBuilder<User>(
|
||||
future: spotify.me.get(),
|
||||
builder: (context, snapshot) {
|
||||
var avatarImg = imageToUrlString(snapshot.data?.images,
|
||||
index: (snapshot.data?.images?.length ?? 1) - 1);
|
||||
return extended.value
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundImage:
|
||||
CachedNetworkImageProvider(avatarImg),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
snapshot.data?.displayName ?? "User's name",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.settings_outlined),
|
||||
onPressed: () => _goToSettings(context)),
|
||||
],
|
||||
))
|
||||
: InkWell(
|
||||
onTap: () => _goToSettings(context),
|
||||
child: CircleAvatar(
|
||||
backgroundImage: CachedNetworkImageProvider(avatarImg),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
30
lib/components/Home/SpotubeNavigationBar.dart
Normal file
30
lib/components/Home/SpotubeNavigationBar.dart
Normal file
@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:spotube/models/sideBarTiles.dart';
|
||||
|
||||
class SpotubeNavigationBar extends HookWidget {
|
||||
final int selectedIndex;
|
||||
final void Function(int) onSelectedIndexChanged;
|
||||
|
||||
const SpotubeNavigationBar({
|
||||
required this.selectedIndex,
|
||||
required this.onSelectedIndexChanged,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
|
||||
if (width > 400) return Container();
|
||||
return NavigationBar(
|
||||
destinations: sidebarTileList
|
||||
.map(
|
||||
(e) => NavigationDestination(icon: Icon(e.icon), label: e.title),
|
||||
)
|
||||
.toList(),
|
||||
selectedIndex: selectedIndex,
|
||||
onDestinationSelected: onSelectedIndexChanged,
|
||||
);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ void main() async {
|
||||
await hotKeyManager.unregisterAll();
|
||||
runApp(ProviderScope(child: MyApp()));
|
||||
doWhenWindowReady(() {
|
||||
appWindow.minSize = const Size(900, 700);
|
||||
appWindow.minSize = const Size(280, 700);
|
||||
appWindow.size = const Size(900, 700);
|
||||
appWindow.alignment = Alignment.center;
|
||||
appWindow.maximize();
|
||||
@ -88,6 +88,10 @@ class MyApp extends HookConsumerWidget {
|
||||
color: Colors.grey[850],
|
||||
),
|
||||
),
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
backgroundColor: Colors.blueGrey[50],
|
||||
height: 55,
|
||||
),
|
||||
cardTheme: CardTheme(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
@ -122,6 +126,10 @@ class MyApp extends HookConsumerWidget {
|
||||
backgroundColor: Colors.blueGrey[800],
|
||||
unselectedIconTheme: const IconThemeData(opacity: 1),
|
||||
),
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
backgroundColor: Colors.blueGrey[800],
|
||||
height: 55,
|
||||
),
|
||||
cardTheme: CardTheme(
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
|
Loading…
Reference in New Issue
Block a user