diff --git a/flutter_client/lib/admin/admin_landing_screen.dart b/flutter_client/lib/admin/admin_landing_screen.dart index 3849c77f..79d0a03c 100644 --- a/flutter_client/lib/admin/admin_landing_screen.dart +++ b/flutter_client/lib/admin/admin_landing_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -34,7 +35,7 @@ class AdminLandingScreen extends ConsumerWidget { children: [ AdminSectionCard( key: const Key('admin_card_requests'), - icon: Icons.inbox, + icon: LucideIcons.inbox, title: 'Requests', subtitle: 'Approve or reject Lidarr requests', count: c.requests, @@ -42,7 +43,7 @@ class AdminLandingScreen extends ConsumerWidget { ), AdminSectionCard( key: const Key('admin_card_quarantine'), - icon: Icons.warning_amber, + icon: LucideIcons.triangle_alert, title: 'Quarantine', subtitle: 'Resolve scan failures', count: c.quarantine, @@ -50,7 +51,7 @@ class AdminLandingScreen extends ConsumerWidget { ), AdminSectionCard( key: const Key('admin_card_users'), - icon: Icons.people, + icon: LucideIcons.users, title: 'Users', subtitle: 'Manage accounts and invites', count: c.users, diff --git a/flutter_client/lib/admin/admin_users_screen.dart b/flutter_client/lib/admin/admin_users_screen.dart index d12226e2..122a5891 100644 --- a/flutter_client/lib/admin/admin_users_screen.dart +++ b/flutter_client/lib/admin/admin_users_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -59,7 +60,7 @@ class AdminUsersScreen extends ConsumerWidget { trailing: TextButton.icon( key: const Key('invite_generate_button'), onPressed: () => _showGenerateInvite(context, ref), - icon: Icon(Icons.add, color: fs.parchment), + icon: Icon(LucideIcons.plus, color: fs.parchment), label: Text('Generate', style: TextStyle(color: fs.parchment)), ), diff --git a/flutter_client/lib/admin/widgets/admin_quarantine_row.dart b/flutter_client/lib/admin/widgets/admin_quarantine_row.dart index 6e81e7e7..8221b82b 100644 --- a/flutter_client/lib/admin/widgets/admin_quarantine_row.dart +++ b/flutter_client/lib/admin/widgets/admin_quarantine_row.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import '../../models/admin_quarantine_item.dart'; import '../../theme/theme_extension.dart'; @@ -45,7 +46,7 @@ class AdminQuarantineRow extends StatelessWidget { ), trailing: PopupMenuButton( 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 { switch (action) { case 'resolve': diff --git a/flutter_client/lib/admin/widgets/admin_user_row.dart b/flutter_client/lib/admin/widgets/admin_user_row.dart index b029f748..e4deee49 100644 --- a/flutter_client/lib/admin/widgets/admin_user_row.dart +++ b/flutter_client/lib/admin/widgets/admin_user_row.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import '../../models/admin_user.dart'; import '../../theme/theme_extension.dart'; @@ -29,7 +30,7 @@ class AdminUserRow extends StatelessWidget { _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, ); } diff --git a/flutter_client/lib/admin/widgets/invite_row.dart b/flutter_client/lib/admin/widgets/invite_row.dart index 6b74a6a5..5a9987dd 100644 --- a/flutter_client/lib/admin/widgets/invite_row.dart +++ b/flutter_client/lib/admin/widgets/invite_row.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter/services.dart'; import '../../models/invite.dart'; @@ -31,7 +32,7 @@ class InviteRow extends StatelessWidget { ), ), IconButton( - icon: Icon(Icons.copy, color: fs.ash, size: 18), + icon: Icon(LucideIcons.copy, color: fs.ash, size: 18), tooltip: 'Copy', onPressed: () => Clipboard.setData(ClipboardData(text: invite.token)), @@ -63,7 +64,7 @@ class InviteRow extends StatelessWidget { ], ), trailing: IconButton( - icon: Icon(Icons.delete_outline, color: fs.oxblood), + icon: Icon(LucideIcons.trash_2, color: fs.oxblood), tooltip: 'Revoke', onPressed: onRevoke, ), diff --git a/flutter_client/lib/discover/discover_screen.dart b/flutter_client/lib/discover/discover_screen.dart index 9519d109..bee54a48 100644 --- a/flutter_client/lib/discover/discover_screen.dart +++ b/flutter_client/lib/discover/discover_screen.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -167,7 +168,7 @@ class _DiscoverScreenState extends ConsumerState { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: Text('Discover', style: TextStyle(color: fs.parchment)), @@ -193,7 +194,7 @@ class _DiscoverScreenState extends ConsumerState { borderSide: BorderSide(color: fs.accent), ), suffixIcon: IconButton( - icon: Icon(Icons.search, color: fs.ash), + icon: Icon(LucideIcons.search, color: fs.ash), onPressed: _runSearch, ), ), @@ -336,14 +337,14 @@ class _ResultTile extends StatelessWidget { height: 56, color: fs.slate, child: row.imageUrl.isEmpty - ? Icon(Icons.album, color: fs.ash) + ? Icon(LucideIcons.disc_3, color: fs.ash) : CachedNetworkImage( imageUrl: row.imageUrl, fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 120), fadeOutDuration: Duration.zero, errorWidget: (_, __, ___) => - Icon(Icons.album, color: fs.ash), + Icon(LucideIcons.disc_3, color: fs.ash), ), ), ), @@ -419,14 +420,14 @@ class _SuggestionTile extends StatelessWidget { height: 56, color: fs.slate, child: s.imageUrl.isEmpty - ? Icon(Icons.person, color: fs.ash) + ? Icon(LucideIcons.user, color: fs.ash) : CachedNetworkImage( imageUrl: s.imageUrl, fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 120), fadeOutDuration: Duration.zero, errorWidget: (_, __, ___) => - Icon(Icons.person, color: fs.ash), + Icon(LucideIcons.user, color: fs.ash), ), ), ), diff --git a/flutter_client/lib/library/album_detail_screen.dart b/flutter_client/lib/library/album_detail_screen.dart index 9b628906..621a8fcd 100644 --- a/flutter_client/lib/library/album_detail_screen.dart +++ b/flutter_client/lib/library/album_detail_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../api/endpoints/likes.dart'; @@ -115,7 +116,7 @@ class AlbumDetailScreen extends ConsumerWidget { width: 48, height: 48, decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle), child: IconButton( - icon: Icon(Icons.play_arrow, color: fs.parchment), + icon: Icon(LucideIcons.play, color: fs.parchment), onPressed: () => ref.read(playerActionsProvider).playTracks(r.tracks), ), ), diff --git a/flutter_client/lib/library/artist_detail_screen.dart b/flutter_client/lib/library/artist_detail_screen.dart index 9f83ec38..f893c4fc 100644 --- a/flutter_client/lib/library/artist_detail_screen.dart +++ b/flutter_client/lib/library/artist_detail_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -90,7 +91,7 @@ class ArtistDetailScreen extends ConsumerWidget { width: 48, height: 48, decoration: BoxDecoration(color: fs.accent, shape: BoxShape.circle), child: IconButton( - icon: Icon(Icons.play_arrow, color: fs.parchment), + icon: Icon(LucideIcons.play, color: fs.parchment), onPressed: () async { try { final tracks = diff --git a/flutter_client/lib/library/home_screen.dart b/flutter_client/lib/library/home_screen.dart index a3eff3dc..df488102 100644 --- a/flutter_client/lib/library/home_screen.dart +++ b/flutter_client/lib/library/home_screen.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -245,12 +246,12 @@ class _PlaylistsSection extends StatelessWidget { if (offline) ...const [ _OfflinePoolCard( label: 'Recently played', - icon: Icons.history, + icon: LucideIcons.history, kind: _OfflinePoolKind.recentlyPlayed, ), _OfflinePoolCard( label: 'Liked', - icon: Icons.favorite, + icon: LucideIcons.heart, kind: _OfflinePoolKind.liked, ), ], diff --git a/flutter_client/lib/library/library_screen.dart b/flutter_client/lib/library/library_screen.dart index d6cb3a93..4695bccb 100644 --- a/flutter_client/lib/library/library_screen.dart +++ b/flutter_client/lib/library/library_screen.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:drift/drift.dart' as drift; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -382,7 +383,7 @@ class _LibraryScreenState extends ConsumerState IconButton( key: const Key('shuffle_all_button'), tooltip: 'Shuffle all', - icon: Icon(Icons.shuffle, color: fs.parchment), + icon: Icon(LucideIcons.shuffle, color: fs.parchment), onPressed: () async { final messenger = ScaffoldMessenger.of(context); final refs = await ref.read(shuffleSourceProvider).tracks(); @@ -866,7 +867,7 @@ class _QuarantineTile extends ConsumerWidget { ), IconButton( tooltip: 'Unhide', - icon: Icon(Icons.restore, color: fs.ash, size: 20), + icon: Icon(LucideIcons.archive_restore, color: fs.ash, size: 20), onPressed: () async { try { await ref.read(myQuarantineProvider.notifier).unflag(row.trackId); diff --git a/flutter_client/lib/library/widgets/cached_indicator.dart b/flutter_client/lib/library/widgets/cached_indicator.dart index 8a3c0d84..685aabc5 100644 --- a/flutter_client/lib/library/widgets/cached_indicator.dart +++ b/flutter_client/lib/library/widgets/cached_indicator.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../cache/audio_cache_manager.dart'; @@ -21,7 +22,7 @@ class CachedIndicator extends ConsumerWidget { if (snap.data != true) return const SizedBox.shrink(); return Padding( 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), ); }, ); diff --git a/flutter_client/lib/library/widgets/play_circle_button.dart b/flutter_client/lib/library/widgets/play_circle_button.dart index 6c76dac7..acfb0562 100644 --- a/flutter_client/lib/library/widgets/play_circle_button.dart +++ b/flutter_client/lib/library/widgets/play_circle_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import '../../theme/theme_extension.dart'; @@ -85,7 +86,7 @@ class _PlayCircleButtonState extends State { ), ) : Icon( - Icons.play_arrow, + LucideIcons.play, color: fs.parchment, size: iconSize, ), diff --git a/flutter_client/lib/player/now_playing_screen.dart b/flutter_client/lib/player/now_playing_screen.dart index 5f529aea..95817b8f 100644 --- a/flutter_client/lib/player/now_playing_screen.dart +++ b/flutter_client/lib/player/now_playing_screen.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -376,13 +377,13 @@ class _TopBar extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 4), child: Row(children: [ IconButton( - icon: Icon(Icons.expand_more, color: fs.parchment), + icon: Icon(LucideIcons.chevron_down, color: fs.parchment), tooltip: 'Close', onPressed: () => Navigator.of(context).maybePop(), ), const Spacer(), IconButton( - icon: Icon(Icons.queue_music, color: fs.parchment), + icon: Icon(LucideIcons.list_music, color: fs.parchment), tooltip: 'Queue', onPressed: () => GoRouter.of(context).push('/queue'), ), @@ -535,13 +536,13 @@ class _PrimaryControls extends StatelessWidget { children: [ IconButton( iconSize: 36, - icon: Icon(Icons.skip_previous, color: fs.parchment), + icon: Icon(LucideIcons.skip_back, color: fs.parchment), onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(), ), IconButton( iconSize: 72, icon: Icon( - isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled, + isPlaying ? LucideIcons.circle_pause : LucideIcons.circle_play, color: fs.accent, ), onPressed: () { @@ -555,7 +556,7 @@ class _PrimaryControls extends StatelessWidget { ), IconButton( iconSize: 36, - icon: Icon(Icons.skip_next, color: fs.parchment), + icon: Icon(LucideIcons.skip_forward, color: fs.parchment), onPressed: () => ref.read(audioHandlerProvider).skipToNext(), ), ], @@ -589,7 +590,7 @@ class _SecondaryControls extends StatelessWidget { IconButton( tooltip: shuffleOn ? 'Shuffle on' : 'Shuffle off', icon: Icon( - Icons.shuffle, + LucideIcons.shuffle, color: shuffleOn ? fs.accent : fs.ash, ), onPressed: actions.toggleShuffle, @@ -602,8 +603,8 @@ class _SecondaryControls extends StatelessWidget { }, icon: Icon( repeatMode == AudioServiceRepeatMode.one - ? Icons.repeat_one - : Icons.repeat, + ? LucideIcons.repeat_1 + : LucideIcons.repeat, color: repeatMode == AudioServiceRepeatMode.none ? fs.ash : fs.accent, @@ -612,7 +613,7 @@ class _SecondaryControls extends StatelessWidget { ), IconButton( tooltip: 'Queue', - icon: Icon(Icons.queue_music, color: fs.ash), + icon: Icon(LucideIcons.list_music, color: fs.ash), onPressed: () => GoRouter.of(context).push('/queue'), ), LikeButton(kind: LikeKind.track, id: media.id, size: 22), diff --git a/flutter_client/lib/player/player_bar.dart b/flutter_client/lib/player/player_bar.dart index e2d559ea..3c8be42d 100644 --- a/flutter_client/lib/player/player_bar.dart +++ b/flutter_client/lib/player/player_bar.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:audio_service/audio_service.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -229,7 +230,7 @@ class _PlayControls extends StatelessWidget { child: IconButton( padding: EdgeInsets.zero, iconSize: 22, - icon: Icon(Icons.skip_previous, color: fs.parchment), + icon: Icon(LucideIcons.skip_back, color: fs.parchment), onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(), ), ), @@ -240,7 +241,7 @@ class _PlayControls extends StatelessWidget { padding: EdgeInsets.zero, iconSize: 32, icon: Icon( - isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled, + isPlaying ? LucideIcons.circle_pause : LucideIcons.circle_play, color: fs.accent, ), onPressed: () { @@ -259,7 +260,7 @@ class _PlayControls extends StatelessWidget { child: IconButton( padding: EdgeInsets.zero, iconSize: 22, - icon: Icon(Icons.skip_next, color: fs.parchment), + icon: Icon(LucideIcons.skip_forward, color: fs.parchment), onPressed: () => ref.read(audioHandlerProvider).skipToNext(), ), ), diff --git a/flutter_client/lib/player/queue_screen.dart b/flutter_client/lib/player/queue_screen.dart index f09c45c1..87eff48f 100644 --- a/flutter_client/lib/player/queue_screen.dart +++ b/flutter_client/lib/player/queue_screen.dart @@ -1,5 +1,6 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -20,7 +21,7 @@ class QueueScreen extends ConsumerWidget { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: Text('Queue', style: TextStyle(color: fs.parchment)), @@ -84,7 +85,7 @@ class _QueueRow extends StatelessWidget { if (isCurrent) Padding( 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( child: Column( diff --git a/flutter_client/lib/playlists/playlist_detail_screen.dart b/flutter_client/lib/playlists/playlist_detail_screen.dart index ddb19d77..c91e733e 100644 --- a/flutter_client/lib/playlists/playlist_detail_screen.dart +++ b/flutter_client/lib/playlists/playlist_detail_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -54,7 +55,7 @@ class PlaylistDetailScreen extends ConsumerWidget { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: headerName.isEmpty @@ -268,7 +269,7 @@ class _Header extends ConsumerWidget { OutlinedButton.icon( key: const Key('regenerate_playlist_button'), onPressed: () => _regenerate(context, ref), - icon: const Icon(Icons.refresh, size: 16), + icon: const Icon(LucideIcons.refresh_cw, size: 16), label: const Text('Regenerate'), ), const SizedBox(width: 8), @@ -281,7 +282,7 @@ class _Header extends ConsumerWidget { source: p.refreshable ? p.systemVariant : null, ); }, - icon: const Icon(Icons.play_arrow), + icon: const Icon(LucideIcons.play), label: const Text('Play'), style: FilledButton.styleFrom( backgroundColor: fs.accent, diff --git a/flutter_client/lib/playlists/playlists_list_screen.dart b/flutter_client/lib/playlists/playlists_list_screen.dart index bfddbf9a..23410842 100644 --- a/flutter_client/lib/playlists/playlists_list_screen.dart +++ b/flutter_client/lib/playlists/playlists_list_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -82,11 +83,11 @@ class _PlaylistTile extends StatelessWidget { height: 56, color: fs.slate, child: playlist.coverUrl.isEmpty - ? Icon(Icons.queue_music, color: fs.ash) + ? Icon(LucideIcons.list_music, color: fs.ash) : ServerImage( url: playlist.coverUrl, 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), ]), ), ); diff --git a/flutter_client/lib/playlists/widgets/playlist_card.dart b/flutter_client/lib/playlists/widgets/playlist_card.dart index c7a0a2c5..7e16cc8f 100644 --- a/flutter_client/lib/playlists/widgets/playlist_card.dart +++ b/flutter_client/lib/playlists/widgets/playlist_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -55,12 +56,12 @@ class PlaylistCard extends ConsumerWidget { // errorBuilder shows the queue_music icon over the // slate background. child: playlist.coverUrl.isEmpty - ? Icon(Icons.queue_music, color: fs.ash, size: 56) + ? Icon(LucideIcons.list_music, color: fs.ash, size: 56) : ServerImage( url: playlist.coverUrl, fit: BoxFit.cover, 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, right: 2, child: PopupMenuButton( - icon: Icon(Icons.more_vert, color: fs.parchment, size: 18), + icon: Icon(LucideIcons.ellipsis_vertical, color: fs.parchment, size: 18), tooltip: 'Playlist actions', color: fs.iron, onSelected: (_) => _refresh(context, ref), @@ -88,7 +89,7 @@ class PlaylistCard extends ConsumerWidget { PopupMenuItem( value: 'refresh', child: Row(children: [ - Icon(Icons.refresh, color: fs.parchment, size: 18), + Icon(LucideIcons.refresh_cw, color: fs.parchment, size: 18), const SizedBox(width: 8), Text(_refreshLabel, style: TextStyle(color: fs.parchment)), diff --git a/flutter_client/lib/playlists/widgets/playlist_placeholder_card.dart b/flutter_client/lib/playlists/widgets/playlist_placeholder_card.dart index 59db7b92..d2192c26 100644 --- a/flutter_client/lib/playlists/widgets/playlist_placeholder_card.dart +++ b/flutter_client/lib/playlists/widgets/playlist_placeholder_card.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import '../../theme/theme_extension.dart'; @@ -65,9 +66,9 @@ class PlaylistPlaceholderCard extends StatelessWidget { child: CircularProgressIndicator(strokeWidth: 2, color: fs.accent), ); case 'failed': - return Icon(Icons.warning_amber, color: fs.error, size: 32); + return Icon(LucideIcons.triangle_alert, color: fs.error, size: 32); default: - return Icon(Icons.queue_music, color: fs.ash, size: 40); + return Icon(LucideIcons.list_music, color: fs.ash, size: 40); } } diff --git a/flutter_client/lib/requests/requests_screen.dart b/flutter_client/lib/requests/requests_screen.dart index 2cf98fdd..d4a15d38 100644 --- a/flutter_client/lib/requests/requests_screen.dart +++ b/flutter_client/lib/requests/requests_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -32,7 +33,7 @@ class RequestsScreen extends ConsumerWidget { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: Text('Your requests', style: TextStyle(color: fs.parchment)), @@ -130,9 +131,9 @@ class _RequestRow extends StatelessWidget { Widget _kindAvatar(FabledSwordTheme fs) { final icon = switch (request.kind) { - 'artist' => Icons.album, - 'album' => Icons.library_music, - _ => Icons.music_note, + 'artist' => LucideIcons.disc_3, + 'album' => LucideIcons.library_big, + _ => LucideIcons.music, }; return CircleAvatar( backgroundColor: fs.iron, @@ -164,7 +165,7 @@ class _RequestRow extends StatelessWidget { ); if (ok == true) onCancel(); }, - icon: const Icon(Icons.close, size: 16), + icon: const Icon(LucideIcons.x, size: 16), label: const Text('Cancel'), style: TextButton.styleFrom(foregroundColor: fs.ash), ); @@ -172,7 +173,7 @@ class _RequestRow extends StatelessWidget { if (request.status == 'completed' && href != null) { return TextButton.icon( onPressed: () => context.push(href), - icon: const Icon(Icons.play_arrow, size: 16), + icon: const Icon(LucideIcons.play, size: 16), label: const Text('Listen'), style: TextButton.styleFrom(foregroundColor: fs.accent), ); diff --git a/flutter_client/lib/search/search_screen.dart b/flutter_client/lib/search/search_screen.dart index 6b4728b0..06315eb6 100644 --- a/flutter_client/lib/search/search_screen.dart +++ b/flutter_client/lib/search/search_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -47,7 +48,7 @@ class _SearchScreenState extends ConsumerState { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: TextField( @@ -67,7 +68,7 @@ class _SearchScreenState extends ConsumerState { actions: [ if (_controller.text.isNotEmpty) IconButton( - icon: Icon(Icons.clear, color: fs.ash), + icon: Icon(LucideIcons.x, color: fs.ash), onPressed: () { _controller.clear(); ref.read(searchQueryProvider.notifier).set(''); diff --git a/flutter_client/lib/settings/about_section.dart b/flutter_client/lib/settings/about_section.dart index efd5ada1..9a6131be 100644 --- a/flutter_client/lib/settings/about_section.dart +++ b/flutter_client/lib/settings/about_section.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -88,7 +89,7 @@ class _AboutSectionState extends ConsumerState { padding: const EdgeInsets.fromLTRB(16, 0, 16, 4), child: Row( children: [ - Icon(Icons.info_outline, color: fs.parchment, size: 18), + Icon(LucideIcons.info, color: fs.parchment, size: 18), const SizedBox(width: 8), Text('Installed version', style: TextStyle(color: fs.parchment, fontSize: 14)), @@ -105,7 +106,7 @@ class _AboutSectionState extends ConsumerState { padding: const EdgeInsets.fromLTRB(16, 4, 16, 4), child: Row( children: [ - Icon(Icons.cloud_outlined, color: fs.parchment, size: 18), + Icon(LucideIcons.cloud, color: fs.parchment, size: 18), const SizedBox(width: 8), Text('Latest version', style: TextStyle(color: fs.parchment, fontSize: 14)), @@ -148,7 +149,7 @@ class _AboutSectionState extends ConsumerState { valueColor: AlwaysStoppedAnimation(fs.parchment), ), ) - : const Icon(Icons.refresh, size: 18), + : const Icon(LucideIcons.refresh_cw, size: 18), label: Text(_checking ? 'Checking…' : 'Check for updates'), ), if (hasUpdate) ...[ @@ -172,7 +173,7 @@ class _AboutSectionState extends ConsumerState { valueColor: AlwaysStoppedAnimation(fs.parchment), ), ) - : const Icon(Icons.system_update, size: 18), + : const Icon(LucideIcons.download, size: 18), label: Text( _installStage == _InstallStage.downloading ? 'Downloading…' diff --git a/flutter_client/lib/settings/settings_screen.dart b/flutter_client/lib/settings/settings_screen.dart index e8810062..ba611366 100644 --- a/flutter_client/lib/settings/settings_screen.dart +++ b/flutter_client/lib/settings/settings_screen.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -37,7 +38,7 @@ class SettingsScreen extends ConsumerWidget { backgroundColor: fs.obsidian, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back, color: fs.parchment), + icon: Icon(LucideIcons.arrow_left, color: fs.parchment), onPressed: () => context.pop(), ), title: Text('Settings', style: TextStyle(color: fs.parchment)), @@ -107,7 +108,7 @@ class _RequestsSection extends StatelessWidget { final fs = Theme.of(context).extension()!; return ListTile( key: const Key('settings_requests_card'), - leading: Icon(Icons.queue_music, color: fs.parchment), + leading: Icon(LucideIcons.list_music, color: fs.parchment), title: Text( 'My requests', style: TextStyle( @@ -120,7 +121,7 @@ class _RequestsSection extends StatelessWidget { "Track what you've asked Minstrel to add", 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'), ); } @@ -143,7 +144,7 @@ class _AdminSection extends ConsumerWidget { const _Divider(), ListTile( key: const Key('settings_admin_card'), - leading: Icon(Icons.shield, color: fs.parchment), + leading: Icon(LucideIcons.shield, color: fs.parchment), title: Text( 'Admin', style: TextStyle( @@ -156,7 +157,7 @@ class _AdminSection extends ConsumerWidget { 'Manage requests, quarantine, and users', 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'), ), ], diff --git a/flutter_client/lib/settings/storage_section.dart b/flutter_client/lib/settings/storage_section.dart index 68e6b84c..8bee9d7a 100644 --- a/flutter_client/lib/settings/storage_section.dart +++ b/flutter_client/lib/settings/storage_section.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../cache/audio_cache_manager.dart'; @@ -140,7 +141,7 @@ class _StorageSectionState extends ConsumerState { height: 14, child: CircularProgressIndicator(strokeWidth: 2), ) - : const Icon(Icons.sync, size: 16), + : const Icon(LucideIcons.refresh_cw, size: 16), label: const Text('Sync now'), ), ]), diff --git a/flutter_client/lib/shared/widgets/main_app_bar_actions.dart b/flutter_client/lib/shared/widgets/main_app_bar_actions.dart index e0eab4a8..741cd4db 100644 --- a/flutter_client/lib/shared/widgets/main_app_bar_actions.dart +++ b/flutter_client/lib/shared/widgets/main_app_bar_actions.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -26,27 +27,27 @@ class MainAppBarActions extends ConsumerWidget { if (currentRoute != '/home') IconButton( key: const Key('app_bar_home'), - icon: Icon(Icons.home, color: fs.parchment), + icon: Icon(LucideIcons.house, color: fs.parchment), tooltip: 'Home', onPressed: () => context.go('/home'), ), if (currentRoute != '/library') IconButton( key: const Key('app_bar_library'), - icon: Icon(Icons.library_music, color: fs.parchment), + icon: Icon(LucideIcons.library_big, color: fs.parchment), tooltip: 'Library', onPressed: () => context.push('/library'), ), if (currentRoute != '/search') IconButton( key: const Key('app_bar_search'), - icon: Icon(Icons.search, color: fs.parchment), + icon: Icon(LucideIcons.search, color: fs.parchment), tooltip: 'Search', onPressed: () => context.push('/search'), ), PopupMenuButton( key: const Key('app_bar_overflow'), - icon: Icon(Icons.more_vert, color: fs.parchment), + icon: Icon(LucideIcons.ellipsis_vertical, color: fs.parchment), tooltip: 'More', onSelected: (route) => context.push(route), itemBuilder: (_) => [ diff --git a/flutter_client/lib/shared/widgets/track_actions/add_to_playlist_sheet.dart b/flutter_client/lib/shared/widgets/track_actions/add_to_playlist_sheet.dart index 28814fb4..b3103420 100644 --- a/flutter_client/lib/shared/widgets/track_actions/add_to_playlist_sheet.dart +++ b/flutter_client/lib/shared/widgets/track_actions/add_to_playlist_sheet.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../playlists/playlists_provider.dart'; @@ -70,7 +71,7 @@ class AddToPlaylistSheet extends ConsumerWidget { final p = owned[i]; return ListTile( 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( p.name, style: TextStyle(color: fs.parchment), diff --git a/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart b/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart index 6937e9a9..e5c58772 100644 --- a/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart +++ b/flutter_client/lib/shared/widgets/track_actions/track_actions_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import '../../../models/track.dart'; import '../../../theme/theme_extension.dart'; @@ -29,7 +30,7 @@ class TrackActionsButton extends StatelessWidget { Widget build(BuildContext context) { final fs = Theme.of(context).extension()!; 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', onPressed: () => TrackActionsSheet.show( context, diff --git a/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart b/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart index 68e2391d..4847784b 100644 --- a/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart +++ b/flutter_client/lib/shared/widgets/track_actions/track_actions_sheet.dart @@ -1,5 +1,6 @@ import 'package:drift/drift.dart' as drift; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -73,7 +74,7 @@ class TrackActionsSheet extends ConsumerWidget { if (!hideQueueActions) ...[ _MenuItem( key: const Key('track_actions_play_next'), - icon: Icons.playlist_play, + icon: LucideIcons.list_video, label: 'Play next', onTap: () async { Navigator.pop(context); @@ -87,7 +88,7 @@ class TrackActionsSheet extends ConsumerWidget { ), _MenuItem( key: const Key('track_actions_enqueue'), - icon: Icons.queue_music, + icon: LucideIcons.list_music, label: 'Add to queue', onTap: () async { Navigator.pop(context); @@ -103,7 +104,7 @@ class TrackActionsSheet extends ConsumerWidget { ], _MenuItem( key: const Key('track_actions_like'), - icon: liked ? Icons.favorite : Icons.favorite_border, + icon: LucideIcons.heart, label: liked ? 'Unlike' : 'Like', onTap: () async { Navigator.pop(context); @@ -112,7 +113,7 @@ class TrackActionsSheet extends ConsumerWidget { ), _MenuItem( key: const Key('track_actions_add_to_playlist'), - icon: Icons.playlist_add, + icon: LucideIcons.list_plus, label: 'Add to playlist…', onTap: () async { Navigator.pop(context); @@ -136,7 +137,7 @@ class TrackActionsSheet extends ConsumerWidget { ), _MenuItem( key: const Key('track_actions_start_radio'), - icon: Icons.radio, + icon: LucideIcons.radio, label: 'Start radio', onTap: () async { Navigator.pop(context); @@ -154,7 +155,7 @@ class TrackActionsSheet extends ConsumerWidget { const _Divider(), _MenuItem( key: const Key('track_actions_go_to_album'), - icon: Icons.album, + icon: LucideIcons.disc_3, label: 'Go to album', onTap: () { Navigator.pop(context); @@ -168,7 +169,7 @@ class TrackActionsSheet extends ConsumerWidget { ), _MenuItem( key: const Key('track_actions_go_to_artist'), - icon: Icons.person, + icon: LucideIcons.user, label: 'Go to artist', onTap: () { Navigator.pop(context); @@ -183,7 +184,7 @@ class TrackActionsSheet extends ConsumerWidget { const _Divider(), _MenuItem( key: const Key('track_actions_hide'), - icon: hidden ? Icons.visibility : Icons.visibility_off, + icon: hidden ? LucideIcons.eye : LucideIcons.eye_off, label: hidden ? 'Unhide' : 'Hide', onTap: () async { Navigator.pop(context); diff --git a/flutter_client/lib/shared/widgets/version_gate.dart b/flutter_client/lib/shared/widgets/version_gate.dart index 2d001910..ab57acc6 100644 --- a/flutter_client/lib/shared/widgets/version_gate.dart +++ b/flutter_client/lib/shared/widgets/version_gate.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:pub_semver/pub_semver.dart'; @@ -238,7 +239,7 @@ class VersionTooOldBanner extends ConsumerWidget { color: fs.error.withValues(alpha: 0.15), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), 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), Expanded( child: Text( diff --git a/flutter_client/lib/update/update_banner.dart b/flutter_client/lib/update/update_banner.dart index 6605dc28..559777a9 100644 --- a/flutter_client/lib/update/update_banner.dart +++ b/flutter_client/lib/update/update_banner.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../theme/theme_extension.dart'; @@ -66,7 +67,7 @@ class _UpdateBannerState extends ConsumerState { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - Icon(Icons.system_update, color: fs.parchment, size: 16), + Icon(LucideIcons.download, color: fs.parchment, size: 16), const SizedBox(width: 8), Expanded( child: Column( @@ -132,7 +133,7 @@ class _UpdateBannerState extends ConsumerState { tooltip: 'Dismiss', padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.close, color: fs.ash), + icon: Icon(LucideIcons.x, color: fs.ash), onPressed: () => _onDismiss(info), ), ),