Skip to content

Commit

Permalink
feat: add download tab on library
Browse files Browse the repository at this point in the history
Addition of download badge in sidebar and navbar library icon
Fix SpotubeMarqueeText behavior using auto_size_text
  • Loading branch information
KRTirtho committed Aug 19, 2022
1 parent a23ce61 commit 8d77b69
Show file tree
Hide file tree
Showing 13 changed files with 376 additions and 156 deletions.
2 changes: 0 additions & 2 deletions lib/components/Home/Home.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:io';

import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:flutter/material.dart' hide Page;
import 'package:flutter/services.dart';
Expand Down
43 changes: 31 additions & 12 deletions lib/components/Home/Sidebar.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:badges/badges.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
Expand All @@ -8,6 +9,7 @@ import 'package:spotube/hooks/useBreakpointValue.dart';
import 'package:spotube/hooks/useBreakpoints.dart';
import 'package:spotube/models/sideBarTiles.dart';
import 'package:spotube/provider/Auth.dart';
import 'package:spotube/provider/Downloader.dart';
import 'package:spotube/provider/SpotifyRequests.dart';
import 'package:spotube/utils/platform.dart';
import 'package:spotube/utils/type_conversion_utils.dart';
Expand Down Expand Up @@ -40,6 +42,9 @@ class Sidebar extends HookConsumerWidget {
final extended = useState(false);
final meSnapshot = ref.watch(currentUserQuery);
final auth = ref.watch(authProvider);
final downloadCount = ref.watch(
downloaderProvider.select((s) => s.currentlyRunning),
);

final int titleBarDragMaxWidth = useBreakpointValue(
md: 80,
Expand Down Expand Up @@ -90,20 +95,34 @@ class Sidebar extends HookConsumerWidget {
),
Expanded(
child: NavigationRail(
destinations: sidebarTileList
.map(
(e) => NavigationRailDestination(
icon: Icon(e.icon),
label: Text(
e.title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
destinations: sidebarTileList.map(
(e) {
final icon = Icon(e.icon);
return NavigationRailDestination(
icon: e.title == "Library" && downloadCount > 0
? Badge(
badgeColor: Colors.red[100]!,
badgeContent: Text(
downloadCount.toString(),
style: const TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
animationType: BadgeAnimationType.fade,
child: icon,
)
: icon,
label: Text(
e.title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
)
.toList(),
);
},
).toList(),
selectedIndex: selectedIndex,
onDestinationSelected: onSelectedIndexChanged,
extended: extended.value,
Expand Down
31 changes: 28 additions & 3 deletions lib/components/Home/SpotubeNavigationBar.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotube/components/Home/Sidebar.dart';
import 'package:spotube/hooks/useBreakpoints.dart';
import 'package:spotube/models/sideBarTiles.dart';
import 'package:spotube/provider/Downloader.dart';

class SpotubeNavigationBar extends HookWidget {
class SpotubeNavigationBar extends HookConsumerWidget {
final int selectedIndex;
final void Function(int) onSelectedIndexChanged;

Expand All @@ -15,14 +18,36 @@ class SpotubeNavigationBar extends HookWidget {
}) : super(key: key);

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, ref) {
final downloadCount = ref.watch(
downloaderProvider.select((s) => s.currentlyRunning),
);
final breakpoint = useBreakpoints();

if (breakpoint.isMoreThan(Breakpoints.sm)) return Container();
return NavigationBar(
destinations: [
...sidebarTileList.map(
(e) => NavigationDestination(icon: Icon(e.icon), label: e.title),
(e) {
final icon = Icon(e.icon);
return NavigationDestination(
icon: e.title == "Library" && downloadCount > 0
? Badge(
badgeColor: Colors.red[100]!,
badgeContent: Text(
downloadCount.toString(),
style: const TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
animationType: BadgeAnimationType.fade,
child: icon,
)
: icon,
label: e.title,
);
},
),
const NavigationDestination(
icon: Icon(Icons.settings_rounded),
Expand Down
83 changes: 83 additions & 0 deletions lib/components/Library/UserDownloads.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/provider/Downloader.dart';
import 'package:spotube/utils/type_conversion_utils.dart';

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

@override
Widget build(BuildContext context, ref) {
final downloader = ref.watch(downloaderProvider);

final inQueue = downloader.inQueue.toList();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: AutoSizeText(
"Currently downloading (${downloader.currentlyRunning})",
maxLines: 1,
style: Theme.of(context).textTheme.headline5,
),
),
const SizedBox(width: 10),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red[50],
onPrimary: Colors.red[400],
),
child: const Text("Cancel All"),
onPressed: downloader.currentlyRunning > 0
? downloader.cancelAll
: null,
),
],
),
),
ListView.builder(
itemCount: inQueue.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final track = inQueue[index];
return ListTile(
title: Text(track.name!),
leading: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
height: 40,
width: 40,
imageUrl: TypeConversionUtils.image_X_UrlString(
track.album?.images,
),
),
),
),
trailing: const SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator.adaptive(),
),
horizontalTitleGap: 5,
subtitle: Text(
TypeConversionUtils.artists_X_String<Artist>(
track.artists ?? [],
),
),
);
},
),
],
);
}
}
5 changes: 4 additions & 1 deletion lib/components/Library/UserLibrary.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart' hide Image;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotube/components/Library/UserAlbums.dart';
import 'package:spotube/components/Library/UserArtists.dart';
import 'package:spotube/components/Library/UserDownloads.dart';
import 'package:spotube/components/Library/UserPlaylists.dart';
import 'package:spotube/components/Shared/AnonymousFallback.dart';
import 'package:spotube/provider/Auth.dart';
Expand All @@ -14,7 +15,7 @@ class UserLibrary extends ConsumerWidget {

return Expanded(
child: DefaultTabController(
length: 3,
length: 4,
child: SafeArea(
child: Scaffold(
appBar: TabBar(
Expand All @@ -26,13 +27,15 @@ class UserLibrary extends ConsumerWidget {
Tab(text: "Playlist"),
Tab(text: "Artists"),
Tab(text: "Album"),
Tab(text: "Downloads"),
],
),
body: auth.isLoggedIn
? TabBarView(children: [
const UserPlaylists(),
UserArtists(),
const UserAlbums(),
const UserDownloads(),
])
: const AnonymousFallback(),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/components/Shared/PlaybuttonCard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class PlaybuttonCard extends StatelessWidget {
text: title,
style:
const TextStyle(fontWeight: FontWeight.bold),
minStartLength: 25,
minStartLength: 20,
isHovering: isHovering,
),
),
Expand Down
58 changes: 22 additions & 36 deletions lib/components/Shared/SpotubeMarqueeText.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:marquee/marquee.dart';
import 'package:spotube/utils/platform.dart';

class SpotubeMarqueeText extends HookWidget {
final int? minStartLength;
Expand All @@ -18,46 +18,32 @@ class SpotubeMarqueeText extends HookWidget {

@override
Widget build(BuildContext context) {
final hovering = useState(false);
final isInitial = useState(true);
final uKey = useState(UniqueKey());

useEffect(() {
if (isHovering != null && isHovering != hovering.value) {
hovering.value = isHovering!;
}
return null;
uKey.value = UniqueKey();
return;
}, [isHovering]);

if ((!isInitial.value && !hovering.value && kIsDesktop) ||
minStartLength != null && text.length <= minStartLength!) {
return Text(
text,
style: style,
overflow: TextOverflow.ellipsis,
);
}

return Marquee(
text: text,
return AutoSizeText(
text,
minFontSize: 13,
style: style,
scrollAxis: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.start,
blankSpace: 40.0,
velocity: 30.0,
accelerationDuration: const Duration(seconds: 1),
accelerationCurve: Curves.linear,
decelerationDuration: const Duration(milliseconds: 500),
decelerationCurve: Curves.easeOut,
fadingEdgeStartFraction: 0.15,
fadingEdgeEndFraction: 0.15,
showFadingOnlyWhenScrolling: true,
onDone: () {
if (isInitial.value) {
isInitial.value = false;
hovering.value = false;
}
},
numberOfRounds: hovering.value ? null : 1,
overflowReplacement: Marquee(
key: uKey.value,
text: text,
style: style,
scrollAxis: Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.start,
blankSpace: 40.0,
velocity: 30.0,
accelerationDuration: const Duration(seconds: 1),
accelerationCurve: Curves.linear,
decelerationDuration: const Duration(milliseconds: 500),
decelerationCurve: Curves.easeOut,
showFadingOnlyWhenScrolling: true,
numberOfRounds: isHovering == true ? null : 1,
),
);
}
}
16 changes: 8 additions & 8 deletions lib/components/Shared/TrackTile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,15 @@ class TrackTile extends HookConsumerWidget {
Checkbox(
value: isChecked,
onChanged: (s) => onCheckChange?.call(s),
)
else
SizedBox(
height: 20,
width: 25,
child: Center(
child: Text((track.key + 1).toString()),
),
),
SizedBox(
height: 20,
width: 15,
child: Text(
(track.key + 1).toString(),
textAlign: TextAlign.center,
),
),
if (thumbnailUrl != null)
Padding(
padding: EdgeInsets.symmetric(
Expand Down
24 changes: 10 additions & 14 deletions lib/components/Shared/TracksTableView.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,23 +132,11 @@ class TracksTableView extends HookConsumerWidget {
return const DownloadConfirmationDialog();
});
if (isConfirmed != true) return;
final queue = Queue(
delay: const Duration(seconds: 5),
);
for (final selectedTrack in selectedTracks) {
queue.add(() async {
downloader.addToQueue(
await playback.toSpotubeTrack(
selectedTrack,
noSponsorBlock: true,
),
);
});
downloader.addToQueue(selectedTrack);
}

selected.value = [];
showCheck.value = false;
await queue.onComplete;
break;
}
default:
Expand All @@ -171,7 +159,15 @@ class TracksTableView extends HookConsumerWidget {
},
onTap: () {
if (showCheck.value) {
selected.value = [...selected.value, track.value.id!];
final alreadyChecked =
selected.value.contains(track.value.id);
if (alreadyChecked) {
selected.value = selected.value
.where((id) => id != track.value.id)
.toList();
} else {
selected.value = [...selected.value, track.value.id!];
}
} else {
onTrackPlayButtonPressed?.call(track.value);
}
Expand Down
Loading

0 comments on commit 8d77b69

Please sign in to comment.