refactor: track page

This commit is contained in:
Kingkor Roy Tirtho 2025-01-05 16:32:14 +06:00
parent dd0bb01af5
commit b734985199
3 changed files with 112 additions and 80 deletions

View File

@ -110,7 +110,6 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
backgroundColor: context.theme.colorScheme.card, backgroundColor: context.theme.colorScheme.card,
builder: (context) { builder: (context) {
return ListView.builder( return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: childrenModified.length, itemCount: childrenModified.length,
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) {

View File

@ -1,10 +1,10 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart' hide Page;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart'; import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotify/spotify.dart' hide Offset; import 'package:spotify/spotify.dart' hide Offset;
@ -69,16 +69,20 @@ class TrackOptions extends HookConsumerWidget {
void actionShare(BuildContext context, Track track) { void actionShare(BuildContext context, Track track) {
final data = "https://open.spotify.com/track/${track.id}"; final data = "https://open.spotify.com/track/${track.id}";
Clipboard.setData(ClipboardData(text: data)).then((_) { Clipboard.setData(ClipboardData(text: data)).then((_) {
ScaffoldMessenger.of(context).showSnackBar( if (context.mounted) {
SnackBar( showToast(
width: 300, context: context,
behavior: SnackBarBehavior.floating, location: ToastLocation.topRight,
content: Text( builder: (context, overlay) {
context.l10n.copied_to_clipboard(data), return SurfaceCard(
textAlign: TextAlign.center, child: Text(
), context.l10n.copied_to_clipboard(data),
), textAlign: TextAlign.center,
); ),
);
},
);
}
}); });
} }
@ -161,7 +165,6 @@ class TrackOptions extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final scaffoldMessenger = ScaffoldMessenger.of(context);
final mediaQuery = MediaQuery.of(context); final mediaQuery = MediaQuery.of(context);
final router = GoRouter.of(context); final router = GoRouter.of(context);
final ThemeData(:colorScheme) = Theme.of(context); final ThemeData(:colorScheme) = Theme.of(context);
@ -220,36 +223,57 @@ class TrackOptions extends HookConsumerWidget {
case TrackOptionValue.addToQueue: case TrackOptionValue.addToQueue:
await playback.addTrack(track); await playback.addTrack(track);
if (context.mounted) { if (context.mounted) {
scaffoldMessenger.showSnackBar( showToast(
SnackBar( context: context,
content: Text( location: ToastLocation.topRight,
context.l10n.added_track_to_queue(track.name!), builder: (context, overlay) {
), return SurfaceCard(
), child: Text(
context.l10n.added_track_to_queue(track.name!),
textAlign: TextAlign.center,
),
);
},
); );
} }
break; break;
case TrackOptionValue.playNext: case TrackOptionValue.playNext:
playback.addTracksAtFirst([track]); playback.addTracksAtFirst([track]);
scaffoldMessenger.showSnackBar(
SnackBar( if (context.mounted) {
content: Text( showToast(
context.l10n.track_will_play_next(track.name!), context: context,
), location: ToastLocation.topRight,
), builder: (context, overlay) {
); return SurfaceCard(
child: Text(
context.l10n.track_will_play_next(track.name!),
textAlign: TextAlign.center,
),
);
},
);
}
break; break;
case TrackOptionValue.removeFromQueue: case TrackOptionValue.removeFromQueue:
playback.removeTrack(track.id!); playback.removeTrack(track.id!);
scaffoldMessenger.showSnackBar(
SnackBar( if (context.mounted) {
content: Text( showToast(
context.l10n.removed_track_from_queue( context: context,
track.name!, location: ToastLocation.topRight,
), builder: (context, overlay) {
), return SurfaceCard(
), child: Text(
); context.l10n.removed_track_from_queue(
track.name!,
),
textAlign: TextAlign.center,
),
);
},
);
}
break; break;
case TrackOptionValue.favorite: case TrackOptionValue.favorite:
favorites.toggleTrackLike(track); favorites.toggleTrackLike(track);
@ -286,7 +310,10 @@ class TrackOptions extends HookConsumerWidget {
case TrackOptionValue.details: case TrackOptionValue.details:
showDialog( showDialog(
context: context, context: context,
builder: (context) => TrackDetailsDialog(track: track), builder: (context) => ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 400),
child: TrackDetailsDialog(track: track),
),
); );
break; break;
case TrackOptionValue.download: case TrackOptionValue.download:
@ -299,8 +326,7 @@ class TrackOptions extends HookConsumerWidget {
}, },
icon: icon ?? const Icon(SpotubeIcons.moreHorizontal), icon: icon ?? const Icon(SpotubeIcons.moreHorizontal),
headings: [ headings: [
ListTile( Basic(
dense: true,
leading: AspectRatio( leading: AspectRatio(
aspectRatio: 1, aspectRatio: 1,
child: ClipRRect( child: ClipRRect(
@ -316,8 +342,7 @@ class TrackOptions extends HookConsumerWidget {
track.name!, track.name!,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleMedium, ).semiBold(),
),
subtitle: Align( subtitle: Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: ArtistLink( child: ArtistLink(
@ -449,7 +474,7 @@ class TrackOptions extends HookConsumerWidget {
leading: Assets.logos.songlinkTransparent.image( leading: Assets.logos.songlinkTransparent.image(
width: 22, width: 22,
height: 22, height: 22,
color: colorScheme.onSurface.withOpacity(0.5), color: colorScheme.foreground.withOpacity(0.5),
), ),
child: Text(context.l10n.song_link), child: Text(context.l10n.song_link),
), ),
@ -471,11 +496,6 @@ class TrackOptions extends HookConsumerWidget {
adaptivePopSheetList.showDropdownMenu(context, offsetFromRect); adaptivePopSheetList.showDropdownMenu(context, offsetFromRect);
}; };
return ListTileTheme( return adaptivePopSheetList;
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: adaptivePopSheetList,
);
} }
} }

View File

@ -1,8 +1,8 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:skeletonizer/skeletonizer.dart'; import 'package:skeletonizer/skeletonizer.dart';
import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/fake.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
@ -32,7 +32,7 @@ class TrackPage extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, ref) { Widget build(BuildContext context, ref) {
final ThemeData(:textTheme, :colorScheme) = Theme.of(context); final ThemeData(:typography, :colorScheme) = Theme.of(context);
final mediaQuery = MediaQuery.of(context); final mediaQuery = MediaQuery.of(context);
final playlist = ref.watch(audioPlayerProvider); final playlist = ref.watch(audioPlayerProvider);
@ -53,12 +53,15 @@ class TrackPage extends HookConsumerWidget {
} }
return Scaffold( return Scaffold(
appBar: const TitleBar( headers: const [
automaticallyImplyLeading: true, TitleBar(
backgroundColor: Colors.transparent, automaticallyImplyLeading: true,
), backgroundColor: Colors.transparent,
extendBodyBehindAppBar: true, surfaceBlur: 0,
body: Stack( )
],
floatingHeader: true,
child: Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: Container( child: Container(
@ -71,7 +74,7 @@ class TrackPage extends HookConsumerWidget {
), ),
fit: BoxFit.cover, fit: BoxFit.cover,
colorFilter: ColorFilter.mode( colorFilter: ColorFilter.mode(
colorScheme.surface.withOpacity(0.5), colorScheme.background.withOpacity(0.5),
BlendMode.srcOver, BlendMode.srcOver,
), ),
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
@ -89,7 +92,7 @@ class TrackPage extends HookConsumerWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [ colors: [
colorScheme.surface, colorScheme.background,
Colors.transparent, Colors.transparent,
], ],
begin: Alignment.topCenter, begin: Alignment.topCenter,
@ -125,8 +128,7 @@ class TrackPage extends HookConsumerWidget {
children: [ children: [
Text( Text(
track.name!, track.name!,
style: textTheme.titleLarge, ).large().semiBold(),
),
const Gap(10), const Gap(10),
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -170,9 +172,10 @@ class TrackPage extends HookConsumerWidget {
if (!isActive && if (!isActive &&
!playlist.tracks !playlist.tracks
.containsBy(track, (t) => t.id)) .containsBy(track, (t) => t.id))
OutlinedButton.icon( Button.outline(
icon: const Icon(SpotubeIcons.queueAdd), leading:
label: Text(context.l10n.queue), const Icon(SpotubeIcons.queueAdd),
child: Text(context.l10n.queue),
onPressed: () { onPressed: () {
playlistNotifier.addTrack(track); playlistNotifier.addTrack(track);
}, },
@ -181,27 +184,37 @@ class TrackPage extends HookConsumerWidget {
if (!isActive && if (!isActive &&
!playlist.tracks !playlist.tracks
.containsBy(track, (t) => t.id)) .containsBy(track, (t) => t.id))
IconButton.outlined( Tooltip(
icon: tooltip: TooltipContainer(
const Icon(SpotubeIcons.lightning), child: Text(context.l10n.play_next),
tooltip: context.l10n.play_next, ),
onPressed: () { child: IconButton.outline(
playlistNotifier icon: const Icon(
.addTracksAtFirst([track]); SpotubeIcons.lightning),
}, onPressed: () {
playlistNotifier
.addTracksAtFirst([track]);
},
),
), ),
const Gap(5), const Gap(5),
IconButton.filled( Tooltip(
tooltip: isActive tooltip: TooltipContainer(
? context.l10n.pause_playback child: Text(
: context.l10n.play, isActive
icon: Icon( ? context.l10n.pause_playback
isActive : context.l10n.play,
? SpotubeIcons.pause ),
: SpotubeIcons.play, ),
color: colorScheme.onPrimary, child: IconButton.primary(
shape: ButtonShape.circle,
icon: Icon(
isActive
? SpotubeIcons.pause
: SpotubeIcons.play,
),
onPressed: onPlay,
), ),
onPressed: onPlay,
), ),
const Gap(5), const Gap(5),
if (mediaQuery.smAndDown) if (mediaQuery.smAndDown)