mirror of
https://github.com/clangen/musikcube.git
synced 2025-01-29 21:32:41 +00:00
Added fast scrollers to RecyclerViews, and also integrated an
OkHttpDataStream for ExoPlayer so we can take advantage of its caching capabilities.
This commit is contained in:
parent
881ef906a2
commit
8ce038c416
@ -29,6 +29,7 @@ android {
|
||||
|
||||
repositories {
|
||||
flatDir { dirs 'libs' }
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -47,10 +48,12 @@ dependencies {
|
||||
compile 'io.reactivex.rxjava2:rxjava:2.0.9'
|
||||
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
|
||||
compile 'com.google.android.exoplayer:exoplayer:r2.4.0'
|
||||
compile 'com.google.android.exoplayer:extension-okhttp:r2.4.0'
|
||||
compile 'com.github.pluscubed:recycler-fast-scroll:0.3.2@aar'
|
||||
|
||||
compile 'com.android.support:appcompat-v7:25.1.1'
|
||||
compile 'com.android.support:recyclerview-v7:25.1.1'
|
||||
compile 'com.android.support:design:25.1.1'
|
||||
compile 'com.android.support:appcompat-v7:25.3.1'
|
||||
compile 'com.android.support:recyclerview-v7:25.3.1'
|
||||
compile 'com.android.support:design:25.3.1'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
@ -19,16 +20,20 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelector;
|
||||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import io.casey.musikcube.remote.Application;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class ExoPlayerWrapper extends PlayerWrapper {
|
||||
private BandwidthMeter bandwidth;
|
||||
private static OkHttpClient audioStreamClient = null;
|
||||
private DefaultBandwidthMeter bandwidth;
|
||||
private DataSource.Factory datasources;
|
||||
private ExtractorsFactory extractors;
|
||||
private MediaSource source;
|
||||
@ -41,13 +46,38 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
||||
final TrackSelection.Factory trackFactory = new AdaptiveTrackSelection.Factory(bandwidth);
|
||||
final TrackSelector trackSelector = new DefaultTrackSelector(trackFactory);
|
||||
this.player = ExoPlayerFactory.newSimpleInstance(c, trackSelector);
|
||||
this.datasources = new DefaultDataSourceFactory(c, Util.getUserAgent(c, "musikdroid"));
|
||||
this.extractors = new DefaultExtractorsFactory();
|
||||
this.player.addListener(eventListener);
|
||||
}
|
||||
|
||||
private void initDataSourceFactory(final String uri) {
|
||||
final Context context = Application.getInstance();
|
||||
|
||||
synchronized (ExoPlayerWrapper.class) {
|
||||
if (audioStreamClient == null) {
|
||||
final File path = new File(context.getExternalCacheDir(), "audio");
|
||||
|
||||
audioStreamClient = new OkHttpClient.Builder()
|
||||
.cache(new Cache(path, 1048576 * 256)) /* 256 meg cache */
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
if (uri.startsWith("http")) {
|
||||
this.datasources = new OkHttpDataSourceFactory(
|
||||
audioStreamClient,
|
||||
Util.getUserAgent(context, "musikdroid"),
|
||||
bandwidth);
|
||||
}
|
||||
else {
|
||||
this.datasources = new DefaultDataSourceFactory(
|
||||
context, Util.getUserAgent(context, "musikdroid"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play(String uri) {
|
||||
initDataSourceFactory(uri);
|
||||
this.source = new ExtractorMediaSource(Uri.parse(uri), datasources, extractors, null, null);
|
||||
this.player.setPlayWhenReady(true);
|
||||
this.player.prepare(this.source);
|
||||
@ -57,6 +87,7 @@ public class ExoPlayerWrapper extends PlayerWrapper {
|
||||
|
||||
@Override
|
||||
public void prefetch(String uri) {
|
||||
initDataSourceFactory(uri);
|
||||
this.prefetch = true;
|
||||
this.source = new ExtractorMediaSource(Uri.parse(uri), datasources, extractors, null, null);
|
||||
this.player.setPlayWhenReady(false);
|
||||
|
@ -11,6 +11,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -89,9 +91,9 @@ public class AlbumBrowseActivity extends WebSocketActivityBase implements Filter
|
||||
this.wss = getWebSocketService();
|
||||
this.adapter = new Adapter();
|
||||
|
||||
final RecyclerFastScroller fastScroller = (RecyclerFastScroller) findViewById(R.id.fast_scroller);
|
||||
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, adapter);
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, fastScroller, adapter);
|
||||
|
||||
transport = Views.addTransportFragment(this,
|
||||
(TransportFragment fragment) -> adapter.notifyDataSetChanged());
|
||||
|
@ -11,6 +11,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@ -88,9 +90,9 @@ public class CategoryBrowseActivity extends WebSocketActivityBase implements Fil
|
||||
setTitle(CATEGORY_NAME_TO_TITLE.get(category));
|
||||
}
|
||||
|
||||
final RecyclerFastScroller fastScroller = (RecyclerFastScroller) findViewById(R.id.fast_scroller);
|
||||
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, this.adapter);
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, fastScroller, adapter);
|
||||
|
||||
transport = Views.addTransportFragment(this,
|
||||
(TransportFragment fragment) -> adapter.notifyDataSetChanged());
|
||||
|
@ -10,6 +10,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import io.casey.musikcube.remote.R;
|
||||
@ -47,12 +49,14 @@ public class PlayQueueActivity extends WebSocketActivityBase {
|
||||
Views.enableUpNavigation(this);
|
||||
|
||||
this.adapter = new Adapter();
|
||||
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, adapter);
|
||||
final RecyclerFastScroller fastScroller = (RecyclerFastScroller) findViewById(R.id.fast_scroller);
|
||||
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, fastScroller, adapter);
|
||||
|
||||
this.tracks = new TrackListSlidingWindow<>(
|
||||
recyclerView,
|
||||
fastScroller,
|
||||
this.wss,
|
||||
this.playback.getPlaylistQueryFactory(),
|
||||
(JSONObject obj) -> obj);
|
||||
|
@ -11,6 +11,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import io.casey.musikcube.remote.R;
|
||||
@ -79,11 +81,16 @@ public class TrackListActivity extends WebSocketActivityBase implements Filterab
|
||||
createCategoryQueryFactory(categoryType, categoryId);
|
||||
|
||||
final Adapter adapter = new Adapter();
|
||||
final RecyclerFastScroller fastScroller = (RecyclerFastScroller) findViewById(R.id.fast_scroller);
|
||||
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, adapter);
|
||||
Views.setupDefaultRecyclerView(this, recyclerView, fastScroller, adapter);
|
||||
|
||||
tracks = new TrackListSlidingWindow<>(
|
||||
recyclerView, getWebSocketService(), queryFactory, (JSONObject track) -> track);
|
||||
recyclerView,
|
||||
fastScroller,
|
||||
getWebSocketService(),
|
||||
queryFactory,
|
||||
(JSONObject track) -> track);
|
||||
|
||||
transport = Views.addTransportFragment(this,
|
||||
(TransportFragment fragment) -> adapter.notifyDataSetChanged());
|
||||
|
@ -1,6 +1,10 @@
|
||||
package io.casey.musikcube.remote.ui.model;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
@ -18,10 +22,12 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
|
||||
private int count = 0;
|
||||
private RecyclerView recyclerView;
|
||||
private RecyclerFastScroller fastScroller;
|
||||
private WebSocketService wss;
|
||||
private Mapper<TrackType> mapper;
|
||||
private QueryFactory queryFactory;
|
||||
private int scrollState = RecyclerView.SCROLL_STATE_IDLE;
|
||||
private boolean fastScrollActive = false;
|
||||
private int queryOffset = -1, queryLimit = -1;
|
||||
private int initialPosition = -1;
|
||||
private int windowSize = DEFAULT_WINDOW_SIZE;
|
||||
@ -54,28 +60,30 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
}
|
||||
|
||||
public TrackListSlidingWindow(RecyclerView recyclerView,
|
||||
RecyclerFastScroller fastScroller,
|
||||
WebSocketService wss,
|
||||
QueryFactory queryFactory,
|
||||
Mapper<TrackType> mapper) {
|
||||
this.recyclerView = recyclerView;
|
||||
this.fastScroller = fastScroller;
|
||||
this.wss = wss;
|
||||
this.queryFactory = queryFactory;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public TrackListSlidingWindow(WebSocketService wss,
|
||||
QueryFactory queryFactory,
|
||||
Mapper<TrackType> mapper) {
|
||||
this.recyclerView = null;
|
||||
this.wss = wss;
|
||||
this.queryFactory = queryFactory;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public void setQueryFactory(final QueryFactory factory) {
|
||||
this.queryFactory = factory;
|
||||
requery();
|
||||
}
|
||||
private View.OnTouchListener fastScrollerTouch = (view, event) -> {
|
||||
if (event != null) {
|
||||
final int type = event.getActionMasked();
|
||||
if (type == MotionEvent.ACTION_DOWN) {
|
||||
fastScrollActive = true;
|
||||
}
|
||||
else if (type == MotionEvent.ACTION_UP) {
|
||||
fastScrollActive = false;
|
||||
requery();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
public void requery() {
|
||||
if (connected) {
|
||||
@ -118,6 +126,10 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
if (this.recyclerView != null) {
|
||||
this.recyclerView.removeOnScrollListener(scrollListener);
|
||||
}
|
||||
|
||||
if (this.fastScroller != null) {
|
||||
fastScroller.setOnHandleTouchListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
@ -125,8 +137,13 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
this.recyclerView.addOnScrollListener(scrollListener);
|
||||
}
|
||||
|
||||
if (this.fastScroller != null) {
|
||||
fastScroller.setOnHandleTouchListener(fastScrollerTouch);
|
||||
}
|
||||
|
||||
this.wss.addClient(this.client);
|
||||
connected = true;
|
||||
fastScrollActive = false;
|
||||
}
|
||||
|
||||
public void setInitialPosition(int initialIndex) {
|
||||
@ -177,7 +194,7 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
}
|
||||
|
||||
private void getPageAround(int index) {
|
||||
if (!connected) {
|
||||
if (!connected || scrolling()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,11 +251,15 @@ public class TrackListSlidingWindow<TrackType> {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean scrolling() {
|
||||
return scrollState != RecyclerView.SCROLL_STATE_IDLE || fastScrollActive;
|
||||
}
|
||||
|
||||
private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
|
||||
scrollState = newState;
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
if (!scrolling()) {
|
||||
notifyAdapterChanged();
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ import android.view.ViewPropertyAnimator;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.pluscubed.recyclerfastscroll.RecyclerFastScroller;
|
||||
|
||||
import io.casey.musikcube.remote.R;
|
||||
import io.casey.musikcube.remote.ui.activity.Filterable;
|
||||
import io.casey.musikcube.remote.ui.fragment.TransportFragment;
|
||||
@ -35,11 +37,13 @@ public final class Views {
|
||||
|
||||
public static void setupDefaultRecyclerView(final Context context,
|
||||
final RecyclerView recyclerView,
|
||||
final RecyclerFastScroller fastScroller,
|
||||
final RecyclerView.Adapter adapter) {
|
||||
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
recyclerView.setAdapter(adapter);
|
||||
fastScroller.attachRecyclerView(recyclerView);
|
||||
|
||||
final DividerItemDecoration dividerItemDecoration =
|
||||
new DividerItemDecoration(context, layoutManager.getOrientation());
|
||||
|
@ -1,15 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
<RelativeLayout
|
||||
android:layout_weight="1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp" />
|
||||
android:layout_height="0dp">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.pluscubed.recyclerfastscroll.RecyclerFastScroller
|
||||
android:id="@+id/fast_scroller"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="8dp"
|
||||
android:layout_alignParentRight="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/transport_container"
|
||||
|
Loading…
x
Reference in New Issue
Block a user