This commit is contained in:
Forrest 2026-07-29 22:41:38 -04:00
parent 981b4836f9
commit ed910748cb
34 changed files with 2054 additions and 153 deletions

View file

@ -6,11 +6,14 @@ import '../state/providers.dart';
import '../subsonic/models.dart';
import '../theme/tokens.dart';
import '../widgets/hairline_panel.dart';
import '../widgets/toast.dart';
import 'add_tag_sheet.dart';
import 'add_to_playlist_sheet.dart';
import 'downloads_screen.dart';
import 'favorites_screen.dart';
import 'playlists_screen.dart';
import 'search_screen.dart';
import 'tags_screen.dart';
/// Browser tab — Artists / Albums / Tracks browse modes over the live Subsonic
/// server. Artists and Albums drill down by pushing onto the (nested) navigator;
@ -58,6 +61,13 @@ class BrowserScreen extends ConsumerWidget {
MaterialPageRoute(builder: (_) => const PlaylistsScreen()),
),
),
_Action(
icon: Icons.label_outline,
label: 'Tags',
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (_) => const TagsScreen()),
),
),
_Action(
icon: Icons.download,
label: 'Downloads',
@ -344,6 +354,7 @@ class _TracksPanelState extends ConsumerState<_TracksPanel> {
onAddToQueue: () => playback.addToQueue(song),
onAddToPlaylist: () =>
showAddToPlaylistSheet(context, songs: [song]),
onAddToTag: () => showAddTagSheet(context, songs: [song]),
onDownload: () =>
ref.read(downloadManagerProvider.notifier).download(song),
onRemoveDownload: () =>
@ -472,11 +483,7 @@ class AlbumScreen extends ConsumerWidget {
ref
.read(downloadManagerProvider.notifier)
.downloadAll(songs);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Downloading album…'),
duration: Duration(seconds: 2)),
);
showToast(context, 'Downloading album…');
},
icon: const Icon(Icons.download),
),
@ -499,6 +506,7 @@ class AlbumScreen extends ConsumerWidget {
onAddToQueue: () => playback.addToQueue(song),
onAddToPlaylist: () =>
showAddToPlaylistSheet(context, songs: [song]),
onAddToTag: () => showAddTagSheet(context, songs: [song]),
onDownload: () =>
ref.read(downloadManagerProvider.notifier).download(song),
onRemoveDownload: () =>
@ -523,6 +531,7 @@ class BrowseRow extends StatelessWidget {
this.onPlayNext,
this.onAddToQueue,
this.onAddToPlaylist,
this.onAddToTag,
this.onDownload,
this.onRemoveDownload,
this.downloadStatus,
@ -540,6 +549,7 @@ class BrowseRow extends StatelessWidget {
/// Secondary song actions, folded into a trailing overflow menu so the row
/// stays uncluttered.
final VoidCallback? onAddToPlaylist;
final VoidCallback? onAddToTag;
final VoidCallback? onDownload;
final VoidCallback? onRemoveDownload;
@ -548,7 +558,10 @@ class BrowseRow extends StatelessWidget {
final DownloadStatus? downloadStatus;
bool get _hasMenu =>
onAddToPlaylist != null || onDownload != null || onRemoveDownload != null;
onAddToPlaylist != null ||
onAddToTag != null ||
onDownload != null ||
onRemoveDownload != null;
@override
Widget build(BuildContext context) {
@ -600,14 +613,27 @@ class BrowseRow extends StatelessWidget {
style: const TextStyle(color: TimbreColors.dimmed)),
],
if (onPlayNext != null)
_RowIcon(icon: Icons.playlist_play, onTap: onPlayNext!),
_RowIcon(
icon: Icons.playlist_play,
onTap: () {
onPlayNext!();
showToast(context, 'Playing next', icon: Icons.check);
},
),
if (onAddToQueue != null)
_RowIcon(icon: Icons.add, onTap: onAddToQueue!),
_RowIcon(
icon: Icons.add,
onTap: () {
onAddToQueue!();
showToast(context, 'Added to queue', icon: Icons.check);
},
),
if (_hasMenu)
_RowMenu(
isDownloaded: isDone,
isDownloading: isActive,
onAddToPlaylist: onAddToPlaylist,
onAddToTag: onAddToTag,
onDownload: onDownload,
onRemoveDownload: onRemoveDownload,
),
@ -626,6 +652,7 @@ class _RowMenu extends StatelessWidget {
required this.isDownloaded,
required this.isDownloading,
this.onAddToPlaylist,
this.onAddToTag,
this.onDownload,
this.onRemoveDownload,
});
@ -633,6 +660,7 @@ class _RowMenu extends StatelessWidget {
final bool isDownloaded;
final bool isDownloading;
final VoidCallback? onAddToPlaylist;
final VoidCallback? onAddToTag;
final VoidCallback? onDownload;
final VoidCallback? onRemoveDownload;
@ -648,6 +676,8 @@ class _RowMenu extends StatelessWidget {
switch (v) {
case 'playlist':
onAddToPlaylist?.call();
case 'tag':
onAddToTag?.call();
case 'download':
onDownload?.call();
case 'remove_download':
@ -658,6 +688,8 @@ class _RowMenu extends StatelessWidget {
if (onAddToPlaylist != null)
const PopupMenuItem(
value: 'playlist', child: Text('Add to playlist')),
if (onAddToTag != null)
const PopupMenuItem(value: 'tag', child: Text('Add tag…')),
if (isDownloaded && onRemoveDownload != null)
const PopupMenuItem(
value: 'remove_download', child: Text('Remove download'))