From 9a891a9a9847751fb71184300bb99428d6346626 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 20 Dec 2025 12:24:34 +0800 Subject: [PATCH] :recycle: Update the icon set --- lib/ui/screens/album_detail_screen.dart | 5 +- lib/ui/screens/library_screen.dart | 45 ++++++------- lib/ui/screens/player_screen.dart | 73 +++++++++++----------- lib/ui/screens/playlist_detail_screen.dart | 5 +- lib/ui/screens/settings_screen.dart | 17 +++-- lib/ui/tabs/albums_tab.dart | 3 +- lib/ui/tabs/playlists_tab.dart | 9 +-- lib/ui/widgets/mini_player.dart | 33 +++++----- lib/ui/widgets/track_tile.dart | 7 ++- lib/ui/widgets/universal_image.dart | 3 +- macos/Runner/Info.plist | 2 + pubspec.lock | 16 +++++ pubspec.yaml | 11 ++-- test/widget_test.dart | 30 --------- 14 files changed, 132 insertions(+), 127 deletions(-) delete mode 100644 test/widget_test.dart diff --git a/lib/ui/screens/album_detail_screen.dart b/lib/ui/screens/album_detail_screen.dart index f685ae0..280fe43 100644 --- a/lib/ui/screens/album_detail_screen.dart +++ b/lib/ui/screens/album_detail_screen.dart @@ -5,6 +5,7 @@ import 'package:groovybox/providers/audio_provider.dart'; import 'package:groovybox/ui/widgets/track_tile.dart'; import 'package:groovybox/ui/widgets/universal_image.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; class AlbumDetailScreen extends HookConsumerWidget { @@ -30,7 +31,7 @@ class AlbumDetailScreen extends HookConsumerWidget { : Container( color: Colors.grey[800], child: const Icon( - Icons.album, + Symbols.album, size: 100, color: Colors.white54, ), @@ -66,7 +67,7 @@ class AlbumDetailScreen extends HookConsumerWidget { onPressed: () { _playAlbum(ref, tracks); }, - icon: const Icon(Icons.play_arrow), + icon: const Icon(Symbols.play_arrow), label: const Text('Play All'), ), ), diff --git a/lib/ui/screens/library_screen.dart b/lib/ui/screens/library_screen.dart index 6dc67bd..ccb4358 100644 --- a/lib/ui/screens/library_screen.dart +++ b/lib/ui/screens/library_screen.dart @@ -14,6 +14,7 @@ import 'package:groovybox/ui/tabs/albums_tab.dart'; import 'package:groovybox/ui/tabs/playlists_tab.dart'; import 'package:groovybox/ui/widgets/track_tile.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:path/path.dart' as p; import 'package:styled_widget/styled_widget.dart'; @@ -75,14 +76,14 @@ class LibraryScreen extends HookConsumerWidget { appBar: isSelectionMode ? AppBar( leading: IconButton( - icon: const Icon(Icons.close), + icon: const Icon(Symbols.close), onPressed: clearSelection, ), title: Text('${selectedTrackIds.value.length} selected'), backgroundColor: Theme.of(context).primaryColorDark, actions: [ IconButton( - icon: const Icon(Icons.playlist_add), + icon: const Icon(Symbols.playlist_add), tooltip: 'Add to Playlist', onPressed: () { _batchAddToPlaylist( @@ -94,7 +95,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.delete), + icon: const Icon(Symbols.delete), tooltip: 'Delete', onPressed: () { _batchDelete( @@ -132,10 +133,10 @@ class LibraryScreen extends HookConsumerWidget { ), ); }, - icon: const Icon(Icons.settings), + icon: const Icon(Symbols.settings), ), IconButton( - icon: const Icon(Icons.add_circle_outline), + icon: const Icon(Symbols.add_circle_outline), tooltip: 'Import Files', onPressed: () async { final result = await FilePicker.platform.pickFiles( @@ -198,15 +199,15 @@ class LibraryScreen extends HookConsumerWidget { onDestinationSelected: (index) => selectedTab.value = index, destinations: const [ NavigationRailDestination( - icon: Icon(Icons.audiotrack), + icon: Icon(Symbols.audiotrack), label: Text('Tracks'), ), NavigationRailDestination( - icon: Icon(Icons.album), + icon: Icon(Symbols.album), label: Text('Albums'), ), NavigationRailDestination( - icon: Icon(Icons.queue_music), + icon: Icon(Symbols.queue_music), label: Text('Playlists'), ), ], @@ -236,14 +237,14 @@ class LibraryScreen extends HookConsumerWidget { appBar: isSelectionMode ? AppBar( leading: IconButton( - icon: const Icon(Icons.close), + icon: const Icon(Symbols.close), onPressed: clearSelection, ), title: Text('${selectedTrackIds.value.length} selected'), backgroundColor: Theme.of(context).primaryColorDark, actions: [ IconButton( - icon: const Icon(Icons.playlist_add), + icon: const Icon(Symbols.playlist_add), tooltip: 'Add to Playlist', onPressed: () { _batchAddToPlaylist( @@ -255,7 +256,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.delete), + icon: const Icon(Symbols.delete), tooltip: 'Delete', onPressed: () { _batchDelete( @@ -274,14 +275,14 @@ class LibraryScreen extends HookConsumerWidget { title: const Text('Library'), bottom: const TabBar( tabs: [ - Tab(text: 'Tracks', icon: Icon(Icons.audiotrack)), - Tab(text: 'Albums', icon: Icon(Icons.album)), - Tab(text: 'Playlists', icon: Icon(Icons.queue_music)), + Tab(text: 'Tracks', icon: Icon(Symbols.audiotrack)), + Tab(text: 'Albums', icon: Icon(Symbols.album)), + Tab(text: 'Playlists', icon: Icon(Symbols.queue_music)), ], ), actions: [ IconButton( - icon: const Icon(Icons.add_circle_outline), + icon: const Icon(Symbols.add_circle_outline), tooltip: 'Import Files', onPressed: () async { final result = await FilePicker.platform.pickFiles( @@ -480,7 +481,7 @@ class LibraryScreen extends HookConsumerWidget { color: Colors.red, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), - child: const Icon(Icons.delete, color: Colors.white), + child: const Icon(Symbols.delete, color: Colors.white), ), confirmDismiss: (direction) async { return await showDialog( @@ -551,7 +552,7 @@ class LibraryScreen extends HookConsumerWidget { child: SearchBar( onChanged: (value) => searchQuery.value = value, hintText: hintText, - leading: const Icon(Icons.search), + leading: const Icon(Symbols.search), padding: WidgetStatePropertyAll( EdgeInsets.symmetric(horizontal: 24), ), @@ -601,7 +602,7 @@ class LibraryScreen extends HookConsumerWidget { mainAxisSize: MainAxisSize.min, children: [ ListTile( - leading: const Icon(Icons.playlist_add), + leading: const Icon(Symbols.playlist_add), title: const Text('Add to Playlist'), onTap: () { Navigator.pop(context); @@ -609,7 +610,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), ListTile( - leading: const Icon(Icons.info_outline), + leading: const Icon(Symbols.info), title: const Text('View Details'), onTap: () { Navigator.pop(context); @@ -617,7 +618,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), ListTile( - leading: const Icon(Icons.edit), + leading: const Icon(Symbols.edit), title: const Text('Edit Metadata'), onTap: () { Navigator.pop(context); @@ -625,7 +626,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), ListTile( - leading: const Icon(Icons.lyrics_outlined), + leading: const Icon(Symbols.lyrics), title: const Text('Import Lyrics'), onTap: () { Navigator.pop(context); @@ -633,7 +634,7 @@ class LibraryScreen extends HookConsumerWidget { }, ), ListTile( - leading: const Icon(Icons.delete, color: Colors.red), + leading: const Icon(Symbols.delete, color: Colors.red), title: const Text( 'Delete Track', style: TextStyle(color: Colors.red), diff --git a/lib/ui/screens/player_screen.dart b/lib/ui/screens/player_screen.dart index 714962a..400d499 100644 --- a/lib/ui/screens/player_screen.dart +++ b/lib/ui/screens/player_screen.dart @@ -20,6 +20,7 @@ import 'package:groovybox/ui/widgets/mini_player.dart'; import 'package:groovybox/ui/widgets/track_tile.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:media_kit/media_kit.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:super_sliver_list/super_sliver_list.dart'; @@ -136,7 +137,7 @@ class PlayerScreen extends HookConsumerWidget { top: MediaQuery.of(context).padding.top + 16, left: 16, child: IconButton( - icon: const Icon(Icons.keyboard_arrow_down), + icon: const Icon(Symbols.keyboard_arrow_down), onPressed: () => Navigator.of(context).pop(), padding: EdgeInsets.zero, iconSize: 24, @@ -439,7 +440,7 @@ class _PlayerCoverArt extends StatelessWidget { child: currentMetadata?.artBytes == null ? Center( child: Icon( - Icons.music_note, + Symbols.music_note, size: 80, color: Theme.of( context, @@ -544,7 +545,7 @@ class _PlayerLyrics extends HookConsumerWidget { ), const SizedBox(height: 16), ElevatedButton.icon( - icon: const Icon(Icons.download), + icon: const Icon(Symbols.download), label: const Text('Fetch Lyrics'), onPressed: () => _showFetchLyricsDialog( context, @@ -706,7 +707,7 @@ class _FetchLyricsDialog extends StatelessWidget { children: [ ListTile( dense: true, - leading: const Icon(Icons.library_music), + leading: const Icon(Symbols.library_music), title: const Text('Musixmatch'), shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(12)), @@ -725,7 +726,7 @@ class _FetchLyricsDialog extends StatelessWidget { ), ListTile( dense: true, - leading: const Icon(Icons.music_video), + leading: const Icon(Symbols.music_video), title: const Text('NetEase'), shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(12)), @@ -744,7 +745,7 @@ class _FetchLyricsDialog extends StatelessWidget { ), ListTile( dense: true, - leading: const Icon(Icons.file_upload), + leading: const Icon(Symbols.file_upload), title: const Text('Manual Import'), shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(12)), @@ -826,7 +827,7 @@ class _LyricsAdjustButton extends HookConsumerWidget { } return IconButton( - icon: const Icon(Icons.settings_applications), + icon: const Icon(Symbols.settings_applications), iconSize: 24, tooltip: 'Adjust Lyrics', onPressed: () => _showLyricsRefreshDialog( @@ -901,7 +902,7 @@ class _LyricsAdjustButton extends HookConsumerWidget { children: [ Expanded( child: ElevatedButton.icon( - icon: const Icon(Icons.refresh), + icon: const Icon(Symbols.refresh), label: const Text('Re-fetch'), onPressed: () { Navigator.of(context).pop(); @@ -920,7 +921,7 @@ class _LyricsAdjustButton extends HookConsumerWidget { ), Expanded( child: ElevatedButton.icon( - icon: const Icon(Icons.clear), + icon: const Icon(Symbols.clear), label: const Text('Clear'), style: ElevatedButton.styleFrom( backgroundColor: Colors.red, @@ -972,7 +973,7 @@ class _LyricsAdjustButton extends HookConsumerWidget { SizedBox( width: double.infinity, child: ElevatedButton.icon( - icon: const Icon(Icons.sync), + icon: const Icon(Symbols.sync), label: const Text('Live Sync Lyrics'), onPressed: () { Navigator.of(context).pop(); @@ -989,7 +990,7 @@ class _LyricsAdjustButton extends HookConsumerWidget { SizedBox( width: double.infinity, child: ElevatedButton.icon( - icon: const Icon(Icons.tune), + icon: const Icon(Symbols.tune), label: const Text('Manual Offset'), onPressed: () { Navigator.of(context).pop(); @@ -1098,11 +1099,11 @@ class _ViewToggleButton extends StatelessWidget { IconData getIcon() { switch (viewMode.value) { case ViewMode.cover: - return Icons.album; + return Symbols.album; case ViewMode.lyrics: - return Icons.lyrics; + return Symbols.lyrics; case ViewMode.queue: - return Icons.queue_music; + return Symbols.queue_music; } } @@ -1193,7 +1194,7 @@ class _QueueView extends HookConsumerWidget { color: Colors.red, alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), - child: const Icon(Icons.delete, color: Colors.white), + child: const Icon(Symbols.delete, color: Colors.white), ), onDismissed: (direction) => player.remove(index), child: TrackTile( @@ -1231,7 +1232,7 @@ class _QueueView extends HookConsumerWidget { alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), child: const Icon( - Icons.delete, + Symbols.delete, color: Colors.white, ), ), @@ -1636,7 +1637,7 @@ class _PlayerControls extends HookWidget { builder: (context, snapshot) { final shuffle = snapshot.data ?? false; return Icon( - Icons.shuffle, + Symbols.shuffle, color: shuffle ? Theme.of(context).colorScheme.primary : Theme.of(context).disabledColor, @@ -1649,7 +1650,7 @@ class _PlayerControls extends HookWidget { ), // Previous IconButton( - icon: const Icon(Icons.skip_previous, size: 32), + icon: const Icon(Symbols.skip_previous, size: 32), onPressed: player.previous, ), // Play/Pause @@ -1669,7 +1670,7 @@ class _PlayerControls extends HookWidget { ); }, child: Icon( - playing ? Icons.pause : Icons.play_arrow, + playing ? Symbols.pause : Symbols.play_arrow, key: ValueKey(playing), size: 48, ), @@ -1681,7 +1682,7 @@ class _PlayerControls extends HookWidget { ), // Next IconButton( - icon: const Icon(Icons.skip_next, size: 32), + icon: const Icon(Symbols.skip_next, size: 32), onPressed: player.next, ), // Loop Mode @@ -1695,15 +1696,15 @@ class _PlayerControls extends HookWidget { Color? color; switch (mode) { case PlaylistMode.none: - icon = Icons.repeat; + icon = Symbols.repeat; color = Theme.of(context).disabledColor; break; case PlaylistMode.single: - icon = Icons.repeat_one; + icon = Symbols.repeat_one; color = Theme.of(context).colorScheme.primary; break; case PlaylistMode.loop: - icon = Icons.repeat; + icon = Symbols.repeat; color = Theme.of(context).colorScheme.primary; break; } @@ -1744,10 +1745,10 @@ class _PlayerControls extends HookWidget { children: [ Icon( volume == 0 - ? Icons.volume_off + ? Symbols.volume_off : volume < 50 - ? Icons.volume_down - : Icons.volume_up, + ? Symbols.volume_down + : Symbols.volume_up, color: Theme.of(context).colorScheme.onSurfaceVariant, ), Expanded( @@ -1812,12 +1813,12 @@ class _LiveLyricsSyncDialog extends HookConsumerWidget { appBar: AppBar( title: const Text('Live Lyrics Sync'), leading: IconButton( - icon: const Icon(Icons.close), + icon: const Icon(Symbols.close), onPressed: () => Navigator.of(context).pop(), ), actions: [ IconButton( - icon: const Icon(Icons.check), + icon: const Icon(Symbols.check), onPressed: () async { // Store context before async operation final navigator = Navigator.of(context); @@ -1890,30 +1891,30 @@ class _LiveLyricsSyncDialog extends HookConsumerWidget { runAlignment: WrapAlignment.center, children: [ ElevatedButton.icon( - icon: const Icon(Icons.fast_rewind), + icon: const Icon(Symbols.fast_rewind), label: const Text('-100ms'), onPressed: () => tempOffset.value = (tempOffset.value - 100), ), ElevatedButton.icon( - icon: const Icon(Icons.skip_previous), + icon: const Icon(Symbols.skip_previous), label: const Text('-10ms'), onPressed: () => tempOffset.value = (tempOffset.value - 10), ), ElevatedButton.icon( - icon: const Icon(Icons.refresh), + icon: const Icon(Symbols.refresh), label: const Text('Reset'), onPressed: () => tempOffset.value = 0, ), ElevatedButton.icon( - icon: const Icon(Icons.skip_next), + icon: const Icon(Symbols.skip_next), label: const Text('+10ms'), onPressed: () => tempOffset.value = (tempOffset.value + 10), ), ElevatedButton.icon( - icon: const Icon(Icons.fast_forward), + icon: const Icon(Symbols.fast_forward), label: const Text('+100ms'), onPressed: () => tempOffset.value = (tempOffset.value + 100), @@ -1947,7 +1948,7 @@ class _LiveLyricsSyncDialog extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( - icon: const Icon(Icons.skip_previous, size: 32), + icon: const Icon(Symbols.skip_previous, size: 32), onPressed: player.previous, ), const SizedBox(width: 16), @@ -1958,7 +1959,7 @@ class _LiveLyricsSyncDialog extends HookConsumerWidget { final playing = snapshot.data ?? false; return IconButton.filled( icon: Icon( - playing ? Icons.pause : Icons.play_arrow, + playing ? Symbols.pause : Symbols.play_arrow, size: 48, ), onPressed: playing ? player.pause : player.play, @@ -1968,7 +1969,7 @@ class _LiveLyricsSyncDialog extends HookConsumerWidget { ), const SizedBox(width: 16), IconButton( - icon: const Icon(Icons.skip_next, size: 32), + icon: const Icon(Symbols.skip_next, size: 32), onPressed: player.next, ), ], diff --git a/lib/ui/screens/playlist_detail_screen.dart b/lib/ui/screens/playlist_detail_screen.dart index c8c0d6f..9c4f108 100644 --- a/lib/ui/screens/playlist_detail_screen.dart +++ b/lib/ui/screens/playlist_detail_screen.dart @@ -4,6 +4,7 @@ import 'package:groovybox/data/playlist_repository.dart'; import 'package:groovybox/providers/audio_provider.dart'; import 'package:groovybox/ui/widgets/track_tile.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:material_symbols_icons/symbols.dart'; class PlaylistDetailScreen extends HookConsumerWidget { final Playlist playlist; @@ -36,7 +37,7 @@ class PlaylistDetailScreen extends HookConsumerWidget { ), child: const Center( child: Icon( - Icons.queue_music, + Symbols.queue_music, size: 80, color: Colors.white70, ), @@ -73,7 +74,7 @@ class PlaylistDetailScreen extends HookConsumerWidget { onPressed: () { _playPlaylist(ref, tracks); }, - icon: const Icon(Icons.play_arrow), + icon: const Icon(Symbols.play_arrow), label: const Text('Play All'), ), ), diff --git a/lib/ui/screens/settings_screen.dart b/lib/ui/screens/settings_screen.dart index 61877ec..b29dfe2 100644 --- a/lib/ui/screens/settings_screen.dart +++ b/lib/ui/screens/settings_screen.dart @@ -5,6 +5,7 @@ import 'package:groovybox/providers/watch_folder_provider.dart'; import 'package:groovybox/providers/remote_provider.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; class SettingsScreen extends ConsumerWidget { @@ -99,7 +100,7 @@ class SettingsScreen extends ConsumerWidget { IconButton( onPressed: () => _scanLibraries(context, ref), - icon: const Icon(Icons.refresh), + icon: const Icon(Symbols.refresh), tooltip: 'Scan Libraries', visualDensity: const VisualDensity( horizontal: -4, @@ -109,7 +110,7 @@ class SettingsScreen extends ConsumerWidget { IconButton( onPressed: () => _addMusicLibrary(context, ref), - icon: const Icon(Icons.add), + icon: const Icon(Symbols.add), tooltip: 'Add Music Library', visualDensity: const VisualDensity( horizontal: -4, @@ -165,7 +166,9 @@ class SettingsScreen extends ConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.delete), + icon: const Icon( + Symbols.delete, + ), onPressed: () { ref .read( @@ -215,7 +218,7 @@ class SettingsScreen extends ConsumerWidget { IconButton( onPressed: () => _indexRemoteProviders(context, ref), - icon: const Icon(Icons.refresh), + icon: const Icon(Symbols.refresh), tooltip: 'Index Remote Providers', visualDensity: const VisualDensity( horizontal: -4, @@ -225,7 +228,7 @@ class SettingsScreen extends ConsumerWidget { IconButton( onPressed: () => _addRemoteProvider(context, ref), - icon: const Icon(Icons.add), + icon: const Icon(Symbols.add), tooltip: 'Add Remote Provider', visualDensity: const VisualDensity( horizontal: -4, @@ -281,7 +284,9 @@ class SettingsScreen extends ConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.delete), + icon: const Icon( + Symbols.delete, + ), onPressed: () { ref .read( diff --git a/lib/ui/tabs/albums_tab.dart b/lib/ui/tabs/albums_tab.dart index 20ca5a0..cdd013e 100644 --- a/lib/ui/tabs/albums_tab.dart +++ b/lib/ui/tabs/albums_tab.dart @@ -4,6 +4,7 @@ import 'package:groovybox/data/playlist_repository.dart'; import 'package:groovybox/ui/screens/album_detail_screen.dart'; import 'package:groovybox/ui/widgets/universal_image.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:material_symbols_icons/symbols.dart'; class AlbumsTab extends HookConsumerWidget { const AlbumsTab({super.key}); @@ -52,7 +53,7 @@ class AlbumsTab extends HookConsumerWidget { child: UniversalImage( uri: album.artUri, fit: BoxFit.cover, - fallbackIcon: Icons.album, + fallbackIcon: Symbols.album, fallbackIconSize: 48, ), ), diff --git a/lib/ui/tabs/playlists_tab.dart b/lib/ui/tabs/playlists_tab.dart index 6a9bb13..5955440 100644 --- a/lib/ui/tabs/playlists_tab.dart +++ b/lib/ui/tabs/playlists_tab.dart @@ -3,6 +3,7 @@ import 'package:groovybox/data/db.dart'; import 'package:groovybox/data/playlist_repository.dart'; import 'package:groovybox/ui/screens/playlist_detail_screen.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; class PlaylistsTab extends HookConsumerWidget { @@ -16,8 +17,8 @@ class PlaylistsTab extends HookConsumerWidget { body: Column( children: [ ListTile( - leading: const Icon(Icons.add), - trailing: const Icon(Icons.chevron_right).padding(right: 8), + leading: const Icon(Symbols.add), + trailing: const Icon(Symbols.chevron_right).padding(right: 8), title: Text('Create One'), subtitle: Text('Add a new playlist'), onTap: () async { @@ -70,13 +71,13 @@ class PlaylistsTab extends HookConsumerWidget { itemBuilder: (context, index) { final playlist = playlists[index]; return ListTile( - leading: const Icon(Icons.queue_music), + leading: const Icon(Symbols.queue_music), title: Text(playlist.name), subtitle: Text( '${playlist.createdAt.day}/${playlist.createdAt.month}/${playlist.createdAt.year}', ), trailing: IconButton( - icon: const Icon(Icons.delete), + icon: const Icon(Symbols.delete), onPressed: () => repo.deletePlaylist(playlist.id), ), onTap: () { diff --git a/lib/ui/widgets/mini_player.dart b/lib/ui/widgets/mini_player.dart index 49d8969..cdb090e 100644 --- a/lib/ui/widgets/mini_player.dart +++ b/lib/ui/widgets/mini_player.dart @@ -7,6 +7,7 @@ import 'package:groovybox/ui/screens/player_screen.dart'; import 'package:groovybox/ui/widgets/track_tile.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:media_kit/media_kit.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -151,7 +152,7 @@ class _MobileMiniPlayer extends HookConsumerWidget { : Container( color: Colors.grey[800], child: const Icon( - Icons.music_note, + Symbols.music_note, color: Colors.white54, ), ), @@ -205,7 +206,7 @@ class _MobileMiniPlayer extends HookConsumerWidget { ); }, child: Icon( - playing ? Icons.pause : Icons.play_arrow, + playing ? Symbols.pause : Symbols.play_arrow, key: ValueKey(playing), ), ), @@ -216,7 +217,7 @@ class _MobileMiniPlayer extends HookConsumerWidget { ), // Next Button IconButton( - icon: const Icon(Icons.skip_next), + icon: const Icon(Symbols.skip_next), onPressed: player.next, iconSize: 24, ), @@ -376,7 +377,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { : Container( color: Colors.grey[800], child: const Icon( - Icons.music_note, + Symbols.music_note, color: Colors.white54, ), ), @@ -434,15 +435,15 @@ class _DesktopMiniPlayer extends HookConsumerWidget { Color? color; switch (mode) { case PlaylistMode.none: - icon = Icons.repeat; + icon = Symbols.repeat; color = Theme.of(context).disabledColor; break; case PlaylistMode.single: - icon = Icons.repeat_one; + icon = Symbols.repeat_one; color = Theme.of(context).colorScheme.primary; break; case PlaylistMode.loop: - icon = Icons.repeat; + icon = Symbols.repeat; color = Theme.of(context).colorScheme.primary; break; } @@ -469,7 +470,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.skip_previous), + icon: const Icon(Symbols.skip_previous), onPressed: player.previous, iconSize: 24, ), @@ -499,7 +500,9 @@ class _DesktopMiniPlayer extends HookConsumerWidget { ); }, child: Icon( - playing ? Icons.pause : Icons.play_arrow, + playing + ? Symbols.pause + : Symbols.play_arrow, key: ValueKey(playing), ), ), @@ -511,12 +514,12 @@ class _DesktopMiniPlayer extends HookConsumerWidget { }, ), IconButton( - icon: const Icon(Icons.skip_next), + icon: const Icon(Symbols.skip_next), onPressed: player.next, iconSize: 24, ), IconButton( - icon: const Icon(Icons.queue_music), + icon: const Icon(Symbols.queue_music), onPressed: () => _showQueueDialog(context, ref, player), iconSize: 24, @@ -530,7 +533,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { child: Row( children: [ Icon( - Icons.volume_up, + Symbols.volume_up, size: 16, color: Theme.of( context, @@ -599,7 +602,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { const Text('Queue', style: TextStyle(fontSize: 20)), const Spacer(), IconButton( - icon: const Icon(Icons.close), + icon: const Icon(Symbols.close), onPressed: () => Navigator.of(bottomSheetContext).pop(), ), ], @@ -650,7 +653,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), child: const Icon( - Icons.delete, + Symbols.delete, color: Colors.white, ), ), @@ -696,7 +699,7 @@ class _DesktopMiniPlayer extends HookConsumerWidget { alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), child: const Icon( - Icons.delete, + Symbols.delete, color: Colors.white, ), ), diff --git a/lib/ui/widgets/track_tile.dart b/lib/ui/widgets/track_tile.dart index 413981e..7d5b05d 100644 --- a/lib/ui/widgets/track_tile.dart +++ b/lib/ui/widgets/track_tile.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:groovybox/data/db.dart' as db; import 'package:groovybox/ui/widgets/universal_image.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; class TrackTile extends StatelessWidget { @@ -52,7 +53,7 @@ class TrackTile extends StatelessWidget { uri: track.artUri, fit: BoxFit.cover, borderRadius: BorderRadius.circular(8), - fallbackIcon: Icons.music_note, + fallbackIcon: Symbols.music_note, fallbackIconSize: 24, ).clipRRect(all: 8), ), @@ -79,12 +80,12 @@ class TrackTile extends StatelessWidget { ), trailing: showTrailingIcon ? IconButton( - icon: const Icon(Icons.more_vert), + icon: const Icon(Symbols.more_vert), onPressed: onTrailingPressed, ) : isPlaying ? Icon( - Icons.play_arrow, + Symbols.play_arrow, color: Theme.of(context).colorScheme.primary, ) : null, diff --git a/lib/ui/widgets/universal_image.dart b/lib/ui/widgets/universal_image.dart index b4912c7..38e8adf 100644 --- a/lib/ui/widgets/universal_image.dart +++ b/lib/ui/widgets/universal_image.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:material_symbols_icons/symbols.dart'; class UniversalImage extends StatelessWidget { final String? uri; @@ -21,7 +22,7 @@ class UniversalImage extends StatelessWidget { this.width, this.height, this.fallback, - this.fallbackIcon = Icons.image, + this.fallbackIcon = Symbols.image, this.fallbackIconSize = 48, this.fallbackIconColor = Colors.white54, this.borderRadius, diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index 53e6351..968501b 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -26,6 +26,8 @@ $(PRODUCT_COPYRIGHT) NSMainNibFile MainMenu + LSApplicationCategoryType + public.app-category.music NSPrincipalClass NSApplication diff --git a/pubspec.lock b/pubspec.lock index b203529..c4fb9f9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -185,6 +185,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + chalkdart: + dependency: transitive + description: + name: chalkdart + sha256: "7ffc6bd39c81453fb9ba8dbce042a9c960219b75ea1c07196a7fa41c2fab9e86" + url: "https://pub.dev" + source: hosted + version: "3.0.5" characters: dependency: transitive description: @@ -688,6 +696,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.11.1" + material_symbols_icons: + dependency: "direct main" + description: + name: material_symbols_icons + sha256: "02555a48e1ec02b16e532dfd4ef13c4f6bf7ec7c20230e58e56641a393433dc3" + url: "https://pub.dev" + source: hosted + version: "4.2892.0" media_kit: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ff12582..affadf4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,21 +44,22 @@ dependencies: path_provider: ^2.1.5 path: ^1.9.1 riverpod_annotation: ^3.0.3 - file_picker: ^10.3.7 + file_picker: ^10.3.8 flutter_media_metadata: ^1.0.0+1 animations: ^2.1.1 gap: ^3.0.1 styled_widget: ^0.4.1 super_sliver_list: ^0.4.1 - dio: ^5.0.0 - http: ^1.2.2 + dio: ^5.9.0 + http: ^1.6.0 audio_service: ^0.18.18 - palette_generator: ^0.3.3+4 + palette_generator: ^0.3.3+7 watcher: ^1.2.0 - shared_preferences: ^2.3.5 + shared_preferences: ^2.5.4 jellyfin_dart: ^0.1.2 cached_network_image: ^3.4.1 flutter_cache_manager: ^3.4.1 + material_symbols_icons: ^4.2892.0 dev_dependencies: flutter_test: diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 74b2564..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:groovybox/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const GroovyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}