Converted chapters list to RecyclerView

This fixes scrolling in bottom sheet
This commit is contained in:
ByteHamster 2020-03-23 11:08:19 +01:00
parent cc3e39a223
commit 6b79daacfe
2 changed files with 82 additions and 88 deletions

View File

@ -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 {

View File

@ -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);
} }
} }
} }