summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java30
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/YearStatisticsListAdapter.java121
-rw-r--r--app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadStatisticsFragment.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java197
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java42
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/SubscriptionStatisticsFragment.java279
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/SwipePreferencesFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/YearsStatisticsFragment.java87
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/LineChartView.java138
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java2
-rw-r--r--app/src/main/res/layout/feed_statistics.xml18
-rw-r--r--app/src/main/res/layout/statistics_filter_dialog.xml95
-rw-r--r--app/src/main/res/layout/statistics_listitem_linechart.xml22
-rw-r--r--app/src/main/res/layout/statistics_listitem_total.xml36
-rw-r--r--app/src/main/res/layout/statistics_mode_select_dialog.xml25
-rw-r--r--app/src/main/res/layout/statistics_year_listitem.xml32
-rw-r--r--app/src/main/res/menu/mediaplayer.xml8
-rw-r--r--app/src/main/res/menu/statistics.xml9
-rw-r--r--app/src/main/res/xml/preferences.xml5
-rw-r--r--app/src/main/res/xml/preferences_playback.xml7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java63
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java50
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java71
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java49
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java9
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/StatisticsItem.java16
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java2
-rw-r--r--core/src/main/res/values/arrays.xml22
-rw-r--r--core/src/main/res/values/strings.xml25
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java2
-rw-r--r--event/src/main/java/de/danoeh/antennapod/event/FavoritesEvent.java21
-rw-r--r--event/src/main/java/de/danoeh/antennapod/event/FeedItemEvent.java22
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java4
-rw-r--r--net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java73
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java1
-rw-r--r--parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java5
-rw-r--r--parser/media/src/main/java/de/danoeh/antennapod/parser/media/id3/ID3Chapter.java5
-rw-r--r--parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReaderException.java8
-rw-r--r--playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java6
-rw-r--r--playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlayerStatus.java4
-rw-r--r--playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastEnabledActivity.java1
-rw-r--r--playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java5
69 files changed, 1001 insertions, 820 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
index 6b294244a..6b85f3bf8 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/feedgenerator/Rss2Generator.java
@@ -127,15 +127,9 @@ public class Rss2Generator implements FeedGenerator {
}
}
- writeAdditionalAttributes(xml);
-
xml.endTag(null, "channel");
xml.endTag(null, "rss");
xml.endDocument();
}
-
- protected void writeAdditionalAttributes(XmlSerializer xml) throws IOException {
-
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index 1fc16ab32..05a514c76 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -4,7 +4,6 @@ import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -131,12 +130,6 @@ public class PreferenceActivity extends AppCompatActivity implements SearchPrefe
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
index 4ff2a5775..954a6c2f6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -91,6 +91,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
private PlaybackController controller;
private boolean showTimeLeft = false;
private boolean isFavorite = false;
+ private boolean switchToAudioOnly = false;
private Disposable disposable;
private float prog;
@@ -119,6 +120,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
+ switchToAudioOnly = false;
if (PlaybackService.isCasting()) {
Intent intent = PlaybackService.getPlayerActivityIntent(this);
if (!intent.getComponent().getClassName().equals(VideoplayerActivity.class.getName())) {
@@ -149,8 +151,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
@Override
public void onUserLeaveHint() {
- if (!PictureInPictureUtil.isInPictureInPictureMode(this) && UserPreferences.getVideoBackgroundBehavior()
- == UserPreferences.VideoBackgroundBehavior.PICTURE_IN_PICTURE) {
+ if (!PictureInPictureUtil.isInPictureInPictureMode(this)) {
compatEnterPictureInPicture();
}
}
@@ -480,9 +481,7 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "Videosurface was destroyed");
videoSurfaceCreated = false;
- if (controller != null && !destroyingDueToReload
- && UserPreferences.getVideoBackgroundBehavior()
- != UserPreferences.VideoBackgroundBehavior.CONTINUE_PLAYING) {
+ if (controller != null && !destroyingDueToReload && !switchToAudioOnly) {
controller.notifyVideoSurfaceAbandoned();
}
}
@@ -590,17 +589,16 @@ public class VideoplayerActivity extends CastEnabledActivity implements SeekBar.
menu.findItem(R.id.set_sleeptimer_item).setVisible(!controller.sleepTimerActive());
menu.findItem(R.id.disable_sleeptimer_item).setVisible(controller.sleepTimerActive());
- if (PictureInPictureUtil.supportsPictureInPicture(this)) {
- menu.findItem(R.id.player_go_to_picture_in_picture).setVisible(true);
- }
+ menu.findItem(R.id.player_switch_to_audio_only).setVisible(true);
menu.findItem(R.id.audio_controls).setIcon(R.drawable.ic_sliders);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.player_go_to_picture_in_picture) {
- compatEnterPictureInPicture();
+ if (item.getItemId() == R.id.player_switch_to_audio_only) {
+ switchToAudioOnly = true;
+ finish();
return true;
}
if (item.getItemId() == android.R.id.home) {
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
index 2d2fd643b..7245ce675 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/WidgetConfigActivity.java
@@ -47,7 +47,7 @@ public class WidgetConfigActivity extends AppCompatActivity {
opacityTextView = findViewById(R.id.widget_opacity_textView);
opacitySeekBar = findViewById(R.id.widget_opacity_seekBar);
widgetPreview = findViewById(R.id.widgetLayout);
- findViewById(R.id.butConfirm).setOnClickListener(this::confirmCreateWidget);
+ findViewById(R.id.butConfirm).setOnClickListener(v -> confirmCreateWidget());
opacitySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
@@ -94,7 +94,7 @@ public class WidgetConfigActivity extends AppCompatActivity {
widgetPreview.findViewById(R.id.butRew).setVisibility(ckRewind.isChecked() ? View.VISIBLE : View.GONE);
}
- private void confirmCreateWidget(View v) {
+ private void confirmCreateWidget() {
int backgroundColor = getColorWithAlpha(PlayerWidget.DEFAULT_COLOR, opacitySeekBar.getProgress());
SharedPreferences prefs = getSharedPreferences(PlayerWidget.PREFS_NAME, MODE_PRIVATE);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
index 26674b2b2..e566836e4 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/PlaybackStatisticsListAdapter.java
@@ -2,15 +2,15 @@ package de.danoeh.antennapod.adapter;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
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.fragment.FeedStatisticsDialogFragment;
import de.danoeh.antennapod.view.PieChartView;
+import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import java.util.Locale;
/**
* Adapter for the playback statistics list.
@@ -18,26 +18,30 @@ import java.util.List;
public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
private final Fragment fragment;
- boolean countAll = true;
+ private long timeFilterFrom = 0;
+ private long timeFilterTo = Long.MAX_VALUE;
+ private boolean includeMarkedAsPlayed = false;
public PlaybackStatisticsListAdapter(Fragment fragment) {
super(fragment.getContext());
this.fragment = fragment;
}
- public void setCountAll(boolean countAll) {
- this.countAll = countAll;
+ public void setTimeFilter(boolean includeMarkedAsPlayed, long timeFilterFrom, long timeFilterTo) {
+ this.includeMarkedAsPlayed = includeMarkedAsPlayed;
+ this.timeFilterFrom = timeFilterFrom;
+ this.timeFilterTo = timeFilterTo;
}
@Override
String getHeaderCaption() {
- long usageCounting = UserPreferences.getUsageCountingDateMillis();
- if (usageCounting > 0) {
- String date = DateFormatter.formatAbbrev(context, new Date(usageCounting));
- return context.getString(R.string.statistics_counting_since, date);
- } else {
- return context.getString(R.string.total_time_listened_to_podcasts);
+ if (includeMarkedAsPlayed) {
+ return context.getString(R.string.statistics_counting_total);
}
+ SimpleDateFormat dateFormat = new SimpleDateFormat("MMM yyyy", Locale.getDefault());
+ String dateFrom = dateFormat.format(new Date(timeFilterFrom));
+ String dateTo = dateFormat.format(new Date(timeFilterTo));
+ return context.getString(R.string.statistics_counting_range, dateFrom, dateTo);
}
@Override
@@ -50,14 +54,14 @@ public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
float[] dataValues = new float[statisticsData.size()];
for (int i = 0; i < statisticsData.size(); i++) {
StatisticsItem item = statisticsData.get(i);
- dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
+ dataValues[i] = item.timePlayed;
}
return new PieChartView.PieChartData(dataValues);
}
@Override
void onBindFeedViewHolder(StatisticsHolder holder, StatisticsItem statsItem) {
- long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
+ long time = statsItem.timePlayed;
holder.value.setText(Converter.shortLocalizedDuration(context, time));
holder.itemView.setOnClickListener(v -> {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
index 23b5cfdce..f0451e974 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java
@@ -48,10 +48,7 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
if (viewType == TYPE_HEADER) {
- View view = inflater.inflate(R.layout.statistics_listitem_total, parent, false);
- TextView totalText = view.findViewById(R.id.total_description);
- totalText.setText(getHeaderCaption());
- return new HeaderHolder(view);
+ return new HeaderHolder(inflater.inflate(R.layout.statistics_listitem_total, parent, false));
}
return new StatisticsHolder(inflater.inflate(R.layout.statistics_listitem, parent, false));
}
@@ -62,6 +59,7 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
HeaderHolder holder = (HeaderHolder) h;
holder.pieChart.setData(pieChartData);
holder.totalTime.setText(getHeaderValue());
+ holder.totalText.setText(getHeaderCaption());
} else {
StatisticsHolder holder = (StatisticsHolder) h;
StatisticsItem statsItem = statisticsData.get(position - 1);
@@ -90,11 +88,13 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
static class HeaderHolder extends RecyclerView.ViewHolder {
TextView totalTime;
PieChartView pieChart;
+ TextView totalText;
HeaderHolder(View itemView) {
super(itemView);
totalTime = itemView.findViewById(R.id.total_time);
pieChart = itemView.findViewById(R.id.pie_chart);
+ totalText = itemView.findViewById(R.id.total_description);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/YearStatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/YearStatisticsListAdapter.java
new file mode 100644
index 000000000..ad20574b3
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/YearStatisticsListAdapter.java
@@ -0,0 +1,121 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.view.LineChartView;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Adapter for the yearly playback statistics list.
+ */
+public class YearStatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ private static final int TYPE_HEADER = 0;
+ private static final int TYPE_FEED = 1;
+ final Context context;
+ private List<DBReader.MonthlyStatisticsItem> statisticsData = new ArrayList<>();
+ LineChartView.LineChartData lineChartData;
+
+ public YearStatisticsListAdapter(Context context) {
+ this.context = context;
+ }
+
+ @Override
+ public int getItemCount() {
+ return statisticsData.size() + 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return position == 0 ? TYPE_HEADER : TYPE_FEED;
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ if (viewType == TYPE_HEADER) {
+ return new HeaderHolder(inflater.inflate(R.layout.statistics_listitem_linechart, parent, false));
+ }
+ return new StatisticsHolder(inflater.inflate(R.layout.statistics_year_listitem, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
+ if (getItemViewType(position) == TYPE_HEADER) {
+ HeaderHolder holder = (HeaderHolder) h;
+ holder.lineChart.setData(lineChartData);
+ } else {
+ StatisticsHolder holder = (StatisticsHolder) h;
+ DBReader.MonthlyStatisticsItem statsItem = statisticsData.get(position - 1);
+ holder.year.setText(String.format(Locale.getDefault(), "%d ", statsItem.year));
+ holder.hours.setText(String.format(Locale.getDefault(), "%.1f ", statsItem.timePlayed / 3600000.0f)
+ + context.getString(R.string.time_hours));
+ }
+ }
+
+ public void update(List<DBReader.MonthlyStatisticsItem> statistics) {
+ int lastYear = statistics.size() > 0 ? statistics.get(0).year : 0;
+ int lastDataPoint = statistics.size() > 0 ? (statistics.get(0).month - 1) + lastYear * 12 : 0;
+ long yearSum = 0;
+ statisticsData.clear();
+ LongList lineChartValues = new LongList();
+ LongList lineChartHorizontalLines = new LongList();
+ for (DBReader.MonthlyStatisticsItem statistic : statistics) {
+ if (statistic.year != lastYear) {
+ DBReader.MonthlyStatisticsItem yearAggregate = new DBReader.MonthlyStatisticsItem();
+ yearAggregate.year = lastYear;
+ yearAggregate.timePlayed = yearSum;
+ statisticsData.add(yearAggregate);
+ yearSum = 0;
+ lastYear = statistic.year;
+ lineChartHorizontalLines.add(lineChartValues.size());
+ }
+ yearSum += statistic.timePlayed;
+ while (lastDataPoint + 1 < (statistic.month - 1) + statistic.year * 12) {
+ lineChartValues.add(0); // Compensate for months without playback
+ lastDataPoint++;
+ }
+ lineChartValues.add(statistic.timePlayed);
+ lastDataPoint = (statistic.month - 1) + statistic.year * 12;
+ }
+ DBReader.MonthlyStatisticsItem yearAggregate = new DBReader.MonthlyStatisticsItem();
+ yearAggregate.year = lastYear;
+ yearAggregate.timePlayed = yearSum;
+ statisticsData.add(yearAggregate);
+ Collections.reverse(statisticsData);
+ lineChartData = new LineChartView.LineChartData(lineChartValues.toArray(), lineChartHorizontalLines.toArray());
+ notifyDataSetChanged();
+ }
+
+ static class HeaderHolder extends RecyclerView.ViewHolder {
+ LineChartView lineChart;
+
+ HeaderHolder(View itemView) {
+ super(itemView);
+ lineChart = itemView.findViewById(R.id.lineChart);
+ }
+ }
+
+ static class StatisticsHolder extends RecyclerView.ViewHolder {
+ TextView year;
+ TextView hours;
+
+ StatisticsHolder(View itemView) {
+ super(itemView);
+ year = itemView.findViewById(R.id.yearLabel);
+ hours = itemView.findViewById(R.id.hoursLabel);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
index 767845cb4..c8096e9c5 100644
--- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
+++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java
@@ -39,10 +39,6 @@ public class PodcastSearchResult {
this.author = author;
}
- private PodcastSearchResult(String title, @Nullable String imageUrl, @Nullable String feedUrl) {
- this(title, imageUrl, feedUrl, "");
- }
-
public static PodcastSearchResult dummy() {
return new PodcastSearchResult("", "", "", "");
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java
index e85c2a386..d6ab34855 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedStatisticsFragment.java
@@ -17,7 +17,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import java.util.List;
+import java.util.Collections;
import java.util.Locale;
public class FeedStatisticsFragment extends Fragment {
@@ -60,8 +60,11 @@ public class FeedStatisticsFragment extends Fragment {
private void loadStatistics() {
disposable =
Observable.fromCallable(() -> {
- List<StatisticsItem> statisticsData = DBReader.getStatistics();
- for (StatisticsItem statisticsItem : statisticsData) {
+ DBReader.StatisticsResult statisticsData = DBReader.getStatistics(true, 0, Long.MAX_VALUE);
+ Collections.sort(statisticsData.feedTime, (item1, item2) ->
+ Long.compare(item2.timePlayed, item1.timePlayed));
+
+ for (StatisticsItem statisticsItem : statisticsData.feedTime) {
if (statisticsItem.feed.getId() == feedId) {
return statisticsItem;
}
@@ -77,7 +80,6 @@ public class FeedStatisticsFragment extends Fragment {
viewBinding.startedTotalLabel.setText(String.format(Locale.getDefault(), "%d / %d",
s.episodesStarted, s.episodes));
viewBinding.timePlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayed));
- viewBinding.durationPlayedLabel.setText(Converter.shortLocalizedDuration(getContext(), s.timePlayedCountAll));
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));
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 715786921..7d9814998 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -283,7 +283,7 @@ public class ItemFragment extends Fragment {
if (item.getPubDate() != null) {
String pubDateStr = DateFormatter.formatAbbrev(getActivity(), item.getPubDate());
txtvPublished.setText(pubDateStr);
- txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(getContext(), item.getPubDate()));
+ txtvPublished.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate()));
}
RequestOptions options = new RequestOptions()
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index 6526be005..1a3962de2 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -335,8 +335,8 @@ public class SearchFragment extends Fragment {
return new Pair<>(Collections.emptyList(), Collections.emptyList());
}
long feed = getArguments().getLong(ARG_FEED);
- List<FeedItem> items = FeedSearcher.searchFeedItems(getContext(), query, feed);
- List<Feed> feeds = FeedSearcher.searchFeeds(getContext(), query);
+ List<FeedItem> items = FeedSearcher.searchFeedItems(query, feed);
+ List<Feed> feeds = FeedSearcher.searchFeeds(query);
return new Pair<>(items, feeds);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
index e3dfe8ade..9067b17a7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/actions/FeedMultiSelectActionHandler.java
@@ -8,8 +8,6 @@ import androidx.core.util.Consumer;
import com.google.android.material.snackbar.Snackbar;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -66,9 +64,6 @@ public class FeedMultiSelectActionHandler {
preferenceSwitchDialog.openDialog();
}
- private static final DecimalFormat SPEED_FORMAT =
- new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US));
-
private void playbackSpeedPrefHandler() {
PlaybackSpeedFeedSettingDialogBinding viewBinding =
PlaybackSpeedFeedSettingDialogBinding.inflate(activity.getLayoutInflater());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
index 62e2e30d1..655cd6ed4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -15,8 +15,6 @@ import de.danoeh.antennapod.net.sync.gpoddernet.model.GpodnetTag;
* Use the newInstance method of this class to create a new TagFragment.
*/
public class TagFragment extends PodcastListFragment {
-
- private static final String TAG = "TagFragment";
private static final int PODCAST_COUNT = 50;
private GpodnetTag tag;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadStatisticsFragment.java
index ff94cc20c..f8f489fc4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadStatisticsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/DownloadStatisticsFragment.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.fragment.preferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
@@ -16,14 +17,12 @@ import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadStatisticsListAdapter;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.StatisticsItem;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.util.Collections;
-import java.util.List;
/**
* Displays the 'download statistics' screen
@@ -36,14 +35,10 @@ public class DownloadStatisticsFragment extends Fragment {
private ProgressBar progressBar;
private DownloadStatisticsListAdapter listAdapter;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
@Nullable
@Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.statistics_activity, container, false);
downloadStatisticsList = root.findViewById(R.id.statistics_list);
progressBar = root.findViewById(R.id.progressBar);
@@ -59,6 +54,13 @@ public class DownloadStatisticsFragment extends Fragment {
refreshDownloadStatistics();
}
+ @Override
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.statistics_reset).setVisible(false);
+ menu.findItem(R.id.statistics_filter).setVisible(false);
+ }
+
private void refreshDownloadStatistics() {
progressBar.setVisibility(View.VISIBLE);
downloadStatisticsList.setVisibility(View.GONE);
@@ -72,15 +74,16 @@ public class DownloadStatisticsFragment extends Fragment {
disposable =
Observable.fromCallable(() -> {
- List<StatisticsItem> statisticsData = DBReader.getStatistics();
- Collections.sort(statisticsData, (item1, item2) ->
+ // Filters do not matter here
+ DBReader.StatisticsResult statisticsData = DBReader.getStatistics(false, 0, Long.MAX_VALUE);
+ Collections.sort(statisticsData.feedTime, (item1, item2) ->
Long.compare(item2.totalDownloadSize, item1.totalDownloadSize));
return statisticsData;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
- listAdapter.update(result);
+ listAdapter.update(result.feedTime);
progressBar.setVisibility(View.GONE);
downloadStatisticsList.setVisibility(View.VISIBLE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
index 5156de432..5bbc8f0a0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/ImportExportPreferencesFragment.java
@@ -31,7 +31,6 @@ import de.danoeh.antennapod.core.export.ExportWriter;
import de.danoeh.antennapod.core.export.favorites.FavoritesWriter;
import de.danoeh.antennapod.core.export.html.HtmlWriter;
import de.danoeh.antennapod.core.export.opml.OpmlWriter;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DatabaseExporter;
import io.reactivex.Completable;
import io.reactivex.Observable;
@@ -263,7 +262,6 @@ public class ImportExportPreferencesFragment extends PreferenceFragmentCompat {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {
showDatabaseImportSuccessDialog();
- UserPreferences.unsetUsageCountingDate();
progressDialog.dismiss();
}, this::showExportErrorDialog);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
index 891d3737b..e2c5036df 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java
@@ -29,7 +29,6 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_VIEW_FORUM = "prefViewForum";
private static final String PREF_SEND_BUG_REPORT = "prefSendBugReport";
private static final String PREF_CATEGORY_PROJECT = "project";
- private static final String STATISTICS = "statistics";
private static final String PREF_ABOUT = "prefAbout";
private static final String PREF_NOTIFICATION = "notifications";
private static final String PREF_CONTRIBUTE = "prefContribute";
@@ -106,14 +105,6 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat {
return true;
}
);
- findPreference(STATISTICS).setOnPreferenceClickListener(
- preference -> {
- getParentFragmentManager().beginTransaction()
- .replace(R.id.settingsContainer, new StatisticsFragment())
- .addToBackStack(getString(R.string.statistics_label)).commit();
- return true;
- }
- );
findPreference(PREF_DOCUMENTATION).setOnPreferenceClickListener(preference -> {
IntentUtils.openInBrowser(getContext(), "https://antennapod.org/documentation/");
return true;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
index 7fa2ed4d1..933a7d456 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java
@@ -13,7 +13,6 @@ import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.preferences.UsageStatistics;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil;
import de.danoeh.antennapod.dialog.SkipPreferenceDialog;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
import java.util.Map;
@@ -54,11 +53,6 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat {
SkipPreferenceDialog.showSkipPreference(activity, SkipPreferenceDialog.SkipDirection.SKIP_FORWARD, null);
return true;
});
- if (!PictureInPictureUtil.supportsPictureInPicture(activity)) {
- ListPreference behaviour = findPreference(UserPreferences.PREF_VIDEO_BEHAVIOR);
- behaviour.setEntries(R.array.video_background_behavior_options_without_pip);
- behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip);
- }
findPreference(PREF_PLAYBACK_PREFER_STREAMING).setOnPreferenceChangeListener((preference, newValue) -> {
// Update all visible lists to reflect new streaming action button
EventBus.getDefault().post(new UnreadItemsUpdateEvent());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java
deleted file mode 100644
index ba6164212..000000000
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackStatisticsFragment.java
+++ /dev/null
@@ -1,197 +0,0 @@
-package de.danoeh.antennapod.fragment.preferences;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ProgressBar;
-import android.widget.RadioButton;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.adapter.PlaybackStatisticsListAdapter;
-import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.StatisticsItem;
-import io.reactivex.Completable;
-import io.reactivex.Observable;
-import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.disposables.Disposable;
-import io.reactivex.schedulers.Schedulers;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Displays the 'playback statistics' screen
- */
-public class PlaybackStatisticsFragment extends Fragment {
- private static final String TAG = PlaybackStatisticsFragment.class.getSimpleName();
- private static final String PREF_NAME = "StatisticsActivityPrefs";
- private static final String PREF_COUNT_ALL = "countAll";
-
- private Disposable disposable;
- private RecyclerView feedStatisticsList;
- private ProgressBar progressBar;
- private PlaybackStatisticsListAdapter listAdapter;
- private boolean countAll = false;
- private SharedPreferences prefs;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- countAll = prefs.getBoolean(PREF_COUNT_ALL, false);
- setHasOptionsMenu(true);
- }
-
- @Nullable
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
- View root = inflater.inflate(R.layout.statistics_activity, container, false);
- feedStatisticsList = root.findViewById(R.id.statistics_list);
- progressBar = root.findViewById(R.id.progressBar);
- listAdapter = new PlaybackStatisticsListAdapter(this);
- listAdapter.setCountAll(countAll);
- feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
- feedStatisticsList.setAdapter(listAdapter);
- return root;
- }
-
- @Override
- public void onStart() {
- super.onStart();
- refreshStatistics();
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- if (disposable != null) {
- disposable.dispose();
- }
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.statistics, menu);
- menu.findItem(R.id.statistics_reset).setEnabled(!countAll);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.statistics_mode) {
- selectStatisticsMode();
- return true;
- }
- if (item.getItemId() == R.id.statistics_reset) {
- confirmResetStatistics();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void selectStatisticsMode() {
- View contentView = View.inflate(getContext(), R.layout.statistics_mode_select_dialog, null);
- AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
- builder.setView(contentView);
- builder.setTitle(R.string.statistics_mode);
-
- if (countAll) {
- ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true);
- } else {
- ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true);
- }
-
- builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
- countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked();
- listAdapter.setCountAll(countAll);
- prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply();
- refreshStatistics();
- getActivity().invalidateOptionsMenu();
- });
-
- builder.show();
- }
-
- private void confirmResetStatistics() {
- if (!countAll) {
- ConfirmationDialog conDialog = new ConfirmationDialog(
- getActivity(),
- R.string.statistics_reset_data,
- R.string.statistics_reset_data_msg) {
-
- @Override
- public void onConfirmButtonPressed(DialogInterface dialog) {
- dialog.dismiss();
- doResetStatistics();
- }
- };
- conDialog.createNewDialog().show();
- }
- }
-
- private void doResetStatistics() {
- progressBar.setVisibility(View.VISIBLE);
- feedStatisticsList.setVisibility(View.GONE);
- if (disposable != null) {
- disposable.dispose();
- }
-
- disposable = Completable.fromFuture(DBWriter.resetStatistics())
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(() -> {
- refreshStatistics();
- UserPreferences.resetUsageCountingDate();
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
-
- private void refreshStatistics() {
- progressBar.setVisibility(View.VISIBLE);
- feedStatisticsList.setVisibility(View.GONE);
- loadStatistics();
- }
-
- private void loadStatistics() {
- if (disposable != null) {
- disposable.dispose();
- }
- disposable = Observable.fromCallable(this::fetchStatistics)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(result -> {
- listAdapter.update(result);
- progressBar.setVisibility(View.GONE);
- feedStatisticsList.setVisibility(View.VISIBLE);
- }, error -> Log.e(TAG, Log.getStackTraceString(error)));
- }
-
- private List<StatisticsItem> fetchStatistics() {
- List<StatisticsItem> statisticsData = DBReader.getStatistics();
- if (countAll) {
- Collections.sort(statisticsData, (item1, item2) ->
- Long.compare(item2.timePlayedCountAll, item1.timePlayedCountAll));
- } else {
- Collections.sort(statisticsData, (item1, item2) ->
- Long.compare(item2.timePlayed, item1.timePlayed));
- }
- return statisticsData;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
index 2c72ab75b..1c5a6acd4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java
@@ -16,28 +16,25 @@ import com.google.android.material.tabs.TabLayoutMediator;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
+import de.danoeh.antennapod.fragment.PagedToolbarFragment;
/**
* Displays the 'statistics' screen
*/
-public class StatisticsFragment extends Fragment {
+public class StatisticsFragment extends PagedToolbarFragment {
public static final String TAG = "StatisticsFragment";
- private static final int POS_LISTENED_HOURS = 0;
- private static final int POS_SPACE_TAKEN = 1;
- private static final int TOTAL_COUNT = 2;
-
+ private static final int POS_SUBSCRIPTIONS = 0;
+ private static final int POS_YEARS = 1;
+ private static final int POS_SPACE_TAKEN = 2;
+ private static final int TOTAL_COUNT = 3;
private TabLayout tabLayout;
private ViewPager2 viewPager;
private Toolbar toolbar;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
@@ -46,29 +43,28 @@ public class StatisticsFragment extends Fragment {
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
viewPager = rootView.findViewById(R.id.viewpager);
toolbar = rootView.findViewById(R.id.toolbar);
+ toolbar.setTitle(getString(R.string.statistics_label));
+ toolbar.inflateMenu(R.menu.statistics);
+ toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
viewPager.setAdapter(new StatisticsPagerAdapter(this));
// Give the TabLayout the ViewPager
tabLayout = rootView.findViewById(R.id.sliding_tabs);
+ super.setupPagedToolbar(toolbar, viewPager);
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
- case POS_LISTENED_HOURS:
- tab.setText(R.string.playback_statistics_label);
+ case POS_SUBSCRIPTIONS:
+ tab.setText(R.string.subscriptions_label);
+ break;
+ case POS_YEARS:
+ tab.setText(R.string.years_statistics_label);
break;
case POS_SPACE_TAKEN:
- tab.setText(R.string.download_statistics_label);
+ tab.setText(R.string.downloads_label);
break;
default:
break;
}
}).attach();
-
- if (getActivity().getClass() == PreferenceActivity.class) {
- rootView.findViewById(R.id.toolbar).setVisibility(View.GONE);
- } else {
- toolbar.setTitle(getString(R.string.statistics_label));
- toolbar.setNavigationOnClickListener(v -> getParentFragmentManager().popBackStack());
- }
-
return rootView;
}
@@ -90,8 +86,10 @@ public class StatisticsFragment extends Fragment {
@Override
public Fragment createFragment(int position) {
switch (position) {
- case POS_LISTENED_HOURS:
- return new PlaybackStatisticsFragment();
+ case POS_SUBSCRIPTIONS:
+ return new SubscriptionStatisticsFragment();
+ case POS_YEARS:
+ return new YearsStatisticsFragment();
default:
case POS_SPACE_TAKEN:
return new DownloadStatisticsFragment();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
index e5617b8ea..00ff9fb64 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java
@@ -10,7 +10,6 @@ import de.danoeh.antennapod.dialog.ChooseDataFolderDialog;
import java.io.File;
public class StoragePreferencesFragment extends PreferenceFragmentCompat {
- private static final String TAG = "StoragePrefFragment";
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
private static final String PREF_IMPORT_EXPORT = "prefImportExport";
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SubscriptionStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SubscriptionStatisticsFragment.java
new file mode 100644
index 000000000..ef701d35c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SubscriptionStatisticsFragment.java
@@ -0,0 +1,279 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ProgressBar;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.util.Pair;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.PlaybackStatisticsListAdapter;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.databinding.StatisticsFilterDialogBinding;
+import io.reactivex.Completable;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Displays the 'playback statistics' screen
+ */
+public class SubscriptionStatisticsFragment extends Fragment {
+ private static final String TAG = SubscriptionStatisticsFragment.class.getSimpleName();
+ private static final String PREF_NAME = "StatisticsActivityPrefs";
+ private static final String PREF_INCLUDE_MARKED_PLAYED = "countAll";
+ private static final String PREF_FILTER_FROM = "filterFrom";
+ private static final String PREF_FILTER_TO = "filterTo";
+
+ private Disposable disposable;
+ private RecyclerView feedStatisticsList;
+ private ProgressBar progressBar;
+ private PlaybackStatisticsListAdapter listAdapter;
+ private boolean includeMarkedAsPlayed = false;
+ private long timeFilterFrom = 0;
+ private long timeFilterTo = Long.MAX_VALUE;
+ private SharedPreferences prefs;
+ private DBReader.StatisticsResult statisticsResult;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ includeMarkedAsPlayed = prefs.getBoolean(PREF_INCLUDE_MARKED_PLAYED, false);
+ timeFilterFrom = prefs.getLong(PREF_FILTER_FROM, 0);
+ timeFilterTo = prefs.getLong(PREF_FILTER_TO, Long.MAX_VALUE);
+ setHasOptionsMenu(true);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.statistics_activity, container, false);
+ feedStatisticsList = root.findViewById(R.id.statistics_list);
+ progressBar = root.findViewById(R.id.progressBar);
+ listAdapter = new PlaybackStatisticsListAdapter(this);
+ feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
+ feedStatisticsList.setAdapter(listAdapter);
+ return root;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ refreshStatistics();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.statistics_reset).setVisible(true);
+ menu.findItem(R.id.statistics_filter).setVisible(true);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.statistics_filter) {
+ selectStatisticsFilter();
+ return true;
+ } else if (item.getItemId() == R.id.statistics_reset) {
+ confirmResetStatistics();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void selectStatisticsFilter() {
+ if (statisticsResult == null) {
+ return;
+ }
+ StatisticsFilterDialogBinding dialogBinding = StatisticsFilterDialogBinding.inflate(getLayoutInflater());
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setView(dialogBinding.getRoot());
+ builder.setTitle(R.string.filter);
+ dialogBinding.includeMarkedCheckbox.setOnCheckedChangeListener((compoundButton, checked) -> {
+ dialogBinding.timeToSpinner.setEnabled(!checked);
+ dialogBinding.timeFromSpinner.setEnabled(!checked);
+ dialogBinding.lastYearButton.setEnabled(!checked);
+ dialogBinding.allTimeButton.setEnabled(!checked);
+ dialogBinding.dateSelectionContainer.setAlpha(checked ? 0.5f : 1f);
+ });
+ dialogBinding.includeMarkedCheckbox.setChecked(includeMarkedAsPlayed);
+
+ Pair<String[], Long[]> filterDates = makeMonthlyList(statisticsResult.oldestDate);
+
+ ArrayAdapter<String> adapterFrom = new ArrayAdapter<>(getContext(),
+ android.R.layout.simple_spinner_item, filterDates.first);
+ adapterFrom.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ dialogBinding.timeFromSpinner.setAdapter(adapterFrom);
+ for (int i = 0; i < filterDates.second.length; i++) {
+ if (filterDates.second[i] >= timeFilterFrom) {
+ dialogBinding.timeFromSpinner.setSelection(i);
+ break;
+ }
+ }
+
+ ArrayAdapter<String> adapterTo = new ArrayAdapter<>(getContext(),
+ android.R.layout.simple_spinner_item, filterDates.first);
+ adapterTo.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ dialogBinding.timeToSpinner.setAdapter(adapterTo);
+ for (int i = 0; i < filterDates.second.length; i++) {
+ if (filterDates.second[i] >= timeFilterTo) {
+ dialogBinding.timeToSpinner.setSelection(i);
+ break;
+ }
+ }
+
+ dialogBinding.allTimeButton.setOnClickListener(v -> {
+ dialogBinding.timeFromSpinner.setSelection(0);
+ dialogBinding.timeToSpinner.setSelection(filterDates.first.length - 1);
+ });
+ dialogBinding.lastYearButton.setOnClickListener(v -> {
+ dialogBinding.timeFromSpinner.setSelection(Math.max(0, filterDates.first.length - 14));
+ dialogBinding.timeToSpinner.setSelection(filterDates.first.length - 2);
+ });
+
+ builder.setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ includeMarkedAsPlayed = dialogBinding.includeMarkedCheckbox.isChecked();
+ if (includeMarkedAsPlayed) {
+ // We do not know the date at which something was marked as played, so filtering does not make sense
+ timeFilterFrom = 0;
+ timeFilterTo = Long.MAX_VALUE;
+ } else {
+ timeFilterFrom = filterDates.second[dialogBinding.timeFromSpinner.getSelectedItemPosition()];
+ timeFilterTo = filterDates.second[dialogBinding.timeToSpinner.getSelectedItemPosition()];
+ }
+ prefs.edit()
+ .putBoolean(PREF_INCLUDE_MARKED_PLAYED, includeMarkedAsPlayed)
+ .putLong(PREF_FILTER_FROM, timeFilterFrom)
+ .putLong(PREF_FILTER_TO, timeFilterTo)
+ .apply();
+ refreshStatistics();
+ });
+ builder.show();
+ }
+
+ private Pair<String[], Long[]> makeMonthlyList(long oldestDate) {
+ Calendar date = Calendar.getInstance();
+ date.setTimeInMillis(oldestDate);
+ date.set(Calendar.DAY_OF_MONTH, 1);
+ ArrayList<String> names = new ArrayList<>();
+ ArrayList<Long> timestamps = new ArrayList<>();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("MMM yyyy", Locale.getDefault());
+ while (date.getTimeInMillis() < System.currentTimeMillis()) {
+ names.add(dateFormat.format(new Date(date.getTimeInMillis())));
+ timestamps.add(date.getTimeInMillis());
+ if (date.get(Calendar.MONTH) == Calendar.DECEMBER) {
+ date.set(Calendar.MONTH, Calendar.JANUARY);
+ date.set(Calendar.YEAR, date.get(Calendar.YEAR) + 1);
+ } else {
+ date.set(Calendar.MONTH, date.get(Calendar.MONTH) + 1);
+ }
+ }
+ names.add(getString(R.string.statistics_today));
+ timestamps.add(Long.MAX_VALUE);
+ return new Pair<>(names.toArray(new String[0]), timestamps.toArray(new Long[0]));
+ }
+
+ private void confirmResetStatistics() {
+ ConfirmationDialog conDialog = new ConfirmationDialog(
+ getActivity(),
+ R.string.statistics_reset_data,
+ R.string.statistics_reset_data_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ dialog.dismiss();
+ doResetStatistics();
+ }
+ };
+ conDialog.createNewDialog().show();
+ }
+
+ private void doResetStatistics() {
+ progressBar.setVisibility(View.VISIBLE);
+ feedStatisticsList.setVisibility(View.GONE);
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ includeMarkedAsPlayed = false;
+ timeFilterFrom = 0;
+ timeFilterTo = Long.MAX_VALUE;
+ prefs.edit()
+ .putBoolean(PREF_INCLUDE_MARKED_PLAYED, includeMarkedAsPlayed)
+ .putLong(PREF_FILTER_FROM, timeFilterFrom)
+ .putLong(PREF_FILTER_TO, timeFilterTo)
+ .apply();
+
+ disposable = Completable.fromFuture(DBWriter.resetStatistics())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::refreshStatistics, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+
+ private void refreshStatistics() {
+ progressBar.setVisibility(View.VISIBLE);
+ feedStatisticsList.setVisibility(View.GONE);
+ loadStatistics();
+ }
+
+ private void loadStatistics() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(
+ () -> {
+ DBReader.StatisticsResult statisticsData = DBReader.getStatistics(
+ includeMarkedAsPlayed, timeFilterFrom, timeFilterTo);
+ Collections.sort(statisticsData.feedTime, (item1, item2) ->
+ Long.compare(item2.timePlayed, item1.timePlayed));
+ return statisticsData;
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ statisticsResult = result;
+ // When "from" is "today", set it to today
+ listAdapter.setTimeFilter(includeMarkedAsPlayed, Math.max(
+ Math.min(timeFilterFrom, System.currentTimeMillis()), result.oldestDate),
+ Math.min(timeFilterTo, System.currentTimeMillis()));
+ listAdapter.update(result.feedTime);
+ progressBar.setVisibility(View.GONE);
+ feedStatisticsList.setVisibility(View.VISIBLE);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SwipePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SwipePreferencesFragment.java
index 3d9709f74..19099a380 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SwipePreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/SwipePreferencesFragment.java
@@ -11,8 +11,6 @@ import de.danoeh.antennapod.fragment.QueueFragment;
public class SwipePreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_SWIPE_FEED = "prefSwipeFeed";
private static final String PREF_SWIPE_QUEUE = "prefSwipeQueue";
- //private static final String PREF_SWIPE_INBOX = "prefSwipeInbox";
- //private static final String PREF_SWIPE_EPISODES = "prefSwipeEpisodes";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/YearsStatisticsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/YearsStatisticsFragment.java
new file mode 100644
index 000000000..c58a59801
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/YearsStatisticsFragment.java
@@ -0,0 +1,87 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.YearStatisticsListAdapter;
+import de.danoeh.antennapod.core.storage.DBReader;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Displays the yearly statistics screen
+ */
+public class YearsStatisticsFragment extends Fragment {
+ private static final String TAG = YearsStatisticsFragment.class.getSimpleName();
+
+ private Disposable disposable;
+ private RecyclerView yearStatisticsList;
+ private ProgressBar progressBar;
+ private YearStatisticsListAdapter listAdapter;
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.statistics_activity, container, false);
+ yearStatisticsList = root.findViewById(R.id.statistics_list);
+ progressBar = root.findViewById(R.id.progressBar);
+ listAdapter = new YearStatisticsListAdapter(getContext());
+ yearStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
+ yearStatisticsList.setAdapter(listAdapter);
+ return root;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ refreshStatistics();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(@NonNull Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.statistics_reset).setVisible(false);
+ menu.findItem(R.id.statistics_filter).setVisible(false);
+ }
+
+ private void refreshStatistics() {
+ progressBar.setVisibility(View.VISIBLE);
+ yearStatisticsList.setVisibility(View.GONE);
+ loadStatistics();
+ }
+
+ private void loadStatistics() {
+ if (disposable != null) {
+ disposable.dispose();
+ }
+ disposable = Observable.fromCallable(DBReader::getMonthlyTimeStatistics)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(result -> {
+ listAdapter.update(result);
+ progressBar.setVisibility(View.GONE);
+ yearStatisticsList.setVisibility(View.VISIBLE);
+ }, error -> Log.e(TAG, Log.getStackTraceString(error)));
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
index 20cef1313..caa8031ae 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/about/ContributorsPagerFragment.java
@@ -17,19 +17,12 @@ import de.danoeh.antennapod.activity.PreferenceActivity;
* Displays the 'about->Contributors' pager screen.
*/
public class ContributorsPagerFragment extends Fragment {
-
- public static final String TAG = "StatisticsFragment";
-
private static final int POS_DEVELOPERS = 0;
private static final int POS_TRANSLATORS = 1;
private static final int POS_SPECIAL_THANKS = 2;
private static final int TOTAL_COUNT = 3;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java
index 9dfe6840c..358985cea 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/synchronization/GpodderAuthenticationFragment.java
@@ -250,18 +250,6 @@ public class GpodderAuthenticationFragment extends DialogFragment {
return false;
}
- private GpodnetDevice findDevice(String id) {
- if (devices == null) {
- return null;
- }
- for (GpodnetDevice device : devices) {
- if (device.getId().equals(id)) {
- return device;
- }
- }
- return null;
- }
-
private void setupFinishView(View view) {
final Button sync = view.findViewById(R.id.butSyncNow);
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index af35bbac9..a2c5ca3ff 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -39,9 +39,6 @@ public class PreferenceUpgrader {
private static void upgrade(int oldVersion, Context context) {
if (oldVersion == -1) {
//New installation
- if (UserPreferences.getUsageCountingDateMillis() < 0) {
- UserPreferences.resetUsageCountingDate();
- }
return;
}
if (oldVersion < 1070196) {
@@ -93,9 +90,6 @@ public class PreferenceUpgrader {
UserPreferences.setEnqueueLocation(enqueueLocation);
}
}
- if (oldVersion < 1080100) {
- prefs.edit().putString(UserPreferences.PREF_VIDEO_BEHAVIOR, "pip").apply();
- }
if (oldVersion < 2010300) {
// Migrate hardware button preferences
if (prefs.getBoolean("prefHardwareForwardButtonSkips", false)) {
diff --git a/app/src/main/java/de/danoeh/antennapod/view/LineChartView.java b/app/src/main/java/de/danoeh/antennapod/view/LineChartView.java
new file mode 100644
index 000000000..0eb225e8e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/LineChartView.java
@@ -0,0 +1,138 @@
+package de.danoeh.antennapod.view;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.DashPathEffect;
+import android.graphics.LinearGradient;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.appcompat.widget.ThemeUtils;
+import de.danoeh.antennapod.R;
+import io.reactivex.annotations.Nullable;
+
+public class LineChartView extends AppCompatImageView {
+ private LineChartDrawable drawable;
+
+ public LineChartView(Context context) {
+ super(context);
+ setup();
+ }
+
+ public LineChartView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public LineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup();
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ private void setup() {
+ drawable = new LineChartDrawable();
+ setImageDrawable(drawable);
+ }
+
+ /**
+ * Set of data values to display.
+ */
+ public void setData(LineChartData data) {
+ drawable.data = data;
+ }
+
+ public static class LineChartData {
+ private final long valueMax;
+ private final long[] values;
+ private final long[] verticalLines;
+
+ public LineChartData(long[] values, long[] verticalLines) {
+ this.values = values;
+ long valueMax = 0;
+ for (long datum : values) {
+ valueMax = Math.max(datum, valueMax);
+ }
+ this.valueMax = valueMax;
+ this.verticalLines = verticalLines;
+ }
+
+ public float getHeight(int item) {
+ return (float) values[item] / valueMax;
+ }
+ }
+
+ private class LineChartDrawable extends Drawable {
+ private LineChartData data;
+ private final Paint paintLine;
+ private final Paint paintBackground;
+ private final Paint paintVerticalLines;
+
+ private LineChartDrawable() {
+ paintLine = new Paint();
+ paintLine.setFlags(Paint.ANTI_ALIAS_FLAG);
+ paintLine.setStyle(Paint.Style.STROKE);
+ paintLine.setStrokeJoin(Paint.Join.ROUND);
+ paintLine.setStrokeCap(Paint.Cap.ROUND);
+ paintLine.setColor(ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorAccent));
+ paintBackground = new Paint();
+ paintBackground.setStyle(Paint.Style.FILL);
+ paintVerticalLines = new Paint();
+ paintVerticalLines.setStyle(Paint.Style.STROKE);
+ paintVerticalLines.setPathEffect(new DashPathEffect(new float[] {10f, 10f}, 0f));
+ paintVerticalLines.setColor(0x66777777);
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ float width = getBounds().width();
+ float height = getBounds().height();
+ float usableHeight = height * 0.9f;
+ float stepSize = width / (data.values.length + 1);
+
+ paintVerticalLines.setStrokeWidth(height * 0.005f);
+ for (long line : data.verticalLines) {
+ canvas.drawLine((line + 1) * stepSize, 0, (line + 1) * stepSize, height, paintVerticalLines);
+ }
+
+ paintLine.setStrokeWidth(height * 0.015f);
+ Path path = new Path();
+ for (int i = 0; i < data.values.length; i++) {
+ if (i == 0) {
+ path.moveTo((i + 1) * stepSize, (1 - data.getHeight(i)) * usableHeight + height * 0.05f);
+ } else {
+ path.lineTo((i + 1) * stepSize, (1 - data.getHeight(i)) * usableHeight + height * 0.05f);
+ }
+ }
+ canvas.drawPath(path, paintLine);
+
+ path.lineTo(data.values.length * stepSize, height);
+ path.lineTo(stepSize, height);
+ paintBackground.setShader(new LinearGradient(0, 0, 0, height,
+ (ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorAccent) & 0xffffff) + 0x66000000,
+ Color.TRANSPARENT, Shader.TileMode.CLAMP));
+ canvas.drawPath(path, paintBackground);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+ }
+}
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 d231e522f..c1ab3a7a6 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
@@ -104,7 +104,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
title.setText(item.getTitle());
leftPadding.setContentDescription(item.getTitle());
pubDate.setText(DateFormatter.formatAbbrev(activity, item.getPubDate()));
- pubDate.setContentDescription(DateFormatter.formatForAccessibility(activity, item.getPubDate()));
+ pubDate.setContentDescription(DateFormatter.formatForAccessibility(item.getPubDate()));
isNew.setVisibility(item.isNew() ? View.VISIBLE : View.GONE);
isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE);
isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE);
diff --git a/app/src/main/res/layout/feed_statistics.xml b/app/src/main/res/layout/feed_statistics.xml
index f8f5ac555..7897a7d5f 100644
--- a/app/src/main/res/layout/feed_statistics.xml
+++ b/app/src/main/res/layout/feed_statistics.xml
@@ -46,24 +46,6 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/statistics_duration_played_episodes" />
-
- <TextView
- android:id="@+id/durationPlayedLabel"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginStart="8dp"
- tools:text="0 min" />
-
- </TableRow>
-
- <TableRow
- android:tag="detailed">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
android:text="@string/statistics_total_duration" />
<TextView
diff --git a/app/src/main/res/layout/statistics_filter_dialog.xml b/app/src/main/res/layout/statistics_filter_dialog.xml
new file mode 100644
index 000000000..d37226c07
--- /dev/null
+++ b/app/src/main/res/layout/statistics_filter_dialog.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <CheckBox
+ android:id="@+id/includeMarkedCheckbox"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_include_marked"
+ android:layout_marginBottom="8dp" />
+
+ <LinearLayout
+ android:id="@+id/dateSelectionContainer"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_from"
+ android:padding="4dp"
+ android:layout_weight="1" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_to"
+ android:padding="4dp"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Spinner
+ android:id="@+id/timeFromSpinner"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ <Spinner
+ android:id="@+id/timeToSpinner"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/lastYearButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_filter_last_year"
+ android:layout_weight="1"
+ android:layout_marginEnd="4dp"
+ style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
+
+ <Button
+ android:id="@+id/allTimeButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_filter_all_time"
+ android:layout_weight="1"
+ android:layout_marginStart="4dp"
+ style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/statistics_speed_not_counted"
+ android:layout_marginTop="16dp" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/statistics_listitem_linechart.xml b/app/src/main/res/layout/statistics_listitem_linechart.xml
new file mode 100644
index 000000000..0794a1c09
--- /dev/null
+++ b/app/src/main/res/layout/statistics_listitem_linechart.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <de.danoeh.antennapod.view.LineChartView
+ android:id="@+id/lineChart"
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginEnd="8dp" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_marginTop="16dp"
+ android:background="?android:attr/dividerVertical" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/statistics_listitem_total.xml b/app/src/main/res/layout/statistics_listitem_total.xml
index 628e26c1f..11ff24977 100644
--- a/app/src/main/res/layout/statistics_listitem_total.xml
+++ b/app/src/main/res/layout/statistics_listitem_total.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -16,33 +17,32 @@
android:layout_marginLeft="8dp" />
<TextView
- android:id="@+id/total_description"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_centerHorizontal="true"
- android:textAlignment="center"
- android:layout_marginLeft="56dp"
- android:layout_marginRight="56dp"
- android:maxLines="3"
- android:layout_above="@id/total_time"
- android:textSize="14sp" />
-
- <TextView
+ android:id="@+id/total_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:id="@+id/total_time"
android:textColor="?android:attr/textColorPrimary"
android:gravity="center_horizontal"
android:textSize="28sp"
+ android:layout_marginBottom="4dp"
+ android:layout_above="@id/total_description"
+ tools:text="10.0 hours" />
+
+ <TextView
+ android:id="@+id/total_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:textAlignment="center"
+ android:maxLines="3"
+ android:textSize="14sp"
android:layout_marginBottom="16dp"
- android:layout_alignBottom="@id/pie_chart"
- tools:text="10.0 hours"/>
+ android:layout_alignBottom="@id/pie_chart" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="?android:attr/dividerVertical"
- android:layout_below="@+id/pie_chart"/>
+ android:layout_below="@+id/pie_chart" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/app/src/main/res/layout/statistics_mode_select_dialog.xml b/app/src/main/res/layout/statistics_mode_select_dialog.xml
deleted file mode 100644
index 8f8e1e657..000000000
--- a/app/src/main/res/layout/statistics_mode_select_dialog.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="16dp">
-
- <TextView
- android:text="@string/statistics_speed_not_counted"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"/>
-
- <RadioButton
- android:id="@+id/statistics_mode_normal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/statistics_mode_normal"/>
-
- <RadioButton
- android:id="@+id/statistics_mode_count_all"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/statistics_mode_count_all"/>
-</RadioGroup>
diff --git a/app/src/main/res/layout/statistics_year_listitem.xml b/app/src/main/res/layout/statistics_year_listitem.xml
new file mode 100644
index 000000000..48b910c7f
--- /dev/null
+++ b/app/src/main/res/layout/statistics_year_listitem.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="8dp"
+ android:background="?android:attr/selectableItemBackground">
+
+ <TextView
+ android:id="@+id/yearLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp"
+ tools:text="2020" />
+
+ <TextView
+ android:id="@+id/hoursLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="14sp"
+ tools:text="23 hours" />
+
+</LinearLayout>
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index a9f15317b..e25872ade 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -52,10 +52,10 @@
</item>
<item
- android:id="@+id/player_go_to_picture_in_picture"
- custom:showAsAction="collapseActionView"
- android:title="@string/player_go_to_picture_in_picture"
- android:visible="false">
+ android:id="@+id/player_switch_to_audio_only"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/player_switch_to_audio_only"
+ android:visible="false">
</item>
<item
diff --git a/app/src/main/res/menu/statistics.xml b/app/src/main/res/menu/statistics.xml
index 9e4b7fab1..71bd12b63 100644
--- a/app/src/main/res/menu/statistics.xml
+++ b/app/src/main/res/menu/statistics.xml
@@ -5,14 +5,13 @@
<item
android:id="@+id/statistics_reset"
android:title="@string/statistics_reset_data"
- custom:showAsAction="never"
- />
+ custom:showAsAction="never" />
<item
- android:id="@+id/statistics_mode"
+ android:id="@+id/statistics_filter"
android:icon="@drawable/ic_filter"
- android:title="@string/statistics_mode"
- custom:showAsAction="never">
+ android:title="@string/filter"
+ custom:showAsAction="always">
</item>
</menu>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 91ba649d2..9967d7fd1 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -44,11 +44,6 @@
android:title="@string/notification_pref_fragment"
android:icon="@drawable/ic_notifications"/>
- <Preference
- android:icon="@drawable/chart_box_outline"
- android:key="statistics"
- android:title="@string/statistics_label" />
-
<PreferenceCategory
android:key="project"
android:title="@string/project_pref">
diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml
index add9e8d4c..969013056 100644
--- a/app/src/main/res/xml/preferences_playback.xml
+++ b/app/src/main/res/xml/preferences_playback.xml
@@ -34,13 +34,6 @@
android:key="prefResumeAfterCall"
android:summary="@string/pref_resumeAfterCall_sum"
android:title="@string/pref_resumeAfterCall_title"/>
- <ListPreference
- android:defaultValue="pip"
- android:entries="@array/video_background_behavior_options"
- android:entryValues="@array/video_background_behavior_values"
- android:key="prefVideoBehavior"
- android:summary="@string/pref_videoBehavior_sum"
- android:title="@string/pref_videoBehavior_title"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/playback_control">
diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
index c9fe886fb..47b5dcd09 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
@@ -13,50 +13,43 @@ import de.danoeh.antennapod.core.R;
*/
public abstract class ConfirmationDialog {
- private static final String TAG = ConfirmationDialog.class.getSimpleName();
+ private static final String TAG = ConfirmationDialog.class.getSimpleName();
- private final Context context;
- private final int titleId;
- private final String message;
+ private final Context context;
+ private final int titleId;
+ private final String message;
- private int positiveText;
- private int negativeText;
+ private int positiveText;
- public ConfirmationDialog(Context context, int titleId, int messageId) {
- this(context, titleId, context.getString(messageId));
- }
+ public ConfirmationDialog(Context context, int titleId, int messageId) {
+ this(context, titleId, context.getString(messageId));
+ }
- public ConfirmationDialog(Context context, int titleId, String message) {
- this.context = context;
- this.titleId = titleId;
- this.message = message;
- }
+ public ConfirmationDialog(Context context, int titleId, String message) {
+ this.context = context;
+ this.titleId = titleId;
+ this.message = message;
+ }
- private void onCancelButtonPressed(DialogInterface dialog) {
- Log.d(TAG, "Dialog was cancelled");
- dialog.dismiss();
- }
+ private void onCancelButtonPressed(DialogInterface dialog) {
+ Log.d(TAG, "Dialog was cancelled");
+ dialog.dismiss();
+ }
public void setPositiveText(int id) {
this.positiveText = id;
}
- public void setNegativeText(int id) {
- this.negativeText = id;
+ public abstract void onConfirmButtonPressed(DialogInterface dialog);
+
+ public final AlertDialog createNewDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(titleId);
+ builder.setMessage(message);
+ builder.setPositiveButton(positiveText != 0 ? positiveText : R.string.confirm_label,
+ (dialog, which) -> onConfirmButtonPressed(dialog));
+ builder.setNegativeButton(R.string.cancel_label, (dialog, which) -> onCancelButtonPressed(dialog));
+ builder.setOnCancelListener(ConfirmationDialog.this::onCancelButtonPressed);
+ return builder.create();
}
-
-
- public abstract void onConfirmButtonPressed(DialogInterface dialog);
-
- public final AlertDialog createNewDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(titleId);
- builder.setMessage(message);
- builder.setPositiveButton(positiveText != 0 ? positiveText : R.string.confirm_label,
- (dialog, which) -> onConfirmButtonPressed(dialog));
- builder.setNegativeButton(negativeText != 0 ? negativeText : R.string.cancel_label,
- (dialog, which) -> onCancelButtonPressed(dialog));
- builder.setOnCancelListener(ConfirmationDialog.this::onCancelButtonPressed);
- return builder.create();
- }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
index b6b607904..9d270360a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
@@ -16,9 +16,6 @@ import java.io.InputStream;
// see https://github.com/bumptech/glide/issues/699
class AudioCoverFetcher implements DataFetcher<InputStream> {
-
- private static final String TAG = "AudioCoverFetcher";
-
private final String path;
private final Context context;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index 74f89a039..82e1fb55a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -23,7 +23,6 @@ import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -88,7 +87,6 @@ public class UserPreferences {
private static final String PREF_PLAYBACK_SPEED_ARRAY = "prefPlaybackSpeedArray";
public static final String PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS = "prefPauseForFocusLoss";
private static final String PREF_RESUME_AFTER_CALL = "prefResumeAfterCall";
- public static final String PREF_VIDEO_BEHAVIOR = "prefVideoBehavior";
private static final String PREF_TIME_RESPECTS_SPEED = "prefPlaybackTimeRespectsSpeed";
public static final String PREF_STREAM_OVER_DOWNLOAD = "prefStreamOverDownload";
@@ -127,12 +125,9 @@ public class UserPreferences {
private static final String PREF_FAST_FORWARD_SECS = "prefFastForwardSecs";
private static final String PREF_REWIND_SECS = "prefRewindSecs";
private static final String PREF_QUEUE_LOCKED = "prefQueueLocked";
- private static final String PREF_LEFT_VOLUME = "prefLeftVolume";
- private static final String PREF_RIGHT_VOLUME = "prefRightVolume";
// Experimental
private static final String PREF_STEREO_TO_MONO = "PrefStereoToMono";
- public static final String PREF_CAST_ENABLED = "prefCast"; //Used for enabling Chromecast support
public static final int EPISODE_CLEANUP_QUEUE = -1;
public static final int EPISODE_CLEANUP_NULL = -2;
public static final int EPISODE_CLEANUP_EXCEPT_FAVORITE = -3;
@@ -829,10 +824,6 @@ public class UserPreferences {
return getMediaPlayer().equals(PREF_MEDIA_PLAYER_EXOPLAYER);
}
- public static void enableSonic() {
- prefs.edit().putString(PREF_MEDIA_PLAYER, "sonic").apply();
- }
-
public static void enableExoplayer() {
prefs.edit().putString(PREF_MEDIA_PLAYER, PREF_MEDIA_PLAYER_EXOPLAYER).apply();
}
@@ -847,15 +838,6 @@ public class UserPreferences {
.apply();
}
- public static VideoBackgroundBehavior getVideoBackgroundBehavior() {
- switch (prefs.getString(PREF_VIDEO_BEHAVIOR, "pip")) {
- case "stop": return VideoBackgroundBehavior.STOP;
- case "continue": return VideoBackgroundBehavior.CONTINUE_PLAYING;
- case "pip": //Deliberate fall-through
- default: return VideoBackgroundBehavior.PICTURE_IN_PICTURE;
- }
- }
-
public static EpisodeCleanupAlgorithm getEpisodeCleanupAlgorithm() {
if (!isEnableAutodownload()) {
return new APNullCleanupAlgorithm();
@@ -967,17 +949,6 @@ public class UserPreferences {
return getUpdateTimeOfDay().length == 2;
}
- /**
- * Evaluates whether Cast support (Chromecast, Audio Cast, etc) is enabled on the preferences.
- */
- public static boolean isCastEnabled() {
- return prefs.getBoolean(PREF_CAST_ENABLED, false);
- }
-
- public enum VideoBackgroundBehavior {
- STOP, PICTURE_IN_PICTURE, CONTINUE_PLAYING
- }
-
public enum BackButtonBehavior {
DEFAULT, OPEN_DRAWER, DOUBLE_TAP, SHOW_PROMPT, GO_TO_PAGE
}
@@ -1071,28 +1042,7 @@ public class UserPreferences {
.apply();
}
- public static long getUsageCountingDateMillis() {
- return prefs.getLong(PREF_USAGE_COUNTING_DATE, -1);
- }
-
- private static void setUsageCountingDateMillis(long value) {
- prefs.edit().putLong(PREF_USAGE_COUNTING_DATE, value).apply();
- }
-
- public static void resetUsageCountingDate() {
- setUsageCountingDateMillis(Calendar.getInstance().getTimeInMillis());
- }
-
- public static void unsetUsageCountingDate() {
- setUsageCountingDateMillis(-1);
- }
-
public static boolean shouldShowSubscriptionTitle() {
return prefs.getBoolean(PREF_SUBSCRIPTION_TITLE, false);
}
-
- public static void setSubscriptionTitleSetting(boolean showTitle) {
- prefs.edit().putBoolean(PREF_SUBSCRIPTION_TITLE, showTitle).apply();
- }
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
index 9760c57b1..8f559a889 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
@@ -9,7 +9,6 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
public class FeedSyncTask {
- private static final String TAG = "FeedParserTask";
private final DownloadRequest request;
private final Context context;
private DownloadStatus downloadStatus;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
index d54d10dc6..f1b9510d9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java
@@ -713,7 +713,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
return stream;
}
-
/**
* Releases internally used resources. This method should only be called when the object is not used anymore.
*/
@@ -738,16 +737,6 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
releaseWifiLockIfNecessary();
}
- /**
- * Releases internally used resources. This method should only be called when the object is not used anymore.
- * This method is executed on an internal executor service.
- */
- @Override
- public void shutdownQuietly() {
- executor.submit(this::shutdown);
- executor.shutdown();
- }
-
@Override
public void setVideoSurface(final SurfaceHolder surface) {
executor.submit(() -> {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index d6d11bc8a..07e197752 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -82,7 +82,6 @@ import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import de.danoeh.antennapod.core.util.playback.PlayableUtils;
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
import de.danoeh.antennapod.core.widget.WidgetUpdater;
-import de.danoeh.antennapod.model.feed.Chapter;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedMedia;
@@ -1663,24 +1662,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
mediaPlayer.setStartWhenPrepared(s);
}
-
public void seekTo(final int t) {
mediaPlayer.seekTo(t);
}
-
private void seekDelta(final int d) {
mediaPlayer.seekDelta(d);
}
/**
- * Seek to the start of the specified chapter.
- */
- public void seekToChapter(Chapter c) {
- seekTo((int) c.getStart());
- }
-
- /**
* call getDuration() on mediaplayer or return INVALID_TIME if player is in
* an invalid state.
*/
@@ -1792,7 +1782,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void onPlayFromSearch(String query, Bundle extras) {
Log.d(TAG, "onPlayFromSearch query=" + query + " extras=" + extras.toString());
- List<FeedItem> results = FeedSearcher.searchFeedItems(getBaseContext(), query, 0);
+ List<FeedItem> results = FeedSearcher.searchFeedItems(query, 0);
if (results.size() > 0 && results.get(0).getMedia() != null) {
FeedMedia media = results.get(0).getMedia();
startPlaying(media, false);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
index 83c065e0e..addc6b996 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceStateManager.java
@@ -36,10 +36,6 @@ class PlaybackServiceStateManager {
isInForeground = false;
}
- boolean isInForeground() {
- return isInForeground;
- }
-
boolean hasReceivedValidStartCommand() {
return hasReceivedValidStartCommand;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index da6987910..11ff813a9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -771,26 +771,56 @@ public final class DBReader {
}
}
+ public static class MonthlyStatisticsItem {
+ public int year = 0;
+ public int month = 0;
+ public long timePlayed = 0;
+ }
+
+ @NonNull
+ public static List<MonthlyStatisticsItem> getMonthlyTimeStatistics() {
+ List<MonthlyStatisticsItem> months = new ArrayList<>();
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ try (Cursor cursor = adapter.getMonthlyStatisticsCursor()) {
+ int indexMonth = cursor.getColumnIndexOrThrow("month");
+ int indexYear = cursor.getColumnIndexOrThrow("year");
+ int indexTotalDuration = cursor.getColumnIndexOrThrow("total_duration");
+ while (cursor.moveToNext()) {
+ MonthlyStatisticsItem item = new MonthlyStatisticsItem();
+ item.month = Integer.parseInt(cursor.getString(indexMonth));
+ item.year = Integer.parseInt(cursor.getString(indexYear));
+ item.timePlayed = cursor.getLong(indexTotalDuration);
+ months.add(item);
+ }
+ }
+ adapter.close();
+ return months;
+ }
+
+ public static class StatisticsResult {
+ public List<StatisticsItem> feedTime = new ArrayList<>();
+ public long oldestDate = System.currentTimeMillis();
+ }
+
/**
* Searches the DB for statistics.
*
* @return The list of statistics objects
*/
@NonNull
- public static List<StatisticsItem> getStatistics() {
+ public static StatisticsResult getStatistics(boolean includeMarkedAsPlayed,
+ long timeFilterFrom, long timeFilterTo) {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- List<StatisticsItem> feedTime = new ArrayList<>();
-
+ StatisticsResult result = new StatisticsResult();
List<Feed> feeds = getFeedList();
for (Feed feed : feeds) {
- long feedPlayedTimeCountAll = 0;
long feedPlayedTime = 0;
long feedTotalTime = 0;
long episodes = 0;
long episodesStarted = 0;
- long episodesStartedIncludingMarked = 0;
long totalDownloadSize = 0;
long episodesDownloadCount = 0;
List<FeedItem> items = getFeed(feed.getId()).getItems();
@@ -800,20 +830,22 @@ public final class DBReader {
continue;
}
- feedPlayedTime += media.getPlayedDuration() / 1000;
-
- if (item.isPlayed()) {
- feedPlayedTimeCountAll += media.getDuration() / 1000;
- } else {
- feedPlayedTimeCountAll += media.getPosition() / 1000;
+ if (media.getLastPlayedTime() > 0 && media.getPlayedDuration() != 0) {
+ result.oldestDate = Math.min(result.oldestDate, media.getLastPlayedTime());
}
-
- if (media.getPlaybackCompletionDate() != null || media.getPlayedDuration() > 0) {
- episodesStarted++;
+ if (media.getLastPlayedTime() >= timeFilterFrom
+ && media.getLastPlayedTime() <= timeFilterTo) {
+ if (media.getPlayedDuration() != 0) {
+ feedPlayedTime += media.getPlayedDuration() / 1000;
+ } else if (includeMarkedAsPlayed && item.isPlayed()) {
+ feedPlayedTime += media.getDuration() / 1000;
+ }
}
- if (item.isPlayed() || media.getPosition() != 0) {
- episodesStartedIncludingMarked++;
+ boolean markedAsStarted = item.isPlayed() || media.getPosition() != 0;
+ boolean hasStatistics = media.getPlaybackCompletionDate() != null || media.getPlayedDuration() > 0;
+ if (hasStatistics || (includeMarkedAsPlayed && markedAsStarted)) {
+ episodesStarted++;
}
feedTotalTime += media.getDuration() / 1000;
@@ -825,13 +857,12 @@ public final class DBReader {
episodes++;
}
- feedTime.add(new StatisticsItem(
- feed, feedTotalTime, feedPlayedTime, feedPlayedTimeCountAll, episodes,
- episodesStarted, episodesStartedIncludingMarked, totalDownloadSize, episodesDownloadCount));
+ result.feedTime.add(new StatisticsItem(feed, feedTotalTime, feedPlayedTime, episodes,
+ episodesStarted, totalDownloadSize, episodesDownloadCount));
}
adapter.close();
- return feedTime;
+ return result;
}
/**
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index d1c041723..f447090a8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -176,7 +176,7 @@ public final class DBTasks {
media.setDownloaded(false);
media.setFile_url(null);
DBWriter.setFeedMedia(media);
- EventBus.getDefault().post(FeedItemEvent.deletedMedia(media.getItem()));
+ EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
EventBus.getDefault().post(new MessageEvent(context.getString(R.string.error_file_not_found)));
}
@@ -230,36 +230,7 @@ public final class DBTasks {
UserPreferences.getEpisodeCleanupAlgorithm().performCleanup(context);
}
- /**
- * Returns the successor of a FeedItem in the queue.
- *
- * @param itemId ID of the FeedItem
- * @param queue Used for determining the successor of the item. If this parameter is null, the method will load
- * the queue from the database in the same thread.
- * @return Successor of the FeedItem or null if the FeedItem is not in the queue or has no successor.
- */
- public static FeedItem getQueueSuccessorOfItem(final long itemId, List<FeedItem> queue) {
- FeedItem result = null;
- if (queue == null) {
- queue = DBReader.getQueue();
- }
- if (queue != null) {
- Iterator<FeedItem> iterator = queue.iterator();
- while (iterator.hasNext()) {
- FeedItem item = iterator.next();
- if (item.getId() == itemId) {
- if (iterator.hasNext()) {
- result = iterator.next();
- }
- break;
- }
- }
- }
- return result;
- }
-
- private static Feed searchFeedByIdentifyingValueOrID(PodDBAdapter adapter,
- Feed feed) {
+ private static Feed searchFeedByIdentifyingValueOrID(Feed feed) {
if (feed.getId() != 0) {
return DBReader.getFeed(feed.getId());
} else {
@@ -322,7 +293,7 @@ public final class DBTasks {
adapter.open();
// Look up feed in the feedslist
- final Feed savedFeed = searchFeedByIdentifyingValueOrID(adapter, newFeed);
+ final Feed savedFeed = searchFeedByIdentifyingValueOrID(newFeed);
if (savedFeed == null) {
Log.d(TAG, "Found no existing Feed with title "
+ newFeed.getTitle() + ". Adding as new one.");
@@ -456,7 +427,7 @@ public final class DBTasks {
if (savedFeed == null) {
DBWriter.addNewFeed(context, newFeed).get();
// Update with default values that are set in database
- resultFeed = searchFeedByIdentifyingValueOrID(adapter, newFeed);
+ resultFeed = searchFeedByIdentifyingValueOrID(newFeed);
} else {
DBWriter.setCompleteFeed(savedFeed).get();
}
@@ -487,15 +458,13 @@ public final class DBTasks {
/**
* Searches the FeedItems of a specific Feed for a given string.
*
- * @param context Used for accessing the DB.
* @param feedID The id of the feed whose items should be searched.
* @param query The search string.
* @return A FutureTask object that executes the search request
* and returns the search result as a List of FeedItems.
*/
- public static FutureTask<List<FeedItem>> searchFeedItems(final Context context,
- final long feedID, final String query) {
- return new FutureTask<>(new QueryTask<List<FeedItem>>(context) {
+ public static FutureTask<List<FeedItem>> searchFeedItems(final long feedID, final String query) {
+ return new FutureTask<>(new QueryTask<List<FeedItem>>() {
@Override
public void execute(PodDBAdapter adapter) {
Cursor searchResult = adapter.searchItems(feedID, query);
@@ -507,8 +476,8 @@ public final class DBTasks {
});
}
- public static FutureTask<List<Feed>> searchFeeds(final Context context, final String query) {
- return new FutureTask<>(new QueryTask<List<Feed>>(context) {
+ public static FutureTask<List<Feed>> searchFeeds(final String query) {
+ return new FutureTask<>(new QueryTask<List<Feed>>() {
@Override
public void execute(PodDBAdapter adapter) {
Cursor cursor = adapter.searchFeeds(query);
@@ -533,7 +502,7 @@ public final class DBTasks {
abstract static class QueryTask<T> implements Callable<T> {
private T result;
- public QueryTask(Context context) {
+ public QueryTask() {
}
@Override
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
index af57cbdae..e572b4d8c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
@@ -13,7 +13,6 @@ import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -142,7 +141,7 @@ public class DBWriter {
.build();
SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, action);
}
- EventBus.getDefault().post(FeedItemEvent.deletedMedia(Collections.singletonList(media.getItem())));
+ EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
return true;
}
@@ -550,7 +549,7 @@ public class DBWriter {
adapter.addFavoriteItem(item);
adapter.close();
item.addTag(FeedItem.TAG_FAVORITE);
- EventBus.getDefault().post(FavoritesEvent.added(item));
+ EventBus.getDefault().post(new FavoritesEvent());
EventBus.getDefault().post(FeedItemEvent.updated(item));
});
}
@@ -561,7 +560,7 @@ public class DBWriter {
adapter.removeFavoriteItem(item);
adapter.close();
item.removeTag(FeedItem.TAG_FAVORITE);
- EventBus.getDefault().post(FavoritesEvent.removed(item));
+ EventBus.getDefault().post(new FavoritesEvent());
EventBus.getDefault().post(FeedItemEvent.updated(item));
});
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
index c3dd52b49..68ce7b7ef 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.core.storage;
-import android.content.Context;
import androidx.annotation.NonNull;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
@@ -19,9 +18,9 @@ public class FeedSearcher {
}
@NonNull
- public static List<FeedItem> searchFeedItems(final Context context, final String query, final long selectedFeed) {
+ public static List<FeedItem> searchFeedItems(final String query, final long selectedFeed) {
try {
- FutureTask<List<FeedItem>> itemSearchTask = DBTasks.searchFeedItems(context, selectedFeed, query);
+ FutureTask<List<FeedItem>> itemSearchTask = DBTasks.searchFeedItems(selectedFeed, query);
itemSearchTask.run();
return itemSearchTask.get();
} catch (ExecutionException | InterruptedException e) {
@@ -31,9 +30,9 @@ public class FeedSearcher {
}
@NonNull
- public static List<Feed> searchFeeds(final Context context, final String query) {
+ public static List<Feed> searchFeeds(final String query) {
try {
- FutureTask<List<Feed>> feedSearchTask = DBTasks.searchFeeds(context, query);
+ FutureTask<List<Feed>> feedSearchTask = DBTasks.searchFeeds(query);
feedSearchTask.run();
return feedSearchTask.get();
} catch (ExecutionException | InterruptedException e) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 43d9c7f11..ea4617f16 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -1133,6 +1133,17 @@ public class PodDBAdapter {
return db.rawQuery(query, null);
}
+ public final Cursor getMonthlyStatisticsCursor() {
+ final String query = "SELECT SUM(" + KEY_PLAYED_DURATION + ") AS total_duration"
+ + ", strftime('%m', datetime(" + KEY_LAST_PLAYED_TIME + "/1000, 'unixepoch')) AS month"
+ + ", strftime('%Y', datetime(" + KEY_LAST_PLAYED_TIME + "/1000, 'unixepoch')) AS year"
+ + " FROM " + TABLE_NAME_FEED_MEDIA
+ + " WHERE " + KEY_LAST_PLAYED_TIME + " > 0 AND " + KEY_PLAYED_DURATION + " > 0"
+ + " GROUP BY year, month"
+ + " ORDER BY year, month";
+ return db.rawQuery(query, null);
+ }
+
public int getQueueSize() {
final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_QUEUE);
Cursor c = db.rawQuery(query, null);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/StatisticsItem.java b/core/src/main/java/de/danoeh/antennapod/core/storage/StatisticsItem.java
index 90978d6b8..1bc4997dd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/StatisticsItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/StatisticsItem.java
@@ -12,11 +12,6 @@ public class StatisticsItem {
public final long timePlayed;
/**
- * Simply sums up time of podcasts that are marked as played.
- */
- public final long timePlayedCountAll;
-
- /**
* Number of episodes.
*/
public final long episodes;
@@ -27,11 +22,6 @@ public class StatisticsItem {
public final long episodesStarted;
/**
- * All episodes that are marked as played (or have position != 0).
- */
- public final long episodesStartedIncludingMarked;
-
- /**
* Simply sums up the size of download podcasts.
*/
public final long totalDownloadSize;
@@ -41,16 +31,14 @@ public class StatisticsItem {
*/
public final long episodesDownloadCount;
- public StatisticsItem(Feed feed, long time, long timePlayed, long timePlayedCountAll,
- long episodes, long episodesStarted, long episodesStartedIncludingMarked,
+ public StatisticsItem(Feed feed, long time, long timePlayed,
+ long episodes, long episodesStarted,
long totalDownloadSize, long episodesDownloadCount) {
this.feed = feed;
this.time = time;
this.timePlayed = timePlayed;
- this.timePlayedCountAll = timePlayedCountAll;
this.episodes = episodes;
this.episodesStarted = episodesStarted;
- this.episodesStartedIncludingMarked = episodesStartedIncludingMarked;
this.totalDownloadSize = totalDownloadSize;
this.episodesDownloadCount = episodesDownloadCount;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
index 99628dfcc..dc7ed4508 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateFormatter.java
@@ -37,7 +37,7 @@ public class DateFormatter {
return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format);
}
- public static String formatForAccessibility(final Context context, final Date date) {
+ public static String formatForAccessibility(final Date date) {
if (date == null) {
return "";
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
index 0bf301366..85be3c787 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
@@ -5,7 +5,6 @@ import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.text.TextUtils;
@@ -146,18 +145,6 @@ public class NetworkUtils {
return selectedNetworks.contains(Integer.toString(wm.getConnectionInfo().getNetworkId()));
}
- /**
- * Returns the SSID of the wifi connection, or <code>null</code> if there is no wifi.
- */
- public static String getWifiSsid() {
- WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
- WifiInfo wifiInfo = wifiManager.getConnectionInfo();
- if (wifiInfo != null) {
- return wifiInfo.getSSID();
- }
- return null;
- }
-
public static boolean wasDownloadBlocked(Throwable throwable) {
String message = throwable.getMessage();
if (message != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java
index 39deea36a..a1fadb4dc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/PowerUtils.java
@@ -10,8 +10,6 @@ import android.os.BatteryManager;
*/
public class PowerUtils {
- private static final String TAG = "PowerUtils";
-
private PowerUtils() {
}
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index de83bbf59..f3cf4361d 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -247,28 +247,6 @@
<item>@string/skip_episode_label</item>
</string-array>
- <string-array name="video_background_behavior_options">
- <item>@string/stop_playback</item>
- <item>@string/player_go_to_picture_in_picture</item>
- <item>@string/continue_playback</item>
- </string-array>
-
- <string-array name="video_background_behavior_values">
- <item>stop</item>
- <item>pip</item>
- <item>continue</item>
- </string-array>
-
- <string-array name="video_background_behavior_options_without_pip">
- <item>@string/stop_playback</item>
- <item>@string/continue_playback</item>
- </string-array>
-
- <string-array name="video_background_behavior_values_without_pip">
- <item>stop</item>
- <item>continue</item>
- </string-array>
-
<string-array name="back_button_behavior_options">
<item>@string/back_button_default</item>
<item>@string/back_button_go_to_page</item>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 1196c0eee..197d0c636 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -28,8 +28,7 @@
<string name="gpodnet_main_label">gpodder.net</string>
<string name="episode_cache_full_title">Episode cache full</string>
<string name="episode_cache_full_message">The episode cache limit has been reached. You can increase the cache size in the Settings.</string>
- <string name="playback_statistics_label">Playback</string>
- <string name="download_statistics_label">Downloads</string>
+ <string name="years_statistics_label">Years</string>
<string name="notification_pref_fragment">Notifications</string>
<!-- Google Assistant -->
@@ -44,17 +43,20 @@
<string name="change_setting">Change</string>
<!-- Statistics fragment -->
- <string name="total_time_listened_to_podcasts">Total time of episodes played:</string>
- <string name="statistics_mode">Statistics mode</string>
- <string name="statistics_mode_normal">Calculate duration that was actually played. Playing twice is counted twice, while marking as played is not counted</string>
- <string name="statistics_mode_count_all">Sum up all episodes marked as played</string>
+ <string name="statistics_include_marked">Include duration of episodes that are just marked as played</string>
<string name="statistics_speed_not_counted">Notice: Playback speed is never taken into account.</string>
+ <string name="statistics_from">From</string>
+ <string name="statistics_to">To</string>
+ <string name="statistics_today">Today</string>
+ <string name="statistics_filter_all_time">All time</string>
+ <string name="statistics_filter_last_year">Last year</string>
<string name="statistics_reset_data">Reset statistics data</string>
<string name="statistics_reset_data_msg">This will erase the history of duration played for all episodes. Are you sure you want to proceed?</string>
- <string name="statistics_counting_since">Since %s,\nyou played</string>
+ <string name="statistics_counting_range">Played between %1$s and %2$s</string>
+ <string name="statistics_counting_total">Played in total</string>
<!-- Download Statistics fragment -->
- <string name="total_size_downloaded_podcasts">Total size of episodes on the device:</string>
+ <string name="total_size_downloaded_podcasts">Total size of episodes on the device</string>
<!-- Main activity -->
<string name="drawer_open">Open menu</string>
@@ -302,7 +304,6 @@
<string name="playback_error_unknown">Unknown Error</string>
<string name="no_media_playing_label">No media playing</string>
<string name="position_default_label" translatable="false">00:00:00</string>
- <string name="player_go_to_picture_in_picture">Picture-in-picture mode</string>
<string name="unknown_media_key">AntennaPod - Unknown media key: %1$d</string>
<string name="error_file_not_found">File not found</string>
<string name="no_media_label">Item does not contain a media file</string>
@@ -511,10 +512,6 @@
<string name="media_player_switch_to_exoplayer">Switch to ExoPlayer</string>
<string name="media_player_switched_to_exoplayer">Switched to ExoPlayer.</string>
<string name="pref_skip_silence_title">Skip Silence in Audio</string>
- <string name="pref_videoBehavior_title">Upon exiting video</string>
- <string name="pref_videoBehavior_sum">Behavior when leaving video playback</string>
- <string name="stop_playback">Stop playback</string>
- <string name="continue_playback">Continue audio playback</string>
<string name="behavior">Behavior</string>
<string name="pref_back_button_behavior_title">Back Button Behavior</string>
<string name="pref_back_button_behavior_sum">Change behavior of the back button.</string>
@@ -707,7 +704,6 @@
<string name="auto_download_disabled_globally">Auto download is disabled in the main AntennaPod settings</string>
<string name="statistics_time_played">Time played:</string>
<string name="statistics_total_duration">Total duration (estimate):</string>
- <string name="statistics_duration_played_episodes">Duration of played episodes:</string>
<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>
@@ -793,6 +789,7 @@
<string name="stereo_to_mono">Downmix: Stereo to mono</string>
<string name="sonic_only">Sonic only</string>
<string name="exoplayer_only">ExoPlayer only</string>
+ <string name="player_switch_to_audio_only">Switch to audio only</string>
<!-- proxy settings -->
<string name="proxy_type_label">Type</string>
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
index 2167d9f2c..8df05d10d 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/WearMediaSession.java
@@ -6,8 +6,6 @@ import android.support.v4.media.session.PlaybackStateCompat;
import android.support.wearable.media.MediaControlConstants;
public class WearMediaSession {
- public static final String TAG = "WearMediaSession";
-
static void sessionStateAddActionForWear(PlaybackStateCompat.Builder sessionState, String actionName,
CharSequence name, int icon) {
PlaybackStateCompat.CustomAction.Builder actionBuilder =
diff --git a/event/src/main/java/de/danoeh/antennapod/event/FavoritesEvent.java b/event/src/main/java/de/danoeh/antennapod/event/FavoritesEvent.java
index 8b27f74ab..0a3c65adc 100644
--- a/event/src/main/java/de/danoeh/antennapod/event/FavoritesEvent.java
+++ b/event/src/main/java/de/danoeh/antennapod/event/FavoritesEvent.java
@@ -1,26 +1,7 @@
package de.danoeh.antennapod.event;
-import de.danoeh.antennapod.model.feed.FeedItem;
-
public class FavoritesEvent {
- public enum Action {
- ADDED, REMOVED
- }
-
- private final Action action;
- private final FeedItem item;
-
- private FavoritesEvent(Action action, FeedItem item) {
- this.action = action;
- this.item = item;
- }
-
- public static FavoritesEvent added(FeedItem item) {
- return new FavoritesEvent(Action.ADDED, item);
- }
-
- public static FavoritesEvent removed(FeedItem item) {
- return new FavoritesEvent(Action.REMOVED, item);
+ public FavoritesEvent() {
}
}
diff --git a/event/src/main/java/de/danoeh/antennapod/event/FeedItemEvent.java b/event/src/main/java/de/danoeh/antennapod/event/FeedItemEvent.java
index 6c7adc2d7..125d113d6 100644
--- a/event/src/main/java/de/danoeh/antennapod/event/FeedItemEvent.java
+++ b/event/src/main/java/de/danoeh/antennapod/event/FeedItemEvent.java
@@ -9,33 +9,17 @@ import java.util.List;
import de.danoeh.antennapod.model.feed.FeedItem;
public class FeedItemEvent {
-
- public enum Action {
- UPDATE, DELETE_MEDIA
- }
-
- @NonNull
- private final Action action;
@NonNull public final List<FeedItem> items;
- private FeedItemEvent(@NonNull Action action, @NonNull List<FeedItem> items) {
- this.action = action;
+ public FeedItemEvent(@NonNull List<FeedItem> items) {
this.items = items;
}
- public static FeedItemEvent deletedMedia(List<FeedItem> items) {
- return new FeedItemEvent(Action.DELETE_MEDIA, items);
- }
-
- public static FeedItemEvent deletedMedia(FeedItem... items) {
- return deletedMedia(Arrays.asList(items));
- }
-
public static FeedItemEvent updated(List<FeedItem> items) {
- return new FeedItemEvent(Action.UPDATE, items);
+ return new FeedItemEvent(items);
}
public static FeedItemEvent updated(FeedItem... items) {
- return updated(Arrays.asList(items));
+ return new FeedItemEvent(Arrays.asList(items));
}
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
index d2e4e4556..2fb1a5c0c 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedMedia.java
@@ -226,10 +226,6 @@ public class FeedMedia extends FeedFile implements Playable {
return mime_type;
}
- public void setMime_type(String mime_type) {
- this.mime_type = mime_type;
- }
-
@Nullable
public FeedItem getItem() {
return item;
diff --git a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
index 21a362a40..7c0d7cb51 100644
--- a/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
+++ b/net/sync/gpoddernet/src/main/java/de/danoeh/antennapod/net/sync/gpoddernet/GpodnetService.java
@@ -19,7 +19,6 @@ import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -213,45 +212,6 @@ public class GpodnetService implements ISyncService {
}
/**
- * Returns synchronization status of devices.
- * <p/>
- * This method requires authentication.
- *
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public List<List<String>> getSynchronizedDevices() throws GpodnetServiceException {
- requireLoggedIn();
- try {
- URL url = new URI(baseScheme, null, baseHost, basePort,
- String.format("/api/2/sync-devices/%s.json", username), null, null).toURL();
- Request.Builder request = new Request.Builder().url(url);
- String response = executeRequest(request);
- JSONObject syncStatus = new JSONObject(response);
- List<List<String>> result = new ArrayList<>();
-
- JSONArray synchronizedDevices = syncStatus.getJSONArray("synchronized");
- for (int i = 0; i < synchronizedDevices.length(); i++) {
- JSONArray groupDevices = synchronizedDevices.getJSONArray(i);
- List<String> group = new ArrayList<>();
- for (int j = 0; j < groupDevices.length(); j++) {
- group.add(groupDevices.getString(j));
- }
- result.add(group);
- }
-
- JSONArray notSynchronizedDevices = syncStatus.getJSONArray("not-synchronized");
- for (int i = 0; i < notSynchronizedDevices.length(); i++) {
- result.add(Collections.singletonList(notSynchronizedDevices.getString(i)));
- }
-
- return result;
- } catch (JSONException | MalformedURLException | URISyntaxException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
* Configures the device of a given user.
* <p/>
* This method requires authentication.
@@ -288,39 +248,6 @@ public class GpodnetService implements ISyncService {
}
/**
- * Links devices for synchronization.
- * <p/>
- * This method requires authentication.
- *
- * @throws GpodnetServiceAuthenticationException If there is an authentication error.
- */
- public void linkDevices(@NonNull List<String> deviceIds) throws GpodnetServiceException {
- requireLoggedIn();
- try {
- final URL url = new URI(baseScheme, null, baseHost, basePort,
- String.format("/api/2/sync-devices/%s.json", username), null, null).toURL();
- JSONObject jsonContent = new JSONObject();
- JSONArray group = new JSONArray();
- for (String deviceId : deviceIds) {
- group.put(deviceId);
- }
-
- JSONArray synchronizedGroups = new JSONArray();
- synchronizedGroups.put(group);
- jsonContent.put("synchronize", synchronizedGroups);
- jsonContent.put("stop-synchronize", new JSONArray());
-
- Log.d("aaaa", jsonContent.toString());
- RequestBody body = RequestBody.create(JSON, jsonContent.toString());
- Request.Builder request = new Request.Builder().post(body).url(url);
- executeRequest(request);
- } catch (JSONException | MalformedURLException | URISyntaxException e) {
- e.printStackTrace();
- throw new GpodnetServiceException(e);
- }
- }
-
- /**
* Uploads the subscriptions of a specific device.
* <p/>
* This method requires authentication.
diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
index 003f72e9b..7e2f68a17 100644
--- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
+++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/DublinCore.java
@@ -8,7 +8,6 @@ import org.xml.sax.Attributes;
import de.danoeh.antennapod.model.feed.FeedItem;
public class DublinCore extends Namespace {
- private static final String TAG = "NSDublinCore";
public static final String NSTAG = "dc";
public static final String NSURI = "http://purl.org/dc/elements/1.1/";
diff --git a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java
index 5273c6731..f65d124eb 100644
--- a/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java
+++ b/parser/feed/src/main/java/de/danoeh/antennapod/parser/feed/namespace/Namespace.java
@@ -5,10 +5,7 @@ import de.danoeh.antennapod.parser.feed.element.SyndElement;
import org.xml.sax.Attributes;
public abstract class Namespace {
- public static final String NSTAG = null;
- public static final String NSURI = null;
-
- /** Called by a Feedhandler when in startElement and it detects a namespace element
+ /** Called by a Feedhandler when in startElement and it detects a namespace element
* @return The SyndElement to push onto the stack
* */
public abstract SyndElement handleElementStart(String localName, HandlerState state, Attributes attributes);
diff --git a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/id3/ID3Chapter.java b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/id3/ID3Chapter.java
index fc594ab5a..5396025e9 100644
--- a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/id3/ID3Chapter.java
+++ b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/id3/ID3Chapter.java
@@ -30,9 +30,4 @@ public class ID3Chapter extends Chapter {
public int getChapterType() {
return CHAPTERTYPE_ID3CHAPTER;
}
-
- public String getId3ID() {
- return id3ID;
- }
-
}
diff --git a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReaderException.java b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReaderException.java
index 8de1b29c0..f1a46bda0 100644
--- a/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReaderException.java
+++ b/parser/media/src/main/java/de/danoeh/antennapod/parser/media/vorbis/VorbisCommentReaderException.java
@@ -3,14 +3,6 @@ package de.danoeh.antennapod.parser.media.vorbis;
public class VorbisCommentReaderException extends Exception {
private static final long serialVersionUID = 1L;
- public VorbisCommentReaderException() {
- super();
- }
-
- public VorbisCommentReaderException(String message, Throwable cause) {
- super(message, cause);
- }
-
public VorbisCommentReaderException(String message) {
super(message);
}
diff --git a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
index d03695896..a2ccb3f88 100644
--- a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
+++ b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlaybackServiceMediaPlayer.java
@@ -179,12 +179,6 @@ public abstract class PlaybackServiceMediaPlayer {
*/
public abstract void shutdown();
- /**
- * Releases internally used resources. This method should only be called when the object is not used anymore.
- * This method is executed on an internal executor service.
- */
- public abstract void shutdownQuietly();
-
public abstract void setVideoSurface(SurfaceHolder surface);
public abstract void resetVideoSurface();
diff --git a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlayerStatus.java b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlayerStatus.java
index d995ae21f..154fc0c83 100644
--- a/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlayerStatus.java
+++ b/playback/base/src/main/java/de/danoeh/antennapod/playback/base/PlayerStatus.java
@@ -23,10 +23,6 @@ public enum PlayerStatus {
statusValue = val;
}
- public static PlayerStatus fromOrdinal(int o) {
- return fromOrdinalLookup[o];
- }
-
public boolean isAtLeast(PlayerStatus other) {
return other == null || this.statusValue >= other.statusValue;
}
diff --git a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastEnabledActivity.java b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastEnabledActivity.java
index 2cebde6a3..83abd98b7 100644
--- a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastEnabledActivity.java
+++ b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastEnabledActivity.java
@@ -13,7 +13,6 @@ import com.google.android.gms.common.GoogleApiAvailability;
* network.
*/
public abstract class CastEnabledActivity extends AppCompatActivity {
- private static final String TAG = "CastEnabledActivity";
private boolean canCast = false;
@Override
diff --git a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
index 8e74154e8..d3c4f3468 100644
--- a/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
+++ b/playback/cast/src/play/java/de/danoeh/antennapod/playback/cast/CastPsmp.java
@@ -456,11 +456,6 @@ public class CastPsmp extends PlaybackServiceMediaPlayer {
}
@Override
- public void shutdownQuietly() {
- shutdown();
- }
-
- @Override
public void setVideoSurface(SurfaceHolder surface) {
throw new UnsupportedOperationException("Setting Video Surface unsupported in Remote Media Player");
}