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