Project restructure for history part 1
- add HistoryInfoItem (deriving from StreamInfoItem) in order to add a special options menu for the list items - delete HistoryActivity and everything that belongs to its UI (not the manager tho) - put everything that is local into local. (subscriptions still missing)
This commit is contained in:
parent
cceedab864
commit
004c2fa55a
|
@ -41,7 +41,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
supportLibVersion = '27.1.0'
|
supportLibVersion = '27.1.1'
|
||||||
exoPlayerLibVersion = '2.7.3'
|
exoPlayerLibVersion = '2.7.3'
|
||||||
roomDbLibVersion = '1.0.0'
|
roomDbLibVersion = '1.0.0'
|
||||||
leakCanaryLibVersion = '1.5.4'
|
leakCanaryLibVersion = '1.5.4'
|
||||||
|
|
|
@ -151,7 +151,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
settings.setOnClickListener(view -> NavigationHelper.openSettings(this));
|
settings.setOnClickListener(view -> NavigationHelper.openSettings(this));
|
||||||
downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this));
|
downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this));
|
||||||
history.setOnClickListener(view -> NavigationHelper.openHistory(this));
|
history.setOnClickListener(view ->
|
||||||
|
NavigationHelper.openLastPlayedFragment(getSupportFragmentManager()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDrawerHeader() {
|
private void setupDrawerHeader() {
|
||||||
|
@ -327,17 +328,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
onHomeButtonPressed();
|
onHomeButtonPressed();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_settings:
|
|
||||||
NavigationHelper.openSettings(this);
|
|
||||||
return true;
|
|
||||||
case R.id.action_show_downloads:
|
|
||||||
return NavigationHelper.openDownloads(this);
|
|
||||||
case R.id.action_about:
|
case R.id.action_about:
|
||||||
NavigationHelper.openAbout(this);
|
NavigationHelper.openAbout(this);
|
||||||
return true;
|
|
||||||
case R.id.action_history:
|
|
||||||
NavigationHelper.openHistory(this);
|
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog;
|
import org.schabi.newpipe.fragments.local.dialog.PlaylistAppendDialog;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||||
|
@ -140,9 +141,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||||
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() {
|
infoListAdapter.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() {
|
||||||
@Override
|
@Override
|
||||||
public void selected(StreamInfoItem selectedItem) {
|
public void selected(StreamInfoItem selectedItem) {
|
||||||
onItemSelected(selectedItem);
|
onStreamSelected(selectedItem);
|
||||||
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
|
|
||||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,6 +150,18 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
infoListAdapter.setOnHistoryItemSelectedListener(new OnClickGesture<HistoryInfoItem>() {
|
||||||
|
@Override
|
||||||
|
public void selected(HistoryInfoItem selectedItem) {
|
||||||
|
onStreamSelected(selectedItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void held(HistoryInfoItem selectedItem) {
|
||||||
|
showHistoryItemDialog(selectedItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||||
@Override
|
@Override
|
||||||
public void selected(ChannelInfoItem selectedItem) {
|
public void selected(ChannelInfoItem selectedItem) {
|
||||||
|
@ -178,6 +189,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onStreamSelected(StreamInfoItem selectedItem) {
|
||||||
|
onItemSelected(selectedItem);
|
||||||
|
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
|
||||||
|
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||||
|
}
|
||||||
|
|
||||||
protected void onScrollToBottom() {
|
protected void onScrollToBottom() {
|
||||||
if (hasMoreItems() && !isLoading.get()) {
|
if (hasMoreItems() && !isLoading.get()) {
|
||||||
loadMoreItems();
|
loadMoreItems();
|
||||||
|
@ -216,6 +233,42 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||||
|
|
||||||
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void showHistoryItemDialog(final HistoryInfoItem item) {
|
||||||
|
final Context context = getContext();
|
||||||
|
final Activity activity = getActivity();
|
||||||
|
if (context == null || context.getResources() == null || getActivity() == null) return;
|
||||||
|
|
||||||
|
final String[] commands = new String[]{
|
||||||
|
context.getResources().getString(R.string.enqueue_on_background),
|
||||||
|
context.getResources().getString(R.string.enqueue_on_popup),
|
||||||
|
context.getResources().getString(R.string.append_playlist),
|
||||||
|
context.getResources().getString(R.string.delete)
|
||||||
|
};
|
||||||
|
|
||||||
|
final DialogInterface.OnClickListener actions = (dialogInterface, i) -> {
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
NavigationHelper.enqueueOnBackgroundPlayer(context, new SinglePlayQueue(item));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
NavigationHelper.enqueueOnPopupPlayer(activity, new SinglePlayQueue(item));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (getFragmentManager() != null) {
|
||||||
|
PlaylistAppendDialog.fromStreamInfoItems(Collections.singletonList(item))
|
||||||
|
.show(getFragmentManager(), TAG);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
new InfoItemDialog(getActivity(), item, commands, actions).show();
|
||||||
|
}
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Menu
|
// Menu
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -27,10 +27,9 @@ import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.fragments.local.RemotePlaylistManager;
|
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
|
import org.schabi.newpipe.playlist.PlaylistPlayQueue;
|
||||||
|
|
|
@ -41,7 +41,7 @@ import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||||
import org.schabi.newpipe.fragments.BackPressable;
|
import org.schabi.newpipe.fragments.BackPressable;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||||
import org.schabi.newpipe.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.AnimationUtils;
|
import org.schabi.newpipe.util.AnimationUtils;
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
package org.schabi.newpipe.history;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.design.widget.TabLayout;
|
|
||||||
import android.support.v4.app.Fragment;
|
|
||||||
import android.support.v4.app.FragmentManager;
|
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
|
||||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
|
||||||
import android.support.v4.view.ViewPager;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
|
|
||||||
import com.jakewharton.rxbinding2.view.RxView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
|
|
||||||
public class HistoryActivity extends AppCompatActivity {
|
|
||||||
|
|
||||||
private static final String TAG = "HistoryActivity";
|
|
||||||
/**
|
|
||||||
* The {@link android.support.v4.view.PagerAdapter} that will provide
|
|
||||||
* fragments for each of the sections. We use a
|
|
||||||
* {@link FragmentPagerAdapter} derivative, which will keep every
|
|
||||||
* loaded fragment in memory. If this becomes too memory intensive, it
|
|
||||||
* may be best to switch to a
|
|
||||||
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
|
|
||||||
*/
|
|
||||||
private SectionsPagerAdapter mSectionsPagerAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link ViewPager} that will host the section contents.
|
|
||||||
*/
|
|
||||||
private ViewPager mViewPager;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
ThemeHelper.setTheme(this);
|
|
||||||
setContentView(R.layout.activity_history);
|
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
if (getSupportActionBar() != null) {
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
getSupportActionBar().setTitle(R.string.title_activity_history);
|
|
||||||
}
|
|
||||||
// Create the adapter that will return a fragment for each of the three
|
|
||||||
// primary sections of the activity.
|
|
||||||
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
|
|
||||||
|
|
||||||
// Set up the ViewPager with the sections adapter.
|
|
||||||
mViewPager = findViewById(R.id.container);
|
|
||||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
|
||||||
|
|
||||||
TabLayout tabLayout = findViewById(R.id.tabs);
|
|
||||||
tabLayout.setupWithViewPager(mViewPager);
|
|
||||||
|
|
||||||
final FloatingActionButton fab = findViewById(R.id.fab);
|
|
||||||
RxView.clicks(fab)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(ignored -> {
|
|
||||||
int currentItem = mViewPager.getCurrentItem();
|
|
||||||
HistoryFragment fragment = (HistoryFragment) mSectionsPagerAdapter
|
|
||||||
.instantiateItem(mViewPager, currentItem);
|
|
||||||
fragment.onHistoryCleared();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
|
||||||
getMenuInflater().inflate(R.menu.menu_history, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case android.R.id.home:
|
|
||||||
finish();
|
|
||||||
return true;
|
|
||||||
case R.id.action_settings:
|
|
||||||
Intent intent = new Intent(this, SettingsActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
|
||||||
* one of the sections/tabs/pages.
|
|
||||||
*/
|
|
||||||
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
|
|
||||||
|
|
||||||
public SectionsPagerAdapter(FragmentManager fm) {
|
|
||||||
super(fm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Fragment getItem(int position) {
|
|
||||||
Fragment fragment;
|
|
||||||
switch (position) {
|
|
||||||
case 0:
|
|
||||||
fragment = SearchHistoryFragment.newInstance();
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
fragment = WatchHistoryFragment.newInstance();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("position: " + position);
|
|
||||||
}
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CharSequence getPageTitle(int position) {
|
|
||||||
switch (position) {
|
|
||||||
case 0:
|
|
||||||
return getString(R.string.title_history_search);
|
|
||||||
case 1:
|
|
||||||
return getString(R.string.title_history_view);
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("position: " + position);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCount() {
|
|
||||||
// Show 3 total pages.
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,286 +0,0 @@
|
||||||
package org.schabi.newpipe.history;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
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.app.AlertDialog;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
|
||||||
import org.reactivestreams.Subscription;
|
|
||||||
import org.schabi.newpipe.BaseFragment;
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
import io.reactivex.Flowable;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|
||||||
|
|
||||||
public abstract class HistoryFragment<E> 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 Subscription historySubscription;
|
|
||||||
|
|
||||||
protected HistoryRecordManager historyRecordManager;
|
|
||||||
protected CompositeDisposable disposables;
|
|
||||||
|
|
||||||
@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);
|
|
||||||
|
|
||||||
historyRecordManager = new HistoryRecordManager(getContext());
|
|
||||||
disposables = new CompositeDisposable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected abstract HistoryEntryAdapter<E, ? extends RecyclerView.ViewHolder> createAdapter();
|
|
||||||
|
|
||||||
protected abstract Single<List<Long>> insert(final Collection<E> entries);
|
|
||||||
|
|
||||||
protected abstract Single<Integer> delete(final Collection<E> entries);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected abstract Flowable<List<E>> getAll();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
getAll().observeOn(AndroidSchedulers.mainThread()).subscribe(getHistorySubscriber());
|
|
||||||
|
|
||||||
final boolean newEnabled = isHistoryEnabled();
|
|
||||||
if (newEnabled != mHistoryIsEnabled) {
|
|
||||||
onHistoryIsEnabledChanged(newEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Subscriber<List<E>> getHistorySubscriber() {
|
|
||||||
return new Subscriber<List<E>>() {
|
|
||||||
@Override
|
|
||||||
public void onSubscribe(Subscription s) {
|
|
||||||
if (historySubscription != null) historySubscription.cancel();
|
|
||||||
|
|
||||||
historySubscription = s;
|
|
||||||
historySubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNext(List<E> entries) {
|
|
||||||
if (!entries.isEmpty()) {
|
|
||||||
mHistoryAdapter.setEntries(entries);
|
|
||||||
animateView(mEmptyHistoryView, false, 200);
|
|
||||||
|
|
||||||
if (mRecyclerViewState != null) {
|
|
||||||
mRecyclerView.getLayoutManager().onRestoreInstanceState(mRecyclerViewState);
|
|
||||||
mRecyclerViewState = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mHistoryAdapter.clear();
|
|
||||||
showEmptyHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (historySubscription != null) historySubscription.request(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@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() {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
|
|
||||||
new AlertDialog.Builder(getContext())
|
|
||||||
.setTitle(R.string.delete_all)
|
|
||||||
.setMessage(R.string.delete_all_history_prompt)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setNegativeButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.delete_all, (dialog, i) -> clearHistory())
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void makeSnackbar(@StringRes final int text) {
|
|
||||||
if (getActivity() == null) return;
|
|
||||||
|
|
||||||
View view = getActivity().findViewById(R.id.main_content);
|
|
||||||
if (view == null) view = mRecyclerView.getRootView();
|
|
||||||
Snackbar.make(view, text, Snackbar.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearHistory() {
|
|
||||||
final Collection<E> itemsToDelete = new ArrayList<>(mHistoryAdapter.getItems());
|
|
||||||
|
|
||||||
final Disposable deletion = delete(itemsToDelete)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.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()
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.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);
|
|
||||||
|
|
||||||
makeSnackbar(R.string.history_cleared);
|
|
||||||
mHistoryAdapter.clear();
|
|
||||||
showEmptyHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showEmptyHistory() {
|
|
||||||
if (mHistoryIsEnabled) {
|
|
||||||
animateView(mEmptyHistoryView, true, 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull 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);
|
|
||||||
mDisabledView = rootView.findViewById(R.id.history_disabled_view);
|
|
||||||
mEmptyHistoryView = rootView.findViewById(R.id.history_empty);
|
|
||||||
|
|
||||||
if (mHistoryIsEnabled) {
|
|
||||||
mRecyclerView.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
mRecyclerView.setVisibility(View.GONE);
|
|
||||||
mDisabledView.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
if (disposables != null) disposables.dispose();
|
|
||||||
if (historySubscription != null) historySubscription.cancel();
|
|
||||||
|
|
||||||
mSharedPreferences.unregisterOnSharedPreferenceChangeListener(mHistoryIsEnabledChangeListener);
|
|
||||||
mSharedPreferences = null;
|
|
||||||
mHistoryIsEnabledChangeListener = null;
|
|
||||||
mHistoryIsEnabledKey = null;
|
|
||||||
historySubscription = null;
|
|
||||||
disposables = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
mRecyclerViewState = mRecyclerView.getLayoutManager().onSaveInstanceState();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
package org.schabi.newpipe.history;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.StringRes;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.reactivex.Flowable;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
|
|
||||||
public class SearchHistoryFragment extends HistoryFragment<SearchHistoryEntry> {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static SearchHistoryFragment newInstance() {
|
|
||||||
return new SearchHistoryFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected SearchHistoryAdapter createAdapter() {
|
|
||||||
return new SearchHistoryAdapter(getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Single<List<Long>> insert(Collection<SearchHistoryEntry> entries) {
|
|
||||||
return historyRecordManager.insertSearches(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Single<Integer> delete(Collection<SearchHistoryEntry> entries) {
|
|
||||||
return historyRecordManager.deleteSearches(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected Flowable<List<SearchHistoryEntry>> getAll() {
|
|
||||||
return historyRecordManager.getSearchHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@StringRes
|
|
||||||
@Override
|
|
||||||
int getEnabledConfigKey() {
|
|
||||||
return R.string.enable_search_history_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHistoryItemClick(final SearchHistoryEntry historyItem) {
|
|
||||||
NavigationHelper.openSearch(getContext(), historyItem.getServiceId(),
|
|
||||||
historyItem.getSearch());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHistoryItemLongClick(final SearchHistoryEntry item) {
|
|
||||||
if (activity == null) return;
|
|
||||||
|
|
||||||
new AlertDialog.Builder(activity)
|
|
||||||
.setTitle(item.getSearch())
|
|
||||||
.setMessage(R.string.delete_item_search_history)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setNeutralButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
|
||||||
final Disposable onDelete = historyRecordManager
|
|
||||||
.deleteSearches(Collections.singleton(item))
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
ignored -> {/*successful*/},
|
|
||||||
error -> Log.e(TAG, "Search history Delete One failed:", error)
|
|
||||||
);
|
|
||||||
disposables.add(onDelete);
|
|
||||||
makeSnackbar(R.string.item_deleted);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
|
||||||
final Disposable onDeleteAll = historyRecordManager
|
|
||||||
.deleteSearchHistory(item.getSearch())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
ignored -> {/*successful*/},
|
|
||||||
error -> Log.e(TAG, "Search history Delete All failed:", error)
|
|
||||||
);
|
|
||||||
disposables.add(onDeleteAll);
|
|
||||||
makeSnackbar(R.string.item_deleted);
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private final TextView search;
|
|
||||||
private final TextView info;
|
|
||||||
|
|
||||||
public ViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
search = itemView.findViewById(R.id.search);
|
|
||||||
info = itemView.findViewById(R.id.info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class SearchHistoryAdapter extends HistoryEntryAdapter<SearchHistoryEntry, ViewHolder> {
|
|
||||||
|
|
||||||
SearchHistoryAdapter(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
|
||||||
View rootView = inflater.inflate(R.layout.item_search_history, parent, false);
|
|
||||||
return new ViewHolder(rootView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void onBindViewHolder(ViewHolder holder, SearchHistoryEntry entry, int position) {
|
|
||||||
holder.search.setText(entry.getSearch());
|
|
||||||
|
|
||||||
final String info = Localization.concatenateStrings(
|
|
||||||
getFormattedDate(entry.getCreationDate()),
|
|
||||||
NewPipe.getNameOfService(entry.getServiceId()));
|
|
||||||
holder.info.setText(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
package org.schabi.newpipe.history;
|
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.StringRes;
|
|
||||||
import android.support.v7.app.AlertDialog;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntry;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import io.reactivex.Flowable;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.disposables.Disposable;
|
|
||||||
|
|
||||||
|
|
||||||
public class WatchHistoryFragment extends HistoryFragment<StreamHistoryEntry> {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static WatchHistoryFragment newInstance() {
|
|
||||||
return new WatchHistoryFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
@StringRes
|
|
||||||
@Override
|
|
||||||
int getEnabledConfigKey() {
|
|
||||||
return R.string.enable_watch_history_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected StreamHistoryAdapter createAdapter() {
|
|
||||||
return new StreamHistoryAdapter(getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Single<List<Long>> insert(Collection<StreamHistoryEntry> entries) {
|
|
||||||
return historyRecordManager.insertStreamHistory(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Single<Integer> delete(Collection<StreamHistoryEntry> entries) {
|
|
||||||
return historyRecordManager.deleteStreamHistory(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
protected Flowable<List<StreamHistoryEntry>> getAll() {
|
|
||||||
return historyRecordManager.getStreamHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHistoryItemClick(StreamHistoryEntry historyItem) {
|
|
||||||
NavigationHelper.openVideoDetail(getContext(), historyItem.serviceId, historyItem.url,
|
|
||||||
historyItem.title);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHistoryItemLongClick(StreamHistoryEntry item) {
|
|
||||||
new AlertDialog.Builder(activity)
|
|
||||||
.setTitle(item.title)
|
|
||||||
.setMessage(R.string.delete_stream_history_prompt)
|
|
||||||
.setCancelable(true)
|
|
||||||
.setNeutralButton(R.string.cancel, null)
|
|
||||||
.setPositiveButton(R.string.delete_one, (dialog, i) -> {
|
|
||||||
final Disposable onDelete = historyRecordManager
|
|
||||||
.deleteStreamHistory(Collections.singleton(item))
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
ignored -> {/*successful*/},
|
|
||||||
error -> Log.e(TAG, "Watch history Delete One failed:", error)
|
|
||||||
);
|
|
||||||
disposables.add(onDelete);
|
|
||||||
makeSnackbar(R.string.item_deleted);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.delete_all, (dialog, i) -> {
|
|
||||||
final Disposable onDeleteAll = historyRecordManager
|
|
||||||
.deleteStreamHistory(item.streamId)
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
ignored -> {/*successful*/},
|
|
||||||
error -> Log.e(TAG, "Watch history Delete All failed:", error)
|
|
||||||
);
|
|
||||||
disposables.add(onDeleteAll);
|
|
||||||
makeSnackbar(R.string.item_deleted);
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class StreamHistoryAdapter extends HistoryEntryAdapter<StreamHistoryEntry, ViewHolder> {
|
|
||||||
|
|
||||||
StreamHistoryAdapter(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
|
||||||
View itemView = inflater.inflate(R.layout.list_stream_item, parent, false);
|
|
||||||
return new ViewHolder(itemView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onViewRecycled(ViewHolder holder) {
|
|
||||||
holder.itemView.setOnClickListener(null);
|
|
||||||
ImageLoader.getInstance()
|
|
||||||
.cancelDisplayTask(holder.thumbnailView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void onBindViewHolder(ViewHolder holder, StreamHistoryEntry entry, int position) {
|
|
||||||
final String formattedDate = getFormattedDate(entry.accessDate);
|
|
||||||
final String info;
|
|
||||||
if (entry.repeatCount > 1) {
|
|
||||||
info = Localization.concatenateStrings(formattedDate,
|
|
||||||
getFormattedViewString(entry.repeatCount));
|
|
||||||
} else {
|
|
||||||
info = formattedDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.info.setText(info);
|
|
||||||
holder.streamTitle.setText(entry.title);
|
|
||||||
holder.uploader.setText(entry.uploader);
|
|
||||||
holder.duration.setText(Localization.getDurationString(entry.duration));
|
|
||||||
ImageLoader.getInstance().displayImage(entry.thumbnailUrl, holder.thumbnailView,
|
|
||||||
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private final TextView info;
|
|
||||||
private final TextView streamTitle;
|
|
||||||
private final ImageView thumbnailView;
|
|
||||||
private final TextView uploader;
|
|
||||||
private final TextView duration;
|
|
||||||
|
|
||||||
public ViewHolder(View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
thumbnailView = itemView.findViewById(R.id.itemThumbnailView);
|
|
||||||
info = itemView.findViewById(R.id.itemAdditionalDetails);
|
|
||||||
streamTitle = itemView.findViewById(R.id.itemVideoTitleView);
|
|
||||||
uploader = itemView.findViewById(R.id.itemUploaderView);
|
|
||||||
duration = itemView.findViewById(R.id.itemDurationView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,6 +12,7 @@ import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryInfoItem;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
||||||
|
@ -50,6 +51,7 @@ public class InfoItemBuilder {
|
||||||
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
|
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
|
||||||
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
|
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
|
||||||
private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener;
|
private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener;
|
||||||
|
private OnClickGesture<HistoryInfoItem> onHistoryItemSelectedListener;
|
||||||
|
|
||||||
public InfoItemBuilder(Context context) {
|
public InfoItemBuilder(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
@ -111,4 +113,11 @@ public class InfoItemBuilder {
|
||||||
this.onPlaylistSelectedListener = listener;
|
this.onPlaylistSelectedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OnClickGesture<HistoryInfoItem> getOnHistoryItemSelectedListener() {
|
||||||
|
return onHistoryItemSelectedListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnHistoryItemSelectedListener(OnClickGesture<HistoryInfoItem> onHistoryItemSelectedListener) {
|
||||||
|
this.onHistoryItemSelectedListener = onHistoryItemSelectedListener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryInfoItem;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
||||||
|
@ -89,6 +90,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
||||||
infoItemBuilder.setOnPlaylistSelectedListener(listener);
|
infoItemBuilder.setOnPlaylistSelectedListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOnHistoryItemSelectedListener(OnClickGesture<HistoryInfoItem> listener) {
|
||||||
|
infoItemBuilder.setOnHistoryItemSelectedListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
public void useMiniItemVariants(boolean useMiniVariant) {
|
public void useMiniItemVariants(boolean useMiniVariant) {
|
||||||
this.useMiniVariant = useMiniVariant;
|
this.useMiniVariant = useMiniVariant;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.fragments.local;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
|
@ -19,8 +19,9 @@ import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||||
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
import org.schabi.newpipe.fragments.local.BaseLocalListFragment;
|
||||||
import org.schabi.newpipe.fragments.local.RemotePlaylistManager;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||||
|
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||||
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 org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
@ -38,7 +39,6 @@ import io.reactivex.disposables.CompositeDisposable;
|
||||||
public final class BookmarkFragment
|
public final class BookmarkFragment
|
||||||
extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
|
extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
|
||||||
|
|
||||||
private View lastPlayedButton;
|
|
||||||
private View mostPlayedButton;
|
private View mostPlayedButton;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
|
@ -98,7 +98,6 @@ public final class BookmarkFragment
|
||||||
protected View getListHeader() {
|
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);
|
||||||
lastPlayedButton = headerRootLayout.findViewById(R.id.lastPlayed);
|
|
||||||
mostPlayedButton = headerRootLayout.findViewById(R.id.mostPlayed);
|
mostPlayedButton = headerRootLayout.findViewById(R.id.mostPlayed);
|
||||||
return headerRootLayout;
|
return headerRootLayout;
|
||||||
}
|
}
|
||||||
|
@ -137,12 +136,6 @@ public final class BookmarkFragment
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
lastPlayedButton.setOnClickListener(view -> {
|
|
||||||
if (getParentFragment() != null) {
|
|
||||||
NavigationHelper.openLastPlayedFragment(getParentFragment().getFragmentManager());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mostPlayedButton.setOnClickListener(view -> {
|
mostPlayedButton.setOnClickListener(view -> {
|
||||||
if (getParentFragment() != null) {
|
if (getParentFragment() != null) {
|
||||||
NavigationHelper.openMostPlayedFragment(getParentFragment().getFragmentManager());
|
NavigationHelper.openMostPlayedFragment(getParentFragment().getFragmentManager());
|
||||||
|
@ -181,7 +174,6 @@ public final class BookmarkFragment
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
if (mostPlayedButton != null) mostPlayedButton.setOnClickListener(null);
|
if (mostPlayedButton != null) mostPlayedButton.setOnClickListener(null);
|
||||||
if (lastPlayedButton != null) lastPlayedButton.setOnClickListener(null);
|
|
||||||
|
|
||||||
if (disposables != null) disposables.clear();
|
if (disposables != null) disposables.clear();
|
||||||
if (databaseSubscription != null) databaseSubscription.cancel();
|
if (databaseSubscription != null) databaseSubscription.cancel();
|
|
@ -19,7 +19,7 @@ import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.local.LocalItemListAdapter;
|
import org.schabi.newpipe.fragments.local.LocalItemListAdapter;
|
||||||
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import android.widget.Toast;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.history;
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
|
||||||
|
public class HistoryInfoItem extends StreamInfoItem {
|
||||||
|
public HistoryInfoItem(int serviceId, String url, String name, StreamType streamType) {
|
||||||
|
super(serviceId, url, name, streamType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.history;
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.history;
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
|
@ -1,7 +1,8 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.fragments.local.history;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
|
import org.schabi.newpipe.playlist.StatisticsPlaylistFragment;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,7 +1,8 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.fragments.local.history;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
|
import org.schabi.newpipe.playlist.StatisticsPlaylistFragment;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -26,7 +26,7 @@ import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.local.LocalPlaylistManager;
|
import org.schabi.newpipe.fragments.local.BaseLocalListFragment;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
import org.schabi.newpipe.playlist.PlayQueue;
|
||||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||||
|
@ -173,7 +173,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
@Override
|
@Override
|
||||||
public void held(LocalItem selectedItem) {
|
public void held(LocalItem selectedItem) {
|
||||||
if (selectedItem instanceof PlaylistStreamEntry) {
|
if (selectedItem instanceof PlaylistStreamEntry) {
|
||||||
showStreamDialog((PlaylistStreamEntry) selectedItem);
|
showStreamItemDialog((PlaylistStreamEntry) selectedItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -506,7 +506,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected void showStreamDialog(final PlaylistStreamEntry item) {
|
protected void showStreamItemDialog(final PlaylistStreamEntry item) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
final Activity activity = getActivity();
|
final Activity activity = getActivity();
|
||||||
if (context == null || context.getResources() == null || getActivity() == null) return;
|
if (context == null || context.getResources() == null || getActivity() == null) return;
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.fragments.local;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.fragments.local;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.AppDatabase;
|
import org.schabi.newpipe.database.AppDatabase;
|
||||||
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
|
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
|
||||||
|
@ -13,11 +13,9 @@ import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
public class RemotePlaylistManager {
|
public class RemotePlaylistManager {
|
||||||
|
|
||||||
private final AppDatabase database;
|
|
||||||
private final PlaylistRemoteDAO playlistRemoteTable;
|
private final PlaylistRemoteDAO playlistRemoteTable;
|
||||||
|
|
||||||
public RemotePlaylistManager(final AppDatabase db) {
|
public RemotePlaylistManager(final AppDatabase db) {
|
||||||
database = db;
|
|
||||||
playlistRemoteTable = db.playlistRemoteDAO();
|
playlistRemoteTable = db.playlistRemoteDAO();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ import org.schabi.newpipe.Downloader;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.player.helper.AudioReactor;
|
import org.schabi.newpipe.player.helper.AudioReactor;
|
||||||
import org.schabi.newpipe.player.helper.LoadController;
|
import org.schabi.newpipe.player.helper.LoadController;
|
||||||
import org.schabi.newpipe.player.helper.MediaSessionManager;
|
import org.schabi.newpipe.player.helper.MediaSessionManager;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package org.schabi.newpipe.fragments.local.bookmark;
|
package org.schabi.newpipe.playlist;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -17,10 +17,9 @@ import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
import org.schabi.newpipe.database.stream.StreamStatisticsEntry;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.history.HistoryRecordManager;
|
import org.schabi.newpipe.fragments.local.BaseLocalListFragment;
|
||||||
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||||
import org.schabi.newpipe.playlist.PlayQueue;
|
|
||||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
|
||||||
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 org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
|
@ -37,11 +37,10 @@ import org.schabi.newpipe.fragments.list.feed.FeedFragment;
|
||||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||||
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
|
import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment;
|
||||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||||
import org.schabi.newpipe.fragments.local.bookmark.LastPlayedFragment;
|
import org.schabi.newpipe.fragments.local.history.LastPlayedFragment;
|
||||||
import org.schabi.newpipe.fragments.local.bookmark.LocalPlaylistFragment;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
|
||||||
import org.schabi.newpipe.fragments.local.bookmark.MostPlayedFragment;
|
import org.schabi.newpipe.fragments.local.history.MostPlayedFragment;
|
||||||
import org.schabi.newpipe.fragments.subscription.SubscriptionsImportFragment;
|
import org.schabi.newpipe.fragments.subscription.SubscriptionsImportFragment;
|
||||||
import org.schabi.newpipe.history.HistoryActivity;
|
|
||||||
import org.schabi.newpipe.player.BackgroundPlayer;
|
import org.schabi.newpipe.player.BackgroundPlayer;
|
||||||
import org.schabi.newpipe.player.BackgroundPlayerActivity;
|
import org.schabi.newpipe.player.BackgroundPlayerActivity;
|
||||||
import org.schabi.newpipe.player.BasePlayer;
|
import org.schabi.newpipe.player.BasePlayer;
|
||||||
|
@ -417,11 +416,6 @@ public class NavigationHelper {
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openHistory(Context context) {
|
|
||||||
Intent intent = new Intent(context, HistoryActivity.class);
|
|
||||||
context.startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void openSettings(Context context) {
|
public static void openSettings(Context context) {
|
||||||
Intent intent = new Intent(context, SettingsActivity.class);
|
Intent intent = new Intent(context, SettingsActivity.class);
|
||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
|
|
|
@ -7,42 +7,10 @@
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:background="?attr/selectableItemBackground">
|
android:background="?attr/selectableItemBackground">
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/lastPlayed"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/lastPlayedIcon"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="28dp"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginLeft="12dp"
|
|
||||||
android:layout_marginRight="12dp"
|
|
||||||
android:src="?attr/history"
|
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/lastPlayedText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:layout_toRightOf="@+id/lastPlayedIcon"
|
|
||||||
android:gravity="left|center"
|
|
||||||
android:text="@string/title_last_played"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:ignore="RtlHardcoded"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/mostPlayed"
|
android:id="@+id/mostPlayed"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/lastPlayed"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true">
|
android:focusable="true">
|
||||||
|
|
Loading…
Reference in New Issue