2018-04-23 22:02:36 +02:00
|
|
|
package org.schabi.newpipe.local.bookmark;
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.os.Parcelable;
|
2021-07-27 19:31:58 +02:00
|
|
|
import android.text.InputType;
|
2020-01-13 20:24:24 +01:00
|
|
|
import android.util.Log;
|
2020-03-31 19:20:15 +02:00
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2021-04-01 21:46:29 +02:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.fragment.app.FragmentManager;
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
import org.reactivestreams.Subscriber;
|
|
|
|
import org.reactivestreams.Subscription;
|
|
|
|
import org.schabi.newpipe.NewPipeDatabase;
|
|
|
|
import org.schabi.newpipe.R;
|
2018-02-06 06:32:23 +01:00
|
|
|
import org.schabi.newpipe.database.AppDatabase;
|
2018-01-28 07:14:38 +01:00
|
|
|
import org.schabi.newpipe.database.LocalItem;
|
2018-02-06 06:32:23 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
2018-01-17 06:12:03 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
2018-02-06 06:32:23 +01:00
|
|
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
2021-07-27 19:31:58 +02:00
|
|
|
import org.schabi.newpipe.databinding.DialogEditTextBinding;
|
2020-12-11 14:55:47 +01:00
|
|
|
import org.schabi.newpipe.error.ErrorInfo;
|
2020-12-11 15:07:18 +01:00
|
|
|
import org.schabi.newpipe.error.UserAction;
|
2018-04-21 23:10:01 +02:00
|
|
|
import org.schabi.newpipe.local.BaseLocalListFragment;
|
2018-04-12 23:46:03 +02:00
|
|
|
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
|
|
|
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
2018-01-17 06:12:03 +01:00
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
2018-01-31 01:21:50 +01:00
|
|
|
import org.schabi.newpipe.util.OnClickGesture;
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import icepick.State;
|
2021-01-15 17:11:04 +01:00
|
|
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
2020-10-31 21:55:45 +01:00
|
|
|
import io.reactivex.rxjava3.core.Flowable;
|
|
|
|
import io.reactivex.rxjava3.core.Single;
|
|
|
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
|
|
import io.reactivex.rxjava3.disposables.Disposable;
|
2018-01-17 06:12:03 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
|
2018-01-17 06:12:03 +01:00
|
|
|
@State
|
|
|
|
protected Parcelable itemsListState;
|
|
|
|
|
|
|
|
private Subscription databaseSubscription;
|
|
|
|
private CompositeDisposable disposables = new CompositeDisposable();
|
|
|
|
private LocalPlaylistManager localPlaylistManager;
|
2018-02-06 06:32:23 +01:00
|
|
|
private RemotePlaylistManager remotePlaylistManager;
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2018-01-31 01:01:11 +01:00
|
|
|
// Fragment LifeCycle - Creation
|
2018-01-17 06:12:03 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onCreate(final Bundle savedInstanceState) {
|
2018-01-31 01:01:11 +01:00
|
|
|
super.onCreate(savedInstanceState);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2018-03-27 21:10:48 +02:00
|
|
|
final AppDatabase database = NewPipeDatabase.getInstance(activity);
|
2018-02-06 06:32:23 +01:00
|
|
|
localPlaylistManager = new LocalPlaylistManager(database);
|
|
|
|
remotePlaylistManager = new RemotePlaylistManager(database);
|
2018-01-31 01:01:11 +01:00
|
|
|
disposables = new CompositeDisposable();
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public View onCreateView(@NonNull final LayoutInflater inflater,
|
|
|
|
@Nullable final ViewGroup container,
|
|
|
|
final Bundle savedInstanceState) {
|
2018-01-17 06:12:03 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (!useAsFrontPage) {
|
2018-06-11 01:55:14 +02:00
|
|
|
setTitle(activity.getString(R.string.tab_bookmarks));
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void setUserVisibleHint(final boolean isVisibleToUser) {
|
2018-01-31 01:01:11 +01:00
|
|
|
super.setUserVisibleHint(isVisibleToUser);
|
2018-03-25 19:26:24 +02:00
|
|
|
if (activity != null && isVisibleToUser) {
|
|
|
|
setTitle(activity.getString(R.string.tab_bookmarks));
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Fragment LifeCycle - Views
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-01-17 06:12:03 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
2018-01-17 06:12:03 +01:00
|
|
|
super.initViews(rootView, savedInstanceState);
|
2018-01-31 01:01:11 +01:00
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void initListeners() {
|
|
|
|
super.initListeners();
|
|
|
|
|
2018-01-31 01:21:50 +01:00
|
|
|
itemListAdapter.setSelectedListener(new OnClickGesture<LocalItem>() {
|
2018-01-17 06:12:03 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void selected(final LocalItem selectedItem) {
|
2018-06-19 22:40:43 +02:00
|
|
|
final FragmentManager fragmentManager = getFM();
|
|
|
|
|
|
|
|
if (selectedItem instanceof PlaylistMetadataEntry) {
|
|
|
|
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
|
|
|
|
NavigationHelper.openLocalPlaylistFragment(fragmentManager, entry.uid,
|
|
|
|
entry.name);
|
|
|
|
|
|
|
|
} else if (selectedItem instanceof PlaylistRemoteEntity) {
|
|
|
|
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
|
|
|
|
NavigationHelper.openPlaylistFragment(
|
|
|
|
fragmentManager,
|
|
|
|
entry.getServiceId(),
|
|
|
|
entry.getUrl(),
|
|
|
|
entry.getName());
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void held(final LocalItem selectedItem) {
|
2018-01-28 07:14:38 +01:00
|
|
|
if (selectedItem instanceof PlaylistMetadataEntry) {
|
2020-01-21 20:56:06 +01:00
|
|
|
showLocalDialog((PlaylistMetadataEntry) selectedItem);
|
2018-02-06 06:32:23 +01:00
|
|
|
} else if (selectedItem instanceof PlaylistRemoteEntity) {
|
|
|
|
showRemoteDeleteDialog((PlaylistRemoteEntity) selectedItem);
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2020-04-02 13:51:10 +02:00
|
|
|
// Fragment LifeCycle - Loading
|
2018-01-17 06:12:03 +01:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void startLoading(final boolean forceLoad) {
|
2018-01-17 06:12:03 +01:00
|
|
|
super.startLoading(forceLoad);
|
2018-02-06 06:32:23 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
Flowable.combineLatest(localPlaylistManager.getPlaylists(),
|
2020-07-04 11:31:24 +02:00
|
|
|
remotePlaylistManager.getPlaylists(), PlaylistLocalItem::merge)
|
2020-03-31 19:20:15 +02:00
|
|
|
.onBackpressureLatest()
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(getPlaylistsSubscriber());
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Fragment LifeCycle - Destruction
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-01-31 01:01:11 +01:00
|
|
|
@Override
|
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroyView() {
|
|
|
|
super.onDestroyView();
|
2018-02-07 23:20:16 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (disposables != null) {
|
|
|
|
disposables.clear();
|
|
|
|
}
|
|
|
|
if (databaseSubscription != null) {
|
|
|
|
databaseSubscription.cancel();
|
|
|
|
}
|
2018-01-31 01:01:11 +01:00
|
|
|
|
|
|
|
databaseSubscription = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (disposables != null) {
|
|
|
|
disposables.dispose();
|
|
|
|
}
|
2018-01-31 01:01:11 +01:00
|
|
|
|
|
|
|
disposables = null;
|
|
|
|
localPlaylistManager = null;
|
2018-02-06 06:32:23 +01:00
|
|
|
remotePlaylistManager = null;
|
2018-01-31 01:01:11 +01:00
|
|
|
itemsListState = null;
|
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Subscriptions Loader
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-02-06 06:32:23 +01:00
|
|
|
private Subscriber<List<PlaylistLocalItem>> getPlaylistsSubscriber() {
|
|
|
|
return new Subscriber<List<PlaylistLocalItem>>() {
|
2018-01-17 06:12:03 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSubscribe(final Subscription s) {
|
2018-01-17 06:12:03 +01:00
|
|
|
showLoading();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (databaseSubscription != null) {
|
|
|
|
databaseSubscription.cancel();
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
databaseSubscription = s;
|
|
|
|
databaseSubscription.request(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onNext(final List<PlaylistLocalItem> subscriptions) {
|
2018-01-17 06:12:03 +01:00
|
|
|
handleResult(subscriptions);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (databaseSubscription != null) {
|
|
|
|
databaseSubscription.request(1);
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onError(final Throwable exception) {
|
2020-12-11 14:55:47 +01:00
|
|
|
showError(new ErrorInfo(exception,
|
|
|
|
UserAction.REQUESTED_BOOKMARK, "Loading playlists"));
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onComplete() { }
|
2018-01-17 06:12:03 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void handleResult(@NonNull final List<PlaylistLocalItem> result) {
|
2018-01-17 06:12:03 +01:00
|
|
|
super.handleResult(result);
|
|
|
|
|
2018-01-28 07:14:38 +01:00
|
|
|
itemListAdapter.clearStreamItemList();
|
2018-01-17 06:12:03 +01:00
|
|
|
|
|
|
|
if (result.isEmpty()) {
|
|
|
|
showEmptyState();
|
2018-01-31 01:01:11 +01:00
|
|
|
return;
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
2018-01-31 01:01:11 +01:00
|
|
|
itemListAdapter.addItems(result);
|
|
|
|
if (itemsListState != null) {
|
|
|
|
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
|
|
|
itemsListState = null;
|
|
|
|
}
|
|
|
|
hideLoading();
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Fragment Error Handling
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-01-17 06:12:03 +01:00
|
|
|
@Override
|
2018-01-31 01:01:11 +01:00
|
|
|
protected void resetFragment() {
|
|
|
|
super.resetFragment();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (disposables != null) {
|
|
|
|
disposables.clear();
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2018-02-06 06:32:23 +01:00
|
|
|
private void showRemoteDeleteDialog(final PlaylistRemoteEntity item) {
|
|
|
|
showDeleteDialog(item.getName(), remotePlaylistManager.deletePlaylist(item.getUid()));
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void showLocalDialog(final PlaylistMetadataEntry selectedItem) {
|
2021-07-27 19:31:58 +02:00
|
|
|
final DialogEditTextBinding dialogBinding
|
|
|
|
= DialogEditTextBinding.inflate(getLayoutInflater());
|
|
|
|
dialogBinding.dialogEditText.setHint(R.string.name);
|
|
|
|
dialogBinding.dialogEditText.setInputType(InputType.TYPE_CLASS_TEXT);
|
|
|
|
dialogBinding.dialogEditText.setText(selectedItem.name);
|
2020-02-02 12:54:43 +01:00
|
|
|
|
2021-04-01 21:46:29 +02:00
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
2021-07-27 19:31:58 +02:00
|
|
|
builder.setView(dialogBinding.getRoot())
|
2020-08-27 22:56:41 +02:00
|
|
|
.setPositiveButton(R.string.rename_playlist, (dialog, which) ->
|
2021-07-27 19:31:58 +02:00
|
|
|
changeLocalPlaylistName(
|
|
|
|
selectedItem.uid,
|
|
|
|
dialogBinding.dialogEditText.getText().toString()))
|
2020-03-31 19:20:15 +02:00
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.setNeutralButton(R.string.delete, (dialog, which) -> {
|
|
|
|
showDeleteDialog(selectedItem.name,
|
|
|
|
localPlaylistManager.deletePlaylist(selectedItem.uid));
|
|
|
|
dialog.dismiss();
|
|
|
|
})
|
|
|
|
.create()
|
|
|
|
.show();
|
2020-01-21 20:56:06 +01:00
|
|
|
}
|
|
|
|
|
2018-02-06 06:32:23 +01:00
|
|
|
private void showDeleteDialog(final String name, final Single<Integer> deleteReactor) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (activity == null || disposables == null) {
|
|
|
|
return;
|
|
|
|
}
|
2018-02-06 06:32:23 +01:00
|
|
|
|
2018-01-31 01:01:11 +01:00
|
|
|
new AlertDialog.Builder(activity)
|
2018-02-06 06:32:23 +01:00
|
|
|
.setTitle(name)
|
2018-01-31 01:01:11 +01:00
|
|
|
.setMessage(R.string.delete_playlist_prompt)
|
|
|
|
.setCancelable(true)
|
|
|
|
.setPositiveButton(R.string.delete, (dialog, i) ->
|
2018-02-06 06:32:23 +01:00
|
|
|
disposables.add(deleteReactor
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2020-12-11 14:55:47 +01:00
|
|
|
.subscribe(ignored -> { /*Do nothing on success*/ }, throwable ->
|
|
|
|
showError(new ErrorInfo(throwable,
|
|
|
|
UserAction.REQUESTED_BOOKMARK,
|
|
|
|
"Deleting playlist")))))
|
2018-01-31 01:01:11 +01:00
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.show();
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void changeLocalPlaylistName(final long id, final String name) {
|
2020-01-13 20:24:24 +01:00
|
|
|
if (localPlaylistManager == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-01 16:27:53 +01:00
|
|
|
if (DEBUG) {
|
2020-03-31 19:20:15 +02:00
|
|
|
Log.d(TAG, "Updating playlist id=[" + id + "] "
|
|
|
|
+ "with new name=[" + name + "] items");
|
2020-02-01 16:27:53 +01:00
|
|
|
}
|
2020-01-13 20:24:24 +01:00
|
|
|
|
|
|
|
localPlaylistManager.renamePlaylist(id, name);
|
|
|
|
final Disposable disposable = localPlaylistManager.renamePlaylist(id, name)
|
2020-03-31 19:20:15 +02:00
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2020-12-11 14:55:47 +01:00
|
|
|
.subscribe(longs -> { /*Do nothing on success*/ }, throwable -> showError(
|
|
|
|
new ErrorInfo(throwable,
|
|
|
|
UserAction.REQUESTED_BOOKMARK,
|
|
|
|
"Changing playlist name")));
|
2020-01-13 20:24:24 +01:00
|
|
|
disposables.add(disposable);
|
|
|
|
}
|
2018-01-17 06:12:03 +01:00
|
|
|
}
|
|
|
|
|