Skip to content

Commit ef4a623

Browse files
committed
See if playlists already contain a stream from db
1 parent b3554a6 commit ef4a623

5 files changed

Lines changed: 84 additions & 84 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.schabi.newpipe.database.playlist;
2+
3+
import androidx.room.ColumnInfo;
4+
5+
/**
6+
* This class adds a field to {@link PlaylistMetadataEntry} that contains an integer representing
7+
* how many times a specific stream is already contained inside a local playlist. Used to be able
8+
* to grey out playlists which already contain the current stream in the playlist append dialog.
9+
* @see org.schabi.newpipe.local.playlist.LocalPlaylistManager#getPlaylistDuplicates(String)
10+
*/
11+
public class PlaylistDuplicatesEntry extends PlaylistMetadataEntry {
12+
public static final String PLAYLIST_TIMES_STREAM_IS_CONTAINED = "timesStreamIsContained";
13+
@ColumnInfo(name = PLAYLIST_TIMES_STREAM_IS_CONTAINED)
14+
public final long timesStreamIsContained;
15+
16+
public PlaylistDuplicatesEntry(final long uid,
17+
final String name,
18+
final String thumbnailUrl,
19+
final long streamCount,
20+
final long timesStreamIsContained) {
21+
super(uid, name, thumbnailUrl, streamCount);
22+
this.timesStreamIsContained = timesStreamIsContained;
23+
}
24+
}

app/src/main/java/org/schabi/newpipe/database/playlist/dao/PlaylistStreamDAO.java

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import androidx.room.Transaction;
77

88
import org.schabi.newpipe.database.BasicDAO;
9+
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
910
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
1011
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
1112
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
@@ -14,6 +15,7 @@
1415

1516
import io.reactivex.rxjava3.core.Flowable;
1617

18+
import static org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry.PLAYLIST_TIMES_STREAM_IS_CONTAINED;
1719
import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
1820
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
1921
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
@@ -50,23 +52,6 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
5052
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
5153
void deleteBatch(long playlistId);
5254

53-
@Query("SELECT COALESCE(COUNT(*), 0)"
54-
+ " FROM " + STREAM_TABLE
55-
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
56-
+ " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
57-
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId "
58-
+ " AND " + STREAM_URL + " = :streamURL"
59-
)
60-
Flowable<Integer> getDuplicateCount(long playlistId, String streamURL);
61-
62-
@Query("SELECT " + JOIN_PLAYLIST_ID
63-
+ " FROM " + STREAM_TABLE
64-
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
65-
+ " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
66-
+ " WHERE " + STREAM_URL + " = :streamURL"
67-
)
68-
Flowable<List<Long>> getDuplicatePlaylists(String streamURL);
69-
7055
@Query("SELECT COALESCE(MAX(" + JOIN_INDEX + "), -1)"
7156
+ " FROM " + PLAYLIST_STREAM_JOIN_TABLE
7257
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
@@ -111,4 +96,24 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
11196
+ " GROUP BY " + PLAYLIST_ID
11297
+ " ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
11398
Flowable<List<PlaylistMetadataEntry>> getPlaylistMetadata();
99+
100+
@Transaction
101+
@Query("SELECT " + PLAYLIST_TABLE + "." + PLAYLIST_ID + ", "
102+
+ PLAYLIST_NAME + ", "
103+
+ PLAYLIST_TABLE + "." + PLAYLIST_THUMBNAIL_URL + ", "
104+
+ "COALESCE(COUNT(" + JOIN_PLAYLIST_ID + "), 0) AS " + PLAYLIST_STREAM_COUNT + ", "
105+
+ "COALESCE(SUM(" + STREAM_URL + " = :streamUrl), 0) AS "
106+
+ PLAYLIST_TIMES_STREAM_IS_CONTAINED
107+
108+
+ " FROM " + PLAYLIST_TABLE
109+
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
110+
+ " ON " + PLAYLIST_TABLE + "." + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID
111+
112+
+ " LEFT JOIN " + STREAM_TABLE
113+
+ " ON " + STREAM_TABLE + "." + STREAM_ID + " = " + JOIN_STREAM_ID
114+
+ " AND :streamUrl = :streamUrl"
115+
116+
+ " GROUP BY " + JOIN_PLAYLIST_ID
117+
+ " ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
118+
Flowable<List<PlaylistDuplicatesEntry>> getPlaylistDuplicatesMetadata(String streamUrl);
114119
}

app/src/main/java/org/schabi/newpipe/local/dialog/PlaylistAppendDialog.java

Lines changed: 14 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import org.schabi.newpipe.NewPipeDatabase;
1515
import org.schabi.newpipe.R;
16-
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
16+
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
1717
import org.schabi.newpipe.database.stream.model.StreamEntity;
1818
import org.schabi.newpipe.local.LocalItemListAdapter;
1919
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
@@ -26,12 +26,8 @@
2626
public final class PlaylistAppendDialog extends PlaylistDialog {
2727
private static final String TAG = PlaylistAppendDialog.class.getCanonicalName();
2828

29-
private static final float DEFAULT_ALPHA = 1f;
30-
private static final float GRAYED_OUT_ALPHA = 0.3f;
31-
3229
private RecyclerView playlistRecyclerView;
3330
private LocalItemListAdapter playlistAdapter;
34-
private List<Long> duplicateIds;
3531

3632
private final CompositeDisposable playlistDisposables = new CompositeDisposable();
3733

@@ -64,15 +60,13 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
6460
final LocalPlaylistManager playlistManager =
6561
new LocalPlaylistManager(NewPipeDatabase.getInstance(requireContext()));
6662

67-
duplicateIds = playlistManager.getDuplicatePlaylists(getStreamEntities().get(0).getUrl())
68-
.blockingFirst();
69-
7063
playlistAdapter = new LocalItemListAdapter(getActivity());
7164
playlistAdapter.setHasStableIds(true);
7265
playlistAdapter.setSelectedListener(selectedItem -> {
7366
final List<StreamEntity> entities = getStreamEntities();
74-
if (selectedItem instanceof PlaylistMetadataEntry && entities != null) {
75-
onPlaylistSelected(playlistManager, (PlaylistMetadataEntry) selectedItem, entities);
67+
if (selectedItem instanceof PlaylistDuplicatesEntry && entities != null) {
68+
onPlaylistSelected(playlistManager,
69+
(PlaylistDuplicatesEntry) selectedItem, entities);
7670
}
7771
});
7872

@@ -83,7 +77,8 @@ public void onViewCreated(@NonNull final View view, @Nullable final Bundle saved
8377
final View newPlaylistButton = view.findViewById(R.id.newPlaylist);
8478
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());
8579

86-
playlistDisposables.add(playlistManager.getPlaylists()
80+
playlistDisposables.add(playlistManager
81+
.getPlaylistDuplicates(getStreamEntities().get(0).getUrl())
8782
.observeOn(AndroidSchedulers.mainThread())
8883
.subscribe(this::onPlaylistsReceived));
8984
}
@@ -125,63 +120,24 @@ public void openCreatePlaylistDialog() {
125120
requireDialog().dismiss();
126121
}
127122

128-
private void onPlaylistsReceived(@NonNull final List<PlaylistMetadataEntry> playlists) {
123+
private void onPlaylistsReceived(@NonNull final List<PlaylistDuplicatesEntry> playlists) {
129124
if (playlistAdapter != null && playlistRecyclerView != null) {
130125
playlistAdapter.clearStreamItemList();
131126
playlistAdapter.addItems(playlists);
132127
playlistRecyclerView.setVisibility(View.VISIBLE);
133-
134-
playlistRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
135-
@Override
136-
public void onScrolled(@NonNull final RecyclerView recyclerView, final int dx,
137-
final int dy) {
138-
showDuplicateIndicators(recyclerView);
139-
}
140-
});
141-
initDuplicateIndicators(playlistRecyclerView);
142-
}
143-
}
144-
145-
public void initDuplicateIndicators(@NonNull final RecyclerView view) {
146-
showDuplicateIndicators(view);
147-
148-
if (!duplicateIds.isEmpty()) {
149-
final View indicatorExplanation = getView()
150-
.findViewById(R.id.playlist_duplicate);
151-
indicatorExplanation.setVisibility(View.VISIBLE);
152-
}
153-
}
154-
155-
public void showDuplicateIndicators(@NonNull final RecyclerView view) {
156-
if (view.getAdapter() == null) {
157-
return;
158-
}
159-
160-
final int count = view.getAdapter().getItemCount();
161-
for (int i = 0; i < count; i++) {
162-
163-
final RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(i);
164-
if (viewHolder != null) {
165-
if (duplicateIds.contains(view.getAdapter().getItemId(i))) {
166-
viewHolder.itemView.setAlpha(GRAYED_OUT_ALPHA);
167-
} else {
168-
viewHolder.itemView.setAlpha(DEFAULT_ALPHA);
169-
}
170-
171-
}
172128
}
173129
}
174130

175131
private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager,
176-
@NonNull final PlaylistMetadataEntry playlist,
132+
@NonNull final PlaylistDuplicatesEntry playlist,
177133
@NonNull final List<StreamEntity> streams) {
178134

179-
final int numOfDuplicates = manager.getPlaylistDuplicateCount(playlist.uid,
180-
streams.get(0).getUrl()).blockingFirst();
181-
String toastText = getString(R.string.playlist_add_stream_success);
182-
183-
if (numOfDuplicates > 0) {
184-
toastText = getString(R.string.playlist_add_stream_success_duplicate, numOfDuplicates);
135+
final String toastText;
136+
if (playlist.timesStreamIsContained > 0) {
137+
toastText = getString(R.string.playlist_add_stream_success_duplicate,
138+
playlist.timesStreamIsContained);
139+
} else {
140+
toastText = getString(R.string.playlist_add_stream_success);
185141
}
186142

187143
final Toast successToast = Toast.makeText(getContext(), toastText, Toast.LENGTH_SHORT);

app/src/main/java/org/schabi/newpipe/local/holder/LocalPlaylistItemHolder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import android.view.ViewGroup;
55

66
import org.schabi.newpipe.database.LocalItem;
7+
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
78
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
89
import org.schabi.newpipe.local.LocalItemBuilder;
910
import org.schabi.newpipe.local.history.HistoryRecordManager;
@@ -13,6 +14,9 @@
1314
import java.time.format.DateTimeFormatter;
1415

1516
public class LocalPlaylistItemHolder extends PlaylistItemHolder {
17+
18+
private static final float GRAYED_OUT_ALPHA = 0.6f;
19+
1620
public LocalPlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final ViewGroup parent) {
1721
super(infoItemBuilder, parent);
1822
}
@@ -38,6 +42,13 @@ public void updateFromItem(final LocalItem localItem,
3842

3943
PicassoHelper.loadPlaylistThumbnail(item.thumbnailUrl).into(itemThumbnailView);
4044

45+
if (item instanceof PlaylistDuplicatesEntry
46+
&& ((PlaylistDuplicatesEntry) item).timesStreamIsContained > 0) {
47+
itemView.setAlpha(GRAYED_OUT_ALPHA);
48+
} else {
49+
itemView.setAlpha(1.0f);
50+
}
51+
4152
super.updateFromItem(localItem, historyRecordManager, dateTimeFormatter);
4253
}
4354
}

app/src/main/java/org/schabi/newpipe/local/playlist/LocalPlaylistManager.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import org.schabi.newpipe.R;
66
import org.schabi.newpipe.database.AppDatabase;
7+
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry;
78
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
89
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
910
import org.schabi.newpipe.database.playlist.dao.PlaylistDAO;
@@ -87,17 +88,20 @@ public Flowable<List<PlaylistMetadataEntry>> getPlaylists() {
8788
return playlistStreamTable.getPlaylistMetadata().subscribeOn(Schedulers.io());
8889
}
8990

90-
public Flowable<List<PlaylistStreamEntry>> getPlaylistStreams(final long playlistId) {
91-
return playlistStreamTable.getOrderedStreamsOf(playlistId).subscribeOn(Schedulers.io());
92-
}
93-
94-
public Flowable<Integer> getPlaylistDuplicateCount(final long playlistId,
95-
final String streamURL) {
96-
return playlistStreamTable.getDuplicateCount(playlistId, streamURL);
91+
/**
92+
* Get playlists with attached information about how many times the provided stream is already
93+
* contained in each playlist.
94+
*
95+
* @param streamUrl the stream url for which to check for duplicates
96+
* @return a list of {@link PlaylistDuplicatesEntry}
97+
*/
98+
public Flowable<List<PlaylistDuplicatesEntry>> getPlaylistDuplicates(final String streamUrl) {
99+
return playlistStreamTable.getPlaylistDuplicatesMetadata(streamUrl)
100+
.subscribeOn(Schedulers.io());
97101
}
98102

99-
public Flowable<List<Long>> getDuplicatePlaylists(final String streamURL) {
100-
return playlistStreamTable.getDuplicatePlaylists(streamURL);
103+
public Flowable<List<PlaylistStreamEntry>> getPlaylistStreams(final long playlistId) {
104+
return playlistStreamTable.getOrderedStreamsOf(playlistId).subscribeOn(Schedulers.io());
101105
}
102106

103107
public Single<Integer> deletePlaylist(final long playlistId) {

0 commit comments

Comments
 (0)