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