diff options
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java')
-rw-r--r-- | app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java | 191 |
1 files changed, 159 insertions, 32 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index 5e1cda43c..f60930a35 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -1,7 +1,9 @@ package de.danoeh.antennapod.fragment; +import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Configuration; +import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.TextUtils; @@ -10,17 +12,29 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.Space; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.graphics.BlendModeColorFilterCompat; +import androidx.core.graphics.BlendModeCompat; import androidx.fragment.app.Fragment; + import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.load.resource.bitmap.FitCenter; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; -import com.bumptech.glide.RequestBuilder; import com.bumptech.glide.request.RequestOptions; + +import org.apache.commons.lang3.StringUtils; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.util.ImageResourceUtils; @@ -28,16 +42,13 @@ import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.DateUtils; import de.danoeh.antennapod.core.util.EmbeddedChapterImage; -import de.danoeh.antennapod.model.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; +import de.danoeh.antennapod.model.feed.Chapter; +import de.danoeh.antennapod.model.playback.Playable; import io.reactivex.Maybe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import org.apache.commons.lang3.StringUtils; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; /** * Displays the cover and the title of a FeedItem. @@ -51,9 +62,16 @@ public class CoverFragment extends Fragment { private TextView txtvPodcastTitle; private TextView txtvEpisodeTitle; private ImageView imgvCover; + private LinearLayout openDescription; + private Space counterweight; + private Space spacer; + private ImageButton butPrevChapter; + private ImageButton butNextChapter; + private LinearLayout episodeDetails; + private LinearLayout chapterControl; private PlaybackController controller; private Disposable disposable; - private int displayedChapterIndex = -2; + private int displayedChapterIndex = -1; private Playable media; @Override @@ -64,7 +82,30 @@ public class CoverFragment extends Fragment { txtvPodcastTitle = root.findViewById(R.id.txtvPodcastTitle); txtvEpisodeTitle = root.findViewById(R.id.txtvEpisodeTitle); imgvCover = root.findViewById(R.id.imgvCover); + episodeDetails = root.findViewById(R.id.episode_details); + final ImageView descriptionIcon = root.findViewById(R.id.description_icon); + chapterControl = root.findViewById(R.id.chapterButton); + butPrevChapter = root.findViewById(R.id.butPrevChapter); + butNextChapter = root.findViewById(R.id.butNextChapter); + imgvCover.setOnClickListener(v -> onPlayPause()); + openDescription = root.findViewById(R.id.openDescription); + counterweight = root.findViewById(R.id.counterweight); + spacer = root.findViewById(R.id.details_spacer); + View.OnClickListener scrollToDesc = view -> + ((AudioPlayerFragment) requireParentFragment()).scrollToPage(AudioPlayerFragment.POS_DESCRIPTION, true); + openDescription.setOnClickListener(scrollToDesc); + ColorFilter colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat( + txtvPodcastTitle.getCurrentTextColor(), BlendModeCompat.SRC_IN); + butNextChapter.setColorFilter(colorFilter); + butPrevChapter.setColorFilter(colorFilter); + descriptionIcon.setColorFilter(colorFilter); + ChaptersFragment chaptersFragment = new ChaptersFragment(); + chapterControl.setOnClickListener(v -> + chaptersFragment.show(getChildFragmentManager(), ChaptersFragment.TAG)); + butPrevChapter.setOnClickListener(v -> seekToPrevChapter()); + butNextChapter.setOnClickListener(v -> seekToNextChapter()); + return root; } @@ -80,6 +121,7 @@ public class CoverFragment extends Fragment { disposable = Maybe.<Playable>create(emitter -> { Playable media = controller.getMedia(); if (media != null) { + ChapterUtils.loadChapters(media, getContext()); emitter.onSuccess(media); } else { emitter.onComplete(); @@ -100,8 +142,73 @@ public class CoverFragment extends Fragment { + "\u00A0" + StringUtils.replace(StringUtils.stripToEmpty(pubDateStr), " ", "\u00A0")); txtvEpisodeTitle.setText(media.getEpisodeTitle()); - displayedChapterIndex = -2; // Force refresh - displayCoverImage(media.getPosition()); + displayedChapterIndex = -1; + refreshChapterData(ChapterUtils.getCurrentChapterIndex(media, media.getPosition())); //calls displayCoverImage + updateChapterControlVisibility(); + } + + private void updateChapterControlVisibility() { + if (media.getChapters() != null) { + boolean chapterControlVisible = media.getChapters().size() > 0; + int newVisibility = chapterControlVisible ? View.VISIBLE : View.GONE; + if (chapterControl.getVisibility() != newVisibility) { + chapterControl.setVisibility(newVisibility); + ObjectAnimator.ofFloat(chapterControl, + "alpha", + chapterControlVisible ? 0 : 1, + chapterControlVisible ? 1 : 0) + .start(); + } + } + } + + private void refreshChapterData(int chapterIndex) { + if (chapterIndex > -1) { + if (media.getPosition() > media.getDuration() || chapterIndex >= media.getChapters().size() - 1) { + displayedChapterIndex = media.getChapters().size() - 1; + butNextChapter.setVisibility(View.INVISIBLE); + } else { + displayedChapterIndex = chapterIndex; + butNextChapter.setVisibility(View.VISIBLE); + } + } + + displayCoverImage(); + } + + private Chapter getCurrentChapter() { + if (media == null || media.getChapters() == null || displayedChapterIndex == -1) { + return null; + } + return media.getChapters().get(displayedChapterIndex); + } + + private void seekToPrevChapter() { + Chapter curr = getCurrentChapter(); + + if (controller == null || curr == null || displayedChapterIndex == -1) { + return; + } + + if (displayedChapterIndex < 1) { + controller.seekTo(0); + } else if ((controller.getPosition() - 10000 * controller.getCurrentPlaybackSpeedMultiplier()) + < curr.getStart()) { + refreshChapterData(displayedChapterIndex - 1); + controller.seekToChapter(media.getChapters().get(displayedChapterIndex)); + } else { + controller.seekToChapter(curr); + } + } + + private void seekToNextChapter() { + if (controller == null || media == null || media.getChapters() == null + || displayedChapterIndex == -1 || displayedChapterIndex + 1 >= media.getChapters().size()) { + return; + } + + refreshChapterData(displayedChapterIndex + 1); + controller.seekToChapter(media.getChapters().get(displayedChapterIndex)); } @Override @@ -139,22 +246,18 @@ public class CoverFragment extends Fragment { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(PlaybackPositionEvent event) { - if (media == null) { - return; + int newChapterIndex = ChapterUtils.getCurrentChapterIndex(media, event.getPosition()); + if (newChapterIndex > -1 && newChapterIndex != displayedChapterIndex) { + refreshChapterData(newChapterIndex); } - displayCoverImage(event.getPosition()); } - private void displayCoverImage(int position) { - int chapter = ChapterUtils.getCurrentChapterIndex(media, position); - if (chapter != displayedChapterIndex) { - displayedChapterIndex = chapter; - - RequestOptions options = new RequestOptions() - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .dontAnimate() - .transforms(new FitCenter(), - new RoundedCorners((int) (16 * getResources().getDisplayMetrics().density))); + private void displayCoverImage() { + RequestOptions options = new RequestOptions() + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .dontAnimate() + .transforms(new FitCenter(), + new RoundedCorners((int) (16 * getResources().getDisplayMetrics().density))); RequestBuilder<Drawable> cover = Glide.with(this) .load(media.getImageLocation()) @@ -163,16 +266,16 @@ public class CoverFragment extends Fragment { .apply(options)) .apply(options); - if (chapter == -1 || TextUtils.isEmpty(media.getChapters().get(chapter).getImageUrl())) { - cover.into(imgvCover); - } else { - Glide.with(this) - .load(EmbeddedChapterImage.getModelFor(media, chapter)) - .apply(options) - .thumbnail(cover) - .error(cover) - .into(imgvCover); - } + if (displayedChapterIndex == -1 || media == null || media.getChapters() == null + || TextUtils.isEmpty(media.getChapters().get(displayedChapterIndex).getImageUrl())) { + cover.into(imgvCover); + } else { + Glide.with(this) + .load(EmbeddedChapterImage.getModelFor(media, displayedChapterIndex)) + .apply(options) + .thumbnail(cover) + .error(cover) + .into(imgvCover); } } @@ -196,6 +299,10 @@ public class CoverFragment extends Fragment { LinearLayout.LayoutParams textParams = (LinearLayout.LayoutParams) textContainer.getLayoutParams(); double ratio = (float) newConfig.screenHeightDp / (float) newConfig.screenWidthDp; + boolean spacerVisible = true; + ViewGroup detailsParent = (ViewGroup) getView(); + int detailsWidth = ViewGroup.LayoutParams.MATCH_PARENT; + if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { double percentageWidth = 0.8; if (ratio <= SIXTEEN_BY_NINE) { @@ -217,6 +324,26 @@ public class CoverFragment extends Fragment { textParams.weight = 1; imgvCover.setLayoutParams(params); } + + spacerVisible = false; + detailsParent = textContainer; + detailsWidth = ViewGroup.LayoutParams.WRAP_CONTENT; + } + + if (displayedChapterIndex == -1) { + detailsWidth = ViewGroup.LayoutParams.WRAP_CONTENT; + } + + spacer.setVisibility(spacerVisible ? View.VISIBLE : View.GONE); + counterweight.setVisibility(spacerVisible ? View.VISIBLE : View.GONE); + LinearLayout.LayoutParams wrapHeight = + new LinearLayout.LayoutParams(detailsWidth, ViewGroup.LayoutParams.WRAP_CONTENT); + episodeDetails.setLayoutParams(wrapHeight); + getView().findViewById(R.id.vertical_divider).setVisibility(spacerVisible ? View.GONE : View.VISIBLE); + + if (episodeDetails.getParent() != detailsParent) { + ((ViewGroup) episodeDetails.getParent()).removeView(episodeDetails); + detailsParent.addView(episodeDetails); } } |