From 2e8b647a51f87840c2bd39f0a1dc25ddc91528fc Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 25 Apr 2023 22:30:07 +0600 Subject: [PATCH] feat(mini_player): show/hide UI on hover toggle --- lib/collections/spotube_icons.dart | 2 + lib/pages/lyrics/mini_lyrics.dart | 306 +++++++++++++++++------------ 2 files changed, 180 insertions(+), 128 deletions(-) diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 8b0fc062c..767fb505a 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -72,4 +72,6 @@ abstract class SpotubeIcons { static const maximize = FeatherIcons.maximize2; static const pinOn = Icons.push_pin_rounded; static const pinOff = Icons.push_pin_outlined; + static const hoverOn = Icons.back_hand_rounded; + static const hoverOff = Icons.back_hand_outlined; } diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index 77c16a3f8..d481deb07 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -29,6 +29,9 @@ class MiniLyricsPage extends HookConsumerWidget { final playlistQueue = ref.watch(PlaylistQueueNotifier.provider); + final areaActive = useState(false); + final hoverMode = useState(true); + useEffect(() { WidgetsBinding.instance.addPostFrameCallback((_) async { prevSize.value = await DesktopTools.window.getSize(); @@ -46,140 +49,187 @@ class MiniLyricsPage extends HookConsumerWidget { ); } - return DefaultTabController( - length: 2, - child: Scaffold( - backgroundColor: theme.colorScheme.surface.withOpacity(0.4), - appBar: PreferredSize( - preferredSize: const Size.fromHeight(60), - child: DragToMoveArea( - child: Row( - children: [ - const SizedBox(width: 10), - SizedBox( - height: 30, - width: 30, - child: Sidebar.brandLogo(), - ), - const Spacer(), - const SizedBox( - height: 30, - child: TabBar( - tabs: [Tab(text: 'Synced'), Tab(text: 'Plain')], - isScrollable: true, - ), - ), - const Spacer(), - FutureBuilder( - future: DesktopTools.window.isAlwaysOnTop(), - builder: (context, snapshot) { - return IconButton( - tooltip: 'Always on top', - icon: Icon( - snapshot.data == true - ? SpotubeIcons.pinOn - : SpotubeIcons.pinOff, - ), - style: ButtonStyle( - foregroundColor: snapshot.data == true - ? MaterialStateProperty.all( - theme.colorScheme.primary) - : null, - ), - onPressed: snapshot.data == null - ? null - : () async { - await DesktopTools.window.setAlwaysOnTop( - snapshot.data == true ? false : true, - ); - update(); - }, - ); - }), - IconButton( - tooltip: 'Exit Mini Player', - icon: const Icon(SpotubeIcons.maximize), - onPressed: () async { - try { - await DesktopTools.window - .setMinimumSize(const Size(300, 700)); - await DesktopTools.window.setAlwaysOnTop(false); - if (wasMaximized.value) { - await DesktopTools.window.maximize(); - } else { - await DesktopTools.window.setSize(prevSize.value!); - } - await DesktopTools.window.setAlignment(Alignment.center); - if (!kIsLinux) { - await DesktopTools.window.setHasShadow(true); - } - await Future.delayed(const Duration(milliseconds: 200)); - } finally { - if (context.mounted) { - GoRouter.of(context).go('/lyrics'); - } - } - }, + return MouseRegion( + onEnter: !hoverMode.value + ? null + : (event) { + areaActive.value = true; + }, + onExit: !hoverMode.value + ? null + : (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: AnimatedCrossFade( + duration: const Duration(milliseconds: 200), + crossFadeState: areaActive.value + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + secondChild: const SizedBox(), + firstChild: DragToMoveArea( + child: Row( + children: [ + const SizedBox(width: 10), + SizedBox( + height: 30, + width: 30, + child: Sidebar.brandLogo(), + ), + const Spacer(), + const SizedBox( + height: 30, + child: TabBar( + tabs: [Tab(text: 'Synced'), Tab(text: 'Plain')], + isScrollable: true, + ), + ), + const Spacer(), + IconButton( + tooltip: 'Show/Hide UI on hover', + icon: hoverMode.value + ? const Icon(SpotubeIcons.hoverOn) + : const Icon(SpotubeIcons.hoverOff), + style: ButtonStyle( + foregroundColor: hoverMode.value + ? MaterialStateProperty.all( + theme.colorScheme.primary) + : null, + ), + onPressed: () async { + if (!hoverMode.value == true) { + areaActive.value = true; + } + hoverMode.value = !hoverMode.value; + }, + ), + FutureBuilder( + future: DesktopTools.window.isAlwaysOnTop(), + builder: (context, snapshot) { + return IconButton( + tooltip: 'Always on top', + icon: Icon( + snapshot.data == true + ? SpotubeIcons.pinOn + : SpotubeIcons.pinOff, + ), + style: ButtonStyle( + foregroundColor: snapshot.data == true + ? MaterialStateProperty.all( + theme.colorScheme.primary) + : null, + ), + onPressed: snapshot.data == null + ? null + : () async { + await DesktopTools.window.setAlwaysOnTop( + snapshot.data == true ? false : true, + ); + update(); + }, + ); + }, + ), + ], ), - ], + ), ), ), - ), - body: Column( - children: [ - if (playlistQueue != null) - Text( - playlistQueue.activeTrack.name!, - style: theme.textTheme.titleMedium, - ), - Expanded( - child: TabBarView( - children: [ - SyncedLyrics( - palette: PaletteColor(theme.colorScheme.background, 0), - isModal: true, - defaultTextZoom: 65, - ), - PlainLyrics( - palette: PaletteColor(theme.colorScheme.background, 0), - isModal: true, - defaultTextZoom: 65, - ), - ], + body: Column( + children: [ + if (playlistQueue != null) + Text( + playlistQueue.activeTrack.name!, + style: theme.textTheme.titleMedium, + ), + Expanded( + child: TabBarView( + children: [ + SyncedLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + PlainLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + ], + ), ), - ), - Row( - children: [ - IconButton( - icon: const Icon(SpotubeIcons.queue), - tooltip: 'Queue', - onPressed: playlistQueue != null - ? () { - showModalBottomSheet( - 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 const PlayerQueue(floating: true); - }, - ); + AnimatedCrossFade( + crossFadeState: areaActive.value + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + duration: const Duration(milliseconds: 200), + secondChild: const SizedBox(), + firstChild: Row( + children: [ + IconButton( + icon: const Icon(SpotubeIcons.queue), + tooltip: 'Queue', + onPressed: playlistQueue != null + ? () { + showModalBottomSheet( + 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 const PlayerQueue(floating: true); + }, + ); + } + : null, + ), + Flexible(child: PlayerControls(compact: true)), + IconButton( + tooltip: 'Exit Mini Player', + icon: const Icon(SpotubeIcons.maximize), + onPressed: () async { + try { + await DesktopTools.window + .setMinimumSize(const Size(300, 700)); + await DesktopTools.window.setAlwaysOnTop(false); + if (wasMaximized.value) { + await DesktopTools.window.maximize(); + } else { + await DesktopTools.window.setSize(prevSize.value!); + } + await DesktopTools.window + .setAlignment(Alignment.center); + if (!kIsLinux) { + await DesktopTools.window.setHasShadow(true); + } + await Future.delayed( + const Duration(milliseconds: 200)); + } finally { + if (context.mounted) { + GoRouter.of(context).go('/lyrics'); + } } - : null, + }, + ), + ], ), - Flexible(child: PlayerControls(compact: true)) - ], - ) - ], + ) + ], + ), ), ), );