refactor: use shadcn for mini lyrics window

This commit is contained in:
Kingkor Roy Tirtho 2025-01-28 21:23:57 +06:00
parent 5c6cb770a8
commit 42158a99ff
2 changed files with 164 additions and 151 deletions

View File

@ -10,6 +10,7 @@ import 'package:spotube/components/image/universal_image.dart';
import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/inter_scrollbar/inter_scrollbar.dart';
import 'package:spotube/components/ui/button_tile.dart'; import 'package:spotube/components/ui/button_tile.dart';
import 'package:spotube/extensions/artist_simple.dart'; import 'package:spotube/extensions/artist_simple.dart';
import 'package:spotube/extensions/constrains.dart';
import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/context.dart';
import 'package:spotube/extensions/duration.dart'; import 'package:spotube/extensions/duration.dart';
import 'package:spotube/hooks/utils/use_debounce.dart'; import 'package:spotube/hooks/utils/use_debounce.dart';
@ -193,7 +194,11 @@ class SiblingTracksSheet extends HookConsumerWidget {
if (!isFetchingActiveTrack && if (!isFetchingActiveTrack &&
sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) { sourceInfo.id != (activeTrack as SourcedTrack).sourceInfo.id) {
activeTrackNotifier.swapSibling(sourceInfo); activeTrackNotifier.swapSibling(sourceInfo);
closeDrawer(context); if (MediaQuery.sizeOf(context).mdAndUp) {
closeOverlay(context);
} else {
closeDrawer(context);
}
} }
}, },
); );

View File

@ -1,13 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gap/gap.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:palette_generator/palette_generator.dart'; import 'package:palette_generator/palette_generator.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/spotube_icons.dart';
import 'package:spotube/modules/player/player_controls.dart'; import 'package:spotube/modules/player/player_controls.dart';
import 'package:spotube/modules/player/player_queue.dart'; import 'package:spotube/modules/player/player_queue.dart';
import 'package:spotube/modules/root/sidebar.dart';
import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/context.dart';
import 'package:spotube/hooks/utils/use_force_update.dart'; import 'package:spotube/hooks/utils/use_force_update.dart';
import 'package:spotube/pages/lyrics/plain_lyrics.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart';
@ -30,6 +29,8 @@ class MiniLyricsPage extends HookConsumerWidget {
final playlistQueue = ref.watch(audioPlayerProvider); final playlistQueue = ref.watch(audioPlayerProvider);
final index = useState(0);
final areaActive = useState(false); final areaActive = useState(false);
final hoverMode = useState(true); final hoverMode = useState(true);
final showLyrics = useState(true); final showLyrics = useState(true);
@ -43,8 +44,6 @@ class MiniLyricsPage extends HookConsumerWidget {
return null; return null;
}, []); }, []);
return MouseRegion( return MouseRegion(
onEnter: !hoverMode.value onEnter: !hoverMode.value
? null ? null
@ -56,12 +55,11 @@ class MiniLyricsPage extends HookConsumerWidget {
: (event) { : (event) {
areaActive.value = false; areaActive.value = false;
}, },
child: DefaultTabController( child: Scaffold(
length: 2, backgroundColor: theme.colorScheme.background.withOpacity(0.4),
child: Scaffold( headers: [
backgroundColor: theme.colorScheme.surface.withOpacity(0.4), Padding(
appBar: PreferredSize( padding: const EdgeInsets.all(8.0),
preferredSize: const Size.fromHeight(60),
child: AnimatedCrossFade( child: AnimatedCrossFade(
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
crossFadeState: areaActive.value crossFadeState: areaActive.value
@ -70,91 +68,90 @@ class MiniLyricsPage extends HookConsumerWidget {
secondChild: const SizedBox(), secondChild: const SizedBox(),
firstChild: DragToMoveArea( firstChild: DragToMoveArea(
child: Row( child: Row(
spacing: 2,
children: [ children: [
const Gap(10), const Gap(10),
if (!kIsMacOS) if (kIsMacOS) const SizedBox(width: 65),
SizedBox(
height: 30,
width: 30,
child: Sidebar.brandLogo(),
),
const Spacer(),
if (showLyrics.value) if (showLyrics.value)
SizedBox( Tabs(
height: 30, index: index.value,
child: TabBar( onChanged: (i) {
tabs: [ index.value = i;
Tab(text: context.l10n.synced), },
Tab(text: context.l10n.plain), tabs: [
], Text(context.l10n.synced),
isScrollable: true, Text(context.l10n.plain),
), ],
), ),
const Spacer(), const Spacer(),
IconButton( Tooltip(
tooltip: context.l10n.lyrics, tooltip:
icon: showLyrics.value TooltipContainer(child: Text(context.l10n.lyrics)),
? const Icon(SpotubeIcons.lyrics) child: IconButton(
: const Icon(SpotubeIcons.lyricsOff), variance: showLyrics.value
style: ButtonStyle( ? ButtonVariance.secondary
foregroundColor: showLyrics.value : ButtonVariance.ghost,
? WidgetStateProperty.all(theme.colorScheme.primary) icon: showLyrics.value
: null, ? const Icon(SpotubeIcons.lyrics)
), : const Icon(SpotubeIcons.lyricsOff),
onPressed: () async { onPressed: () async {
showLyrics.value = !showLyrics.value; showLyrics.value = !showLyrics.value;
areaActive.value = true; areaActive.value = true;
hoverMode.value = false; hoverMode.value = false;
if (kIsDesktop) { if (kIsDesktop) {
await windowManager.setSize( await windowManager.setSize(
showLyrics.value showLyrics.value
? const Size(400, 500) ? const Size(400, 500)
: const Size(400, 150), : const Size(400, 150),
); );
} }
}, },
), ),
IconButton( ),
tooltip: context.l10n.show_hide_ui_on_hover, Tooltip(
icon: hoverMode.value tooltip: TooltipContainer(
? const Icon(SpotubeIcons.hoverOn) child: Text(context.l10n.show_hide_ui_on_hover),
: const Icon(SpotubeIcons.hoverOff), ),
style: ButtonStyle( child: IconButton(
foregroundColor: hoverMode.value variance: hoverMode.value
? WidgetStateProperty.all(theme.colorScheme.primary) ? ButtonVariance.secondary
: null, : ButtonVariance.ghost,
icon: hoverMode.value
? const Icon(SpotubeIcons.hoverOn)
: const Icon(SpotubeIcons.hoverOff),
onPressed: () async {
areaActive.value = true;
hoverMode.value = !hoverMode.value;
},
), ),
onPressed: () async {
areaActive.value = true;
hoverMode.value = !hoverMode.value;
},
), ),
if (kIsDesktop) if (kIsDesktop)
FutureBuilder( FutureBuilder(
future: windowManager.isAlwaysOnTop(), future: windowManager.isAlwaysOnTop(),
builder: (context, snapshot) { builder: (context, snapshot) {
return IconButton( return Tooltip(
tooltip: context.l10n.always_on_top, tooltip: TooltipContainer(
icon: Icon( child: Text(context.l10n.always_on_top),
snapshot.data == true
? SpotubeIcons.pinOn
: SpotubeIcons.pinOff,
), ),
style: ButtonStyle( child: IconButton(
foregroundColor: snapshot.data == true variance: snapshot.data == true
? WidgetStateProperty.all( ? ButtonVariance.secondary
theme.colorScheme.primary) : ButtonVariance.ghost,
: null, icon: Icon(
snapshot.data == true
? SpotubeIcons.pinOn
: SpotubeIcons.pinOff,
),
onPressed: snapshot.data == null
? null
: () async {
await windowManager.setAlwaysOnTop(
snapshot.data == true ? false : true,
);
update();
},
), ),
onPressed: snapshot.data == null
? null
: () async {
await windowManager.setAlwaysOnTop(
snapshot.data == true ? false : true,
);
update();
},
); );
}, },
), ),
@ -163,79 +160,90 @@ class MiniLyricsPage extends HookConsumerWidget {
), ),
), ),
), ),
body: Column( ],
children: [ child: Column(
if (playlistQueue.activeTrack != null) children: [
Text( if (playlistQueue.activeTrack != null)
playlistQueue.activeTrack!.name!, Text(playlistQueue.activeTrack!.name!).semiBold(),
style: theme.textTheme.titleMedium, if (showLyrics.value)
), Expanded(
if (showLyrics.value) child: IndexedStack(
Expanded( index: index.value,
child: TabBarView(
children: [
SyncedLyrics(
palette: PaletteColor(theme.colorScheme.surface, 0),
isModal: true,
defaultTextZoom: 65,
),
PlainLyrics(
palette: PaletteColor(theme.colorScheme.surface, 0),
isModal: true,
defaultTextZoom: 65,
),
],
),
)
else
const Gap(20),
AnimatedCrossFade(
crossFadeState: areaActive.value
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 200),
secondChild: const SizedBox(),
firstChild: Row(
children: [ children: [
IconButton( SyncedLyrics(
palette: PaletteColor(theme.colorScheme.background, 0),
isModal: true,
defaultTextZoom: 65,
),
PlainLyrics(
palette: PaletteColor(theme.colorScheme.background, 0),
isModal: true,
defaultTextZoom: 65,
),
],
),
)
else
const Gap(20),
AnimatedCrossFade(
crossFadeState: areaActive.value
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 200),
secondChild: const SizedBox(),
firstChild: Row(
children: [
Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.queue),
),
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.queue), icon: const Icon(SpotubeIcons.queue),
tooltip: context.l10n.queue,
onPressed: playlistQueue.activeTrack != null onPressed: playlistQueue.activeTrack != null
? () { ? () {
showModalBottomSheet( openDrawer(
context: context, context: context,
isDismissible: true, barrierDismissible: true,
enableDrag: true, draggable: true,
isScrollControlled: true, barrierColor: Colors.black.withAlpha(100),
backgroundColor: Colors.black12, borderRadius: BorderRadius.circular(10),
barrierColor: Colors.black12, transformBackdrop: false,
shape: RoundedRectangleBorder( position: OverlayPosition.bottom,
borderRadius: BorderRadius.circular(10), surfaceBlur: context.theme.surfaceBlur,
), surfaceOpacity: 0.7,
constraints: BoxConstraints( expands: true,
maxHeight: builder: (context) => Consumer(
MediaQuery.of(context).size.height * .7, builder: (context, ref, _) {
), final playlist = ref.watch(
builder: (context) { audioPlayerProvider,
return Consumer(builder: (context, ref, _) {
final playlist =
ref.watch(audioPlayerProvider);
return PlayerQueue.fromAudioPlayerNotifier(
floating: true,
playlist: playlist,
notifier: ref
.read(audioPlayerProvider.notifier),
); );
}); final playlistNotifier =
}, ref.read(audioPlayerProvider.notifier);
return ConstrainedBox(
constraints: BoxConstraints(
maxHeight:
MediaQuery.of(context).size.height *
0.8,
),
child:
PlayerQueue.fromAudioPlayerNotifier(
floating: false,
playlist: playlist,
notifier: playlistNotifier,
),
);
},
),
); );
} }
: null, : null,
), ),
const Flexible(child: PlayerControls(compact: true)), ),
IconButton( const Flexible(child: PlayerControls(compact: true)),
tooltip: context.l10n.exit_mini_player, Tooltip(
tooltip: TooltipContainer(
child: Text(context.l10n.exit_mini_player)),
child: IconButton.ghost(
icon: const Icon(SpotubeIcons.maximize), icon: const Icon(SpotubeIcons.maximize),
onPressed: () async { onPressed: () async {
if (!kIsDesktop) return; if (!kIsDesktop) return;
@ -262,11 +270,11 @@ class MiniLyricsPage extends HookConsumerWidget {
} }
}, },
), ),
], ),
), ],
) ),
], )
), ],
), ),
), ),
); );