1
0
mirror of https://github.com/TeamNewPipe/NewPipe.git synced 2024-11-26 04:52:29 +01:00

Base implementation of showing playback positions in lists

This commit is contained in:
Vasiliy 2019-04-15 21:19:59 +03:00
parent 4e1423d224
commit 73be8cf074
No known key found for this signature in database
GPG Key ID: 9F74C4D2874D7523
16 changed files with 172 additions and 23 deletions

View File

@ -65,6 +65,12 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
infoListAdapter = new InfoListAdapter(activity); infoListAdapter = new InfoListAdapter(activity);
} }
@Override
public void onDetach() {
infoListAdapter.dispose();
super.onDetach();
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);

View File

@ -2,12 +2,14 @@ package org.schabi.newpipe.info_list;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; 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.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
@ -59,13 +61,14 @@ public class InfoItemBuilder {
this.context = context; this.context = context;
} }
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem) { public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, @Nullable StreamStateEntity state) {
return buildView(parent, infoItem, false); return buildView(parent, infoItem, state, false);
} }
public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem, boolean useMiniVariant) { public View buildView(@NonNull ViewGroup parent, @NonNull final InfoItem infoItem,
@Nullable StreamStateEntity state, boolean useMiniVariant) {
InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant); InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
holder.updateFromItem(infoItem); holder.updateFromItem(infoItem, state);
return holder.itemView; return holder.itemView;
} }

View File

@ -7,16 +7,17 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; 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.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
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.info_list.holder.ChannelGridInfoItemHolder;
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.CommentsInfoItemHolder; import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.InfoItemHolder; import org.schabi.newpipe.info_list.holder.InfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
@ -24,12 +25,16 @@ import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder; import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder; import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
import org.schabi.newpipe.local.history.HistoryRecordManager;
import org.schabi.newpipe.util.FallbackViewHolder; import org.schabi.newpipe.util.FallbackViewHolder;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
/* /*
* Created by Christian Schabesberger on 01.08.16. * Created by Christian Schabesberger on 01.08.16.
* *
@ -70,7 +75,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
private static final int COMMENT_HOLDER_TYPE = 0x401; private static final int COMMENT_HOLDER_TYPE = 0x401;
private final InfoItemBuilder infoItemBuilder; private final InfoItemBuilder infoItemBuilder;
private final HistoryRecordManager historyRecordManager;
private final ArrayList<InfoItem> infoItemList; private final ArrayList<InfoItem> infoItemList;
private final ArrayList<StreamStateEntity> states;
private final CompositeDisposable stateLoaders;
private boolean useMiniVariant = false; private boolean useMiniVariant = false;
private boolean useGridVariant = false; private boolean useGridVariant = false;
private boolean showFooter = false; private boolean showFooter = false;
@ -88,7 +96,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
public InfoListAdapter(Activity a) { public InfoListAdapter(Activity a) {
infoItemBuilder = new InfoItemBuilder(a); infoItemBuilder = new InfoItemBuilder(a);
historyRecordManager = new HistoryRecordManager(a);
infoItemList = new ArrayList<>(); infoItemList = new ArrayList<>();
states = new ArrayList<>();
stateLoaders = new CompositeDisposable();
} }
public void setOnStreamSelectedListener(OnClickGesture<StreamInfoItem> listener) { public void setOnStreamSelectedListener(OnClickGesture<StreamInfoItem> listener) {
@ -115,7 +126,17 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
this.useGridVariant = useGridVariant; this.useGridVariant = useGridVariant;
} }
public void addInfoItemList(List<InfoItem> data) { public void addInfoItemList(final List<InfoItem> data) {
stateLoaders.add(
historyRecordManager.loadStreamStateBatch(data)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(streamStateEntities -> {
addInfoItemList(data, streamStateEntities);
})
);
}
private void addInfoItemList(List<InfoItem> data, List<StreamStateEntity> statesEntities) {
if (data != null) { if (data != null) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addInfoItemList() before > infoItemList.size() = " + infoItemList.size() + ", data.size() = " + data.size()); Log.d(TAG, "addInfoItemList() before > infoItemList.size() = " + infoItemList.size() + ", data.size() = " + data.size());
@ -123,6 +144,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
int offsetStart = sizeConsideringHeaderOffset(); int offsetStart = sizeConsideringHeaderOffset();
infoItemList.addAll(data); infoItemList.addAll(data);
states.addAll(statesEntities);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter); Log.d(TAG, "addInfoItemList() after > offsetStart = " + offsetStart + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter);
@ -140,6 +162,16 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
public void addInfoItem(InfoItem data) { public void addInfoItem(InfoItem data) {
stateLoaders.add(
historyRecordManager.loadStreamState(data)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(streamStateEntity -> {
addInfoItem(data, streamStateEntity);
})
);
}
private void addInfoItem(InfoItem data, StreamStateEntity state) {
if (data != null) { if (data != null) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addInfoItem() before > infoItemList.size() = " + infoItemList.size() + ", thread = " + Thread.currentThread()); Log.d(TAG, "addInfoItem() before > infoItemList.size() = " + infoItemList.size() + ", thread = " + Thread.currentThread());
@ -147,6 +179,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
int positionInserted = sizeConsideringHeaderOffset(); int positionInserted = sizeConsideringHeaderOffset();
infoItemList.add(data); infoItemList.add(data);
states.add(state);
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "addInfoItem() after > position = " + positionInserted + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter); Log.d(TAG, "addInfoItem() after > position = " + positionInserted + ", infoItemList.size() = " + infoItemList.size() + ", header = " + header + ", footer = " + footer + ", showFooter = " + showFooter);
@ -167,6 +200,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
return; return;
} }
infoItemList.clear(); infoItemList.clear();
states.clear();
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -284,7 +318,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
// If header isn't null, offset the items by -1 // If header isn't null, offset the items by -1
if (header != null) position--; if (header != null) position--;
((InfoItemHolder) holder).updateFromItem(infoItemList.get(position)); ((InfoItemHolder) holder).updateFromItem(infoItemList.get(position), states.get(position));
} else if (holder instanceof HFHolder && position == 0 && header != null) { } else if (holder instanceof HFHolder && position == 0 && header != null) {
((HFHolder) holder).view = header; ((HFHolder) holder).view = header;
} else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset() && footer != null && showFooter) { } else if (holder instanceof HFHolder && position == sizeConsideringHeaderOffset() && footer != null && showFooter) {
@ -301,4 +335,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
} }
}; };
} }
public void dispose() {
stateLoaders.clear();
}
} }

View File

@ -1,9 +1,11 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -38,8 +40,8 @@ public class ChannelInfoItemHolder extends ChannelMiniInfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem); super.updateFromItem(infoItem, state);
if (!(infoItem instanceof ChannelInfoItem)) return; if (!(infoItem instanceof ChannelInfoItem)) return;
final ChannelInfoItem item = (ChannelInfoItem) infoItem; final ChannelInfoItem item = (ChannelInfoItem) infoItem;

View File

@ -1,9 +1,11 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -30,7 +32,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
if (!(infoItem instanceof ChannelInfoItem)) return; if (!(infoItem instanceof ChannelInfoItem)) return;
final ChannelInfoItem item = (ChannelInfoItem) infoItem; final ChannelInfoItem item = (ChannelInfoItem) infoItem;

View File

@ -1,14 +1,14 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.util.Localization;
/* /*
* Created by Christian Schabesberger on 12.02.17. * Created by Christian Schabesberger on 12.02.17.
@ -41,8 +41,8 @@ public class CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem); super.updateFromItem(infoItem, state);
if (!(infoItem instanceof CommentsInfoItem)) return; if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem; final CommentsInfoItem item = (CommentsInfoItem) infoItem;

View File

@ -1,5 +1,6 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.View; import android.view.View;
@ -8,6 +9,7 @@ import android.widget.TextView;
import org.jsoup.helper.StringUtil; import org.jsoup.helper.StringUtil;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem; import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -65,7 +67,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
if (!(infoItem instanceof CommentsInfoItem)) return; if (!(infoItem instanceof CommentsInfoItem)) return;
final CommentsInfoItem item = (CommentsInfoItem) infoItem; final CommentsInfoItem item = (CommentsInfoItem) infoItem;

View File

@ -1,9 +1,11 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -35,5 +37,5 @@ public abstract class InfoItemHolder extends RecyclerView.ViewHolder {
this.itemBuilder = infoItemBuilder; this.itemBuilder = infoItemBuilder;
} }
public abstract void updateFromItem(final InfoItem infoItem); public abstract void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state);
} }

View File

@ -1,10 +1,12 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -30,7 +32,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
if (!(infoItem instanceof PlaylistInfoItem)) return; if (!(infoItem instanceof PlaylistInfoItem)) return;
final PlaylistInfoItem item = (PlaylistInfoItem) infoItem; final PlaylistInfoItem item = (PlaylistInfoItem) infoItem;

View File

@ -1,10 +1,12 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
@ -40,8 +42,8 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
super.updateFromItem(infoItem); super.updateFromItem(infoItem, state);
if (!(infoItem instanceof StreamInfoItem)) return; if (!(infoItem instanceof StreamInfoItem)) return;
final StreamInfoItem item = (StreamInfoItem) infoItem; final StreamInfoItem item = (StreamInfoItem) infoItem;

View File

@ -1,12 +1,15 @@
package org.schabi.newpipe.info_list.holder; package org.schabi.newpipe.info_list.holder;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.StreamType;
@ -14,12 +17,15 @@ import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.ImageDisplayConstants;
import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.Localization;
import java.util.concurrent.TimeUnit;
public class StreamMiniInfoItemHolder extends InfoItemHolder { public class StreamMiniInfoItemHolder extends InfoItemHolder {
public final ImageView itemThumbnailView; public final ImageView itemThumbnailView;
public final TextView itemVideoTitleView; public final TextView itemVideoTitleView;
public final TextView itemUploaderView; public final TextView itemUploaderView;
public final TextView itemDurationView; public final TextView itemDurationView;
public final ProgressBar itemProgressView;
StreamMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) { StreamMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
super(infoItemBuilder, layoutId, parent); super(infoItemBuilder, layoutId, parent);
@ -28,6 +34,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView); itemVideoTitleView = itemView.findViewById(R.id.itemVideoTitleView);
itemUploaderView = itemView.findViewById(R.id.itemUploaderView); itemUploaderView = itemView.findViewById(R.id.itemUploaderView);
itemDurationView = itemView.findViewById(R.id.itemDurationView); itemDurationView = itemView.findViewById(R.id.itemDurationView);
itemProgressView = itemView.findViewById(R.id.itemProgressView);
} }
public StreamMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) { public StreamMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
@ -35,7 +42,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
} }
@Override @Override
public void updateFromItem(final InfoItem infoItem) { public void updateFromItem(final InfoItem infoItem, @Nullable final StreamStateEntity state) {
if (!(infoItem instanceof StreamInfoItem)) return; if (!(infoItem instanceof StreamInfoItem)) return;
final StreamInfoItem item = (StreamInfoItem) infoItem; final StreamInfoItem item = (StreamInfoItem) infoItem;
@ -47,13 +54,22 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(), itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(),
R.color.duration_background_color)); R.color.duration_background_color));
itemDurationView.setVisibility(View.VISIBLE); itemDurationView.setVisibility(View.VISIBLE);
if (state != null) {
itemProgressView.setVisibility(View.VISIBLE);
itemProgressView.setMax((int) item.getDuration());
itemProgressView.setProgress((int) TimeUnit.MILLISECONDS.toSeconds(state.getProgressTime()));
} else {
itemProgressView.setVisibility(View.GONE);
}
} else if (item.getStreamType() == StreamType.LIVE_STREAM) { } else if (item.getStreamType() == StreamType.LIVE_STREAM) {
itemDurationView.setText(R.string.duration_live); itemDurationView.setText(R.string.duration_live);
itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(), itemDurationView.setBackgroundColor(ContextCompat.getColor(itemBuilder.getContext(),
R.color.live_duration_background_color)); R.color.live_duration_background_color));
itemDurationView.setVisibility(View.VISIBLE); itemDurationView.setVisibility(View.VISIBLE);
itemProgressView.setVisibility(View.GONE);
} else { } else {
itemDurationView.setVisibility(View.GONE); itemDurationView.setVisibility(View.GONE);
itemProgressView.setVisibility(View.GONE);
} }
// Default thumbnail is shown on error, while loading and if the url is empty // Default thumbnail is shown on error, while loading and if the url is empty

View File

@ -36,6 +36,7 @@ import org.schabi.newpipe.database.stream.dao.StreamDAO;
import org.schabi.newpipe.database.stream.dao.StreamStateDAO; import org.schabi.newpipe.database.stream.dao.StreamStateDAO;
import org.schabi.newpipe.database.stream.model.StreamEntity; import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.database.stream.model.StreamStateEntity; import org.schabi.newpipe.database.stream.model.StreamStateEntity;
import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.player.playqueue.PlayQueueItem;
@ -220,6 +221,40 @@ public class HistoryRecordManager {
})).subscribeOn(Schedulers.io()); })).subscribeOn(Schedulers.io());
} }
public Single<StreamStateEntity> loadStreamState(final InfoItem info) {
return Single.fromCallable(() -> {
final List<StreamEntity> entities = streamTable.getStream(info.getServiceId(), info.getUrl()).blockingFirst();
if (entities.isEmpty()) {
return null;
}
final List<StreamStateEntity> states = streamStateTable.getState(entities.get(0).getUid()).blockingFirst();
if (states.isEmpty()) {
return null;
}
return states.get(0);
}).subscribeOn(Schedulers.io());
}
public Single<List<StreamStateEntity>> loadStreamStateBatch(final List<InfoItem> infos) {
return Single.fromCallable(() -> {
final List<StreamStateEntity> result = new ArrayList<>(infos.size());
for (InfoItem info : infos) {
final List<StreamEntity> entities = streamTable.getStream(info.getServiceId(), info.getUrl()).blockingFirst();
if (entities.isEmpty()) {
result.add(null);
continue;
}
final List<StreamStateEntity> states = streamStateTable.getState(entities.get(0).getUid()).blockingFirst();
if (states.isEmpty()) {
result.add(null);
continue;
}
result.add(states.get(0));
}
return result;
}).subscribeOn(Schedulers.io());
}
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////
// Utility // Utility
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////

View File

@ -23,7 +23,6 @@ import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
@ -48,10 +47,8 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor; import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService; import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService; import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.FilePickerActivityHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
@ -131,6 +128,12 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
subscriptionService = SubscriptionService.getInstance(activity); subscriptionService = SubscriptionService.getInstance(activity);
} }
@Override
public void onDetach() {
infoListAdapter.dispose();
super.onDetach();
}
@Nullable @Nullable
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {

View File

@ -66,4 +66,16 @@
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_uploader_text_size" android:textSize="@dimen/video_item_search_uploader_text_size"
tools:text="Uploader"/> tools:text="Uploader"/>
<ProgressBar
android:id="@+id/itemProgressView"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="?progress_horizontal_drawable"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:layout_marginTop="-2dp"
android:layout_alignStart="@id/itemThumbnailView"
android:layout_alignEnd="@id/itemThumbnailView"
android:layout_below="@id/itemThumbnailView"/>
</RelativeLayout> </RelativeLayout>

View File

@ -79,4 +79,16 @@
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_upload_date_text_size" android:textSize="@dimen/video_item_search_upload_date_text_size"
tools:text="2 years ago • 10M views"/> tools:text="2 years ago • 10M views"/>
<ProgressBar
android:id="@+id/itemProgressView"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="?progress_horizontal_drawable"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:layout_marginTop="-2dp"
android:layout_alignStart="@id/itemThumbnailView"
android:layout_alignEnd="@id/itemThumbnailView"
android:layout_below="@id/itemThumbnailView"/>
</RelativeLayout> </RelativeLayout>

View File

@ -69,4 +69,16 @@
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_uploader_text_size" android:textSize="@dimen/video_item_search_uploader_text_size"
tools:text="Uploader" /> tools:text="Uploader" />
<ProgressBar
android:id="@+id/itemProgressView"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:progressDrawable="?progress_horizontal_drawable"
android:layout_width="wrap_content"
android:layout_height="4dp"
android:layout_marginTop="-2dp"
android:layout_alignStart="@id/itemThumbnailView"
android:layout_alignEnd="@id/itemThumbnailView"
android:layout_below="@id/itemThumbnailView"/>
</RelativeLayout> </RelativeLayout>