Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow the user to permanently set a thumbnail #9523

Merged
merged 7 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
737 changes: 737 additions & 0 deletions app/schemas/org.schabi.newpipe.database.AppDatabase/6.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class DatabaseMigrationTest {
@get:Rule
val testHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java.canonicalName, FrameworkSQLiteOpenHelperFactory()
AppDatabase::class.java.canonicalName,
FrameworkSQLiteOpenHelperFactory()
)

@Test
Expand All @@ -42,7 +43,8 @@ class DatabaseMigrationTest {

databaseInV2.run {
insert(
"streams", SQLiteDatabase.CONFLICT_FAIL,
"streams",
SQLiteDatabase.CONFLICT_FAIL,
ContentValues().apply {
put("service_id", DEFAULT_SERVICE_ID)
put("url", DEFAULT_URL)
Expand All @@ -54,14 +56,16 @@ class DatabaseMigrationTest {
}
)
insert(
"streams", SQLiteDatabase.CONFLICT_FAIL,
"streams",
SQLiteDatabase.CONFLICT_FAIL,
ContentValues().apply {
put("service_id", DEFAULT_SECOND_SERVICE_ID)
put("url", DEFAULT_SECOND_URL)
}
)
insert(
"streams", SQLiteDatabase.CONFLICT_FAIL,
"streams",
SQLiteDatabase.CONFLICT_FAIL,
ContentValues().apply {
put("service_id", DEFAULT_SERVICE_ID)
}
Expand All @@ -70,18 +74,31 @@ class DatabaseMigrationTest {
}

testHelper.runMigrationsAndValidate(
AppDatabase.DATABASE_NAME, Migrations.DB_VER_3,
true, Migrations.MIGRATION_2_3
AppDatabase.DATABASE_NAME,
Migrations.DB_VER_3,
true,
Migrations.MIGRATION_2_3
)

testHelper.runMigrationsAndValidate(
AppDatabase.DATABASE_NAME, Migrations.DB_VER_4,
true, Migrations.MIGRATION_3_4
AppDatabase.DATABASE_NAME,
Migrations.DB_VER_4,
true,
Migrations.MIGRATION_3_4
)

testHelper.runMigrationsAndValidate(
AppDatabase.DATABASE_NAME, Migrations.DB_VER_5,
true, Migrations.MIGRATION_4_5
AppDatabase.DATABASE_NAME,
Migrations.DB_VER_5,
true,
Migrations.MIGRATION_4_5
)

testHelper.runMigrationsAndValidate(
AppDatabase.DATABASE_NAME,
Migrations.DB_VER_6,
true,
Migrations.MIGRATION_5_6
)

val migratedDatabaseV3 = getMigratedDatabase()
Expand Down Expand Up @@ -121,7 +138,8 @@ class DatabaseMigrationTest {
private fun getMigratedDatabase(): AppDatabase {
val database: AppDatabase = Room.databaseBuilder(
ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, AppDatabase.DATABASE_NAME
AppDatabase::class.java,
AppDatabase.DATABASE_NAME
)
.build()
testHelper.closeWhenFinished(database)
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/org/schabi/newpipe/NewPipeDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.schabi.newpipe.database.Migrations.MIGRATION_2_3;
import static org.schabi.newpipe.database.Migrations.MIGRATION_3_4;
import static org.schabi.newpipe.database.Migrations.MIGRATION_4_5;
import static org.schabi.newpipe.database.Migrations.MIGRATION_5_6;

import android.content.Context;
import android.database.Cursor;
Expand All @@ -24,7 +25,8 @@ private NewPipeDatabase() {
private static AppDatabase getDatabase(final Context context) {
return Room
.databaseBuilder(context.getApplicationContext(), AppDatabase.class, DATABASE_NAME)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5)
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5,
MIGRATION_5_6)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.schabi.newpipe.database;

import static org.schabi.newpipe.database.Migrations.DB_VER_5;
import static org.schabi.newpipe.database.Migrations.DB_VER_6;

import androidx.room.Database;
import androidx.room.RoomDatabase;
Expand Down Expand Up @@ -38,7 +38,7 @@
FeedEntity.class, FeedGroupEntity.class, FeedGroupSubscriptionEntity.class,
FeedLastUpdatedEntity.class
},
version = DB_VER_5
version = DB_VER_6
)
public abstract class AppDatabase extends RoomDatabase {
public static final String DATABASE_NAME = "newpipe.db";
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/org/schabi/newpipe/database/Migrations.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public final class Migrations {
public static final int DB_VER_3 = 3;
public static final int DB_VER_4 = 4;
public static final int DB_VER_5 = 5;
public static final int DB_VER_6 = 6;

private static final String TAG = Migrations.class.getName();
public static final boolean DEBUG = MainActivity.DEBUG;
Expand Down Expand Up @@ -188,6 +189,14 @@ public void migrate(@NonNull final SupportSQLiteDatabase database) {
}
};

public static final Migration MIGRATION_5_6 = new Migration(DB_VER_5, DB_VER_6) {
@Override
public void migrate(@NonNull final SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` "
+ "INTEGER NOT NULL DEFAULT 0");
}
};

private Migrations() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_THUMBNAIL_URL;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID_ALIAS;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS;
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
Expand Down Expand Up @@ -53,6 +54,15 @@ default Flowable<List<PlaylistStreamEntity>> listByService(final int serviceId)
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId")
Flowable<Integer> getMaximumIndexOf(long playlistId);

@Query("SELECT CASE WHEN COUNT(*) != 0 then " + STREAM_THUMBNAIL_URL + " ELSE :defaultUrl END"
+ " FROM " + STREAM_TABLE
+ " LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE
+ " ON " + STREAM_ID + " = " + JOIN_STREAM_ID
+ " WHERE " + JOIN_PLAYLIST_ID + " = :playlistId "
+ " LIMIT 1"
)
Flowable<String> getAutomaticThumbnailUrl(long playlistId, String defaultUrl);

@RewriteQueriesToDropUnusedColumns
@Transaction
@Query("SELECT * FROM " + STREAM_TABLE + " INNER JOIN "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class PlaylistEntity {
public static final String PLAYLIST_ID = "uid";
public static final String PLAYLIST_NAME = "name";
public static final String PLAYLIST_THUMBNAIL_URL = "thumbnail_url";
public static final String PLAYLIST_THUMBNAIL_PERMANENT = "is_thumbnail_permanent";

@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = PLAYLIST_ID)
Expand All @@ -26,9 +27,14 @@ public class PlaylistEntity {
@ColumnInfo(name = PLAYLIST_THUMBNAIL_URL)
private String thumbnailUrl;

public PlaylistEntity(final String name, final String thumbnailUrl) {
@ColumnInfo(name = PLAYLIST_THUMBNAIL_PERMANENT)
private boolean isThumbnailPermanent;

public PlaylistEntity(final String name, final String thumbnailUrl,
final boolean isThumbnailPermanent) {
this.name = name;
this.thumbnailUrl = thumbnailUrl;
this.isThumbnailPermanent = isThumbnailPermanent;
}

public long getUid() {
Expand All @@ -54,4 +60,13 @@ public String getThumbnailUrl() {
public void setThumbnailUrl(final String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}

public boolean getIsThumbnailPermanent() {
return isThumbnailPermanent;
}

public void setIsThumbnailPermanent(final boolean isThumbnailSet) {
this.isThumbnailPermanent = isThumbnailSet;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.schabi.newpipe.local.bookmark;

import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.InputType;
Expand Down Expand Up @@ -31,6 +32,7 @@
import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture;

import java.util.ArrayList;
import java.util.List;

import icepick.State;
Expand Down Expand Up @@ -256,6 +258,41 @@ private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) {
}

private void showLocalDialog(final PlaylistMetadataEntry selectedItem) {
final String rename = getString(R.string.rename);
final String delete = getString(R.string.delete);
final String unsetThumbnail = getString(R.string.unset_playlist_thumbnail);
final boolean isThumbnailPermanent = localPlaylistManager
.getIsPlaylistThumbnailPermanent(selectedItem.uid);

final AlertDialog.Builder builder = new AlertDialog.Builder(activity);

final ArrayList<String> items = new ArrayList<>();
items.add(rename);
items.add(delete);
if (isThumbnailPermanent) {
items.add(unsetThumbnail);
}

final DialogInterface.OnClickListener action = (d, index) -> {
if (items.get(index).equals(rename)) {
showRenameDialog(selectedItem);
} else if (items.get(index).equals(delete)) {
showDeleteDialog(selectedItem.name,
localPlaylistManager.deletePlaylist(selectedItem.uid));
} else if (isThumbnailPermanent && items.get(index).equals(unsetThumbnail)) {
final String thumbnailUrl = localPlaylistManager
.getAutomaticPlaylistThumbnail(selectedItem.uid);
localPlaylistManager
.changePlaylistThumbnail(selectedItem.uid, thumbnailUrl, false)
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}
};

builder.setItems(items.toArray(new String[0]), action).create().show();
}

private void showRenameDialog(final PlaylistMetadataEntry selectedItem) {
final DialogEditTextBinding dialogBinding =
DialogEditTextBinding.inflate(getLayoutInflater());
dialogBinding.dialogEditText.setHint(R.string.name);
Expand All @@ -269,11 +306,6 @@ private void showLocalDialog(final PlaylistMetadataEntry selectedItem) {
selectedItem.uid,
dialogBinding.dialogEditText.getText().toString()))
.setNegativeButton(R.string.cancel, null)
.setNeutralButton(R.string.delete, (dialog, which) -> {
showDeleteDialog(selectedItem.name,
localPlaylistManager.deletePlaylist(selectedItem.uid));
dialog.dismiss();
})
.create()
.show();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private void onPlaylistSelected(@NonNull final LocalPlaylistManager manager,
if (playlist.thumbnailUrl
.equals("drawable://" + R.drawable.placeholder_thumbnail_playlist)) {
playlistDisposables.add(manager
.changePlaylistThumbnail(playlist.uid, streams.get(0).getThumbnailUrl())
.changePlaylistThumbnail(playlist.uid, streams.get(0).getThumbnailUrl(), false)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ignored -> successToast.show()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,8 @@ public void removeWatchedStreams(final boolean removePartiallyWatched) {
.zipWith(historyIdsMaybe, (playlist, historyStreamIds) -> {
// Remove Watched, Functionality data
final List<PlaylistStreamEntry> notWatchedItems = new ArrayList<>();
final boolean isThumbnailPermanent = playlistManager
.getIsPlaylistThumbnailPermanent(playlistId);
boolean thumbnailVideoRemoved = false;

if (removePartiallyWatched) {
Expand All @@ -414,7 +416,7 @@ public void removeWatchedStreams(final boolean removePartiallyWatched) {

if (indexInHistory < 0) {
notWatchedItems.add(playlistItem);
} else if (!thumbnailVideoRemoved
} else if (!isThumbnailPermanent && !thumbnailVideoRemoved
&& playlistManager.getPlaylistThumbnail(playlistId)
.equals(playlistItem.getStreamEntity().getThumbnailUrl())) {
thumbnailVideoRemoved = true;
Expand All @@ -435,7 +437,7 @@ public void removeWatchedStreams(final boolean removePartiallyWatched) {
if (indexInHistory < 0 || (streamStateEntity != null
&& !streamStateEntity.isFinished(duration))) {
notWatchedItems.add(playlistItem);
} else if (!thumbnailVideoRemoved
} else if (!isThumbnailPermanent && !thumbnailVideoRemoved
&& playlistManager.getPlaylistThumbnail(playlistId)
.equals(playlistItem.getStreamEntity().getThumbnailUrl())) {
thumbnailVideoRemoved = true;
Expand Down Expand Up @@ -585,8 +587,9 @@ private void changePlaylistName(final String title) {
disposables.add(disposable);
}

private void changeThumbnailUrl(final String thumbnailUrl) {
if (playlistManager == null) {
private void changeThumbnailUrl(final String thumbnailUrl, final boolean isPermanent) {
if (playlistManager == null || (!isPermanent && playlistManager
.getIsPlaylistThumbnailPermanent(playlistId))) {
return;
}

Expand All @@ -600,7 +603,7 @@ private void changeThumbnailUrl(final String thumbnailUrl) {
}

final Disposable disposable = playlistManager
.changePlaylistThumbnail(playlistId, thumbnailUrl)
.changePlaylistThumbnail(playlistId, thumbnailUrl, isPermanent)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(ignore -> successToast.show(), throwable ->
showError(new ErrorInfo(throwable, UserAction.REQUESTED_BOOKMARK,
Expand All @@ -609,6 +612,10 @@ private void changeThumbnailUrl(final String thumbnailUrl) {
}

private void updateThumbnailUrl() {
if (playlistManager.getIsPlaylistThumbnailPermanent(playlistId)) {
return;
}

final String newThumbnailUrl;

if (!itemListAdapter.getItemsList().isEmpty()) {
Expand All @@ -618,7 +625,7 @@ private void updateThumbnailUrl() {
newThumbnailUrl = "drawable://" + R.drawable.placeholder_thumbnail_playlist;
}

changeThumbnailUrl(newThumbnailUrl);
changeThumbnailUrl(newThumbnailUrl, false);
}

private void deleteItem(final PlaylistStreamEntry item) {
Expand Down Expand Up @@ -786,7 +793,8 @@ context, getPlayQueueStartingAt(item), true))
.setAction(
StreamDialogDefaultEntry.SET_AS_PLAYLIST_THUMBNAIL,
(f, i) ->
changeThumbnailUrl(item.getStreamEntity().getThumbnailUrl()))
changeThumbnailUrl(item.getStreamEntity().getThumbnailUrl(),
true))
.setAction(
StreamDialogDefaultEntry.DELETE,
(f, i) -> deleteItem(item))
Expand Down
Loading