mirror of https://github.com/TeamNewPipe/NewPipe
312 lines
11 KiB
Java
312 lines
11 KiB
Java
package org.schabi.newpipe.history;
|
|
|
|
|
|
import android.content.SharedPreferences;
|
|
import android.graphics.Color;
|
|
import android.os.Bundle;
|
|
import android.os.Parcelable;
|
|
import android.preference.PreferenceManager;
|
|
import android.support.annotation.CallSuper;
|
|
import android.support.annotation.MainThread;
|
|
import android.support.annotation.NonNull;
|
|
import android.support.annotation.Nullable;
|
|
import android.support.annotation.StringRes;
|
|
import android.support.design.widget.Snackbar;
|
|
import android.support.v7.widget.LinearLayoutManager;
|
|
import android.support.v7.widget.RecyclerView;
|
|
import android.support.v7.widget.helper.ItemTouchHelper;
|
|
import android.view.LayoutInflater;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
|
|
import org.schabi.newpipe.BaseFragment;
|
|
import org.schabi.newpipe.R;
|
|
import org.schabi.newpipe.database.history.dao.HistoryDAO;
|
|
import org.schabi.newpipe.database.history.model.HistoryEntry;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
import icepick.State;
|
|
import io.reactivex.Observer;
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
import io.reactivex.disposables.Disposable;
|
|
import io.reactivex.functions.Consumer;
|
|
import io.reactivex.schedulers.Schedulers;
|
|
import io.reactivex.subjects.PublishSubject;
|
|
|
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|
|
|
public abstract class HistoryFragment<E extends HistoryEntry> extends BaseFragment
|
|
implements HistoryEntryAdapter.OnHistoryItemClickListener<E> {
|
|
|
|
private SharedPreferences mSharedPreferences;
|
|
private String mHistoryIsEnabledKey;
|
|
private boolean mHistoryIsEnabled;
|
|
private HistoryIsEnabledChangeListener mHistoryIsEnabledChangeListener;
|
|
|
|
private View mDisabledView;
|
|
private View mEmptyHistoryView;
|
|
|
|
@State
|
|
Parcelable mRecyclerViewState;
|
|
private RecyclerView mRecyclerView;
|
|
private HistoryEntryAdapter<E, ? extends RecyclerView.ViewHolder> mHistoryAdapter;
|
|
private ItemTouchHelper.SimpleCallback mHistoryItemSwipeCallback;
|
|
private int allowedSwipeToDeleteDirections = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
|
|
|
private HistoryDAO<E> mHistoryDataSource;
|
|
private PublishSubject<Collection<E>> mHistoryEntryDeleteSubject;
|
|
private PublishSubject<Collection<E>> mHistoryEntryInsertSubject;
|
|
|
|
@StringRes
|
|
abstract int getEnabledConfigKey();
|
|
|
|
@CallSuper
|
|
@Override
|
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
|
|
mHistoryIsEnabledKey = getString(getEnabledConfigKey());
|
|
|
|
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
|
// Read history enabled from preferences
|
|
mHistoryIsEnabled = isHistoryEnabled();
|
|
// Register history enabled listener
|
|
mSharedPreferences.registerOnSharedPreferenceChangeListener(mHistoryIsEnabledChangeListener);
|
|
|
|
mHistoryDataSource = createHistoryDAO();
|
|
|
|
mHistoryEntryDeleteSubject = PublishSubject.create();
|
|
mHistoryEntryDeleteSubject
|
|
.observeOn(Schedulers.io())
|
|
.subscribe(new Consumer<Collection<E>>() {
|
|
@Override
|
|
public void accept(Collection<E> historyEntries) throws Exception {
|
|
mHistoryDataSource.delete(historyEntries);
|
|
}
|
|
});
|
|
|
|
mHistoryEntryInsertSubject = PublishSubject.create();
|
|
mHistoryEntryInsertSubject
|
|
.observeOn(Schedulers.io())
|
|
.subscribe(new Consumer<Collection<E>>() {
|
|
@Override
|
|
public void accept(Collection<E> historyEntries) throws Exception {
|
|
mHistoryDataSource.insertAll(historyEntries);
|
|
}
|
|
});
|
|
|
|
mHistoryItemSwipeCallback = new ItemTouchHelper.SimpleCallback(0, allowedSwipeToDeleteDirections) {
|
|
@Override
|
|
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
|
|
if (mHistoryAdapter != null) {
|
|
final E historyEntry = mHistoryAdapter.removeItemAt(viewHolder.getAdapterPosition());
|
|
mHistoryEntryDeleteSubject.onNext(Collections.singletonList(historyEntry));
|
|
|
|
View view = getActivity().findViewById(R.id.main_content);
|
|
if (view == null) view = mRecyclerView.getRootView();
|
|
|
|
Snackbar.make(view, R.string.item_deleted, 5 * 1000)
|
|
.setActionTextColor(Color.WHITE)
|
|
.setAction(R.string.undo, new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
mHistoryEntryInsertSubject.onNext(Collections.singletonList(historyEntry));
|
|
}
|
|
}).show();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
@NonNull
|
|
protected abstract HistoryEntryAdapter<E, ? extends RecyclerView.ViewHolder> createAdapter();
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
mHistoryDataSource.getAll()
|
|
.toObservable()
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(getHistoryListConsumer());
|
|
boolean newEnabled = isHistoryEnabled();
|
|
if (newEnabled != mHistoryIsEnabled) {
|
|
onHistoryIsEnabledChanged(newEnabled);
|
|
}
|
|
}
|
|
|
|
@NonNull
|
|
private Observer<List<E>> getHistoryListConsumer() {
|
|
return new Observer<List<E>>() {
|
|
@Override
|
|
public void onSubscribe(@NonNull Disposable d) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void onNext(@NonNull List<E> historyEntries) {
|
|
if (!historyEntries.isEmpty()) {
|
|
mHistoryAdapter.setEntries(historyEntries);
|
|
animateView(mEmptyHistoryView, false, 200);
|
|
|
|
if (mRecyclerViewState != null) {
|
|
mRecyclerView.getLayoutManager().onRestoreInstanceState(mRecyclerViewState);
|
|
mRecyclerViewState = null;
|
|
}
|
|
} else {
|
|
mHistoryAdapter.clear();
|
|
showEmptyHistory();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onError(@NonNull Throwable e) {
|
|
// TODO: error handling like in (see e.g. subscription fragment)
|
|
}
|
|
|
|
@Override
|
|
public void onComplete() {
|
|
|
|
}
|
|
};
|
|
}
|
|
|
|
private boolean isHistoryEnabled() {
|
|
return mSharedPreferences.getBoolean(mHistoryIsEnabledKey, false);
|
|
}
|
|
|
|
/**
|
|
* Called when the history is cleared to update the views
|
|
*/
|
|
@MainThread
|
|
public void onHistoryCleared() {
|
|
final Parcelable stateBeforeClear = mRecyclerView.getLayoutManager().onSaveInstanceState();
|
|
final Collection<E> itemsToDelete = new ArrayList<>(mHistoryAdapter.getItems());
|
|
mHistoryEntryDeleteSubject.onNext(itemsToDelete);
|
|
|
|
View view = getActivity().findViewById(R.id.main_content);
|
|
if (view == null) view = mRecyclerView.getRootView();
|
|
|
|
if (!itemsToDelete.isEmpty()) {
|
|
Snackbar.make(view, R.string.history_cleared, 5 * 1000)
|
|
.setActionTextColor(Color.WHITE)
|
|
.setAction(R.string.undo, new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
mRecyclerViewState = stateBeforeClear;
|
|
mHistoryEntryInsertSubject.onNext(itemsToDelete);
|
|
}
|
|
}).show();
|
|
} else {
|
|
Snackbar.make(view, R.string.history_cleared, Snackbar.LENGTH_LONG).show();
|
|
}
|
|
|
|
mHistoryAdapter.clear();
|
|
showEmptyHistory();
|
|
|
|
}
|
|
|
|
private void showEmptyHistory() {
|
|
if (mHistoryIsEnabled) {
|
|
animateView(mEmptyHistoryView, true, 200);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@CallSuper
|
|
@Override
|
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
|
View rootView = inflater.inflate(R.layout.fragment_history, container, false);
|
|
mRecyclerView = rootView.findViewById(R.id.history_view);
|
|
|
|
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
|
|
mRecyclerView.setLayoutManager(layoutManager);
|
|
|
|
mHistoryAdapter = createAdapter();
|
|
mHistoryAdapter.setOnHistoryItemClickListener(this);
|
|
mRecyclerView.setAdapter(mHistoryAdapter);
|
|
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mHistoryItemSwipeCallback);
|
|
itemTouchHelper.attachToRecyclerView(mRecyclerView);
|
|
mDisabledView = rootView.findViewById(R.id.history_disabled_view);
|
|
mEmptyHistoryView = rootView.findViewById(R.id.history_empty);
|
|
|
|
if (mHistoryIsEnabled) {
|
|
mRecyclerView.setVisibility(View.VISIBLE);
|
|
} else {
|
|
mDisabledView.setVisibility(View.VISIBLE);
|
|
}
|
|
|
|
return rootView;
|
|
}
|
|
|
|
@CallSuper
|
|
@Override
|
|
public void onDestroy() {
|
|
super.onDestroy();
|
|
mSharedPreferences.unregisterOnSharedPreferenceChangeListener(mHistoryIsEnabledChangeListener);
|
|
mSharedPreferences = null;
|
|
mHistoryIsEnabledChangeListener = null;
|
|
mHistoryIsEnabledKey = null;
|
|
mHistoryDataSource = null;
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
mRecyclerViewState = mRecyclerView.getLayoutManager().onSaveInstanceState();
|
|
}
|
|
|
|
public void setAllowedSwipeToDeleteDirections(int allowedSwipeToDeleteDirections) {
|
|
this.allowedSwipeToDeleteDirections = allowedSwipeToDeleteDirections;
|
|
}
|
|
|
|
/**
|
|
* Called when history enabled flag is changed.
|
|
*
|
|
* @param historyIsEnabled the new value
|
|
*/
|
|
@CallSuper
|
|
public void onHistoryIsEnabledChanged(boolean historyIsEnabled) {
|
|
mHistoryIsEnabled = historyIsEnabled;
|
|
if (historyIsEnabled) {
|
|
animateView(mRecyclerView, true, 300);
|
|
animateView(mDisabledView, false, 300);
|
|
if (mHistoryAdapter.isEmpty()) {
|
|
animateView(mEmptyHistoryView, true, 300);
|
|
}
|
|
} else {
|
|
animateView(mRecyclerView, false, 300);
|
|
animateView(mDisabledView, true, 300);
|
|
animateView(mEmptyHistoryView, false, 300);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new history DAO
|
|
*
|
|
* @return the history DAO
|
|
*/
|
|
@NonNull
|
|
protected abstract HistoryDAO<E> createHistoryDAO();
|
|
|
|
private class HistoryIsEnabledChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener {
|
|
@Override
|
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
if (key.equals(mHistoryIsEnabledKey)) {
|
|
boolean enabled = sharedPreferences.getBoolean(key, false);
|
|
if (mHistoryIsEnabled != enabled) {
|
|
onHistoryIsEnabledChanged(enabled);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|