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

@ -34,13 +34,13 @@ class PlaylistsScreen extends ConsumerWidget {
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(RatuneSpacing.lg),
padding: const EdgeInsets.all(TimbreSpacing.lg),
child: HairlinePanel(
title: 'Playlists',
active: true,
trailing:
state.playlists.isEmpty ? null : '(${state.playlists.length})',
padding: const EdgeInsets.symmetric(vertical: RatuneSpacing.md),
padding: const EdgeInsets.symmetric(vertical: TimbreSpacing.md),
child: state.playlists.isEmpty
? Center(
child: Text(
@ -48,7 +48,7 @@ class PlaylistsScreen extends ConsumerWidget {
? 'No playlists yet. Tap + to create one.'
: 'Connect to a server to see playlists.',
textAlign: TextAlign.center,
style: const TextStyle(color: RatuneColors.dimmed),
style: const TextStyle(color: TimbreColors.dimmed),
),
)
: ListView.builder(
@ -99,7 +99,7 @@ class PlaylistsScreen extends ConsumerWidget {
final ok = await showDialog<bool>(
context: context,
builder: (ctx) => AlertDialog(
backgroundColor: RatuneColors.surface,
backgroundColor: TimbreColors.surface,
title: Text('Delete "${p.name}"?'),
actions: [
TextButton(
@ -136,12 +136,12 @@ class _PlaylistRow 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: [
const Icon(Icons.queue_music, size: 18, color: RatuneColors.dimmed),
const SizedBox(width: RatuneSpacing.md),
const Icon(Icons.queue_music, size: 18, color: TimbreColors.dimmed),
const SizedBox(width: TimbreSpacing.md),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -150,19 +150,19 @@ class _PlaylistRow extends StatelessWidget {
Text(name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: RatuneColors.foreground)),
style: const TextStyle(color: TimbreColors.foreground)),
if (subtitle != null)
Text(subtitle!,
style: const TextStyle(
color: RatuneColors.dimmed, fontSize: 12)),
color: TimbreColors.dimmed, fontSize: 12)),
],
),
),
if (onRename != null || onDelete != null)
PopupMenuButton<String>(
icon: const Icon(Icons.more_vert,
size: 20, color: RatuneColors.dimmed),
color: RatuneColors.surface,
size: 20, color: TimbreColors.dimmed),
color: TimbreColors.surface,
onSelected: (v) {
if (v == 'rename') onRename?.call();
if (v == 'delete') onDelete?.call();
@ -247,16 +247,16 @@ class _PlaylistDetailScreenState extends ConsumerState<PlaylistDetailScreen> {
child: detail == null
? const Center(
child: Text('Loading…',
style: TextStyle(color: RatuneColors.dimmed)),
style: TextStyle(color: TimbreColors.dimmed)),
)
: songs.isEmpty
? const Center(
child: Text('This playlist is empty.',
style: TextStyle(color: RatuneColors.dimmed)),
style: TextStyle(color: TimbreColors.dimmed)),
)
: ListView.builder(
padding: const EdgeInsets.symmetric(
vertical: RatuneSpacing.md),
vertical: TimbreSpacing.md),
itemCount: songs.length,
itemBuilder: (context, i) {
final song = songs[i];
@ -302,14 +302,14 @@ class _TrackRow 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: [
SizedBox(
width: 28,
child: Text('$index',
style: const TextStyle(color: RatuneColors.dimmed)),
style: const TextStyle(color: TimbreColors.dimmed)),
),
Expanded(
child: Column(
@ -319,20 +319,20 @@ class _TrackRow extends StatelessWidget {
Text(song.title ?? 'Untitled',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(color: RatuneColors.foreground)),
style: const TextStyle(color: TimbreColors.foreground)),
if (song.artist != null)
Text(song.artist!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: RatuneColors.dimmed, fontSize: 12)),
color: TimbreColors.dimmed, fontSize: 12)),
],
),
),
PopupMenuButton<String>(
icon: const Icon(Icons.more_vert,
size: 20, color: RatuneColors.dimmed),
color: RatuneColors.surface,
size: 20, color: TimbreColors.dimmed),
color: TimbreColors.surface,
onSelected: (v) {
switch (v) {
case 'next':