Library able to search tracks

This commit is contained in:
2025-12-17 00:03:16 +08:00
parent f436a8a49b
commit c1652e6743

View File

@@ -46,6 +46,7 @@ class LibraryScreen extends HookConsumerWidget {
// Let's assume we use StreamBuilder for now to avoid creating another file/provider on the fly.
final repo = ref.watch(trackRepositoryProvider.notifier);
final selectedTrackIds = useState<Set<int>>({});
final searchQuery = useState<String>('');
final isSelectionMode = selectedTrackIds.value.isNotEmpty;
void toggleSelection(int id) {
@@ -180,13 +181,60 @@ class LibraryScreen extends HookConsumerWidget {
return const Center(child: Text('No tracks yet. Add some!'));
}
return ListView.builder(
List<Track> filteredTracks;
if (searchQuery.value.isEmpty) {
filteredTracks = tracks;
} else {
final query = searchQuery.value.toLowerCase();
filteredTracks = tracks.where((track) {
if (track.title.toLowerCase().contains(query)) return true;
if (track.artist?.toLowerCase().contains(query) ?? false)
return true;
if (track.album?.toLowerCase().contains(query) ?? false)
return true;
if (track.lyrics != null) {
try {
final lyricsData = LyricsData.fromJsonString(
track.lyrics!,
);
for (final line in lyricsData.lines) {
if (line.text.toLowerCase().contains(query))
return true;
}
} catch (e) {
// Ignore parsing errors
}
}
return false;
}).toList();
}
if (filteredTracks.isEmpty && searchQuery.value.isNotEmpty) {
return const Center(
child: Text('No tracks match your search.'),
);
}
return Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: TextField(
onChanged: (value) => searchQuery.value = value,
decoration: const InputDecoration(
hintText: 'Search tracks...',
prefixIcon: Icon(Icons.search),
),
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.only(
bottom: 72 + MediaQuery.paddingOf(context).bottom,
),
itemCount: tracks.length,
itemCount: filteredTracks.length,
itemBuilder: (context, index) {
final track = tracks[index];
final track = filteredTracks[index];
final isSelected = selectedTrackIds.value.contains(
track.id,
);
@@ -220,7 +268,10 @@ class LibraryScreen extends HookConsumerWidget {
color: Colors.red,
alignment: Alignment.centerRight,
padding: const EdgeInsets.only(right: 20),
child: const Icon(Icons.delete, color: Colors.white),
child: const Icon(
Icons.delete,
color: Colors.white,
),
),
confirmDismiss: (direction) async {
return await showDialog(
@@ -255,7 +306,9 @@ class LibraryScreen extends HookConsumerWidget {
.read(trackRepositoryProvider.notifier)
.deleteTrack(track.id);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Deleted "${track.title}"')),
SnackBar(
content: Text('Deleted "${track.title}"'),
),
);
},
child: ListTile(
@@ -267,7 +320,9 @@ class LibraryScreen extends HookConsumerWidget {
borderRadius: BorderRadius.circular(8),
image: track.artUri != null
? DecorationImage(
image: FileImage(File(track.artUri!)),
image: FileImage(
File(track.artUri!),
),
fit: BoxFit.cover,
)
: null,
@@ -309,6 +364,9 @@ class LibraryScreen extends HookConsumerWidget {
),
);
},
),
),
],
);
},
),