Skip to content

Commit 4d5273f

Browse files
committed
refactor(playlist): extract duplicated widgets and utilities into reusable components
1 parent f9013ab commit 4d5273f

File tree

6 files changed

+343
-169
lines changed

6 files changed

+343
-169
lines changed

lib/screens/playlist_page.dart

Lines changed: 40 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ import 'package:musify/utilities/app_utils.dart';
3737
import 'package:musify/utilities/flutter_toast.dart';
3838
import 'package:musify/utilities/offline_playlist_dialogs.dart';
3939
import 'package:musify/utilities/playlist_dialogs.dart';
40+
import 'package:musify/utilities/song_filtering.dart';
4041
import 'package:musify/utilities/sort_utils.dart';
41-
import 'package:musify/widgets/custom_search_bar.dart';
4242
import 'package:musify/widgets/edit_playlist_dialog.dart';
4343
import 'package:musify/widgets/playlist_cube.dart';
44+
import 'package:musify/widgets/playlist_page/empty_playlist_state.dart';
4445
import 'package:musify/widgets/playlist_page/playlist_header.dart';
46+
import 'package:musify/widgets/playlist_page/search_bar_section.dart';
4547
import 'package:musify/widgets/song_bar.dart';
4648
import 'package:musify/widgets/sort_chips.dart';
4749
import 'package:musify/widgets/spinner.dart';
@@ -83,19 +85,13 @@ class _PlaylistPageState extends State<PlaylistPage> {
8385
);
8486

8587
// Search
86-
String _searchQuery = '';
88+
final ValueNotifier<String> _searchQueryNotifier = ValueNotifier('');
8789
late final TextEditingController _searchController;
8890
late final FocusNode _searchFocusNode;
8991

90-
List<dynamic> get _sourceList {
92+
List<dynamic> _getSourceList(String searchQuery) {
9193
final list = _playlist?['list'] as List<dynamic>? ?? [];
92-
if (_searchQuery.isEmpty) return list;
93-
final q = _searchQuery.toLowerCase();
94-
return list.where((s) {
95-
final title = (s['title'] ?? '').toString().toLowerCase();
96-
final artist = (s['artist'] ?? '').toString().toLowerCase();
97-
return title.contains(q) || artist.contains(q);
98-
}).toList();
94+
return filterSongsByQuery(list, searchQuery);
9995
}
10096

10197
@override
@@ -110,6 +106,7 @@ class _PlaylistPageState extends State<PlaylistPage> {
110106
void dispose() {
111107
_searchController.dispose();
112108
_searchFocusNode.dispose();
109+
_searchQueryNotifier.dispose();
113110
super.dispose();
114111
}
115112

@@ -171,53 +168,29 @@ class _PlaylistPageState extends State<PlaylistPage> {
171168
slivers: [
172169
SliverToBoxAdapter(child: _buildHeaderSection()),
173170
if ((_playlist['list'] as List).isNotEmpty) ...[
174-
SliverPadding(
175-
padding: commonListViewBottomPadding,
176-
sliver: SliverList.builder(
177-
itemCount: _sourceList.length,
178-
itemBuilder: (context, index) {
179-
final isRemovable =
180-
_playlist['source'] == 'user-created';
181-
return _buildSongListItem(
182-
_sourceList[index],
183-
index,
184-
isRemovable,
185-
);
186-
},
187-
),
188-
),
189-
] else
190-
SliverFillRemaining(
191-
hasScrollBody: false,
192-
child: Center(
193-
child: Padding(
194-
padding: const EdgeInsets.symmetric(horizontal: 32),
195-
child: Column(
196-
mainAxisSize: MainAxisSize.min,
197-
children: [
198-
Icon(
199-
FluentIcons.music_note_1_24_regular,
200-
size: 64,
201-
color: Theme.of(
202-
context,
203-
).colorScheme.onSurface.withAlpha(120),
204-
),
205-
const SizedBox(height: 16),
206-
Text(
207-
context.l10n!.noSongsInPlaylist,
208-
textAlign: TextAlign.center,
209-
style: TextStyle(
210-
color: Theme.of(
211-
context,
212-
).colorScheme.onSurfaceVariant,
213-
fontSize: 16,
214-
),
215-
),
216-
],
171+
ValueListenableBuilder<String>(
172+
valueListenable: _searchQueryNotifier,
173+
builder: (context, searchQuery, _) {
174+
final sourceList = _getSourceList(searchQuery);
175+
return SliverPadding(
176+
padding: commonListViewBottomPadding,
177+
sliver: SliverList.builder(
178+
itemCount: sourceList.length,
179+
itemBuilder: (context, index) {
180+
final isRemovable =
181+
_playlist['source'] == 'user-created';
182+
return _buildSongListItem(
183+
sourceList[index],
184+
index,
185+
isRemovable,
186+
);
187+
},
217188
),
218-
),
219-
),
189+
);
190+
},
220191
),
192+
] else
193+
EmptyPlaylistState(message: context.l10n!.noSongsInPlaylist),
221194
],
222195
)
223196
: SizedBox(
@@ -334,12 +307,11 @@ class _PlaylistPageState extends State<PlaylistPage> {
334307
],
335308
if (songsLength > 0) ...[
336309
const SizedBox(height: 16),
337-
CustomSearchBar(
338-
controller: _searchController..text = _searchQuery,
310+
SearchBarSection(
311+
controller: _searchController,
339312
focusNode: _searchFocusNode,
313+
onSearchChanged: (value) => _searchQueryNotifier.value = value,
340314
labelText: context.l10n!.search,
341-
onSubmitted: (_) {},
342-
onChanged: (value) => setState(() => _searchQuery = value),
343315
),
344316
],
345317
const SizedBox(height: 16),
@@ -362,7 +334,11 @@ class _PlaylistPageState extends State<PlaylistPage> {
362334
showToast(context, context.l10n!.linkCopied);
363335
}
364336
} catch (e, stackTrace) {
365-
logger.log('Error sharing playlist', error: e, stackTrace: stackTrace);
337+
logger.log(
338+
'Error sharing playlist',
339+
error: e,
340+
stackTrace: stackTrace,
341+
);
366342
if (mounted) {
367343
showToast(context, context.l10n!.error);
368344
}
@@ -696,13 +672,14 @@ class _PlaylistPageState extends State<PlaylistPage> {
696672
}
697673

698674
Widget _buildSongListItem(dynamic song, int index, bool isRemovable) {
699-
final totalItems = _sourceList.length;
675+
final sourceList = _getSourceList(_searchQueryNotifier.value);
676+
final totalItems = sourceList.length;
700677
final borderRadius = getItemBorderRadius(index, totalItems);
701678
final isUserCreatedPlaylist = _playlist?['source'] == 'user-created';
702679
final playlistId = isUserCreatedPlaylist ? _playlist!['ytid'] : null;
703-
final isSearching = _searchQuery.isNotEmpty;
680+
final isSearching = _searchQueryNotifier.value.isNotEmpty;
704681
final playlistForQueue = isSearching
705-
? {..._playlist as Map, 'list': _sourceList}
682+
? {..._playlist as Map, 'list': sourceList}
706683
: _playlist;
707684

708685
return SongBar(

0 commit comments

Comments
 (0)