Add search functionality to playlist selection dialog
- Add search EditText with icon to filter playlists by name - Implement real-time filtering with TextWatcher - Add clear button that appears when text is entered - Search is case-insensitive and matches partial playlist names - Store complete playlist list for filtering operations Closes #13154
This commit is contained in:
parent
56a043669a
commit
7e4ecf0ceb
@ -3,9 +3,12 @@ package org.schabi.newpipe.local.dialog;
|
||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.DEFAULT_THUMBNAIL_ID;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
@ -21,7 +24,10 @@ import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||
import org.schabi.newpipe.local.LocalItemListAdapter;
|
||||
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
@ -32,7 +38,10 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||
private RecyclerView playlistRecyclerView;
|
||||
private LocalItemListAdapter playlistAdapter;
|
||||
private TextView playlistDuplicateIndicator;
|
||||
private EditText playlistSearchEditText;
|
||||
private View playlistSearchClear;
|
||||
|
||||
private List<PlaylistDuplicatesEntry> allPlaylists = new ArrayList<>();
|
||||
private final CompositeDisposable playlistDisposables = new CompositeDisposable();
|
||||
|
||||
/**
|
||||
@ -82,6 +91,11 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||
final View newPlaylistButton = view.findViewById(R.id.newPlaylist);
|
||||
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());
|
||||
|
||||
// Setup search functionality
|
||||
playlistSearchEditText = view.findViewById(R.id.playlist_search_edit_text);
|
||||
playlistSearchClear = view.findViewById(R.id.playlist_search_clear);
|
||||
setupSearch();
|
||||
|
||||
playlistDisposables.add(playlistManager
|
||||
.getPlaylistDuplicates(getStreamEntities().get(0).getUrl())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
@ -103,12 +117,66 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||
playlistDisposables.clear();
|
||||
playlistRecyclerView = null;
|
||||
playlistAdapter = null;
|
||||
playlistSearchEditText = null;
|
||||
playlistSearchClear = null;
|
||||
allPlaylists.clear();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Helper
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void setupSearch() {
|
||||
if (playlistSearchEditText == null || playlistSearchClear == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
playlistSearchEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start,
|
||||
final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start,
|
||||
final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
final String query = s.toString();
|
||||
playlistSearchClear.setVisibility(
|
||||
query.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
filterPlaylists(query);
|
||||
}
|
||||
});
|
||||
|
||||
playlistSearchClear.setOnClickListener(v -> {
|
||||
playlistSearchEditText.setText("");
|
||||
playlistSearchClear.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
private void filterPlaylists(final String query) {
|
||||
if (playlistAdapter == null || allPlaylists.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (query.isEmpty()) {
|
||||
playlistAdapter.clearStreamItemList();
|
||||
playlistAdapter.addItems(allPlaylists);
|
||||
} else {
|
||||
final String lowerCaseQuery = query.toLowerCase(Locale.getDefault());
|
||||
final List<PlaylistDuplicatesEntry> filteredPlaylists = allPlaylists.stream()
|
||||
.filter(playlist -> playlist.name.toLowerCase(Locale.getDefault())
|
||||
.contains(lowerCaseQuery))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
playlistAdapter.clearStreamItemList();
|
||||
playlistAdapter.addItems(filteredPlaylists);
|
||||
}
|
||||
}
|
||||
|
||||
/** Display create playlist dialog. */
|
||||
public void openCreatePlaylistDialog() {
|
||||
if (getStreamEntities() == null || !isAdded()) {
|
||||
@ -129,6 +197,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||
if (playlistAdapter != null
|
||||
&& playlistRecyclerView != null
|
||||
&& playlistDuplicateIndicator != null) {
|
||||
allPlaylists = playlists;
|
||||
playlistAdapter.clearStreamItemList();
|
||||
playlistAdapter.addItems(playlists);
|
||||
playlistRecyclerView.setVisibility(View.VISIBLE);
|
||||
|
||||
@ -3,10 +3,66 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/playlist_search_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?attr/rounded_rectangle_background">
|
||||
|
||||
<org.schabi.newpipe.views.NewPipeEditText
|
||||
android:id="@+id/playlist_search_edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@null"
|
||||
android:drawableStart="@drawable/ic_search"
|
||||
android:drawablePadding="8dp"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:hint="@string/search_playlists"
|
||||
android:imeOptions="actionSearch|flagNoFullscreen"
|
||||
android:inputType="textFilter|textNoSuggestions"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="48dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/playlist_search_clear"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:contentDescription="@string/clear"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<View
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/selectableItemBackgroundBorderless" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/clear"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_close" />
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/newPlaylist"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/playlist_search_container"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
@ -456,6 +456,7 @@
|
||||
<string name="preferred_player_fetcher_notification_title">Getting info…</string>
|
||||
<string name="preferred_player_fetcher_notification_message">"Loading requested content"</string>
|
||||
<!-- Local Playlist -->
|
||||
<string name="search_playlists">Search playlists</string>
|
||||
<string name="create_playlist">New Playlist</string>
|
||||
<string name="duplicate_in_playlist">The playlists that are grayed out already contain this item.</string>
|
||||
<string name="rename_playlist">Rename</string>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user