From f57cf0c31788962300413a97eefdf746476e2177 Mon Sep 17 00:00:00 2001 From: Tony Tam <149837+tonytamsf@users.noreply.github.com> Date: Sun, 14 Feb 2021 03:18:27 -0800 Subject: [PATCH] New preference to show the remaining time in the 'queue' and podcast episode view (#4880) --- .../activity/MediaplayerActivity.java | 10 ++---- .../fragment/AudioPlayerFragment.java | 24 +++++++++----- .../UserInterfacePreferencesFragment.java | 16 +++++++-- .../viewholder/EpisodeItemViewHolder.java | 33 +++++++++++++++---- .../res/xml/preferences_user_interface.xml | 6 ++++ .../core/preferences/UserPreferences.java | 18 ++++++++++ core/src/main/res/values/strings.xml | 2 ++ 7 files changed, 86 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index a9749bab6..76359ddc0 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -65,7 +65,6 @@ import io.reactivex.schedulers.Schedulers; public abstract class MediaplayerActivity extends CastEnabledActivity implements OnSeekBarChangeListener { private static final String TAG = "MediaplayerActivity"; private static final String PREFS = "MediaPlayerActivityPreferences"; - private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; PlaybackController controller; @@ -465,8 +464,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if(controller == null || controller.getMedia() == null) { return false; } - SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); - showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); + showTimeLeft = UserPreferences.shouldShowRemainingTime(); onPositionObserverUpdate(); checkFavorite(); updatePlaybackSpeedButton(); @@ -489,7 +487,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements txtvSeek = findViewById(R.id.txtvSeek); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); - showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); + showTimeLeft = UserPreferences.shouldShowRemainingTime(); Log.d("timeleft", showTimeLeft ? "true" : "false"); txtvLength = findViewById(R.id.txtvLength); if (txtvLength != null) { @@ -513,9 +511,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements } txtvLength.setText(length); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft); - editor.apply(); + UserPreferences.setShowRemainTimeSetting(showTimeLeft); Log.d("timeleft on click", showTimeLeft ? "true" : "false"); }); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java index 671184625..8ff8866e0 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java @@ -1,8 +1,6 @@ package de.danoeh.antennapod.fragment; -import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -31,6 +29,7 @@ import de.danoeh.antennapod.activity.CastEnabledActivity; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.event.FavoritesEvent; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils; @@ -70,8 +69,7 @@ public class AudioPlayerFragment extends Fragment implements private static final int POS_DESCR = 1; private static final int POS_CHAPTERS = 2; private static final int NUM_CONTENT_FRAGMENTS = 3; - private static final String PREFS = "AudioPlayerFragmentPreferences"; - private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; + public static final String PREFS = "AudioPlayerFragmentPreferences"; private static final float EPSILON = 0.001f; PlaybackSpeedIndicatorView butPlaybackSpeed; @@ -217,16 +215,25 @@ public class AudioPlayerFragment extends Fragment implements IntentUtils.sendLocalBroadcast(getActivity(), PlaybackService.ACTION_SKIP_CURRENT_EPISODE)); } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onUnreadItemsUpdate(UnreadItemsUpdateEvent event) { + if (controller == null) { + return; + } + updatePosition(new PlaybackPositionEvent(controller.getPosition(), + controller.getDuration())); + } + private void setupLengthTextView() { - SharedPreferences prefs = getContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE); - showTimeLeft = prefs.getBoolean(PREF_SHOW_TIME_LEFT, false); + showTimeLeft = UserPreferences.shouldShowRemainingTime(); txtvLength.setOnClickListener(v -> { if (controller == null) { return; } showTimeLeft = !showTimeLeft; - prefs.edit().putBoolean(PREF_SHOW_TIME_LEFT, showTimeLeft).apply(); - updatePosition(new PlaybackPositionEvent(controller.getPosition(), controller.getDuration())); + UserPreferences.setShowRemainTimeSetting(showTimeLeft); + updatePosition(new PlaybackPositionEvent(controller.getPosition(), + controller.getDuration())); }); } @@ -439,6 +446,7 @@ public class AudioPlayerFragment extends Fragment implements return; } txtvPosition.setText(Converter.getDurationStringLong(currentPosition)); + showTimeLeft = UserPreferences.shouldShowRemainingTime(); if (showTimeLeft) { txtvLength.setText("-" + Converter.getDurationStringLong(remainingTime)); } else { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index 689a72ba7..4d1b79965 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -9,11 +9,14 @@ import androidx.preference.PreferenceFragmentCompat; import android.widget.ListView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.core.event.PlayerStatusEvent; +import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog; import de.danoeh.antennapod.dialog.FeedSortDialog; import de.danoeh.antennapod.fragment.NavDrawerFragment; import org.apache.commons.lang3.ArrayUtils; +import org.greenrobot.eventbus.EventBus; import java.util.List; @@ -37,8 +40,17 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { (preference, newValue) -> { getActivity().recreate(); return true; - } - ); + }); + + findPreference(UserPreferences.PREF_SHOW_TIME_LEFT) + .setOnPreferenceChangeListener( + (preference, newValue) -> { + UserPreferences.setShowRemainTimeSetting((Boolean) newValue); + EventBus.getDefault().post(new UnreadItemsUpdateEvent()); + EventBus.getDefault().post(new PlayerStatusEvent()); + return true; + }); + findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS) .setOnPreferenceClickListener(preference -> { showDrawerPreferencesDialog(); diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java index 5e49783d9..0e84afe04 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java @@ -13,9 +13,7 @@ import android.widget.TextView; import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView; - import com.joanzapata.iconify.Iconify; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.CoverLoader; @@ -25,7 +23,9 @@ import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.feed.util.ImageResourceUtils; +import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadRequest; +import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.DateUtils; @@ -132,9 +132,6 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { private void bind(FeedMedia media) { isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.GONE); duration.setVisibility(media.getDuration() > 0 ? View.VISIBLE : View.GONE); - duration.setText(Converter.getDurationStringLong(media.getDuration())); - duration.setContentDescription(activity.getString(R.string.chapter_duration, - Converter.getDurationStringLocalized(activity, media.getDuration()))); if (media.isCurrentlyPlaying()) { itemView.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.currently_playing_background)); @@ -152,6 +149,9 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { secondaryActionProgress.setPercentage(0, item); // Animate X% -> 0% } + duration.setText(Converter.getDurationStringLong(media.getDuration())); + duration.setContentDescription(activity.getString(R.string.chapter_duration, + Converter.getDurationStringLocalized(activity, media.getDuration()))); if (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS) { int progress = (int) (100.0 * media.getPosition() / media.getDuration()); progressBar.setProgress(progress); @@ -160,6 +160,11 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { Converter.getDurationStringLocalized(activity, media.getPosition()))); progressBar.setVisibility(View.VISIBLE); position.setVisibility(View.VISIBLE); + if (UserPreferences.shouldShowRemainingTime()) { + duration.setText("-" + Converter.getDurationStringLong(media.getDuration() - media.getPosition())); + duration.setContentDescription(activity.getString(R.string.chapter_duration, + Converter.getDurationStringLocalized(activity, (media.getDuration() - media.getPosition())))); + } } else { progressBar.setVisibility(View.GONE); position.setVisibility(View.GONE); @@ -186,6 +191,22 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { } } + private void updateDuration(PlaybackPositionEvent event) { + int currentPosition = event.getPosition(); + int timeDuration = event.getDuration(); + int remainingTime = event.getDuration() - event.getPosition(); + Log.d(TAG, "currentPosition " + Converter.getDurationStringLong(currentPosition)); + if (currentPosition == PlaybackService.INVALID_TIME || timeDuration == PlaybackService.INVALID_TIME) { + Log.w(TAG, "Could not react to position observer update because of invalid time"); + return; + } + if (UserPreferences.shouldShowRemainingTime()) { + duration.setText("-" + Converter.getDurationStringLong(remainingTime)); + } else { + duration.setText(Converter.getDurationStringLong(timeDuration)); + } + } + public FeedItem getFeedItem() { return item; } @@ -197,7 +218,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder { public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); position.setText(Converter.getDurationStringLong(event.getPosition())); - duration.setText(Converter.getDurationStringLong(event.getDuration())); + updateDuration(event); duration.setVisibility(View.VISIBLE); // Even if the duration was previously unknown, it is now known } diff --git a/app/src/main/res/xml/preferences_user_interface.xml b/app/src/main/res/xml/preferences_user_interface.xml index a3cb53307..f8e80cdff 100644 --- a/app/src/main/res/xml/preferences_user_interface.xml +++ b/app/src/main/res/xml/preferences_user_interface.xml @@ -21,6 +21,12 @@ android:summary="@string/pref_episode_cover_summary" android:defaultValue="true" android:enabled="true"/> + Total number of downloaded episodes cached on the device. Automatic download will be suspended if this number is reached. Use Episode Cover Use the episode specific cover whenever available. If unchecked, the app will always use the podcast cover image. + Show Remaining Time + Display remaining time of episodes when checked. If unchecked, display total duration of episodes. Use system theme Light Dark