This commit is contained in:
Forrest 2026-07-29 16:22:00 -04:00
parent fc22d11df1
commit 27a8a62475
32 changed files with 354 additions and 335 deletions

View file

@ -25,17 +25,17 @@ class BrowserScreen extends ConsumerWidget {
return Padding(
padding: const EdgeInsets.fromLTRB(
RatuneSpacing.lg,
RatuneSpacing.xl,
RatuneSpacing.lg,
RatuneSpacing.lg,
TimbreSpacing.lg,
TimbreSpacing.xl,
TimbreSpacing.lg,
TimbreSpacing.lg,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Wrap(
spacing: RatuneSpacing.xl,
runSpacing: RatuneSpacing.xs,
spacing: TimbreSpacing.xl,
runSpacing: TimbreSpacing.xs,
children: [
_Action(
icon: Icons.search,
@ -67,9 +67,9 @@ class BrowserScreen extends ConsumerWidget {
),
],
),
const SizedBox(height: RatuneSpacing.md),
const SizedBox(height: TimbreSpacing.md),
_ModeSelector(mode: mode),
const SizedBox(height: RatuneSpacing.lg),
const SizedBox(height: TimbreSpacing.lg),
Expanded(
child: client == null
? const HairlinePanel(
@ -105,13 +105,13 @@ class _ModeSelector extends ConsumerWidget {
onTap: () => ref.read(browseModeProvider.notifier).state = m,
child: Container(
constraints:
const BoxConstraints(minHeight: RatuneSpacing.minTouchTarget),
padding: const EdgeInsets.symmetric(horizontal: RatuneSpacing.md),
const BoxConstraints(minHeight: TimbreSpacing.minTouchTarget),
padding: const EdgeInsets.symmetric(horizontal: TimbreSpacing.md),
alignment: Alignment.center,
child: Text(
text,
style: TextStyle(
color: active ? RatuneColors.foreground : RatuneColors.dimmed,
color: active ? TimbreColors.foreground : TimbreColors.dimmed,
fontWeight: active ? FontWeight.w700 : FontWeight.w400,
decoration:
active ? TextDecoration.underline : TextDecoration.none,
@ -127,9 +127,9 @@ class _ModeSelector extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
label('Artists', BrowseMode.artists),
const Text('|', style: TextStyle(color: RatuneColors.border)),
const Text('|', style: TextStyle(color: TimbreColors.border)),
label('Albums', BrowseMode.albums),
const Text('|', style: TextStyle(color: RatuneColors.border)),
const Text('|', style: TextStyle(color: TimbreColors.border)),
label('Tracks', BrowseMode.tracks),
],
);
@ -148,7 +148,7 @@ class _ArtistsPanel extends ConsumerWidget {
trailing: artists.hasValue && artists.value!.isNotEmpty
? '(${artists.value!.length})'
: null,
padding: const EdgeInsets.symmetric(vertical: RatuneSpacing.md),
padding: const EdgeInsets.symmetric(vertical: TimbreSpacing.md),
child: artists.when(
loading: () => const _Centered(child: _Loading()),
error: (e, _) => _Centered(child: _ErrorText('$e')),
@ -186,7 +186,7 @@ class _AlbumsPanel extends ConsumerWidget {
trailing: albums.hasValue && albums.value!.isNotEmpty
? '(${albums.value!.length})'
: null,
padding: const EdgeInsets.all(RatuneSpacing.md),
padding: const EdgeInsets.all(TimbreSpacing.md),
child: albums.when(
loading: () => const _Centered(child: _Loading()),
error: (e, _) => _Centered(child: _ErrorText('$e')),
@ -200,8 +200,8 @@ class _AlbumsPanel extends ConsumerWidget {
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: cols,
mainAxisSpacing: RatuneSpacing.md,
crossAxisSpacing: RatuneSpacing.md,
mainAxisSpacing: TimbreSpacing.md,
crossAxisSpacing: TimbreSpacing.md,
// Square art + two caption lines; extra vertical slack so
// the tile never sub-pixel-overflows.
childAspectRatio: 0.68,
@ -241,7 +241,7 @@ class _AlbumTile extends StatelessWidget {
AspectRatio(
aspectRatio: 1,
child: ColoredBox(
color: RatuneColors.surface,
color: TimbreColors.surface,
child: artUri != null
? Image.network(
artUri!,
@ -253,12 +253,12 @@ class _AlbumTile extends StatelessWidget {
: const _AlbumArtFallback(),
),
),
const SizedBox(height: RatuneSpacing.xs),
const SizedBox(height: TimbreSpacing.xs),
Text(
album.name ?? 'Unknown album',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: RatuneColors.foreground),
style: const TextStyle(color: TimbreColors.foreground),
),
if (album.artist != null)
Text(
@ -266,7 +266,7 @@ class _AlbumTile extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: RatuneColors.dimmed, fontSize: 12),
color: TimbreColors.dimmed, fontSize: 12),
),
],
),
@ -279,7 +279,7 @@ class _AlbumArtFallback extends StatelessWidget {
@override
Widget build(BuildContext context) => const Center(
child: Icon(Icons.album_outlined,
color: RatuneColors.dimmed, size: 32),
color: TimbreColors.dimmed, size: 32),
);
}
@ -317,8 +317,8 @@ class _TracksPanelState extends ConsumerState<_TracksPanel> {
mainAxisSize: MainAxisSize.min,
children: [
const _Loading(),
const SizedBox(height: RatuneSpacing.md),
Text(label, style: const TextStyle(color: RatuneColors.dimmed)),
const SizedBox(height: TimbreSpacing.md),
Text(label, style: const TextStyle(color: TimbreColors.dimmed)),
],
),
);
@ -357,7 +357,7 @@ class _TracksPanelState extends ConsumerState<_TracksPanel> {
title: 'Tracks',
active: true,
trailing: index.songs.isNotEmpty ? '(${index.songs.length})' : null,
padding: const EdgeInsets.symmetric(vertical: RatuneSpacing.md),
padding: const EdgeInsets.symmetric(vertical: TimbreSpacing.md),
child: Column(
children: [
Align(
@ -368,11 +368,11 @@ class _TracksPanelState extends ConsumerState<_TracksPanel> {
: () => ref.read(libraryIndexProvider.notifier).refresh(),
child: const Padding(
padding: EdgeInsets.symmetric(
horizontal: RatuneSpacing.lg,
vertical: RatuneSpacing.sm,
horizontal: TimbreSpacing.lg,
vertical: TimbreSpacing.sm,
),
child: Text('↻ refresh',
style: TextStyle(color: RatuneColors.dimmed)),
style: TextStyle(color: TimbreColors.dimmed)),
),
),
),
@ -395,13 +395,13 @@ class _Action extends StatelessWidget {
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: RatuneSpacing.sm),
padding: const EdgeInsets.symmetric(vertical: TimbreSpacing.sm),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: RatuneColors.dimmed),
const SizedBox(width: RatuneSpacing.sm),
Text(label, style: const TextStyle(color: RatuneColors.foreground)),
Icon(icon, size: 16, color: TimbreColors.dimmed),
const SizedBox(width: TimbreSpacing.sm),
Text(label, style: const TextStyle(color: TimbreColors.foreground)),
],
),
),
@ -561,33 +561,33 @@ class BrowseRow extends StatelessWidget {
onTap: onTap,
child: Container(
constraints:
const BoxConstraints(minHeight: RatuneSpacing.minTouchTarget),
padding: const EdgeInsets.only(left: RatuneSpacing.lg),
const BoxConstraints(minHeight: TimbreSpacing.minTouchTarget),
padding: const EdgeInsets.only(left: TimbreSpacing.lg),
child: Row(
children: [
if (leading != null)
SizedBox(
width: 28,
child: Text(leading!,
style: const TextStyle(color: RatuneColors.dimmed)),
style: const TextStyle(color: TimbreColors.dimmed)),
),
Expanded(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: RatuneColors.foreground),
style: const TextStyle(color: TimbreColors.foreground),
),
),
if (isDone)
Padding(
padding: const EdgeInsets.only(left: RatuneSpacing.sm),
padding: const EdgeInsets.only(left: TimbreSpacing.sm),
child:
Icon(Icons.download_done, size: 14, color: accent),
)
else if (isActive)
const Padding(
padding: EdgeInsets.only(left: RatuneSpacing.sm),
padding: EdgeInsets.only(left: TimbreSpacing.sm),
child: SizedBox(
width: 12,
height: 12,
@ -595,9 +595,9 @@ class BrowseRow extends StatelessWidget {
),
),
if (trailing != null) ...[
const SizedBox(width: RatuneSpacing.md),
const SizedBox(width: TimbreSpacing.md),
Text(trailing!,
style: const TextStyle(color: RatuneColors.dimmed)),
style: const TextStyle(color: TimbreColors.dimmed)),
],
if (onPlayNext != null)
_RowIcon(icon: Icons.playlist_play, onTap: onPlayNext!),
@ -612,7 +612,7 @@ class BrowseRow extends StatelessWidget {
onRemoveDownload: onRemoveDownload,
),
if (onPlayNext == null && onAddToQueue == null && !_hasMenu)
const SizedBox(width: RatuneSpacing.lg),
const SizedBox(width: TimbreSpacing.lg),
],
),
),
@ -639,11 +639,11 @@ class _RowMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PopupMenuButton<String>(
icon: const Icon(Icons.more_vert, size: 20, color: RatuneColors.dimmed),
color: RatuneColors.surface,
icon: const Icon(Icons.more_vert, size: 20, color: TimbreColors.dimmed),
color: TimbreColors.surface,
padding: EdgeInsets.zero,
constraints:
const BoxConstraints(minWidth: RatuneSpacing.minTouchTarget),
const BoxConstraints(minWidth: TimbreSpacing.minTouchTarget),
onSelected: (v) {
switch (v) {
case 'playlist':
@ -684,9 +684,9 @@ class _RowIcon extends StatelessWidget {
onTap: onTap,
customBorder: const CircleBorder(),
child: SizedBox(
width: RatuneSpacing.minTouchTarget,
height: RatuneSpacing.minTouchTarget,
child: Icon(icon, size: 20, color: RatuneColors.dimmed),
width: TimbreSpacing.minTouchTarget,
height: TimbreSpacing.minTouchTarget,
child: Icon(icon, size: 20, color: TimbreColors.dimmed),
),
);
}
@ -728,11 +728,11 @@ class _NotConnected extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Text('Not connected.',
style: TextStyle(color: RatuneColors.foreground)),
SizedBox(height: RatuneSpacing.sm),
style: TextStyle(color: TimbreColors.foreground)),
SizedBox(height: TimbreSpacing.sm),
Text('Tap the status bar to add a Subsonic server.',
textAlign: TextAlign.center,
style: TextStyle(color: RatuneColors.dimmed)),
style: TextStyle(color: TimbreColors.dimmed)),
],
),
);
@ -744,7 +744,7 @@ class _Centered extends StatelessWidget {
final Widget child;
@override
Widget build(BuildContext context) => Padding(
padding: const EdgeInsets.all(RatuneSpacing.xl),
padding: const EdgeInsets.all(TimbreSpacing.xl),
child: Center(child: child),
);
}
@ -766,7 +766,7 @@ class _ErrorText extends StatelessWidget {
Widget build(BuildContext context) => Text(
message,
textAlign: TextAlign.center,
style: const TextStyle(color: RatuneColors.dimmed),
style: const TextStyle(color: TimbreColors.dimmed),
);
}