diff options
Diffstat (limited to 'ui')
3 files changed, 139 insertions, 2 deletions
diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml index 060d2b29f..6ff5154d8 100644 --- a/ui/i18n/src/main/res/values/strings.xml +++ b/ui/i18n/src/main/res/values/strings.xml @@ -723,11 +723,29 @@ <string name="statistics_episodes_on_device">Episodes on the device:</string> <string name="statistics_space_used">Space used:</string> <string name="statistics_episodes_started_total">Episodes started/total:</string> + <string name="statistics_expected_next_episode">Expected next episode:</string> + <string name="statistics_expected_next_episode_any_day">Any day now</string> + <string name="statistics_expected_next_episode_unknown">Unknown</string> <string name="statistics_view_all">View for all podcasts ยป</string> <string name="wait_icon" translatable="false">{fa-spinner}</string> <string name="edit_url_menu">Edit feed URL</string> <string name="edit_url_confirmation_msg">Changing the RSS address can easily break the playback state and episode listings of the podcast. We do NOT recommend changing it and will NOT provide support if anything goes wrong. This cannot be undone. The broken subscription CANNOT be repaired by simply changing the address back. We suggest creating a backup before continuing.</string> + <!-- Podcast release schedules --> + <string name="release_schedule_daily">daily</string> + <string name="release_schedule_weekdays">on weekdays</string> + <string name="release_schedule_weekly">weekly</string> + <string name="release_schedule_biweekly">every two weeks</string> + <string name="release_schedule_monthly">monthly</string> + + <string name="release_schedule_monday">Mon</string> + <string name="release_schedule_tuesday">Tue</string> + <string name="release_schedule_wednesday">Wed</string> + <string name="release_schedule_thursday">Thu</string> + <string name="release_schedule_friday">Fri</string> + <string name="release_schedule_saturday">Sat</string> + <string name="release_schedule_sunday">Sun</string> + <!-- AntennaPodSP --> <string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps…</string> diff --git a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java index 1aeeb8fa9..a7916ac5a 100644 --- a/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java +++ b/ui/statistics/src/main/java/de/danoeh/antennapod/ui/statistics/feed/FeedStatisticsFragment.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.ui.statistics.feed; import android.os.Bundle; import android.text.format.Formatter; +import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,13 +12,23 @@ import androidx.fragment.app.Fragment; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.StatisticsItem; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.DateFormatter; +import de.danoeh.antennapod.core.util.ReleaseScheduleGuesser; +import de.danoeh.antennapod.model.feed.FeedItem; +import de.danoeh.antennapod.model.feed.FeedItemFilter; +import de.danoeh.antennapod.model.feed.SortOrder; +import de.danoeh.antennapod.ui.statistics.R; import de.danoeh.antennapod.ui.statistics.databinding.FeedStatisticsBinding; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import java.util.ArrayList; +import java.util.Calendar; import java.util.Collections; +import java.util.Date; +import java.util.List; import java.util.Locale; public class FeedStatisticsFragment extends Fragment { @@ -66,7 +77,17 @@ public class FeedStatisticsFragment extends Fragment { for (StatisticsItem statisticsItem : statisticsData.feedTime) { if (statisticsItem.feed.getId() == feedId) { - return statisticsItem; + List<FeedItem> items = DBReader.getFeedItemList(statisticsItem.feed, + FeedItemFilter.unfiltered(), SortOrder.DATE_OLD_NEW); + List<Date> dates = new ArrayList<>(); + for (FeedItem item : items) { + dates.add(item.getPubDate()); + } + ReleaseScheduleGuesser.Guess guess = null; + if (dates.size() > 1) { + guess = ReleaseScheduleGuesser.performGuess(dates); + } + return new Pair<>(statisticsItem, guess); } } return null; @@ -76,13 +97,80 @@ public class FeedStatisticsFragment extends Fragment { .subscribe(this::showStats, Throwable::printStackTrace); } - private void showStats(StatisticsItem s) { + private String getReadableDay(int day) { + switch (day) { + case Calendar.MONDAY: + return getString(R.string.release_schedule_monday); + case Calendar.TUESDAY: + return getString(R.string.release_schedule_tuesday); + case Calendar.WEDNESDAY: + return getString(R.string.release_schedule_wednesday); + case Calendar.THURSDAY: + return getString(R.string.release_schedule_thursday); + case Calendar.FRIDAY: + return getString(R.string.release_schedule_friday); + case Calendar.SATURDAY: + return getString(R.string.release_schedule_saturday); + case Calendar.SUNDAY: + return getString(R.string.release_schedule_sunday); + default: + return "error"; + } + } + + private String getReadableSchedule(ReleaseScheduleGuesser.Guess guess) { + switch (guess.schedule) { + case DAILY: + return getString(R.string.release_schedule_daily); + case WEEKDAYS: + return getString(R.string.release_schedule_weekdays); + case WEEKLY: + return getString(R.string.release_schedule_weekly) + ", " + getReadableDay(guess.days.get(0)); + case BIWEEKLY: + return getString(R.string.release_schedule_biweekly) + ", " + getReadableDay(guess.days.get(0)); + case MONTHLY: + return getString(R.string.release_schedule_monthly); + case FOURWEEKLY: + return getString(R.string.release_schedule_monthly) + ", " + getReadableDay(guess.days.get(0)); + case SPECIFIC_DAYS: + StringBuilder days = new StringBuilder(); + for (int i = 0; i < guess.days.size(); i++) { + if (i != 0) { + days.append(", "); + } + days.append(getReadableDay(guess.days.get(i))); + } + return days.toString(); + default: + return getString(R.string.statistics_expected_next_episode_unknown); + } + } + + private void showStats(Pair<StatisticsItem, ReleaseScheduleGuesser.Guess> p) { + StatisticsItem s = p.first; viewBinding.startedTotalLabel.setText(String.format(Locale.getDefault(), "%d / %d", s.episodesStarted, s.episodes)); viewBinding.timePlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayed)); viewBinding.totalDurationLabel.setText(Converter.shortLocalizedDuration(getContext(), s.time)); viewBinding.onDeviceLabel.setText(String.format(Locale.getDefault(), "%d", s.episodesDownloadCount)); viewBinding.spaceUsedLabel.setText(Formatter.formatShortFileSize(getContext(), s.totalDownloadSize)); + + ReleaseScheduleGuesser.Guess guess = p.second; + if (!s.feed.getPreferences().getKeepUpdated()) { + viewBinding.expectedNextEpisodeLabel.setText(R.string.updates_disabled_label); + } else if (guess == null || guess.nextExpectedDate.getTime() <= new Date().getTime() - 7 * 24 * 3600000L) { + // More than 30 days delayed + viewBinding.expectedNextEpisodeLabel.setText(R.string.statistics_expected_next_episode_unknown); + } else { + String text = DateFormatter.formatAbbrev(getContext(), guess.nextExpectedDate); + if (guess.nextExpectedDate.getTime() <= new Date().getTime()) { + text = getString(R.string.statistics_expected_next_episode_any_day); + } + if (guess.schedule != ReleaseScheduleGuesser.Schedule.UNKNOWN) { + text += " (" + getReadableSchedule(guess) + ")"; + } + viewBinding.expectedNextEpisodeLabel.setText(text); + } } @Override diff --git a/ui/statistics/src/main/res/layout/feed_statistics.xml b/ui/statistics/src/main/res/layout/feed_statistics.xml index 6b9a7fa4c..78630758f 100644 --- a/ui/statistics/src/main/res/layout/feed_statistics.xml +++ b/ui/statistics/src/main/res/layout/feed_statistics.xml @@ -11,12 +11,14 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:text="@string/statistics_episodes_started_total" /> <com.joanzapata.iconify.widget.IconTextView android:id="@+id/startedTotalLabel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:text="@string/wait_icon" @@ -29,12 +31,14 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:text="@string/statistics_time_played" /> <com.joanzapata.iconify.widget.IconTextView android:id="@+id/timePlayedLabel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:text="@string/wait_icon" @@ -48,12 +52,14 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:text="@string/statistics_total_duration" /> <com.joanzapata.iconify.widget.IconTextView android:id="@+id/totalDurationLabel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:text="@string/wait_icon" @@ -66,12 +72,14 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:text="@string/statistics_episodes_on_device" /> <com.joanzapata.iconify.widget.IconTextView android:id="@+id/onDeviceLabel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:text="@string/wait_icon" @@ -84,12 +92,14 @@ <TextView android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:text="@string/statistics_space_used" /> <com.joanzapata.iconify.widget.IconTextView android:id="@+id/spaceUsedLabel" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_weight="1" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" android:text="@string/wait_icon" @@ -97,4 +107,25 @@ </TableRow> + <TableRow> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="@string/statistics_expected_next_episode" /> + + <com.joanzapata.iconify.widget.IconTextView + android:id="@+id/expectedNextEpisodeLabel" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_marginLeft="8dp" + android:layout_marginStart="8dp" + android:lines="2" + android:text="@string/wait_icon" + tools:text="Jan 1st (weekly)" /> + + </TableRow> + </TableLayout> |