-Modified BaseLocalItemFragment to no longer cache items when going into background.
-Refactored and restructured all LocalItem related fragments and dialogs. -Added error logging to unmonitored single-use observables. -Modified playlist metadata query to return by alphabetical order. -Removed sending toast when playlist is renamed or deleted as it is obvious. -Removed unused code in main fragment.
This commit is contained in:
parent
75a58d6381
commit
225b43ca3c
|
@ -63,6 +63,7 @@ public abstract class PlaylistStreamDAO implements BasicDAO<PlaylistStreamEntity
|
||||||
" FROM " + PLAYLIST_TABLE +
|
" FROM " + PLAYLIST_TABLE +
|
||||||
" LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE +
|
" LEFT JOIN " + PLAYLIST_STREAM_JOIN_TABLE +
|
||||||
" ON " + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID +
|
" ON " + PLAYLIST_ID + " = " + JOIN_PLAYLIST_ID +
|
||||||
" GROUP BY " + JOIN_PLAYLIST_ID)
|
" GROUP BY " + JOIN_PLAYLIST_ID +
|
||||||
|
" ORDER BY " + PLAYLIST_NAME + " COLLATE NOCASE ASC")
|
||||||
public abstract Flowable<List<PlaylistMetadataEntry>> getPlaylistMetadata();
|
public abstract Flowable<List<PlaylistMetadataEntry>> getPlaylistMetadata();
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,10 +229,6 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||||
ChannelFragment fragment = ChannelFragment.getInstance(serviceId, url, name);
|
ChannelFragment fragment = ChannelFragment.getInstance(serviceId, url, name);
|
||||||
fragment.useAsFrontPage(true);
|
fragment.useAsFrontPage(true);
|
||||||
return fragment;
|
return fragment;
|
||||||
} else if (setMainPage.equals(getString(R.string.bookmark_page_key))) {
|
|
||||||
final BookmarkFragment fragment = new BookmarkFragment();
|
|
||||||
fragment.useAsFrontPage(true);
|
|
||||||
return fragment;
|
|
||||||
} else {
|
} else {
|
||||||
return new BlankFragment();
|
return new BlankFragment();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.schabi.newpipe.fragments.local;
|
package org.schabi.newpipe.fragments.local;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
@ -12,86 +11,44 @@ import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.fragments.list.ListViewContract;
|
import org.schabi.newpipe.fragments.list.ListViewContract;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This fragment is design to be used with persistent data such as
|
||||||
|
* {@link org.schabi.newpipe.database.LocalItem}, and does not cache the data contained
|
||||||
|
* in the list adapter to avoid extra writes when the it exits or re-enters its lifecycle.
|
||||||
|
*
|
||||||
|
* This fragment destroys its adapter and views when {@link Fragment#onDestroyView()} is
|
||||||
|
* called and is memory efficient when in backstack.
|
||||||
|
* */
|
||||||
public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
implements ListViewContract<I, N>, StateSaver.WriteRead {
|
implements ListViewContract<I, N> {
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected View headerRootView;
|
||||||
|
protected View footerRootView;
|
||||||
|
|
||||||
protected LocalItemListAdapter itemListAdapter;
|
protected LocalItemListAdapter itemListAdapter;
|
||||||
protected RecyclerView itemsList;
|
protected RecyclerView itemsList;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// Lifecycle - Creation
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
itemListAdapter = new LocalItemListAdapter(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
StateSaver.onDestroy(savedState);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// State Saving
|
// Lifecycle - View
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
protected StateSaver.SavedState savedState;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generateSuffix() {
|
|
||||||
// Naive solution, but it's good for now (the items don't change)
|
|
||||||
return "." + itemListAdapter.getItemsList().size() + ".list";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTo(Queue<Object> objectsToSave) {
|
|
||||||
objectsToSave.add(itemListAdapter.getItemsList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
|
||||||
itemListAdapter.getItemsList().clear();
|
|
||||||
itemListAdapter.getItemsList().addAll((List<LocalItem>) savedObjects.poll());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(Bundle bundle) {
|
|
||||||
super.onSaveInstanceState(bundle);
|
|
||||||
savedState = StateSaver.tryToSave(activity.isChangingConfigurations(), savedState, bundle, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onRestoreInstanceState(@NonNull Bundle bundle) {
|
|
||||||
super.onRestoreInstanceState(bundle);
|
|
||||||
savedState = StateSaver.tryToRestore(bundle, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected View getListHeader() {
|
protected View getListHeader() {
|
||||||
|
@ -113,8 +70,9 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
itemsList = rootView.findViewById(R.id.items_list);
|
||||||
itemsList.setLayoutManager(getListLayoutManager());
|
itemsList.setLayoutManager(getListLayoutManager());
|
||||||
|
|
||||||
itemListAdapter.setFooter(getListFooter());
|
itemListAdapter = new LocalItemListAdapter(activity);
|
||||||
itemListAdapter.setHeader(getListHeader());
|
itemListAdapter.setHeader(headerRootView = getListHeader());
|
||||||
|
itemListAdapter.setFooter(footerRootView = getListFooter());
|
||||||
|
|
||||||
itemsList.setAdapter(itemListAdapter);
|
itemsList.setAdapter(itemListAdapter);
|
||||||
}
|
}
|
||||||
|
@ -125,12 +83,13 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Lifecycle - Menu
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||||
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu + "], inflater = [" + inflater + "]");
|
if (DEBUG) Log.d(TAG, "onCreateOptionsMenu() called with: menu = [" + menu +
|
||||||
|
"], inflater = [" + inflater + "]");
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
|
@ -143,27 +102,48 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Lifecycle - Destruction
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
itemsList = null;
|
||||||
|
itemListAdapter = null;
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Contract
|
// Contract
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startLoading(boolean forceLoad) {
|
||||||
|
super.startLoading(forceLoad);
|
||||||
|
resetFragment();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showLoading() {
|
public void showLoading() {
|
||||||
super.showLoading();
|
super.showLoading();
|
||||||
// animateView(itemsList, false, 400);
|
animateView(itemsList, false, 200);
|
||||||
|
if (headerRootView != null) animateView(headerRootView, false, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hideLoading() {
|
public void hideLoading() {
|
||||||
super.hideLoading();
|
super.hideLoading();
|
||||||
animateView(itemsList, true, 300);
|
animateView(itemsList, true, 200);
|
||||||
|
if (headerRootView != null) animateView(headerRootView, true, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showError(String message, boolean showRetryButton) {
|
public void showError(String message, boolean showRetryButton) {
|
||||||
super.showError(message, showRetryButton);
|
super.showError(message, showRetryButton);
|
||||||
showListFooter(false);
|
showListFooter(false);
|
||||||
|
|
||||||
animateView(itemsList, false, 200);
|
animateView(itemsList, false, 200);
|
||||||
|
if (headerRootView != null) animateView(headerRootView, false, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -181,4 +161,18 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
public void handleNextItems(N result) {
|
public void handleNextItems(N result) {
|
||||||
isLoading.set(false);
|
isLoading.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Error handling
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected void resetFragment() {
|
||||||
|
if (itemListAdapter != null) itemListAdapter.clearStreamItemList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onError(Throwable exception) {
|
||||||
|
resetFragment();
|
||||||
|
return super.onError(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -38,7 +39,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.subjects.PublishSubject;
|
import io.reactivex.subjects.PublishSubject;
|
||||||
|
|
||||||
|
@ -51,8 +51,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
private View headerRootLayout;
|
private View headerRootLayout;
|
||||||
private TextView headerTitleView;
|
private TextView headerTitleView;
|
||||||
private TextView headerStreamCount;
|
private TextView headerStreamCount;
|
||||||
private View playlistControl;
|
|
||||||
|
|
||||||
|
private View playlistControl;
|
||||||
private View headerPlayAllButton;
|
private View headerPlayAllButton;
|
||||||
private View headerPopupButton;
|
private View headerPopupButton;
|
||||||
private View headerBackgroundButton;
|
private View headerBackgroundButton;
|
||||||
|
@ -66,10 +66,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
|
|
||||||
private ItemTouchHelper itemTouchHelper;
|
private ItemTouchHelper itemTouchHelper;
|
||||||
|
|
||||||
/* Used for independent events */
|
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
private Subscription databaseSubscription;
|
|
||||||
private LocalPlaylistManager playlistManager;
|
private LocalPlaylistManager playlistManager;
|
||||||
|
private Subscription databaseSubscription;
|
||||||
|
|
||||||
private PublishSubject<Long> debouncedSaveSignal;
|
private PublishSubject<Long> debouncedSaveSignal;
|
||||||
private Disposable debouncedSaver;
|
private Disposable debouncedSaver;
|
||||||
|
@ -81,13 +79,14 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment LifeCycle
|
// Fragment LifeCycle - Creation
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onAttach(context);
|
super.onCreate(savedInstanceState);
|
||||||
playlistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(context));
|
playlistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
|
||||||
|
debouncedSaveSignal = PublishSubject.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,53 +96,23 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
return inflater.inflate(R.layout.fragment_playlist, container, false);
|
return inflater.inflate(R.layout.fragment_playlist, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
debouncedSaveSignal = PublishSubject.create();
|
|
||||||
debouncedSaver = getDebouncedSaver();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
if (debouncedSaveSignal != null) debouncedSaveSignal.onComplete();
|
|
||||||
if (debouncedSaver != null) debouncedSaver.dispose();
|
|
||||||
|
|
||||||
debouncedSaveSignal = null;
|
|
||||||
debouncedSaver = null;
|
|
||||||
|
|
||||||
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
if (disposables != null) disposables.clear();
|
|
||||||
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
if (disposables != null) disposables.dispose();
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
|
|
||||||
disposables = null;
|
|
||||||
databaseSubscription = null;
|
|
||||||
playlistManager = null;
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment Views
|
// Fragment Lifecycle - Views
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTitle(final String title) {
|
||||||
|
super.setTitle(title);
|
||||||
|
|
||||||
|
if (headerTitleView != null) {
|
||||||
|
headerTitleView.setText(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
setFragmentTitle(name);
|
setTitle(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -155,6 +124,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
headerTitleView.setSelected(true);
|
headerTitleView.setSelected(true);
|
||||||
|
|
||||||
headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count);
|
headerStreamCount = headerRootLayout.findViewById(R.id.playlist_stream_count);
|
||||||
|
|
||||||
playlistControl = headerRootLayout.findViewById(R.id.playlist_control);
|
playlistControl = headerRootLayout.findViewById(R.id.playlist_control);
|
||||||
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
|
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
|
||||||
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
|
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
|
||||||
|
@ -167,6 +137,8 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
protected void initListeners() {
|
protected void initListeners() {
|
||||||
super.initListeners();
|
super.initListeners();
|
||||||
|
|
||||||
|
headerTitleView.setOnClickListener(view -> createRenameDialog());
|
||||||
|
|
||||||
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
||||||
itemTouchHelper.attachToRecyclerView(itemsList);
|
itemTouchHelper.attachToRecyclerView(itemsList);
|
||||||
|
|
||||||
|
@ -192,9 +164,236 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
if (itemTouchHelper != null) itemTouchHelper.startDrag(viewHolder);
|
if (itemTouchHelper != null) itemTouchHelper.startDrag(viewHolder);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
headerTitleView.setOnClickListener(view -> createRenameDialog());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Lifecycle - Loading
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showLoading() {
|
||||||
|
super.showLoading();
|
||||||
|
animateView(headerRootLayout, false, 200);
|
||||||
|
animateView(playlistControl, false, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hideLoading() {
|
||||||
|
super.hideLoading();
|
||||||
|
animateView(headerRootLayout, true, 200);
|
||||||
|
animateView(playlistControl, true, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startLoading(boolean forceLoad) {
|
||||||
|
super.startLoading(forceLoad);
|
||||||
|
|
||||||
|
if (debouncedSaver != null) debouncedSaver.dispose();
|
||||||
|
debouncedSaver = getDebouncedSaver();
|
||||||
|
|
||||||
|
playlistManager.getPlaylistStreams(playlistId)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(getPlaylistObserver());
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Lifecycle - Destruction
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
if (debouncedSaver != null) debouncedSaver.dispose();
|
||||||
|
|
||||||
|
databaseSubscription = null;
|
||||||
|
debouncedSaver = null;
|
||||||
|
itemTouchHelper = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (debouncedSaveSignal != null) debouncedSaveSignal.onComplete();
|
||||||
|
|
||||||
|
debouncedSaveSignal = null;
|
||||||
|
playlistManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Playlist Stream Loader
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private Subscriber<List<PlaylistStreamEntry>> getPlaylistObserver() {
|
||||||
|
return new Subscriber<List<PlaylistStreamEntry>>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(Subscription s) {
|
||||||
|
showLoading();
|
||||||
|
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
databaseSubscription = s;
|
||||||
|
databaseSubscription.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(List<PlaylistStreamEntry> streams) {
|
||||||
|
// Do not allow saving while the result is being updated
|
||||||
|
if (debouncedSaver != null) debouncedSaver.dispose();
|
||||||
|
handleResult(streams);
|
||||||
|
debouncedSaver = getDebouncedSaver();
|
||||||
|
|
||||||
|
if (databaseSubscription != null) databaseSubscription.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable exception) {
|
||||||
|
LocalPlaylistFragment.this.onError(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleResult(@NonNull List<PlaylistStreamEntry> result) {
|
||||||
|
super.handleResult(result);
|
||||||
|
itemListAdapter.clearStreamItemList();
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
showEmptyState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemListAdapter.addItems(result);
|
||||||
|
if (itemsListState != null) {
|
||||||
|
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
||||||
|
itemsListState = null;
|
||||||
|
}
|
||||||
|
setVideoCount(itemListAdapter.getItemsList().size());
|
||||||
|
|
||||||
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
|
headerPopupButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
||||||
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
||||||
|
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Error Handling
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void resetFragment() {
|
||||||
|
super.resetFragment();
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onError(Throwable exception) {
|
||||||
|
if (super.onError(exception)) return true;
|
||||||
|
|
||||||
|
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
||||||
|
"none", "Local Playlist", R.string.general_error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Playlist Metadata/Streams Manipulation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void createRenameDialog() {
|
||||||
|
if (playlistId == null || name == null || getContext() == null) return;
|
||||||
|
|
||||||
|
final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
||||||
|
EditText nameEdit = dialogView.findViewById(R.id.playlist_name);
|
||||||
|
nameEdit.setText(name);
|
||||||
|
nameEdit.setSelection(nameEdit.getText().length());
|
||||||
|
|
||||||
|
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext())
|
||||||
|
.setTitle(R.string.rename_playlist)
|
||||||
|
.setView(dialogView)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.create, (dialogInterface, i) ->
|
||||||
|
changePlaylistName(nameEdit.getText().toString())
|
||||||
|
);
|
||||||
|
|
||||||
|
dialogBuilder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changePlaylistName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
setTitle(name);
|
||||||
|
|
||||||
|
Log.e(TAG, "Updating playlist id=[" + playlistId +
|
||||||
|
"] with new name=[" + name + "] items");
|
||||||
|
|
||||||
|
playlistManager.renamePlaylist(playlistId, name)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(longs -> {/*Do nothing on success*/}, this::onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeThumbnailUrl(final String thumbnailUrl) {
|
||||||
|
final Toast successToast = Toast.makeText(getActivity(),
|
||||||
|
R.string.playlist_thumbnail_change_success,
|
||||||
|
Toast.LENGTH_SHORT);
|
||||||
|
|
||||||
|
Log.e(TAG, "Updating playlist id=[" + playlistId +
|
||||||
|
"] with new thumbnail url=[" + thumbnailUrl + "]");
|
||||||
|
|
||||||
|
playlistManager.changePlaylistThumbnail(playlistId, thumbnailUrl)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(ignore -> successToast.show(), this::onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteItem(final PlaylistStreamEntry item) {
|
||||||
|
itemListAdapter.removeItem(item);
|
||||||
|
setVideoCount(itemListAdapter.getItemsList().size());
|
||||||
|
saveDebounced();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveDebounced() {
|
||||||
|
debouncedSaveSignal.onNext(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Disposable getDebouncedSaver() {
|
||||||
|
return debouncedSaveSignal
|
||||||
|
.debounce(SAVE_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(ignored -> saveJoin());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveJoin() {
|
||||||
|
final List<LocalItem> items = itemListAdapter.getItemsList();
|
||||||
|
List<Long> streamIds = new ArrayList<>(items.size());
|
||||||
|
for (final LocalItem item : items) {
|
||||||
|
if (item instanceof PlaylistStreamEntry) {
|
||||||
|
streamIds.add(((PlaylistStreamEntry) item).streamId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.e(TAG, "Updating playlist id=[" + playlistId +
|
||||||
|
"] with [" + streamIds.size() + "] items");
|
||||||
|
|
||||||
|
playlistManager.updateJoin(playlistId, streamIds)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(() -> {/*Do nothing on success*/}, this::onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void showStreamDialog(final PlaylistStreamEntry item) {
|
protected void showStreamDialog(final PlaylistStreamEntry item) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
@ -236,9 +435,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
changeThumbnailUrl(item.thumbnailUrl);
|
changeThumbnailUrl(item.thumbnailUrl);
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
itemListAdapter.removeItem(item);
|
deleteItem(item);
|
||||||
setVideoCount(itemListAdapter.getItemsList().size());
|
|
||||||
saveDebounced();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -281,124 +478,11 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetFragment() {
|
|
||||||
if (disposables != null) disposables.clear();
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
if (itemListAdapter != null) itemListAdapter.clearStreamItemList();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Loader
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showLoading() {
|
|
||||||
super.showLoading();
|
|
||||||
animateView(headerRootLayout, false, 200);
|
|
||||||
animateView(itemsList, false, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startLoading(boolean forceLoad) {
|
|
||||||
super.startLoading(forceLoad);
|
|
||||||
resetFragment();
|
|
||||||
|
|
||||||
playlistManager.getPlaylistStreams(playlistId)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(getPlaylistObserver());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Subscriber<List<PlaylistStreamEntry>> getPlaylistObserver() {
|
|
||||||
return new Subscriber<List<PlaylistStreamEntry>>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
showLoading();
|
|
||||||
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
databaseSubscription = s;
|
|
||||||
databaseSubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(List<PlaylistStreamEntry> streams) {
|
|
||||||
handleResult(streams);
|
|
||||||
if (databaseSubscription != null) databaseSubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable exception) {
|
|
||||||
LocalPlaylistFragment.this.onError(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleResult(@NonNull List<PlaylistStreamEntry> result) {
|
|
||||||
super.handleResult(result);
|
|
||||||
itemListAdapter.clearStreamItemList();
|
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
showEmptyState();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
animateView(headerRootLayout, true, 100);
|
|
||||||
animateView(itemsList, true, 300);
|
|
||||||
|
|
||||||
itemListAdapter.addItems(result);
|
|
||||||
if (itemsListState != null) {
|
|
||||||
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
|
||||||
itemsListState = null;
|
|
||||||
}
|
|
||||||
setVideoCount(itemListAdapter.getItemsList().size());
|
|
||||||
|
|
||||||
playlistControl.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
|
||||||
headerPopupButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
|
||||||
hideLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment Error Handling
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean onError(Throwable exception) {
|
|
||||||
resetFragment();
|
|
||||||
if (super.onError(exception)) return true;
|
|
||||||
|
|
||||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
|
||||||
"none", "Local Playlist", R.string.general_error);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void setInitialData(long playlistId, String name) {
|
private void setInitialData(long playlistId, String name) {
|
||||||
this.playlistId = playlistId;
|
this.playlistId = playlistId;
|
||||||
this.name = !TextUtils.isEmpty(name) ? name : "";
|
this.name = !TextUtils.isEmpty(name) ? name : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFragmentTitle(final String title) {
|
|
||||||
if (activity != null && activity.getSupportActionBar() != null) {
|
|
||||||
activity.getSupportActionBar().setTitle(title);
|
|
||||||
}
|
|
||||||
if (headerTitleView != null) {
|
|
||||||
headerTitleView.setText(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setVideoCount(final long count) {
|
private void setVideoCount(final long count) {
|
||||||
if (activity != null && headerStreamCount != null) {
|
if (activity != null && headerStreamCount != null) {
|
||||||
headerStreamCount.setText(Localization.localizeStreamCount(activity, count));
|
headerStreamCount.setText(Localization.localizeStreamCount(activity, count));
|
||||||
|
@ -419,71 +503,5 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
}
|
}
|
||||||
return new SinglePlayQueue(streamInfoItems, index);
|
return new SinglePlayQueue(streamInfoItems, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createRenameDialog() {
|
|
||||||
if (playlistId == null || name == null || getContext() == null) return;
|
|
||||||
|
|
||||||
final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
|
||||||
EditText nameEdit = dialogView.findViewById(R.id.playlist_name);
|
|
||||||
nameEdit.setText(name);
|
|
||||||
nameEdit.setSelection(nameEdit.getText().length());
|
|
||||||
|
|
||||||
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext())
|
|
||||||
.setTitle(R.string.rename_playlist)
|
|
||||||
.setView(dialogView)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.create, (dialogInterface, i) -> {
|
|
||||||
name = nameEdit.getText().toString();
|
|
||||||
setFragmentTitle(name);
|
|
||||||
|
|
||||||
final LocalPlaylistManager playlistManager =
|
|
||||||
new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
|
|
||||||
final Toast successToast = Toast.makeText(getActivity(),
|
|
||||||
R.string.playlist_rename_success,
|
|
||||||
Toast.LENGTH_SHORT);
|
|
||||||
|
|
||||||
playlistManager.renamePlaylist(playlistId, name)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(longs -> successToast.show());
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogBuilder.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void changeThumbnailUrl(final String thumbnailUrl) {
|
|
||||||
final Toast successToast = Toast.makeText(getActivity(),
|
|
||||||
R.string.playlist_thumbnail_change_success,
|
|
||||||
Toast.LENGTH_SHORT);
|
|
||||||
|
|
||||||
playlistManager.changePlaylistThumbnail(playlistId, thumbnailUrl)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(ignore -> successToast.show());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveDebounced() {
|
|
||||||
debouncedSaveSignal.onNext(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Disposable getDebouncedSaver() {
|
|
||||||
return debouncedSaveSignal
|
|
||||||
.debounce(SAVE_DEBOUNCE_MILLIS, TimeUnit.MILLISECONDS)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(ignored -> saveJoin());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveJoin() {
|
|
||||||
final List<LocalItem> items = itemListAdapter.getItemsList();
|
|
||||||
List<Long> streamIds = new ArrayList<>(items.size());
|
|
||||||
for (final LocalItem item : items) {
|
|
||||||
if (item instanceof PlaylistStreamEntry) {
|
|
||||||
streamIds.add(((PlaylistStreamEntry) item).streamId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
playlistManager.updateJoin(playlistId, streamIds)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.fragments.local;
|
package org.schabi.newpipe.fragments.local;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
@ -25,6 +24,8 @@ import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
|
@ -63,26 +64,7 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle - Creation
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
playlistAdapter = new LocalItemListAdapter(getActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
if (playlistReactor != null) playlistReactor.dispose();
|
|
||||||
playlistReactor = null;
|
|
||||||
playlistRecyclerView = null;
|
|
||||||
playlistAdapter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Views
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -95,52 +77,44 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
final View newPlaylistButton = view.findViewById(R.id.newPlaylist);
|
|
||||||
playlistRecyclerView = view.findViewById(R.id.playlist_list);
|
|
||||||
playlistRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
playlistRecyclerView.setAdapter(playlistAdapter);
|
|
||||||
|
|
||||||
final LocalPlaylistManager playlistManager =
|
final LocalPlaylistManager playlistManager =
|
||||||
new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
|
new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
|
||||||
|
|
||||||
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());
|
playlistAdapter = new LocalItemListAdapter(getActivity());
|
||||||
|
|
||||||
playlistAdapter.setSelectedListener(new OnLocalItemGesture<LocalItem>() {
|
playlistAdapter.setSelectedListener(new OnLocalItemGesture<LocalItem>() {
|
||||||
@Override
|
@Override
|
||||||
public void selected(LocalItem selectedItem) {
|
public void selected(LocalItem selectedItem) {
|
||||||
if (!(selectedItem instanceof PlaylistMetadataEntry) || getStreams() == null)
|
if (!(selectedItem instanceof PlaylistMetadataEntry) || getStreams() == null)
|
||||||
return;
|
return;
|
||||||
|
onPlaylistSelected(playlistManager, (PlaylistMetadataEntry) selectedItem,
|
||||||
final long playlistId = ((PlaylistMetadataEntry) selectedItem).uid;
|
getStreams());
|
||||||
@SuppressLint("ShowToast")
|
|
||||||
final Toast successToast = Toast.makeText(getContext(), R.string.playlist_add_stream_success,
|
|
||||||
Toast.LENGTH_SHORT);
|
|
||||||
|
|
||||||
playlistManager.appendToPlaylist(playlistId, getStreams())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.doOnDispose(successToast::show)
|
|
||||||
.subscribe(ignored -> {});
|
|
||||||
|
|
||||||
getDialog().dismiss();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
playlistRecyclerView = view.findViewById(R.id.playlist_list);
|
||||||
|
playlistRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
playlistRecyclerView.setAdapter(playlistAdapter);
|
||||||
|
|
||||||
|
final View newPlaylistButton = view.findViewById(R.id.newPlaylist);
|
||||||
|
newPlaylistButton.setOnClickListener(ignored -> openCreatePlaylistDialog());
|
||||||
|
|
||||||
playlistReactor = playlistManager.getPlaylists()
|
playlistReactor = playlistManager.getPlaylists()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(metadataEntries -> {
|
.subscribe(this::onPlaylistsReceived);
|
||||||
if (metadataEntries.isEmpty()) {
|
}
|
||||||
openCreatePlaylistDialog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playlistAdapter != null) {
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
playlistAdapter.clearStreamItemList();
|
// LifeCycle - Destruction
|
||||||
playlistAdapter.addItems(metadataEntries);
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
}
|
|
||||||
if (playlistRecyclerView != null) {
|
@Override
|
||||||
playlistRecyclerView.setVisibility(View.VISIBLE);
|
public void onDestroyView() {
|
||||||
}
|
super.onDestroyView();
|
||||||
});
|
if (playlistReactor != null) playlistReactor.dispose();
|
||||||
|
|
||||||
|
playlistReactor = null;
|
||||||
|
playlistRecyclerView = null;
|
||||||
|
playlistAdapter = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -153,4 +127,33 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||||
PlaylistCreationDialog.newInstance(getStreams()).show(getFragmentManager(), TAG);
|
PlaylistCreationDialog.newInstance(getStreams()).show(getFragmentManager(), TAG);
|
||||||
getDialog().dismiss();
|
getDialog().dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onPlaylistsReceived(@NonNull final List<PlaylistMetadataEntry> playlists) {
|
||||||
|
if (playlists.isEmpty()) {
|
||||||
|
openCreatePlaylistDialog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playlistAdapter != null && playlistRecyclerView != null) {
|
||||||
|
playlistAdapter.clearStreamItemList();
|
||||||
|
playlistAdapter.addItems(playlists);
|
||||||
|
playlistRecyclerView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPlaylistSelected(@NonNull LocalPlaylistManager manager,
|
||||||
|
@NonNull PlaylistMetadataEntry playlist,
|
||||||
|
@Nonnull List<StreamEntity> streams) {
|
||||||
|
if (getStreams() == null) return;
|
||||||
|
|
||||||
|
@SuppressLint("ShowToast")
|
||||||
|
final Toast successToast = Toast.makeText(getContext(),
|
||||||
|
R.string.playlist_add_stream_success, Toast.LENGTH_SHORT);
|
||||||
|
|
||||||
|
manager.appendToPlaylist(playlist.uid, streams)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(ignored -> successToast.show());
|
||||||
|
|
||||||
|
getDialog().dismiss();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.fragments.local.bookmark;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.util.Log;
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
|
@ -19,29 +16,25 @@ import org.schabi.newpipe.NewPipeDatabase;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.local.BaseLocalListFragment;
|
||||||
import org.schabi.newpipe.fragments.local.LocalItemListAdapter;
|
|
||||||
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
||||||
import org.schabi.newpipe.fragments.local.OnLocalItemGesture;
|
import org.schabi.newpipe.fragments.local.OnLocalItemGesture;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
public final class BookmarkFragment
|
||||||
|
extends BaseLocalListFragment<List<PlaylistMetadataEntry>, Void> {
|
||||||
|
|
||||||
public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEntry>> {
|
|
||||||
private View watchHistoryButton;
|
private View watchHistoryButton;
|
||||||
private View mostWatchedButton;
|
private View mostWatchedButton;
|
||||||
|
|
||||||
private LocalItemListAdapter itemListAdapter;
|
|
||||||
private RecyclerView itemsList;
|
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected Parcelable itemsListState;
|
protected Parcelable itemsListState;
|
||||||
|
|
||||||
|
@ -50,23 +43,14 @@ public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEnt
|
||||||
private LocalPlaylistManager localPlaylistManager;
|
private LocalPlaylistManager localPlaylistManager;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment LifeCycle
|
// Fragment LifeCycle - Creation
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.setUserVisibleHint(isVisibleToUser);
|
super.onCreate(savedInstanceState);
|
||||||
if(isVisibleToUser && activity != null && activity.getSupportActionBar() != null) {
|
localPlaylistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(getContext()));
|
||||||
activity.getSupportActionBar().setTitle(R.string.tab_bookmarks);
|
disposables = new CompositeDisposable();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAttach(Context context) {
|
|
||||||
super.onAttach(context);
|
|
||||||
itemListAdapter = new LocalItemListAdapter(activity);
|
|
||||||
localPlaylistManager = new LocalPlaylistManager(NewPipeDatabase.getInstance(context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -74,62 +58,37 @@ public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEnt
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||||
@Nullable ViewGroup container,
|
@Nullable ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
if (activity.getSupportActionBar() != null) {
|
if (activity != null && activity.getSupportActionBar() != null) {
|
||||||
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
|
activity.getSupportActionBar().setDisplayShowTitleEnabled(true);
|
||||||
|
activity.setTitle(R.string.tab_subscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.setTitle(R.string.tab_bookmarks);
|
|
||||||
if(useAsFrontPage) {
|
|
||||||
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
|
||||||
}
|
|
||||||
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
return inflater.inflate(R.layout.fragment_bookmarks, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||||
if (disposables != null) disposables.clear();
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
if (isVisibleToUser) setTitle(getString(R.string.tab_bookmarks));
|
||||||
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
if (disposables != null) disposables.dispose();
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
|
|
||||||
disposables = null;
|
|
||||||
databaseSubscription = null;
|
|
||||||
localPlaylistManager = null;
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment Views
|
// Fragment LifeCycle - Views
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
itemsList = rootView.findViewById(R.id.items_list);
|
@Override
|
||||||
itemsList.setLayoutManager(new LinearLayoutManager(activity));
|
protected View getListHeader() {
|
||||||
|
|
||||||
final View headerRootLayout = activity.getLayoutInflater()
|
final View headerRootLayout = activity.getLayoutInflater()
|
||||||
.inflate(R.layout.bookmark_header, itemsList, false);
|
.inflate(R.layout.bookmark_header, itemsList, false);
|
||||||
watchHistoryButton = headerRootLayout.findViewById(R.id.watchHistory);
|
watchHistoryButton = headerRootLayout.findViewById(R.id.watchHistory);
|
||||||
mostWatchedButton = headerRootLayout.findViewById(R.id.mostWatched);
|
mostWatchedButton = headerRootLayout.findViewById(R.id.mostWatched);
|
||||||
|
return headerRootLayout;
|
||||||
itemListAdapter.setHeader(headerRootLayout);
|
|
||||||
|
|
||||||
itemsList.setAdapter(itemListAdapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -168,41 +127,51 @@ public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEnt
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDeleteDialog(final PlaylistMetadataEntry item) {
|
|
||||||
new AlertDialog.Builder(activity)
|
|
||||||
.setTitle(item.name)
|
|
||||||
.setMessage(R.string.delete_playlist_prompt)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setPositiveButton(R.string.delete, (dialog, i) -> {
|
|
||||||
final Toast deleteSuccessful = Toast.makeText(getContext(),
|
|
||||||
R.string.playlist_delete_success, Toast.LENGTH_SHORT);
|
|
||||||
disposables.add(localPlaylistManager.deletePlaylist(item.uid)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(ignored -> deleteSuccessful.show()));
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetFragment() {
|
|
||||||
if (disposables != null) disposables.clear();
|
|
||||||
if (itemListAdapter != null) itemListAdapter.clearStreamItemList();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Subscriptions Loader
|
// Fragment LifeCycle - Loading
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startLoading(boolean forceLoad) {
|
public void startLoading(boolean forceLoad) {
|
||||||
super.startLoading(forceLoad);
|
super.startLoading(forceLoad);
|
||||||
resetFragment();
|
|
||||||
|
|
||||||
localPlaylistManager.getPlaylists()
|
localPlaylistManager.getPlaylists()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(getSubscriptionSubscriber());
|
.subscribe(getSubscriptionSubscriber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Destruction
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
if (disposables != null) disposables.clear();
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
|
||||||
|
databaseSubscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
if (disposables != null) disposables.dispose();
|
||||||
|
|
||||||
|
disposables = null;
|
||||||
|
localPlaylistManager = null;
|
||||||
|
itemsListState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Subscriptions Loader
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Subscriber<List<PlaylistMetadataEntry>> getSubscriptionSubscriber() {
|
private Subscriber<List<PlaylistMetadataEntry>> getSubscriptionSubscriber() {
|
||||||
return new Subscriber<List<PlaylistMetadataEntry>>() {
|
return new Subscriber<List<PlaylistMetadataEntry>>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -238,55 +207,58 @@ public class BookmarkFragment extends BaseStateFragment<List<PlaylistMetadataEnt
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
showEmptyState();
|
showEmptyState();
|
||||||
} else {
|
return;
|
||||||
itemListAdapter.addItems(infoItemsOf(result));
|
|
||||||
if (itemsListState != null) {
|
|
||||||
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
|
||||||
itemsListState = null;
|
|
||||||
}
|
|
||||||
hideLoading();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemListAdapter.addItems(result);
|
||||||
|
if (itemsListState != null) {
|
||||||
|
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
||||||
|
itemsListState = null;
|
||||||
|
}
|
||||||
|
hideLoading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private List<PlaylistMetadataEntry> infoItemsOf(List<PlaylistMetadataEntry> playlists) {
|
|
||||||
Collections.sort(playlists, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));
|
|
||||||
return playlists;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Contract
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showLoading() {
|
|
||||||
super.showLoading();
|
|
||||||
animateView(itemsList, false, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hideLoading() {
|
|
||||||
super.hideLoading();
|
|
||||||
animateView(itemsList, true, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showEmptyState() {
|
|
||||||
super.showEmptyState();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment Error Handling
|
// Fragment Error Handling
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onError(Throwable exception) {
|
protected boolean onError(Throwable exception) {
|
||||||
resetFragment();
|
|
||||||
if (super.onError(exception)) return true;
|
if (super.onError(exception)) return true;
|
||||||
|
|
||||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
||||||
"none", "Bookmark", R.string.general_error);
|
"none", "Bookmark", R.string.general_error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void resetFragment() {
|
||||||
|
super.resetFragment();
|
||||||
|
if (disposables != null) disposables.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void showDeleteDialog(final PlaylistMetadataEntry item) {
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle(item.name)
|
||||||
|
.setMessage(R.string.delete_playlist_prompt)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setPositiveButton(R.string.delete, (dialog, i) ->
|
||||||
|
disposables.add(deletePlaylist(item.uid))
|
||||||
|
)
|
||||||
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Disposable deletePlaylist(final long playlistId) {
|
||||||
|
return localPlaylistManager.deletePlaylist(playlistId)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(ignored -> {/*Do nothing on success*/},
|
||||||
|
throwable -> Log.e(TAG, "Playlist deletion failed, id=["
|
||||||
|
+ playlistId + "]")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MostPlayedFragment extends StatisticsPlaylistFragment {
|
public final class MostPlayedFragment extends StatisticsPlaylistFragment {
|
||||||
@Override
|
@Override
|
||||||
protected String getName() {
|
protected String getName() {
|
||||||
return getString(R.string.title_most_played);
|
return getString(R.string.title_most_played);
|
||||||
|
|
|
@ -32,13 +32,9 @@ import java.util.List;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|
||||||
|
|
||||||
public abstract class StatisticsPlaylistFragment
|
public abstract class StatisticsPlaylistFragment
|
||||||
extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> {
|
extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> {
|
||||||
|
|
||||||
private View headerRootLayout;
|
|
||||||
private View playlistControl;
|
|
||||||
private View headerPlayAllButton;
|
private View headerPlayAllButton;
|
||||||
private View headerPopupButton;
|
private View headerPopupButton;
|
||||||
private View headerBackgroundButton;
|
private View headerBackgroundButton;
|
||||||
|
@ -59,13 +55,13 @@ public abstract class StatisticsPlaylistFragment
|
||||||
protected abstract List<StreamStatisticsEntry> processResult(final List<StreamStatisticsEntry> results);
|
protected abstract List<StreamStatisticsEntry> processResult(final List<StreamStatisticsEntry> results);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment LifeCycle
|
// Fragment LifeCycle - Creation
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onAttach(context);
|
super.onCreate(savedInstanceState);
|
||||||
recordManager = new HistoryRecordManager(context);
|
recordManager = new HistoryRecordManager(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,46 +71,23 @@ public abstract class StatisticsPlaylistFragment
|
||||||
return inflater.inflate(R.layout.fragment_playlist, container, false);
|
return inflater.inflate(R.layout.fragment_playlist, container, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
super.onDestroyView();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
databaseSubscription = null;
|
|
||||||
recordManager = null;
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Fragment Views
|
// Fragment LifeCycle - Views
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(View rootView, Bundle savedInstanceState) {
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
setFragmentTitle(getName());
|
setTitle(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected View getListHeader() {
|
protected View getListHeader() {
|
||||||
headerRootLayout = activity.getLayoutInflater().inflate(R.layout.playlist_control,
|
final View headerRootLayout = activity.getLayoutInflater().inflate(R.layout.playlist_control,
|
||||||
itemsList, false);
|
itemsList, false);
|
||||||
playlistControl = headerRootLayout.findViewById(R.id.playlist_control);
|
|
||||||
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
|
headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button);
|
||||||
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
|
headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button);
|
||||||
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
|
headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button);
|
||||||
|
|
||||||
return headerRootLayout;
|
return headerRootLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,9 +112,124 @@ public abstract class StatisticsPlaylistFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Loading
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startLoading(boolean forceLoad) {
|
||||||
|
super.startLoading(forceLoad);
|
||||||
|
recordManager.getStreamStatistics()
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(getHistoryObserver());
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment LifeCycle - Destruction
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
itemsListState = itemsList.getLayoutManager().onSaveInstanceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroyView() {
|
||||||
|
super.onDestroyView();
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
databaseSubscription = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
recordManager = null;
|
||||||
|
itemsListState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Statistics Loader
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private Subscriber<List<StreamStatisticsEntry>> getHistoryObserver() {
|
||||||
|
return new Subscriber<List<StreamStatisticsEntry>>() {
|
||||||
|
@Override
|
||||||
|
public void onSubscribe(Subscription s) {
|
||||||
|
showLoading();
|
||||||
|
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
databaseSubscription = s;
|
||||||
|
databaseSubscription.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(List<StreamStatisticsEntry> streams) {
|
||||||
|
handleResult(streams);
|
||||||
|
if (databaseSubscription != null) databaseSubscription.request(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable exception) {
|
||||||
|
StatisticsPlaylistFragment.this.onError(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onComplete() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleResult(@NonNull List<StreamStatisticsEntry> result) {
|
||||||
|
super.handleResult(result);
|
||||||
|
itemListAdapter.clearStreamItemList();
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
showEmptyState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemListAdapter.addItems(processResult(result));
|
||||||
|
if (itemsListState != null) {
|
||||||
|
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
||||||
|
itemsListState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerPlayAllButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
||||||
|
headerPopupButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
||||||
|
headerBackgroundButton.setOnClickListener(view ->
|
||||||
|
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
||||||
|
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment Error Handling
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void resetFragment() {
|
||||||
|
super.resetFragment();
|
||||||
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onError(Throwable exception) {
|
||||||
|
if (super.onError(exception)) return true;
|
||||||
|
|
||||||
|
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
||||||
|
"none", "History Statistics", R.string.general_error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void showStreamDialog(final StreamStatisticsEntry item) {
|
private void showStreamDialog(final StreamStatisticsEntry item) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
|
@ -182,113 +270,6 @@ public abstract class StatisticsPlaylistFragment
|
||||||
new InfoItemDialog(getActivity(), infoItem, commands, actions).show();
|
new InfoItemDialog(getActivity(), infoItem, commands, actions).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetFragment() {
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
if (itemListAdapter != null) itemListAdapter.clearStreamItemList();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Loader
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showLoading() {
|
|
||||||
super.showLoading();
|
|
||||||
animateView(headerRootLayout, false, 200);
|
|
||||||
animateView(itemsList, false, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startLoading(boolean forceLoad) {
|
|
||||||
super.startLoading(forceLoad);
|
|
||||||
resetFragment();
|
|
||||||
|
|
||||||
recordManager.getStreamStatistics()
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(getHistoryObserver());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Subscriber<List<StreamStatisticsEntry>> getHistoryObserver() {
|
|
||||||
return new Subscriber<List<StreamStatisticsEntry>>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
showLoading();
|
|
||||||
|
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
||||||
databaseSubscription = s;
|
|
||||||
databaseSubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(List<StreamStatisticsEntry> streams) {
|
|
||||||
handleResult(streams);
|
|
||||||
if (databaseSubscription != null) databaseSubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable exception) {
|
|
||||||
StatisticsPlaylistFragment.this.onError(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onComplete() {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleResult(@NonNull List<StreamStatisticsEntry> result) {
|
|
||||||
super.handleResult(result);
|
|
||||||
itemListAdapter.clearStreamItemList();
|
|
||||||
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
showEmptyState();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
animateView(headerRootLayout, true, 100);
|
|
||||||
animateView(itemsList, true, 300);
|
|
||||||
|
|
||||||
itemListAdapter.addItems(processResult(result));
|
|
||||||
if (itemsListState != null) {
|
|
||||||
itemsList.getLayoutManager().onRestoreInstanceState(itemsListState);
|
|
||||||
itemsListState = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
playlistControl.setVisibility(View.VISIBLE);
|
|
||||||
headerPlayAllButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnMainPlayer(activity, getPlayQueue()));
|
|
||||||
headerPopupButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnPopupPlayer(activity, getPlayQueue()));
|
|
||||||
headerBackgroundButton.setOnClickListener(view ->
|
|
||||||
NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue()));
|
|
||||||
hideLoading();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment Error Handling
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean onError(Throwable exception) {
|
|
||||||
resetFragment();
|
|
||||||
if (super.onError(exception)) return true;
|
|
||||||
|
|
||||||
onUnrecoverableError(exception, UserAction.SOMETHING_ELSE,
|
|
||||||
"none", "History Statistics", R.string.general_error);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
protected void setFragmentTitle(final String title) {
|
|
||||||
if (activity.getSupportActionBar() != null) {
|
|
||||||
activity.getSupportActionBar().setTitle(title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayQueue getPlayQueue() {
|
private PlayQueue getPlayQueue() {
|
||||||
return getPlayQueue(0);
|
return getPlayQueue(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WatchHistoryFragment extends StatisticsPlaylistFragment {
|
public final class WatchHistoryFragment extends StatisticsPlaylistFragment {
|
||||||
@Override
|
@Override
|
||||||
protected String getName() {
|
protected String getName() {
|
||||||
return getString(R.string.title_watch_history);
|
return getString(R.string.title_watch_history);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.support.design.widget.Snackbar;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -173,10 +174,19 @@ public abstract class HistoryFragment<E> extends BaseFragment
|
||||||
|
|
||||||
final Disposable deletion = delete(itemsToDelete)
|
final Disposable deletion = delete(itemsToDelete)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe();
|
.subscribe(
|
||||||
|
ignored -> Log.d(TAG, "Clear history deleted [" +
|
||||||
|
itemsToDelete.size() + "] items."),
|
||||||
|
error -> Log.e(TAG, "Clear history delete step failed", error)
|
||||||
|
);
|
||||||
|
|
||||||
final Disposable cleanUp = historyRecordManager.removeOrphanedRecords()
|
final Disposable cleanUp = historyRecordManager.removeOrphanedRecords()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe();
|
.subscribe(
|
||||||
|
ignored -> Log.d(TAG, "Clear history deleted orphaned stream records"),
|
||||||
|
error -> Log.e(TAG, "Clear history remove orphaned records failed", error)
|
||||||
|
);
|
||||||
|
|
||||||
disposables.addAll(deletion, cleanUp);
|
disposables.addAll(deletion, cleanUp);
|
||||||
|
|
||||||
makeSnackbar(R.string.history_cleared);
|
makeSnackbar(R.string.history_cleared);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -83,17 +84,25 @@ public class SearchHistoryFragment extends HistoryFragment<SearchHistoryEntry> {
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setNeutralButton(R.string.cancel, null)
|
.setNeutralButton(R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
||||||
final Single<Integer> onDelete = historyRecordManager
|
final Disposable onDelete = historyRecordManager
|
||||||
.deleteSearches(Collections.singleton(item))
|
.deleteSearches(Collections.singleton(item))
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
disposables.add(onDelete.subscribe());
|
.subscribe(
|
||||||
|
ignored -> {/*successful*/},
|
||||||
|
error -> Log.e(TAG, "Search history Delete One failed:", error)
|
||||||
|
);
|
||||||
|
disposables.add(onDelete);
|
||||||
makeSnackbar(R.string.item_deleted);
|
makeSnackbar(R.string.item_deleted);
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
||||||
final Single<Integer> onDeleteAll = historyRecordManager
|
final Disposable onDeleteAll = historyRecordManager
|
||||||
.deleteSearchHistory(item.getSearch())
|
.deleteSearchHistory(item.getSearch())
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
disposables.add(onDeleteAll.subscribe());
|
.subscribe(
|
||||||
|
ignored -> {/*successful*/},
|
||||||
|
error -> Log.e(TAG, "Search history Delete All failed:", error)
|
||||||
|
);
|
||||||
|
disposables.add(onDeleteAll);
|
||||||
makeSnackbar(R.string.item_deleted);
|
makeSnackbar(R.string.item_deleted);
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
|
@ -112,8 +121,7 @@ public class SearchHistoryFragment extends HistoryFragment<SearchHistoryEntry> {
|
||||||
|
|
||||||
protected class SearchHistoryAdapter extends HistoryEntryAdapter<SearchHistoryEntry, ViewHolder> {
|
protected class SearchHistoryAdapter extends HistoryEntryAdapter<SearchHistoryEntry, ViewHolder> {
|
||||||
|
|
||||||
|
SearchHistoryAdapter(Context context) {
|
||||||
public SearchHistoryAdapter(Context context) {
|
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -29,6 +30,7 @@ import java.util.List;
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.Single;
|
import io.reactivex.Single;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
|
||||||
|
|
||||||
public class WatchedHistoryFragment extends HistoryFragment<StreamHistoryEntry> {
|
public class WatchedHistoryFragment extends HistoryFragment<StreamHistoryEntry> {
|
||||||
|
@ -85,17 +87,25 @@ public class WatchedHistoryFragment extends HistoryFragment<StreamHistoryEntry>
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setNeutralButton(R.string.cancel, null)
|
.setNeutralButton(R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
||||||
final Single<Integer> onDelete = historyRecordManager
|
final Disposable onDelete = historyRecordManager
|
||||||
.deleteStreamHistory(Collections.singleton(item))
|
.deleteStreamHistory(Collections.singleton(item))
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
disposables.add(onDelete.subscribe());
|
.subscribe(
|
||||||
|
ignored -> {/*successful*/},
|
||||||
|
error -> Log.e(TAG, "Watch history Delete One failed:", error)
|
||||||
|
);
|
||||||
|
disposables.add(onDelete);
|
||||||
makeSnackbar(R.string.item_deleted);
|
makeSnackbar(R.string.item_deleted);
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
||||||
final Single<Integer> onDeleteAll = historyRecordManager
|
final Disposable onDeleteAll = historyRecordManager
|
||||||
.deleteStreamHistory(item.streamId)
|
.deleteStreamHistory(item.streamId)
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
disposables.add(onDeleteAll.subscribe());
|
.subscribe(
|
||||||
|
ignored -> {/*successful*/},
|
||||||
|
error -> Log.e(TAG, "Watch history Delete All failed:", error)
|
||||||
|
);
|
||||||
|
disposables.add(onDeleteAll);
|
||||||
makeSnackbar(R.string.item_deleted);
|
makeSnackbar(R.string.item_deleted);
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
|
|
|
@ -676,7 +676,11 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: update exoplayer to 2.6.x in order to register view count on repeated streams
|
// TODO: update exoplayer to 2.6.x in order to register view count on repeated streams
|
||||||
databaseUpdateReactor.add(recordManager.onViewed(currentInfo).subscribe());
|
databaseUpdateReactor.add(recordManager.onViewed(currentInfo).onErrorComplete()
|
||||||
|
.subscribe(
|
||||||
|
ignored -> {/* successful */},
|
||||||
|
error -> Log.e(TAG, "Player onViewed() failure: ", error)
|
||||||
|
));
|
||||||
initThumbnail(info == null ? item.getThumbnailUrl() : info.thumbnail_url);
|
initThumbnail(info == null ? item.getThumbnailUrl() : info.thumbnail_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +848,10 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen
|
||||||
final Disposable stateSaver = recordManager.saveStreamState(info, progress)
|
final Disposable stateSaver = recordManager.saveStreamState(info, progress)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.onErrorComplete()
|
.onErrorComplete()
|
||||||
.subscribe();
|
.subscribe(
|
||||||
|
ignored -> {/* successful */},
|
||||||
|
error -> Log.e(TAG, "savePlaybackState() failure: ", error)
|
||||||
|
);
|
||||||
databaseUpdateReactor.add(stateSaver);
|
databaseUpdateReactor.add(stateSaver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,12 @@
|
||||||
android:id="@+id/playlist_title_view"
|
android:id="@+id/playlist_title_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:paddingTop="6dp"
|
||||||
android:layout_marginRight="8dp"
|
android:paddingBottom="6dp"
|
||||||
android:layout_marginTop="6dp"
|
android:paddingLeft="12dp"
|
||||||
|
android:paddingRight="12dp"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
android:layout_toLeftOf="@id/playlist_stream_count"
|
android:layout_toLeftOf="@id/playlist_stream_count"
|
||||||
android:layout_toStartOf="@id/playlist_stream_count"
|
android:layout_toStartOf="@id/playlist_stream_count"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
|
@ -26,7 +29,7 @@
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
android:textSize="@dimen/playlist_detail_title_text_size"
|
android:textSize="@dimen/playlist_detail_title_text_size"
|
||||||
tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur..." />
|
tools:text="Mix musics #23 title Lorem ipsum dolor sit amet, consectetur..."/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/playlist_stream_count"
|
android:id="@+id/playlist_stream_count"
|
||||||
|
@ -34,7 +37,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignBottom="@id/playlist_title_view"
|
android:layout_alignBottom="@id/playlist_title_view"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_marginRight="6dp"
|
android:padding="6dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:gravity="right|center_vertical"
|
android:gravity="right|center_vertical"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
|
|
|
@ -119,14 +119,12 @@
|
||||||
<string name="subscription_page_key" translatable="false">subscription_page_key</string>
|
<string name="subscription_page_key" translatable="false">subscription_page_key</string>
|
||||||
<string name="kiosk_page_key" translatable="false">kiosk_page</string>
|
<string name="kiosk_page_key" translatable="false">kiosk_page</string>
|
||||||
<string name="channel_page_key" translatable="false">channel_page</string>
|
<string name="channel_page_key" translatable="false">channel_page</string>
|
||||||
<string name="bookmark_page_key" translatable="false">bookmark_page</string>
|
|
||||||
<string-array name="main_page_content_pages" translatable="false">
|
<string-array name="main_page_content_pages" translatable="false">
|
||||||
<item>@string/blank_page_key</item>
|
<item>@string/blank_page_key</item>
|
||||||
<item>@string/kiosk_page_key</item>
|
<item>@string/kiosk_page_key</item>
|
||||||
<item>@string/feed_page_key</item>
|
<item>@string/feed_page_key</item>
|
||||||
<item>@string/subscription_page_key</item>
|
<item>@string/subscription_page_key</item>
|
||||||
<item>@string/channel_page_key</item>
|
<item>@string/channel_page_key</item>
|
||||||
<item>@string/bookmark_page_key</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
<string name="main_page_selected_service" translatable="false">main_page_selected_service</string>
|
<string name="main_page_selected_service" translatable="false">main_page_selected_service</string>
|
||||||
<string name="main_page_selected_channel_name" translatable="false">main_page_selected_channel_name</string>
|
<string name="main_page_selected_channel_name" translatable="false">main_page_selected_channel_name</string>
|
||||||
|
|
|
@ -390,6 +390,5 @@
|
||||||
<string name="playlist_creation_success">Playlist successfully created</string>
|
<string name="playlist_creation_success">Playlist successfully created</string>
|
||||||
<string name="playlist_add_stream_success">Added to playlist</string>
|
<string name="playlist_add_stream_success">Added to playlist</string>
|
||||||
<string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string>
|
<string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string>
|
||||||
<string name="playlist_rename_success">Playlist renamed</string>
|
<string name="playlist_delete_failure">Failed to delete playlist</string>
|
||||||
<string name="playlist_delete_success">Playlist deleted</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue