mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-26 04:47:38 +00:00 
			
		
		
		
	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:
		| @@ -41,7 +41,7 @@ android { | ||||
| } | ||||
|  | ||||
| ext { | ||||
|     supportLibVersion = '27.1.0' | ||||
|     supportLibVersion = '27.1.1' | ||||
|     exoPlayerLibVersion = '2.7.3' | ||||
|     roomDbLibVersion = '1.0.0' | ||||
|     leakCanaryLibVersion = '1.5.4' | ||||
|   | ||||
| @@ -151,7 +151,8 @@ public class MainActivity extends AppCompatActivity { | ||||
|  | ||||
|         settings.setOnClickListener(view -> NavigationHelper.openSettings(this)); | ||||
|         downloads.setOnClickListener(view ->NavigationHelper.openDownloads(this)); | ||||
|         history.setOnClickListener(view -> NavigationHelper.openHistory(this)); | ||||
|         history.setOnClickListener(view -> | ||||
|                 NavigationHelper.openLastPlayedFragment(getSupportFragmentManager())); | ||||
|     } | ||||
|  | ||||
|     private void setupDrawerHeader() { | ||||
| @@ -327,17 +328,8 @@ public class MainActivity extends AppCompatActivity { | ||||
|             case android.R.id.home: | ||||
|                 onHomeButtonPressed(); | ||||
|                 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: | ||||
|                 NavigationHelper.openAbout(this); | ||||
|                 return true; | ||||
|             case R.id.action_history: | ||||
|                 NavigationHelper.openHistory(this); | ||||
|                 return true; | ||||
|             default: | ||||
|                 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.OnScrollBelowItemsListener; | ||||
| 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.InfoListAdapter; | ||||
| 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>() { | ||||
|             @Override | ||||
|             public void selected(StreamInfoItem selectedItem) { | ||||
|                 onItemSelected(selectedItem); | ||||
|                 NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(), | ||||
|                         selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName()); | ||||
|                 onStreamSelected(selectedItem); | ||||
|             } | ||||
|  | ||||
|             @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>() { | ||||
|             @Override | ||||
|             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() { | ||||
|         if (hasMoreItems() && !isLoading.get()) { | ||||
|             loadMoreItems(); | ||||
| @@ -216,6 +233,42 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem | ||||
|  | ||||
|         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 | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|   | ||||
| @@ -27,10 +27,9 @@ import org.schabi.newpipe.extractor.ListExtractor; | ||||
| import org.schabi.newpipe.extractor.NewPipe; | ||||
| import org.schabi.newpipe.extractor.exceptions.ExtractionException; | ||||
| 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.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.playlist.PlayQueue; | ||||
| 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.fragments.BackPressable; | ||||
| 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.util.Constants; | ||||
| 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.playlist.PlaylistInfoItem; | ||||
| 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.ChannelMiniInfoItemHolder; | ||||
| import org.schabi.newpipe.info_list.holder.InfoItemHolder; | ||||
| @@ -50,6 +51,7 @@ public class InfoItemBuilder { | ||||
|     private OnClickGesture<StreamInfoItem> onStreamSelectedListener; | ||||
|     private OnClickGesture<ChannelInfoItem> onChannelSelectedListener; | ||||
|     private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener; | ||||
|     private OnClickGesture<HistoryInfoItem> onHistoryItemSelectedListener; | ||||
|  | ||||
|     public InfoItemBuilder(Context context) { | ||||
|         this.context = context; | ||||
| @@ -111,4 +113,11 @@ public class InfoItemBuilder { | ||||
|         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.playlist.PlaylistInfoItem; | ||||
| 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.ChannelMiniInfoItemHolder; | ||||
| import org.schabi.newpipe.info_list.holder.InfoItemHolder; | ||||
| @@ -89,6 +90,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde | ||||
|         infoItemBuilder.setOnPlaylistSelectedListener(listener); | ||||
|     } | ||||
|  | ||||
|     public void setOnHistoryItemSelectedListener(OnClickGesture<HistoryInfoItem> listener) { | ||||
|         infoItemBuilder.setOnHistoryItemSelectedListener(listener); | ||||
|     } | ||||
|  | ||||
|     public void useMiniItemVariants(boolean 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.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.PlaylistMetadataEntry; | ||||
| import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; | ||||
| import org.schabi.newpipe.fragments.local.LocalPlaylistManager; | ||||
| import org.schabi.newpipe.fragments.local.RemotePlaylistManager; | ||||
| import org.schabi.newpipe.fragments.local.BaseLocalListFragment; | ||||
| import org.schabi.newpipe.local.playlist.LocalPlaylistManager; | ||||
| import org.schabi.newpipe.local.playlist.RemotePlaylistManager; | ||||
| import org.schabi.newpipe.report.UserAction; | ||||
| import org.schabi.newpipe.util.NavigationHelper; | ||||
| import org.schabi.newpipe.util.OnClickGesture; | ||||
| @@ -38,7 +39,6 @@ import io.reactivex.disposables.CompositeDisposable; | ||||
| public final class BookmarkFragment | ||||
|         extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> { | ||||
| 
 | ||||
|     private View lastPlayedButton; | ||||
|     private View mostPlayedButton; | ||||
| 
 | ||||
|     @State | ||||
| @@ -98,7 +98,6 @@ public final class BookmarkFragment | ||||
|     protected View getListHeader() { | ||||
|         final View headerRootLayout = activity.getLayoutInflater() | ||||
|                 .inflate(R.layout.bookmark_header, itemsList, false); | ||||
|         lastPlayedButton = headerRootLayout.findViewById(R.id.lastPlayed); | ||||
|         mostPlayedButton = headerRootLayout.findViewById(R.id.mostPlayed); | ||||
|         return headerRootLayout; | ||||
|     } | ||||
| @@ -137,12 +136,6 @@ public final class BookmarkFragment | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         lastPlayedButton.setOnClickListener(view -> { | ||||
|             if (getParentFragment() != null) { | ||||
|                 NavigationHelper.openLastPlayedFragment(getParentFragment().getFragmentManager()); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         mostPlayedButton.setOnClickListener(view -> { | ||||
|             if (getParentFragment() != null) { | ||||
|                 NavigationHelper.openMostPlayedFragment(getParentFragment().getFragmentManager()); | ||||
| @@ -181,7 +174,6 @@ public final class BookmarkFragment | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|         if (mostPlayedButton != null) mostPlayedButton.setOnClickListener(null); | ||||
|         if (lastPlayedButton != null) lastPlayedButton.setOnClickListener(null); | ||||
| 
 | ||||
|         if (disposables != null) disposables.clear(); | ||||
|         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.StreamInfoItem; | ||||
| 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.util.OnClickGesture; | ||||
| 
 | ||||
| @@ -12,7 +12,7 @@ import android.widget.Toast; | ||||
| import org.schabi.newpipe.NewPipeDatabase; | ||||
| import org.schabi.newpipe.R; | ||||
| 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; | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package org.schabi.newpipe.history; | ||||
| package org.schabi.newpipe.local.history; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 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; | ||||
| 
 | ||||
| @@ -1,4 +1,4 @@ | ||||
| package org.schabi.newpipe.history; | ||||
| package org.schabi.newpipe.local.history; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| 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.database.stream.StreamStatisticsEntry; | ||||
| import org.schabi.newpipe.playlist.StatisticsPlaylistFragment; | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| 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.database.stream.StreamStatisticsEntry; | ||||
| import org.schabi.newpipe.playlist.StatisticsPlaylistFragment; | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| 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.content.Context; | ||||
| @@ -26,7 +26,7 @@ import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.database.LocalItem; | ||||
| import org.schabi.newpipe.database.playlist.PlaylistStreamEntry; | ||||
| 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.playlist.PlayQueue; | ||||
| import org.schabi.newpipe.playlist.SinglePlayQueue; | ||||
| @@ -173,7 +173,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt | ||||
|             @Override | ||||
|             public void held(LocalItem selectedItem) { | ||||
|                 if (selectedItem instanceof PlaylistStreamEntry) { | ||||
|                     showStreamDialog((PlaylistStreamEntry) selectedItem); | ||||
|                     showStreamItemDialog((PlaylistStreamEntry) selectedItem); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| @@ -506,7 +506,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt | ||||
|     // Utils | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
| 
 | ||||
|     protected void showStreamDialog(final PlaylistStreamEntry item) { | ||||
|     protected void showStreamItemDialog(final PlaylistStreamEntry item) { | ||||
|         final Context context = getContext(); | ||||
|         final Activity activity = getActivity(); | ||||
|         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; | ||||
| 
 | ||||
| @@ -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.playlist.dao.PlaylistRemoteDAO; | ||||
| @@ -13,11 +13,9 @@ import io.reactivex.schedulers.Schedulers; | ||||
| 
 | ||||
| public class RemotePlaylistManager { | ||||
| 
 | ||||
|     private final AppDatabase database; | ||||
|     private final PlaylistRemoteDAO playlistRemoteTable; | ||||
| 
 | ||||
|     public RemotePlaylistManager(final AppDatabase db) { | ||||
|         database = db; | ||||
|         playlistRemoteTable = db.playlistRemoteDAO(); | ||||
|     } | ||||
| 
 | ||||
| @@ -58,7 +58,7 @@ import org.schabi.newpipe.Downloader; | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfo; | ||||
| 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.LoadController; | ||||
| 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.content.Context; | ||||
| @@ -17,10 +17,9 @@ import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.database.LocalItem; | ||||
| import org.schabi.newpipe.database.stream.StreamStatisticsEntry; | ||||
| 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.playlist.PlayQueue; | ||||
| import org.schabi.newpipe.playlist.SinglePlayQueue; | ||||
| import org.schabi.newpipe.report.UserAction; | ||||
| import org.schabi.newpipe.util.NavigationHelper; | ||||
| 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.playlist.PlaylistFragment; | ||||
| import org.schabi.newpipe.fragments.list.search.SearchFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.LastPlayedFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.LocalPlaylistFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.MostPlayedFragment; | ||||
| import org.schabi.newpipe.fragments.local.history.LastPlayedFragment; | ||||
| import org.schabi.newpipe.local.playlist.LocalPlaylistFragment; | ||||
| import org.schabi.newpipe.fragments.local.history.MostPlayedFragment; | ||||
| import org.schabi.newpipe.fragments.subscription.SubscriptionsImportFragment; | ||||
| import org.schabi.newpipe.history.HistoryActivity; | ||||
| import org.schabi.newpipe.player.BackgroundPlayer; | ||||
| import org.schabi.newpipe.player.BackgroundPlayerActivity; | ||||
| import org.schabi.newpipe.player.BasePlayer; | ||||
| @@ -417,11 +416,6 @@ public class NavigationHelper { | ||||
|         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) { | ||||
|         Intent intent = new Intent(context, SettingsActivity.class); | ||||
|         context.startActivity(intent); | ||||
|   | ||||
| @@ -7,42 +7,10 @@ | ||||
|     android:layout_marginBottom="12dp" | ||||
|     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 | ||||
|         android:id="@+id/mostPlayed" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_below="@id/lastPlayed" | ||||
|         android:background="?attr/selectableItemBackground" | ||||
|         android:clickable="true" | ||||
|         android:focusable="true"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Christian Schabesberger
					Christian Schabesberger