Converted chapters list to RecyclerView
This fixes scrolling in bottom sheet
This commit is contained in:
parent
cc3e39a223
commit
6b79daacfe
|
@ -2,40 +2,38 @@ package de.danoeh.antennapod.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.load.resource.bitmap.FitCenter;
|
import com.bumptech.glide.load.resource.bitmap.FitCenter;
|
||||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||||
import com.bumptech.glide.request.RequestOptions;
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.feed.Chapter;
|
import de.danoeh.antennapod.core.feed.Chapter;
|
||||||
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
|
|
||||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
import de.danoeh.antennapod.core.util.EmbeddedChapterImage;
|
import de.danoeh.antennapod.core.util.EmbeddedChapterImage;
|
||||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
|
|
||||||
public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
public class ChaptersListAdapter extends RecyclerView.Adapter<ChaptersListAdapter.ChapterHolder> {
|
||||||
private static final String TAG = "ChapterListAdapter";
|
|
||||||
|
|
||||||
private Playable media;
|
private Playable media;
|
||||||
private final Callback callback;
|
private final Callback callback;
|
||||||
|
private final Context context;
|
||||||
private int currentChapterIndex = -1;
|
private int currentChapterIndex = -1;
|
||||||
private boolean hasImages = false;
|
private boolean hasImages = false;
|
||||||
|
|
||||||
public ChaptersListAdapter(Context context, int textViewResourceId, Callback callback) {
|
public ChaptersListAdapter(Context context, Callback callback) {
|
||||||
super(context, textViewResourceId);
|
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMedia(Playable media) {
|
public void setMedia(Playable media) {
|
||||||
|
@ -51,34 +49,10 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
@Override
|
||||||
public View getView(final int position, View convertView, @NonNull ViewGroup parent) {
|
public void onBindViewHolder(@NonNull ChapterHolder holder, int position) {
|
||||||
Holder holder;
|
|
||||||
|
|
||||||
Chapter sc = getItem(position);
|
Chapter sc = getItem(position);
|
||||||
|
|
||||||
// Inflate Layout
|
|
||||||
if (convertView == null) {
|
|
||||||
holder = new Holder();
|
|
||||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
|
||||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
|
|
||||||
convertView = inflater.inflate(R.layout.simplechapter_item, parent, false);
|
|
||||||
holder.view = convertView;
|
|
||||||
holder.title = convertView.findViewById(R.id.txtvTitle);
|
|
||||||
holder.start = convertView.findViewById(R.id.txtvStart);
|
|
||||||
holder.link = convertView.findViewById(R.id.txtvLink);
|
|
||||||
holder.image = convertView.findViewById(R.id.imgvCover);
|
|
||||||
holder.duration = convertView.findViewById(R.id.txtvDuration);
|
|
||||||
holder.secondaryActionButton = convertView.findViewById(R.id.secondaryActionButton);
|
|
||||||
holder.secondaryActionIcon = convertView.findViewById(R.id.secondaryActionIcon);
|
|
||||||
convertView.setTag(holder);
|
|
||||||
} else {
|
|
||||||
holder = (Holder) convertView.getTag();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.title.setText(sc.getTitle());
|
holder.title.setText(sc.getTitle());
|
||||||
holder.start.setText(Converter.getDurationStringLong((int) sc
|
holder.start.setText(Converter.getDurationStringLong((int) sc
|
||||||
.getStart()));
|
.getStart()));
|
||||||
|
@ -89,7 +63,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
} else {
|
} else {
|
||||||
duration = media.getDuration() - sc.getStart();
|
duration = media.getDuration() - sc.getStart();
|
||||||
}
|
}
|
||||||
holder.duration.setText(getContext().getString(R.string.chapter_duration,
|
holder.duration.setText(context.getString(R.string.chapter_duration,
|
||||||
Converter.getDurationStringLong((int) duration)));
|
Converter.getDurationStringLong((int) duration)));
|
||||||
|
|
||||||
if (sc.getLink() == null) {
|
if (sc.getLink() == null) {
|
||||||
|
@ -97,9 +71,9 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
} else {
|
} else {
|
||||||
holder.link.setVisibility(View.VISIBLE);
|
holder.link.setVisibility(View.VISIBLE);
|
||||||
holder.link.setText(sc.getLink());
|
holder.link.setText(sc.getLink());
|
||||||
holder.link.setOnClickListener(v -> IntentUtils.openInBrowser(getContext(), sc.getLink()));
|
holder.link.setOnClickListener(v -> IntentUtils.openInBrowser(context, sc.getLink()));
|
||||||
}
|
}
|
||||||
holder.secondaryActionIcon.setImageResource(ThemeUtils.getDrawableFromAttr(getContext(), R.attr.av_play));
|
holder.secondaryActionIcon.setImageResource(ThemeUtils.getDrawableFromAttr(context, R.attr.av_play));
|
||||||
holder.secondaryActionButton.setOnClickListener(v -> {
|
holder.secondaryActionButton.setOnClickListener(v -> {
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onPlayChapterButtonClicked(position);
|
callback.onPlayChapterButtonClicked(position);
|
||||||
|
@ -107,47 +81,42 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (position == currentChapterIndex) {
|
if (position == currentChapterIndex) {
|
||||||
int playingBackGroundColor = ThemeUtils.getColorFromAttr(getContext(), R.attr.currently_playing_background);
|
int playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background);
|
||||||
holder.view.setBackgroundColor(playingBackGroundColor);
|
holder.itemView.setBackgroundColor(playingBackGroundColor);
|
||||||
} else {
|
} else {
|
||||||
holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
holder.itemView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.transparent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasImages) {
|
if (hasImages) {
|
||||||
holder.image.setVisibility(View.VISIBLE);
|
holder.image.setVisibility(View.VISIBLE);
|
||||||
if (TextUtils.isEmpty(sc.getImageUrl())) {
|
if (TextUtils.isEmpty(sc.getImageUrl())) {
|
||||||
Glide.with(getContext()).clear(holder.image);
|
Glide.with(context).clear(holder.image);
|
||||||
} else {
|
} else {
|
||||||
Glide.with(getContext())
|
Glide.with(context)
|
||||||
.load(EmbeddedChapterImage.getModelFor(media, position))
|
.load(EmbeddedChapterImage.getModelFor(media, position))
|
||||||
.apply(new RequestOptions()
|
.apply(new RequestOptions()
|
||||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
.transforms(new FitCenter(), new RoundedCorners((int)
|
.transforms(new FitCenter(), new RoundedCorners((int)
|
||||||
(4 * getContext().getResources().getDisplayMetrics().density))))
|
(4 * context.getResources().getDisplayMetrics().density))))
|
||||||
.into(holder.image);
|
.into(holder.image);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
holder.image.setVisibility(View.GONE);
|
holder.image.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Holder {
|
@NonNull
|
||||||
View view;
|
@Override
|
||||||
TextView title;
|
public ChapterHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
TextView start;
|
LayoutInflater inflater = LayoutInflater.from(context);
|
||||||
TextView link;
|
return new ChapterHolder(inflater.inflate(R.layout.simplechapter_item, parent, false));
|
||||||
TextView duration;
|
|
||||||
ImageView image;
|
|
||||||
View secondaryActionButton;
|
|
||||||
ImageView secondaryActionIcon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getItemCount() {
|
||||||
if (media == null || media.getChapters() == null) {
|
if (media == null || media.getChapters() == null) {
|
||||||
|
Log.d("aaaaa", "0");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// ignore invalid chapters
|
// ignore invalid chapters
|
||||||
|
@ -157,9 +126,31 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Log.d("aaaaa", "0"+counter);
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ChapterHolder extends RecyclerView.ViewHolder {
|
||||||
|
final TextView title;
|
||||||
|
final TextView start;
|
||||||
|
final TextView link;
|
||||||
|
final TextView duration;
|
||||||
|
final ImageView image;
|
||||||
|
final View secondaryActionButton;
|
||||||
|
final ImageView secondaryActionIcon;
|
||||||
|
|
||||||
|
public ChapterHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
title = itemView.findViewById(R.id.txtvTitle);
|
||||||
|
start = itemView.findViewById(R.id.txtvStart);
|
||||||
|
link = itemView.findViewById(R.id.txtvLink);
|
||||||
|
image = itemView.findViewById(R.id.imgvCover);
|
||||||
|
duration = itemView.findViewById(R.id.txtvDuration);
|
||||||
|
secondaryActionButton = itemView.findViewById(R.id.secondaryActionButton);
|
||||||
|
secondaryActionIcon = itemView.findViewById(R.id.secondaryActionIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void notifyChapterChanged(int newChapterIndex) {
|
public void notifyChapterChanged(int newChapterIndex) {
|
||||||
currentChapterIndex = newChapterIndex;
|
currentChapterIndex = newChapterIndex;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
|
@ -169,7 +160,6 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
return media.getDuration() > 0 && media.getDuration() < c.getStart();
|
return media.getDuration() > 0 && media.getDuration() < c.getStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Chapter getItem(int position) {
|
public Chapter getItem(int position) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Chapter chapter : media.getChapters()) {
|
for (Chapter chapter : media.getChapters()) {
|
||||||
|
@ -181,7 +171,7 @@ public class ChaptersListAdapter extends ArrayAdapter<Chapter> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.getItem(position);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
package de.danoeh.antennapod.fragment;
|
package de.danoeh.antennapod.fragment;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.fragment.app.ListFragment;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ListView;
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import de.danoeh.antennapod.core.util.ChapterUtils;
|
import androidx.annotation.Nullable;
|
||||||
import java.util.List;
|
import androidx.fragment.app.Fragment;
|
||||||
import java.util.ListIterator;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
|
import de.danoeh.antennapod.adapter.ChaptersListAdapter;
|
||||||
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
|
|
||||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||||
import de.danoeh.antennapod.core.feed.Chapter;
|
import de.danoeh.antennapod.core.feed.Chapter;
|
||||||
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
|
||||||
|
import de.danoeh.antennapod.core.util.ChapterUtils;
|
||||||
import de.danoeh.antennapod.core.util.playback.Playable;
|
import de.danoeh.antennapod.core.util.playback.Playable;
|
||||||
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
import de.danoeh.antennapod.core.util.playback.PlaybackController;
|
||||||
|
|
||||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||||
import io.reactivex.Maybe;
|
import io.reactivex.Maybe;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
@ -28,38 +28,43 @@ import org.greenrobot.eventbus.EventBus;
|
||||||
import org.greenrobot.eventbus.Subscribe;
|
import org.greenrobot.eventbus.Subscribe;
|
||||||
import org.greenrobot.eventbus.ThreadMode;
|
import org.greenrobot.eventbus.ThreadMode;
|
||||||
|
|
||||||
public class ChaptersFragment extends ListFragment {
|
public class ChaptersFragment extends Fragment {
|
||||||
private static final String TAG = "ChaptersFragment";
|
private static final String TAG = "ChaptersFragment";
|
||||||
private ChaptersListAdapter adapter;
|
private ChaptersListAdapter adapter;
|
||||||
private PlaybackController controller;
|
private PlaybackController controller;
|
||||||
private Disposable disposable;
|
private Disposable disposable;
|
||||||
private int focusedChapter = -1;
|
private int focusedChapter = -1;
|
||||||
private Playable media;
|
private Playable media;
|
||||||
|
private LinearLayoutManager layoutManager;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
View root = inflater.inflate(R.layout.simple_list_fragment, container, false);
|
||||||
// add padding
|
root.findViewById(R.id.toolbar).setVisibility(View.GONE);
|
||||||
final ListView lv = getListView();
|
RecyclerView recyclerView = root.findViewById(R.id.recyclerView);
|
||||||
lv.setClipToPadding(false);
|
layoutManager = new LinearLayoutManager(getActivity());
|
||||||
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
lv.setPadding(0, vertPadding, 0, vertPadding);
|
recyclerView.setHasFixedSize(true);
|
||||||
|
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
|
||||||
|
|
||||||
|
adapter = new ChaptersListAdapter(getActivity(), pos -> {
|
||||||
|
if (controller.getStatus() != PlayerStatus.PLAYING) {
|
||||||
|
controller.playPause();
|
||||||
|
}
|
||||||
|
Chapter chapter = adapter.getItem(pos);
|
||||||
|
controller.seekToChapter(chapter);
|
||||||
|
updateChapterSelection(pos);
|
||||||
|
});
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
EmptyViewHandler emptyView = new EmptyViewHandler(getContext());
|
EmptyViewHandler emptyView = new EmptyViewHandler(getContext());
|
||||||
emptyView.attachToListView(lv);
|
emptyView.attachToRecyclerView(recyclerView);
|
||||||
emptyView.setIcon(R.attr.ic_bookmark);
|
emptyView.setIcon(R.attr.ic_bookmark);
|
||||||
emptyView.setTitle(R.string.no_chapters_head_label);
|
emptyView.setTitle(R.string.no_chapters_head_label);
|
||||||
emptyView.setMessage(R.string.no_chapters_label);
|
emptyView.setMessage(R.string.no_chapters_label);
|
||||||
|
|
||||||
adapter = new ChaptersListAdapter(getActivity(), 0, pos -> {
|
return root;
|
||||||
if (controller.getStatus() != PlayerStatus.PLAYING) {
|
|
||||||
controller.playPause();
|
|
||||||
}
|
|
||||||
Chapter chapter = (Chapter) getListAdapter().getItem(pos);
|
|
||||||
controller.seekToChapter(chapter);
|
|
||||||
updateChapterSelection(pos);
|
|
||||||
});
|
|
||||||
setListAdapter(adapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -136,7 +141,6 @@ public class ChaptersFragment extends ListFragment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
adapter.setMedia(media);
|
adapter.setMedia(media);
|
||||||
adapter.notifyDataSetChanged();
|
|
||||||
int positionOfCurrentChapter = getCurrentChapter(media);
|
int positionOfCurrentChapter = getCurrentChapter(media);
|
||||||
updateChapterSelection(positionOfCurrentChapter);
|
updateChapterSelection(positionOfCurrentChapter);
|
||||||
}
|
}
|
||||||
|
@ -149,9 +153,9 @@ public class ChaptersFragment extends ListFragment {
|
||||||
if (position != -1 && focusedChapter != position) {
|
if (position != -1 && focusedChapter != position) {
|
||||||
focusedChapter = position;
|
focusedChapter = position;
|
||||||
adapter.notifyChapterChanged(focusedChapter);
|
adapter.notifyChapterChanged(focusedChapter);
|
||||||
if (getListView().getFirstVisiblePosition() >= position
|
if (layoutManager.findFirstCompletelyVisibleItemPosition() >= position
|
||||||
|| getListView().getLastVisiblePosition() <= position) {
|
|| layoutManager.findLastCompletelyVisibleItemPosition() <= position) {
|
||||||
getListView().setSelectionFromTop(position, 100);
|
layoutManager.scrollToPositionWithOffset(position, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue