refactor(ui): Lucide migration unit 2 — Icons.* -> LucideIcons.* sweep (#60)
Mechanical sweep across 30 files: every Material Icons.* replaced with the signed-off Lucide equivalent + a flutter_lucide import per file. Zero Material Icons.* remain in lib/; no unused imports. Judgment-call mappings: album->disc_3, library_music->library_big, playlist_play->list_video, graphic_eq->audio_lines, system_update->download, restore->archive_restore, download_done->circle_check_big. track_actions_sheet like menu row: collapsed `liked ? favorite : favorite_border` to a single LucideIcons.heart (the row's Like/Unlike text label conveys state). Icon-only LikeButton + the notification keep the filled-vs-outline shape per the design decision. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ class AdminLandingScreen extends ConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
AdminSectionCard(
|
AdminSectionCard(
|
||||||
key: const Key('admin_card_requests'),
|
key: const Key('admin_card_requests'),
|
||||||
icon: Icons.inbox,
|
icon: LucideIcons.inbox,
|
||||||
title: 'Requests',
|
title: 'Requests',
|
||||||
subtitle: 'Approve or reject Lidarr requests',
|
subtitle: 'Approve or reject Lidarr requests',
|
||||||
count: c.requests,
|
count: c.requests,
|
||||||
@@ -42,7 +43,7 @@ class AdminLandingScreen extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
AdminSectionCard(
|
AdminSectionCard(
|
||||||
key: const Key('admin_card_quarantine'),
|
key: const Key('admin_card_quarantine'),
|
||||||
icon: Icons.warning_amber,
|
icon: LucideIcons.triangle_alert,
|
||||||
title: 'Quarantine',
|
title: 'Quarantine',
|
||||||
subtitle: 'Resolve scan failures',
|
subtitle: 'Resolve scan failures',
|
||||||
count: c.quarantine,
|
count: c.quarantine,
|
||||||
@@ -50,7 +51,7 @@ class AdminLandingScreen extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
AdminSectionCard(
|
AdminSectionCard(
|
||||||
key: const Key('admin_card_users'),
|
key: const Key('admin_card_users'),
|
||||||
icon: Icons.people,
|
icon: LucideIcons.users,
|
||||||
title: 'Users',
|
title: 'Users',
|
||||||
subtitle: 'Manage accounts and invites',
|
subtitle: 'Manage accounts and invites',
|
||||||
count: c.users,
|
count: c.users,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ class AdminUsersScreen extends ConsumerWidget {
|
|||||||
trailing: TextButton.icon(
|
trailing: TextButton.icon(
|
||||||
key: const Key('invite_generate_button'),
|
key: const Key('invite_generate_button'),
|
||||||
onPressed: () => _showGenerateInvite(context, ref),
|
onPressed: () => _showGenerateInvite(context, ref),
|
||||||
icon: Icon(Icons.add, color: fs.parchment),
|
icon: Icon(LucideIcons.plus, color: fs.parchment),
|
||||||
label: Text('Generate',
|
label: Text('Generate',
|
||||||
style: TextStyle(color: fs.parchment)),
|
style: TextStyle(color: fs.parchment)),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
|
|
||||||
import '../../models/admin_quarantine_item.dart';
|
import '../../models/admin_quarantine_item.dart';
|
||||||
import '../../theme/theme_extension.dart';
|
import '../../theme/theme_extension.dart';
|
||||||
@@ -45,7 +46,7 @@ class AdminQuarantineRow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
trailing: PopupMenuButton<String>(
|
trailing: PopupMenuButton<String>(
|
||||||
key: Key('admin_quarantine_menu_${item.trackId}'),
|
key: Key('admin_quarantine_menu_${item.trackId}'),
|
||||||
icon: Icon(Icons.more_vert, color: fs.parchment),
|
icon: Icon(LucideIcons.ellipsis_vertical, color: fs.parchment),
|
||||||
onSelected: (action) async {
|
onSelected: (action) async {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 'resolve':
|
case 'resolve':
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
|
|
||||||
import '../../models/admin_user.dart';
|
import '../../models/admin_user.dart';
|
||||||
import '../../theme/theme_extension.dart';
|
import '../../theme/theme_extension.dart';
|
||||||
@@ -29,7 +30,7 @@ class AdminUserRow extends StatelessWidget {
|
|||||||
_Badge(label: 'auto-approve', color: fs.moss),
|
_Badge(label: 'auto-approve', color: fs.moss),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.chevron_right, color: fs.ash),
|
trailing: Icon(LucideIcons.chevron_right, color: fs.ash),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import '../../models/invite.dart';
|
import '../../models/invite.dart';
|
||||||
@@ -31,7 +32,7 @@ class InviteRow extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.copy, color: fs.ash, size: 18),
|
icon: Icon(LucideIcons.copy, color: fs.ash, size: 18),
|
||||||
tooltip: 'Copy',
|
tooltip: 'Copy',
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
Clipboard.setData(ClipboardData(text: invite.token)),
|
Clipboard.setData(ClipboardData(text: invite.token)),
|
||||||
@@ -63,7 +64,7 @@ class InviteRow extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: Icon(Icons.delete_outline, color: fs.oxblood),
|
icon: Icon(LucideIcons.trash_2, color: fs.oxblood),
|
||||||
tooltip: 'Revoke',
|
tooltip: 'Revoke',
|
||||||
onPressed: onRevoke,
|
onPressed: onRevoke,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -167,7 +168,7 @@ class _DiscoverScreenState extends ConsumerState<DiscoverScreen> {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: Text('Discover', style: TextStyle(color: fs.parchment)),
|
title: Text('Discover', style: TextStyle(color: fs.parchment)),
|
||||||
@@ -193,7 +194,7 @@ class _DiscoverScreenState extends ConsumerState<DiscoverScreen> {
|
|||||||
borderSide: BorderSide(color: fs.accent),
|
borderSide: BorderSide(color: fs.accent),
|
||||||
),
|
),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(Icons.search, color: fs.ash),
|
icon: Icon(LucideIcons.search, color: fs.ash),
|
||||||
onPressed: _runSearch,
|
onPressed: _runSearch,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -336,14 +337,14 @@ class _ResultTile extends StatelessWidget {
|
|||||||
height: 56,
|
height: 56,
|
||||||
color: fs.slate,
|
color: fs.slate,
|
||||||
child: row.imageUrl.isEmpty
|
child: row.imageUrl.isEmpty
|
||||||
? Icon(Icons.album, color: fs.ash)
|
? Icon(LucideIcons.disc_3, color: fs.ash)
|
||||||
: CachedNetworkImage(
|
: CachedNetworkImage(
|
||||||
imageUrl: row.imageUrl,
|
imageUrl: row.imageUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
fadeInDuration: const Duration(milliseconds: 120),
|
fadeInDuration: const Duration(milliseconds: 120),
|
||||||
fadeOutDuration: Duration.zero,
|
fadeOutDuration: Duration.zero,
|
||||||
errorWidget: (_, __, ___) =>
|
errorWidget: (_, __, ___) =>
|
||||||
Icon(Icons.album, color: fs.ash),
|
Icon(LucideIcons.disc_3, color: fs.ash),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -419,14 +420,14 @@ class _SuggestionTile extends StatelessWidget {
|
|||||||
height: 56,
|
height: 56,
|
||||||
color: fs.slate,
|
color: fs.slate,
|
||||||
child: s.imageUrl.isEmpty
|
child: s.imageUrl.isEmpty
|
||||||
? Icon(Icons.person, color: fs.ash)
|
? Icon(LucideIcons.user, color: fs.ash)
|
||||||
: CachedNetworkImage(
|
: CachedNetworkImage(
|
||||||
imageUrl: s.imageUrl,
|
imageUrl: s.imageUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
fadeInDuration: const Duration(milliseconds: 120),
|
fadeInDuration: const Duration(milliseconds: 120),
|
||||||
fadeOutDuration: Duration.zero,
|
fadeOutDuration: Duration.zero,
|
||||||
errorWidget: (_, __, ___) =>
|
errorWidget: (_, __, ___) =>
|
||||||
Icon(Icons.person, color: fs.ash),
|
Icon(LucideIcons.user, color: fs.ash),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../api/endpoints/likes.dart';
|
import '../api/endpoints/likes.dart';
|
||||||
@@ -115,7 +116,7 @@ class AlbumDetailScreen extends ConsumerWidget {
|
|||||||
width: 48, height: 48,
|
width: 48, height: 48,
|
||||||
decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle),
|
decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.play_arrow, color: fs.parchment),
|
icon: Icon(LucideIcons.play, color: fs.parchment),
|
||||||
onPressed: () => ref.read(playerActionsProvider).playTracks(r.tracks),
|
onPressed: () => ref.read(playerActionsProvider).playTracks(r.tracks),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ class ArtistDetailScreen extends ConsumerWidget {
|
|||||||
width: 48, height: 48,
|
width: 48, height: 48,
|
||||||
decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle),
|
decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.play_arrow, color: fs.parchment),
|
icon: Icon(LucideIcons.play, color: fs.parchment),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
try {
|
try {
|
||||||
final tracks =
|
final tracks =
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -245,12 +246,12 @@ class _PlaylistsSection extends StatelessWidget {
|
|||||||
if (offline) ...const [
|
if (offline) ...const [
|
||||||
_OfflinePoolCard(
|
_OfflinePoolCard(
|
||||||
label: 'Recently played',
|
label: 'Recently played',
|
||||||
icon: Icons.history,
|
icon: LucideIcons.history,
|
||||||
kind: _OfflinePoolKind.recentlyPlayed,
|
kind: _OfflinePoolKind.recentlyPlayed,
|
||||||
),
|
),
|
||||||
_OfflinePoolCard(
|
_OfflinePoolCard(
|
||||||
label: 'Liked',
|
label: 'Liked',
|
||||||
icon: Icons.favorite,
|
icon: LucideIcons.heart,
|
||||||
kind: _OfflinePoolKind.liked,
|
kind: _OfflinePoolKind.liked,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:drift/drift.dart' as drift;
|
import 'package:drift/drift.dart' as drift;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -382,7 +383,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
|
|||||||
IconButton(
|
IconButton(
|
||||||
key: const Key('shuffle_all_button'),
|
key: const Key('shuffle_all_button'),
|
||||||
tooltip: 'Shuffle all',
|
tooltip: 'Shuffle all',
|
||||||
icon: Icon(Icons.shuffle, color: fs.parchment),
|
icon: Icon(LucideIcons.shuffle, color: fs.parchment),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final messenger = ScaffoldMessenger.of(context);
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
final refs = await ref.read(shuffleSourceProvider).tracks();
|
final refs = await ref.read(shuffleSourceProvider).tracks();
|
||||||
@@ -866,7 +867,7 @@ class _QuarantineTile extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: 'Unhide',
|
tooltip: 'Unhide',
|
||||||
icon: Icon(Icons.restore, color: fs.ash, size: 20),
|
icon: Icon(LucideIcons.archive_restore, color: fs.ash, size: 20),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
try {
|
try {
|
||||||
await ref.read(myQuarantineProvider.notifier).unflag(row.trackId);
|
await ref.read(myQuarantineProvider.notifier).unflag(row.trackId);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../cache/audio_cache_manager.dart';
|
import '../../cache/audio_cache_manager.dart';
|
||||||
@@ -21,7 +22,7 @@ class CachedIndicator extends ConsumerWidget {
|
|||||||
if (snap.data != true) return const SizedBox.shrink();
|
if (snap.data != true) return const SizedBox.shrink();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 4),
|
padding: const EdgeInsets.only(left: 4),
|
||||||
child: Icon(Icons.download_done, size: 14, color: fs.accent),
|
child: Icon(LucideIcons.circle_check_big, size: 14, color: fs.accent),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
|
|
||||||
import '../../theme/theme_extension.dart';
|
import '../../theme/theme_extension.dart';
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ class _PlayCircleButtonState extends State<PlayCircleButton> {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Icon(
|
: Icon(
|
||||||
Icons.play_arrow,
|
LucideIcons.play,
|
||||||
color: fs.parchment,
|
color: fs.parchment,
|
||||||
size: iconSize,
|
size: iconSize,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -376,13 +377,13 @@ class _TopBar extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.expand_more, color: fs.parchment),
|
icon: Icon(LucideIcons.chevron_down, color: fs.parchment),
|
||||||
tooltip: 'Close',
|
tooltip: 'Close',
|
||||||
onPressed: () => Navigator.of(context).maybePop(),
|
onPressed: () => Navigator.of(context).maybePop(),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.queue_music, color: fs.parchment),
|
icon: Icon(LucideIcons.list_music, color: fs.parchment),
|
||||||
tooltip: 'Queue',
|
tooltip: 'Queue',
|
||||||
onPressed: () => GoRouter.of(context).push('/queue'),
|
onPressed: () => GoRouter.of(context).push('/queue'),
|
||||||
),
|
),
|
||||||
@@ -535,13 +536,13 @@ class _PrimaryControls extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
iconSize: 36,
|
iconSize: 36,
|
||||||
icon: Icon(Icons.skip_previous, color: fs.parchment),
|
icon: Icon(LucideIcons.skip_back, color: fs.parchment),
|
||||||
onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(),
|
onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
iconSize: 72,
|
iconSize: 72,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled,
|
isPlaying ? LucideIcons.circle_pause : LucideIcons.circle_play,
|
||||||
color: fs.accent,
|
color: fs.accent,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -555,7 +556,7 @@ class _PrimaryControls extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
iconSize: 36,
|
iconSize: 36,
|
||||||
icon: Icon(Icons.skip_next, color: fs.parchment),
|
icon: Icon(LucideIcons.skip_forward, color: fs.parchment),
|
||||||
onPressed: () => ref.read(audioHandlerProvider).skipToNext(),
|
onPressed: () => ref.read(audioHandlerProvider).skipToNext(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -589,7 +590,7 @@ class _SecondaryControls extends StatelessWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
tooltip: shuffleOn ? 'Shuffle on' : 'Shuffle off',
|
tooltip: shuffleOn ? 'Shuffle on' : 'Shuffle off',
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.shuffle,
|
LucideIcons.shuffle,
|
||||||
color: shuffleOn ? fs.accent : fs.ash,
|
color: shuffleOn ? fs.accent : fs.ash,
|
||||||
),
|
),
|
||||||
onPressed: actions.toggleShuffle,
|
onPressed: actions.toggleShuffle,
|
||||||
@@ -602,8 +603,8 @@ class _SecondaryControls extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
repeatMode == AudioServiceRepeatMode.one
|
repeatMode == AudioServiceRepeatMode.one
|
||||||
? Icons.repeat_one
|
? LucideIcons.repeat_1
|
||||||
: Icons.repeat,
|
: LucideIcons.repeat,
|
||||||
color: repeatMode == AudioServiceRepeatMode.none
|
color: repeatMode == AudioServiceRepeatMode.none
|
||||||
? fs.ash
|
? fs.ash
|
||||||
: fs.accent,
|
: fs.accent,
|
||||||
@@ -612,7 +613,7 @@ class _SecondaryControls extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: 'Queue',
|
tooltip: 'Queue',
|
||||||
icon: Icon(Icons.queue_music, color: fs.ash),
|
icon: Icon(LucideIcons.list_music, color: fs.ash),
|
||||||
onPressed: () => GoRouter.of(context).push('/queue'),
|
onPressed: () => GoRouter.of(context).push('/queue'),
|
||||||
),
|
),
|
||||||
LikeButton(kind: LikeKind.track, id: media.id, size: 22),
|
LikeButton(kind: LikeKind.track, id: media.id, size: 22),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
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:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -229,7 +230,7 @@ class _PlayControls extends StatelessWidget {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 22,
|
iconSize: 22,
|
||||||
icon: Icon(Icons.skip_previous, color: fs.parchment),
|
icon: Icon(LucideIcons.skip_back, color: fs.parchment),
|
||||||
onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(),
|
onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -240,7 +241,7 @@ class _PlayControls extends StatelessWidget {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 32,
|
iconSize: 32,
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled,
|
isPlaying ? LucideIcons.circle_pause : LucideIcons.circle_play,
|
||||||
color: fs.accent,
|
color: fs.accent,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -259,7 +260,7 @@ class _PlayControls extends StatelessWidget {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 22,
|
iconSize: 22,
|
||||||
icon: Icon(Icons.skip_next, color: fs.parchment),
|
icon: Icon(LucideIcons.skip_forward, color: fs.parchment),
|
||||||
onPressed: () => ref.read(audioHandlerProvider).skipToNext(),
|
onPressed: () => ref.read(audioHandlerProvider).skipToNext(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ class QueueScreen extends ConsumerWidget {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: Text('Queue', style: TextStyle(color: fs.parchment)),
|
title: Text('Queue', style: TextStyle(color: fs.parchment)),
|
||||||
@@ -84,7 +85,7 @@ class _QueueRow extends StatelessWidget {
|
|||||||
if (isCurrent)
|
if (isCurrent)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 8),
|
padding: const EdgeInsets.only(right: 8),
|
||||||
child: Icon(Icons.graphic_eq, color: fs.accent, size: 16),
|
child: Icon(LucideIcons.audio_lines, color: fs.accent, size: 16),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ class PlaylistDetailScreen extends ConsumerWidget {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: headerName.isEmpty
|
title: headerName.isEmpty
|
||||||
@@ -268,7 +269,7 @@ class _Header extends ConsumerWidget {
|
|||||||
OutlinedButton.icon(
|
OutlinedButton.icon(
|
||||||
key: const Key('regenerate_playlist_button'),
|
key: const Key('regenerate_playlist_button'),
|
||||||
onPressed: () => _regenerate(context, ref),
|
onPressed: () => _regenerate(context, ref),
|
||||||
icon: const Icon(Icons.refresh, size: 16),
|
icon: const Icon(LucideIcons.refresh_cw, size: 16),
|
||||||
label: const Text('Regenerate'),
|
label: const Text('Regenerate'),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
@@ -281,7 +282,7 @@ class _Header extends ConsumerWidget {
|
|||||||
source: p.refreshable ? p.systemVariant : null,
|
source: p.refreshable ? p.systemVariant : null,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.play_arrow),
|
icon: const Icon(LucideIcons.play),
|
||||||
label: const Text('Play'),
|
label: const Text('Play'),
|
||||||
style: FilledButton.styleFrom(
|
style: FilledButton.styleFrom(
|
||||||
backgroundColor: fs.accent,
|
backgroundColor: fs.accent,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -82,11 +83,11 @@ class _PlaylistTile extends StatelessWidget {
|
|||||||
height: 56,
|
height: 56,
|
||||||
color: fs.slate,
|
color: fs.slate,
|
||||||
child: playlist.coverUrl.isEmpty
|
child: playlist.coverUrl.isEmpty
|
||||||
? Icon(Icons.queue_music, color: fs.ash)
|
? Icon(LucideIcons.list_music, color: fs.ash)
|
||||||
: ServerImage(
|
: ServerImage(
|
||||||
url: playlist.coverUrl,
|
url: playlist.coverUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
fallback: Icon(Icons.queue_music, color: fs.ash),
|
fallback: Icon(LucideIcons.list_music, color: fs.ash),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -128,7 +129,7 @@ class _PlaylistTile extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Icon(Icons.chevron_right, color: fs.ash),
|
Icon(LucideIcons.chevron_right, color: fs.ash),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -55,12 +56,12 @@ class PlaylistCard extends ConsumerWidget {
|
|||||||
// errorBuilder shows the queue_music icon over the
|
// errorBuilder shows the queue_music icon over the
|
||||||
// slate background.
|
// slate background.
|
||||||
child: playlist.coverUrl.isEmpty
|
child: playlist.coverUrl.isEmpty
|
||||||
? Icon(Icons.queue_music, color: fs.ash, size: 56)
|
? Icon(LucideIcons.list_music, color: fs.ash, size: 56)
|
||||||
: ServerImage(
|
: ServerImage(
|
||||||
url: playlist.coverUrl,
|
url: playlist.coverUrl,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
fallback:
|
fallback:
|
||||||
Icon(Icons.queue_music, color: fs.ash, size: 56),
|
Icon(LucideIcons.list_music, color: fs.ash, size: 56),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -80,7 +81,7 @@ class PlaylistCard extends ConsumerWidget {
|
|||||||
top: 2,
|
top: 2,
|
||||||
right: 2,
|
right: 2,
|
||||||
child: PopupMenuButton<String>(
|
child: PopupMenuButton<String>(
|
||||||
icon: Icon(Icons.more_vert, color: fs.parchment, size: 18),
|
icon: Icon(LucideIcons.ellipsis_vertical, color: fs.parchment, size: 18),
|
||||||
tooltip: 'Playlist actions',
|
tooltip: 'Playlist actions',
|
||||||
color: fs.iron,
|
color: fs.iron,
|
||||||
onSelected: (_) => _refresh(context, ref),
|
onSelected: (_) => _refresh(context, ref),
|
||||||
@@ -88,7 +89,7 @@ class PlaylistCard extends ConsumerWidget {
|
|||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
value: 'refresh',
|
value: 'refresh',
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
Icon(Icons.refresh, color: fs.parchment, size: 18),
|
Icon(LucideIcons.refresh_cw, color: fs.parchment, size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(_refreshLabel,
|
Text(_refreshLabel,
|
||||||
style: TextStyle(color: fs.parchment)),
|
style: TextStyle(color: fs.parchment)),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
|
|
||||||
import '../../theme/theme_extension.dart';
|
import '../../theme/theme_extension.dart';
|
||||||
|
|
||||||
@@ -65,9 +66,9 @@ class PlaylistPlaceholderCard extends StatelessWidget {
|
|||||||
child: CircularProgressIndicator(strokeWidth: 2, color: fs.accent),
|
child: CircularProgressIndicator(strokeWidth: 2, color: fs.accent),
|
||||||
);
|
);
|
||||||
case 'failed':
|
case 'failed':
|
||||||
return Icon(Icons.warning_amber, color: fs.error, size: 32);
|
return Icon(LucideIcons.triangle_alert, color: fs.error, size: 32);
|
||||||
default:
|
default:
|
||||||
return Icon(Icons.queue_music, color: fs.ash, size: 40);
|
return Icon(LucideIcons.list_music, color: fs.ash, size: 40);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ class RequestsScreen extends ConsumerWidget {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: Text('Your requests', style: TextStyle(color: fs.parchment)),
|
title: Text('Your requests', style: TextStyle(color: fs.parchment)),
|
||||||
@@ -130,9 +131,9 @@ class _RequestRow extends StatelessWidget {
|
|||||||
|
|
||||||
Widget _kindAvatar(FabledSwordTheme fs) {
|
Widget _kindAvatar(FabledSwordTheme fs) {
|
||||||
final icon = switch (request.kind) {
|
final icon = switch (request.kind) {
|
||||||
'artist' => Icons.album,
|
'artist' => LucideIcons.disc_3,
|
||||||
'album' => Icons.library_music,
|
'album' => LucideIcons.library_big,
|
||||||
_ => Icons.music_note,
|
_ => LucideIcons.music,
|
||||||
};
|
};
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: fs.iron,
|
backgroundColor: fs.iron,
|
||||||
@@ -164,7 +165,7 @@ class _RequestRow extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
if (ok == true) onCancel();
|
if (ok == true) onCancel();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.close, size: 16),
|
icon: const Icon(LucideIcons.x, size: 16),
|
||||||
label: const Text('Cancel'),
|
label: const Text('Cancel'),
|
||||||
style: TextButton.styleFrom(foregroundColor: fs.ash),
|
style: TextButton.styleFrom(foregroundColor: fs.ash),
|
||||||
);
|
);
|
||||||
@@ -172,7 +173,7 @@ class _RequestRow extends StatelessWidget {
|
|||||||
if (request.status == 'completed' && href != null) {
|
if (request.status == 'completed' && href != null) {
|
||||||
return TextButton.icon(
|
return TextButton.icon(
|
||||||
onPressed: () => context.push(href),
|
onPressed: () => context.push(href),
|
||||||
icon: const Icon(Icons.play_arrow, size: 16),
|
icon: const Icon(LucideIcons.play, size: 16),
|
||||||
label: const Text('Listen'),
|
label: const Text('Listen'),
|
||||||
style: TextButton.styleFrom(foregroundColor: fs.accent),
|
style: TextButton.styleFrom(foregroundColor: fs.accent),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class _SearchScreenState extends ConsumerState<SearchScreen> {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: TextField(
|
title: TextField(
|
||||||
@@ -67,7 +68,7 @@ class _SearchScreenState extends ConsumerState<SearchScreen> {
|
|||||||
actions: [
|
actions: [
|
||||||
if (_controller.text.isNotEmpty)
|
if (_controller.text.isNotEmpty)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.clear, color: fs.ash),
|
icon: Icon(LucideIcons.x, color: fs.ash),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_controller.clear();
|
_controller.clear();
|
||||||
ref.read(searchQueryProvider.notifier).set('');
|
ref.read(searchQueryProvider.notifier).set('');
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ class _AboutSectionState extends ConsumerState<AboutSection> {
|
|||||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 4),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.info_outline, color: fs.parchment, size: 18),
|
Icon(LucideIcons.info, color: fs.parchment, size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text('Installed version',
|
Text('Installed version',
|
||||||
style: TextStyle(color: fs.parchment, fontSize: 14)),
|
style: TextStyle(color: fs.parchment, fontSize: 14)),
|
||||||
@@ -105,7 +106,7 @@ class _AboutSectionState extends ConsumerState<AboutSection> {
|
|||||||
padding: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.cloud_outlined, color: fs.parchment, size: 18),
|
Icon(LucideIcons.cloud, color: fs.parchment, size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text('Latest version',
|
Text('Latest version',
|
||||||
style: TextStyle(color: fs.parchment, fontSize: 14)),
|
style: TextStyle(color: fs.parchment, fontSize: 14)),
|
||||||
@@ -148,7 +149,7 @@ class _AboutSectionState extends ConsumerState<AboutSection> {
|
|||||||
valueColor: AlwaysStoppedAnimation(fs.parchment),
|
valueColor: AlwaysStoppedAnimation(fs.parchment),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const Icon(Icons.refresh, size: 18),
|
: const Icon(LucideIcons.refresh_cw, size: 18),
|
||||||
label: Text(_checking ? 'Checking…' : 'Check for updates'),
|
label: Text(_checking ? 'Checking…' : 'Check for updates'),
|
||||||
),
|
),
|
||||||
if (hasUpdate) ...[
|
if (hasUpdate) ...[
|
||||||
@@ -172,7 +173,7 @@ class _AboutSectionState extends ConsumerState<AboutSection> {
|
|||||||
valueColor: AlwaysStoppedAnimation(fs.parchment),
|
valueColor: AlwaysStoppedAnimation(fs.parchment),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const Icon(Icons.system_update, size: 18),
|
: const Icon(LucideIcons.download, size: 18),
|
||||||
label: Text(
|
label: Text(
|
||||||
_installStage == _InstallStage.downloading
|
_installStage == _InstallStage.downloading
|
||||||
? 'Downloading…'
|
? 'Downloading…'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ class SettingsScreen extends ConsumerWidget {
|
|||||||
backgroundColor: fs.obsidian,
|
backgroundColor: fs.obsidian,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: Icon(Icons.arrow_back, color: fs.parchment),
|
icon: Icon(LucideIcons.arrow_left, color: fs.parchment),
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
),
|
),
|
||||||
title: Text('Settings', style: TextStyle(color: fs.parchment)),
|
title: Text('Settings', style: TextStyle(color: fs.parchment)),
|
||||||
@@ -107,7 +108,7 @@ class _RequestsSection extends StatelessWidget {
|
|||||||
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
|
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
|
||||||
return ListTile(
|
return ListTile(
|
||||||
key: const Key('settings_requests_card'),
|
key: const Key('settings_requests_card'),
|
||||||
leading: Icon(Icons.queue_music, color: fs.parchment),
|
leading: Icon(LucideIcons.list_music, color: fs.parchment),
|
||||||
title: Text(
|
title: Text(
|
||||||
'My requests',
|
'My requests',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -120,7 +121,7 @@ class _RequestsSection extends StatelessWidget {
|
|||||||
"Track what you've asked Minstrel to add",
|
"Track what you've asked Minstrel to add",
|
||||||
style: TextStyle(color: fs.ash),
|
style: TextStyle(color: fs.ash),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.chevron_right, color: fs.ash),
|
trailing: Icon(LucideIcons.chevron_right, color: fs.ash),
|
||||||
onTap: () => context.push('/requests'),
|
onTap: () => context.push('/requests'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ class _AdminSection extends ConsumerWidget {
|
|||||||
const _Divider(),
|
const _Divider(),
|
||||||
ListTile(
|
ListTile(
|
||||||
key: const Key('settings_admin_card'),
|
key: const Key('settings_admin_card'),
|
||||||
leading: Icon(Icons.shield, color: fs.parchment),
|
leading: Icon(LucideIcons.shield, color: fs.parchment),
|
||||||
title: Text(
|
title: Text(
|
||||||
'Admin',
|
'Admin',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -156,7 +157,7 @@ class _AdminSection extends ConsumerWidget {
|
|||||||
'Manage requests, quarantine, and users',
|
'Manage requests, quarantine, and users',
|
||||||
style: TextStyle(color: fs.ash),
|
style: TextStyle(color: fs.ash),
|
||||||
),
|
),
|
||||||
trailing: Icon(Icons.chevron_right, color: fs.ash),
|
trailing: Icon(LucideIcons.chevron_right, color: fs.ash),
|
||||||
onTap: () => context.push('/admin'),
|
onTap: () => context.push('/admin'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../cache/audio_cache_manager.dart';
|
import '../cache/audio_cache_manager.dart';
|
||||||
@@ -140,7 +141,7 @@ class _StorageSectionState extends ConsumerState<StorageSection> {
|
|||||||
height: 14,
|
height: 14,
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
)
|
)
|
||||||
: const Icon(Icons.sync, size: 16),
|
: const Icon(LucideIcons.refresh_cw, size: 16),
|
||||||
label: const Text('Sync now'),
|
label: const Text('Sync now'),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -26,27 +27,27 @@ class MainAppBarActions extends ConsumerWidget {
|
|||||||
if (currentRoute != '/home')
|
if (currentRoute != '/home')
|
||||||
IconButton(
|
IconButton(
|
||||||
key: const Key('app_bar_home'),
|
key: const Key('app_bar_home'),
|
||||||
icon: Icon(Icons.home, color: fs.parchment),
|
icon: Icon(LucideIcons.house, color: fs.parchment),
|
||||||
tooltip: 'Home',
|
tooltip: 'Home',
|
||||||
onPressed: () => context.go('/home'),
|
onPressed: () => context.go('/home'),
|
||||||
),
|
),
|
||||||
if (currentRoute != '/library')
|
if (currentRoute != '/library')
|
||||||
IconButton(
|
IconButton(
|
||||||
key: const Key('app_bar_library'),
|
key: const Key('app_bar_library'),
|
||||||
icon: Icon(Icons.library_music, color: fs.parchment),
|
icon: Icon(LucideIcons.library_big, color: fs.parchment),
|
||||||
tooltip: 'Library',
|
tooltip: 'Library',
|
||||||
onPressed: () => context.push('/library'),
|
onPressed: () => context.push('/library'),
|
||||||
),
|
),
|
||||||
if (currentRoute != '/search')
|
if (currentRoute != '/search')
|
||||||
IconButton(
|
IconButton(
|
||||||
key: const Key('app_bar_search'),
|
key: const Key('app_bar_search'),
|
||||||
icon: Icon(Icons.search, color: fs.parchment),
|
icon: Icon(LucideIcons.search, color: fs.parchment),
|
||||||
tooltip: 'Search',
|
tooltip: 'Search',
|
||||||
onPressed: () => context.push('/search'),
|
onPressed: () => context.push('/search'),
|
||||||
),
|
),
|
||||||
PopupMenuButton<String>(
|
PopupMenuButton<String>(
|
||||||
key: const Key('app_bar_overflow'),
|
key: const Key('app_bar_overflow'),
|
||||||
icon: Icon(Icons.more_vert, color: fs.parchment),
|
icon: Icon(LucideIcons.ellipsis_vertical, color: fs.parchment),
|
||||||
tooltip: 'More',
|
tooltip: 'More',
|
||||||
onSelected: (route) => context.push(route),
|
onSelected: (route) => context.push(route),
|
||||||
itemBuilder: (_) => [
|
itemBuilder: (_) => [
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../playlists/playlists_provider.dart';
|
import '../../../playlists/playlists_provider.dart';
|
||||||
@@ -70,7 +71,7 @@ class AddToPlaylistSheet extends ConsumerWidget {
|
|||||||
final p = owned[i];
|
final p = owned[i];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
key: Key('add_to_playlist_${p.id}'),
|
key: Key('add_to_playlist_${p.id}'),
|
||||||
leading: Icon(Icons.queue_music, color: fs.parchment),
|
leading: Icon(LucideIcons.list_music, color: fs.parchment),
|
||||||
title: Text(
|
title: Text(
|
||||||
p.name,
|
p.name,
|
||||||
style: TextStyle(color: fs.parchment),
|
style: TextStyle(color: fs.parchment),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
|
|
||||||
import '../../../models/track.dart';
|
import '../../../models/track.dart';
|
||||||
import '../../../theme/theme_extension.dart';
|
import '../../../theme/theme_extension.dart';
|
||||||
@@ -29,7 +30,7 @@ class TrackActionsButton extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
|
final fs = Theme.of(context).extension<FabledSwordTheme>()!;
|
||||||
return IconButton(
|
return IconButton(
|
||||||
icon: Icon(Icons.more_vert, color: fs.ash, size: 18),
|
icon: Icon(LucideIcons.ellipsis_vertical, color: fs.ash, size: 18),
|
||||||
tooltip: 'Track actions',
|
tooltip: 'Track actions',
|
||||||
onPressed: () => TrackActionsSheet.show(
|
onPressed: () => TrackActionsSheet.show(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:drift/drift.dart' as drift;
|
import 'package:drift/drift.dart' as drift;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
if (!hideQueueActions) ...[
|
if (!hideQueueActions) ...[
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_play_next'),
|
key: const Key('track_actions_play_next'),
|
||||||
icon: Icons.playlist_play,
|
icon: LucideIcons.list_video,
|
||||||
label: 'Play next',
|
label: 'Play next',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -87,7 +88,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_enqueue'),
|
key: const Key('track_actions_enqueue'),
|
||||||
icon: Icons.queue_music,
|
icon: LucideIcons.list_music,
|
||||||
label: 'Add to queue',
|
label: 'Add to queue',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -103,7 +104,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_like'),
|
key: const Key('track_actions_like'),
|
||||||
icon: liked ? Icons.favorite : Icons.favorite_border,
|
icon: LucideIcons.heart,
|
||||||
label: liked ? 'Unlike' : 'Like',
|
label: liked ? 'Unlike' : 'Like',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -112,7 +113,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_add_to_playlist'),
|
key: const Key('track_actions_add_to_playlist'),
|
||||||
icon: Icons.playlist_add,
|
icon: LucideIcons.list_plus,
|
||||||
label: 'Add to playlist…',
|
label: 'Add to playlist…',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -136,7 +137,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_start_radio'),
|
key: const Key('track_actions_start_radio'),
|
||||||
icon: Icons.radio,
|
icon: LucideIcons.radio,
|
||||||
label: 'Start radio',
|
label: 'Start radio',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -154,7 +155,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
const _Divider(),
|
const _Divider(),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_go_to_album'),
|
key: const Key('track_actions_go_to_album'),
|
||||||
icon: Icons.album,
|
icon: LucideIcons.disc_3,
|
||||||
label: 'Go to album',
|
label: 'Go to album',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -168,7 +169,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_go_to_artist'),
|
key: const Key('track_actions_go_to_artist'),
|
||||||
icon: Icons.person,
|
icon: LucideIcons.user,
|
||||||
label: 'Go to artist',
|
label: 'Go to artist',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@@ -183,7 +184,7 @@ class TrackActionsSheet extends ConsumerWidget {
|
|||||||
const _Divider(),
|
const _Divider(),
|
||||||
_MenuItem(
|
_MenuItem(
|
||||||
key: const Key('track_actions_hide'),
|
key: const Key('track_actions_hide'),
|
||||||
icon: hidden ? Icons.visibility : Icons.visibility_off,
|
icon: hidden ? LucideIcons.eye : LucideIcons.eye_off,
|
||||||
label: hidden ? 'Unhide' : 'Hide',
|
label: hidden ? 'Unhide' : 'Hide',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:pub_semver/pub_semver.dart';
|
import 'package:pub_semver/pub_semver.dart';
|
||||||
@@ -238,7 +239,7 @@ class VersionTooOldBanner extends ConsumerWidget {
|
|||||||
color: fs.error.withValues(alpha: 0.15),
|
color: fs.error.withValues(alpha: 0.15),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
||||||
child: Row(children: [
|
child: Row(children: [
|
||||||
Icon(Icons.warning_amber_rounded, color: fs.error, size: 18),
|
Icon(LucideIcons.triangle_alert, color: fs.error, size: 18),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_lucide/flutter_lucide.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../theme/theme_extension.dart';
|
import '../theme/theme_extension.dart';
|
||||||
@@ -66,7 +67,7 @@ class _UpdateBannerState extends ConsumerState<UpdateBanner> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.system_update, color: fs.parchment, size: 16),
|
Icon(LucideIcons.download, color: fs.parchment, size: 16),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -132,7 +133,7 @@ class _UpdateBannerState extends ConsumerState<UpdateBanner> {
|
|||||||
tooltip: 'Dismiss',
|
tooltip: 'Dismiss',
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
icon: Icon(Icons.close, color: fs.ash),
|
icon: Icon(LucideIcons.x, color: fs.ash),
|
||||||
onPressed: () => _onDismiss(info),
|
onPressed: () => _onDismiss(info),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user