From 416117515c4e52727f91987e5b537256da34f09a Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 28 Aug 2016 18:35:05 +0200 Subject: [PATCH 1/5] Allow choosing between getDuration and getPlayedDuration --- .../activity/StatisticsActivity.java | 68 +++++++++++-- .../adapter/StatisticsListAdapter.java | 7 +- app/src/main/res/layout/calculation_type.xml | 19 ++++ app/src/main/res/menu/statistics.xml | 12 +++ .../antennapod/core/storage/DBReader.java | 96 +++++++++++++++---- core/src/main/res/values/strings.xml | 3 + 6 files changed, 177 insertions(+), 28 deletions(-) create mode 100644 app/src/main/res/layout/calculation_type.xml create mode 100644 app/src/main/res/menu/statistics.xml diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java index 9bb8f88561..45d9ae6b7d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java @@ -1,14 +1,18 @@ package de.danoeh.antennapod.activity; +import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.ProgressBar; +import android.widget.RadioButton; import android.widget.TextView; import de.danoeh.antennapod.R; @@ -28,12 +32,16 @@ public class StatisticsActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { private static final String TAG = StatisticsActivity.class.getSimpleName(); + private static final String PREF_NAME = "StatisticsActivityPrefs"; + private static final String PREF_COUNT_ALL = "countAll"; private Subscription subscription; private TextView totalTimeTextView; private ListView feedStatisticsList; private ProgressBar progressBar; private StatisticsListAdapter listAdapter; + private boolean countAll = false; + private SharedPreferences prefs; @Override protected void onCreate(Bundle savedInstanceState) { @@ -42,10 +50,14 @@ protected void onCreate(Bundle savedInstanceState) { getSupportActionBar().setDisplayShowHomeEnabled(true); setContentView(R.layout.statistics_activity); + prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); + countAll = prefs.getBoolean(PREF_COUNT_ALL, false); + totalTimeTextView = (TextView) findViewById(R.id.total_time); feedStatisticsList = (ListView) findViewById(R.id.statistics_list); progressBar = (ProgressBar) findViewById(R.id.progressBar); listAdapter = new StatisticsListAdapter(this); + listAdapter.setCountAll(countAll); feedStatisticsList.setAdapter(listAdapter); feedStatisticsList.setOnItemClickListener(this); } @@ -53,10 +65,15 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - progressBar.setVisibility(View.VISIBLE); - totalTimeTextView.setVisibility(View.GONE); - feedStatisticsList.setVisibility(View.GONE); - loadStats(); + refreshStats(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.statistics, menu); + return true; } @Override @@ -64,22 +81,54 @@ public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; + } else if (item.getItemId() == R.id.calculation_type) { + selectCalculationType(); + return true; } else { return super.onOptionsItemSelected(item); } } + private void selectCalculationType() { + View contentView = View.inflate(this, R.layout.calculation_type, null); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setView(contentView); + builder.setTitle(R.string.calculation_type); + + if (countAll) { + ((RadioButton) contentView.findViewById(R.id.calculation_type_count_all)).setChecked(true); + } else { + ((RadioButton) contentView.findViewById(R.id.calculation_type_normal)).setChecked(true); + } + + builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { + countAll = ((RadioButton) contentView.findViewById(R.id.calculation_type_count_all)).isChecked(); + listAdapter.setCountAll(countAll); + prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).commit(); + refreshStats(); + }); + + builder.show(); + } + + private void refreshStats() { + progressBar.setVisibility(View.VISIBLE); + totalTimeTextView.setVisibility(View.GONE); + feedStatisticsList.setVisibility(View.GONE); + loadStats(); + } + private void loadStats() { - if(subscription != null) { + if (subscription != null) { subscription.unsubscribe(); } - subscription = Observable.fromCallable(() -> DBReader.getStatistics()) + subscription = Observable.fromCallable(() -> DBReader.getStatistics(countAll)) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { if (result != null) { totalTimeTextView.setText(Converter - .shortLocalizedDuration(this, result.totalTime)); + .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime)); listAdapter.update(result.feedTime); progressBar.setVisibility(View.GONE); totalTimeTextView.setVisibility(View.VISIBLE); @@ -95,9 +144,10 @@ public void onItemClick(AdapterView parent, View view, int position, long id) AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle(stats.feed.getTitle()); dialog.setMessage(getString(R.string.statistics_details_dialog, - stats.episodesStarted, + countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted, stats.episodes, - Converter.shortLocalizedDuration(this, stats.timePlayed), + Converter.shortLocalizedDuration(this, countAll ? + stats.timePlayedCountAll : stats.timePlayed), Converter.shortLocalizedDuration(this, stats.time))); dialog.setPositiveButton(android.R.string.ok, null); dialog.show(); 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 fe891281b1..c060083a68 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java @@ -25,11 +25,15 @@ public class StatisticsListAdapter extends BaseAdapter { private Context context; List feedTime = new ArrayList<>(); + private boolean countAll = true; public StatisticsListAdapter(Context context) { this.context = context; } + public void setCountAll(boolean countAll) { + this.countAll = countAll; + } @Override public int getCount() { @@ -77,7 +81,8 @@ public View getView(int position, View convertView, ViewGroup parent) { holder.title.setText(feed.getTitle()); holder.time.setText(Converter.shortLocalizedDuration(context, - feedTime.get(position).timePlayed)); + countAll ? feedTime.get(position).timePlayedCountAll + : feedTime.get(position).timePlayed)); return convertView; } diff --git a/app/src/main/res/layout/calculation_type.xml b/app/src/main/res/layout/calculation_type.xml new file mode 100644 index 0000000000..9b422beb9a --- /dev/null +++ b/app/src/main/res/layout/calculation_type.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/app/src/main/res/menu/statistics.xml b/app/src/main/res/menu/statistics.xml new file mode 100644 index 0000000000..bc36bbb38c --- /dev/null +++ b/app/src/main/res/menu/statistics.xml @@ -0,0 +1,12 @@ + + + + + + + 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 1d57d902c0..8b5859eaed 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 @@ -927,64 +927,107 @@ public static FeedMedia getFeedMedia(final long mediaId) { /** * Searches the DB for statistics * + * @param sortByCountAll If true, the statistic items will be sorted according to the + * countAll calculation time * @return The StatisticsInfo object */ - public static StatisticsData getStatistics() { + public static StatisticsData getStatistics(boolean sortByCountAll) { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); + long totalTimeCountAll = 0; long totalTime = 0; List feedTime = new ArrayList<>(); List feeds = getFeedList(); for (Feed feed : feeds) { + long feedPlayedTimeCountAll = 0; long feedPlayedTime = 0; long feedTotalTime = 0; long episodes = 0; long episodesStarted = 0; + long episodesStartedIncludingMarked = 0; List items = getFeed(feed.getId()).getItems(); - for(FeedItem item : items) { + for (FeedItem item : items) { FeedMedia media = item.getMedia(); - if(media == null) { + if (media == null) { continue; } // played duration used to be reset when the item is added to the playback history - if(media.getPlaybackCompletionDate() != null) { + if (media.getPlaybackCompletionDate() != null) { feedPlayedTime += media.getDuration() / 1000; } feedPlayedTime += media.getPlayedDuration() / 1000; + + if (item.isPlayed()) { + feedPlayedTimeCountAll += media.getDuration() / 1000; + } else { + feedPlayedTimeCountAll += media.getPosition() / 1000; + } + if (media.getPlaybackCompletionDate() != null || media.getPlayedDuration() > 0) { episodesStarted++; } + + if (item.isPlayed() || media.getPosition() != 0) { + episodesStartedIncludingMarked++; + } + feedTotalTime += media.getDuration() / 1000; episodes++; } feedTime.add(new StatisticsItem( - feed, feedTotalTime, feedPlayedTime, episodes, episodesStarted)); + feed, feedTotalTime, feedPlayedTime, feedPlayedTimeCountAll, episodes, + episodesStarted, episodesStartedIncludingMarked)); totalTime += feedPlayedTime; + totalTimeCountAll += feedPlayedTimeCountAll; } - Collections.sort(feedTime, (item1, item2) -> { - if(item1.timePlayed > item2.timePlayed) { - return -1; - } else if(item1.timePlayed < item2.timePlayed) { - return 1; - } else { - return 0; - } - }); + if (sortByCountAll) { + Collections.sort(feedTime, (item1, item2) -> + compareLong(item1.timePlayedCountAll, item2.timePlayedCountAll)); + } else { + Collections.sort(feedTime, (item1, item2) -> + compareLong(item1.timePlayed, item2.timePlayed)); + } adapter.close(); - return new StatisticsData(totalTime, feedTime); + return new StatisticsData(totalTime, totalTimeCountAll, feedTime); + } + + /** + * Compares two {@code long} values. Long.compare() is not available before API 19 + * + * @return 0 if long1 = long2, less than 0 if long1 < long2, + * and greater than 0 if long1 > long2. + */ + private static int compareLong(long long1, long long2) { + if (long1 > long2) { + return -1; + } else if (long1 < long2) { + return 1; + } else { + return 0; + } } public static class StatisticsData { + /** + * Simply sums up time of podcasts that are marked as played + */ + public long totalTimeCountAll; + + /** + * Respects speed, listening twice, ... + */ public long totalTime; + public List feedTime; - public StatisticsData(long totalTime, List feedTime) { + public StatisticsData(long totalTime, long totalTimeCountAll, List feedTime) { this.totalTime = totalTime; + this.totalTimeCountAll = totalTimeCountAll; this.feedTime = feedTime; } } @@ -992,17 +1035,34 @@ public StatisticsData(long totalTime, List feedTime) { public static class StatisticsItem { public Feed feed; public long time; + + /** + * Respects speed, listening twice, ... + */ public long timePlayed; + /** + * Simply sums up time of podcasts that are marked as played + */ + public long timePlayedCountAll; public long episodes; + /** + * Episodes that are actually played + */ public long episodesStarted; + /** + * All episodes that are marked as played (or have position != 0) + */ + public long episodesStartedIncludingMarked; - public StatisticsItem(Feed feed, long time, long timePlayed, - long episodes, long episodesStarted) { + public StatisticsItem(Feed feed, long time, long timePlayed, long timePlayedCountAll, + long episodes, long episodesStarted, long episodesStartedIncludingMarked) { this.feed = feed; this.time = time; this.timePlayed = timePlayed; + this.timePlayedCountAll = timePlayedCountAll; this.episodes = episodes; this.episodesStarted = episodesStarted; + this.episodesStartedIncludingMarked = episodesStartedIncludingMarked; } } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index ebddeb243c..f0388b174f 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -31,6 +31,9 @@ Total time of podcasts played: %1$d out of %2$d episodes started.\n\nPlayed %3$s out of %4$s. + Calculation type + The time you actually played podcasts, respecting playback speed + Sum up all played podcast durations, including those just marked as played Open menu From 769ed8b15efb478f5ad877a71f6dc21a9c3e87b3 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 15 Apr 2017 15:34:31 +0200 Subject: [PATCH 2/5] Renamed type to mode --- .../activity/StatisticsActivity.java | 28 +++++++++---------- ....xml => statistics_mode_select_dialog.xml} | 8 +++--- app/src/main/res/menu/statistics.xml | 4 +-- core/src/main/res/values/strings.xml | 6 ++-- 4 files changed, 23 insertions(+), 23 deletions(-) rename app/src/main/res/layout/{calculation_type.xml => statistics_mode_select_dialog.xml} (68%) diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java index 45d9ae6b7d..b2ff43c437 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java @@ -65,7 +65,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - refreshStats(); + refreshStatistics(); } @Override @@ -81,44 +81,44 @@ public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { finish(); return true; - } else if (item.getItemId() == R.id.calculation_type) { - selectCalculationType(); + } else if (item.getItemId() == R.id.statistics_mode) { + selectStatisticsMode(); return true; } else { return super.onOptionsItemSelected(item); } } - private void selectCalculationType() { - View contentView = View.inflate(this, R.layout.calculation_type, null); + private void selectStatisticsMode() { + View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setView(contentView); - builder.setTitle(R.string.calculation_type); + builder.setTitle(R.string.statistics_mode); if (countAll) { - ((RadioButton) contentView.findViewById(R.id.calculation_type_count_all)).setChecked(true); + ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).setChecked(true); } else { - ((RadioButton) contentView.findViewById(R.id.calculation_type_normal)).setChecked(true); + ((RadioButton) contentView.findViewById(R.id.statistics_mode_normal)).setChecked(true); } builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { - countAll = ((RadioButton) contentView.findViewById(R.id.calculation_type_count_all)).isChecked(); + countAll = ((RadioButton) contentView.findViewById(R.id.statistics_mode_count_all)).isChecked(); listAdapter.setCountAll(countAll); - prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).commit(); - refreshStats(); + prefs.edit().putBoolean(PREF_COUNT_ALL, countAll).apply(); + refreshStatistics(); }); builder.show(); } - private void refreshStats() { + private void refreshStatistics() { progressBar.setVisibility(View.VISIBLE); totalTimeTextView.setVisibility(View.GONE); feedStatisticsList.setVisibility(View.GONE); - loadStats(); + loadStatistics(); } - private void loadStats() { + private void loadStatistics() { if (subscription != null) { subscription.unsubscribe(); } diff --git a/app/src/main/res/layout/calculation_type.xml b/app/src/main/res/layout/statistics_mode_select_dialog.xml similarity index 68% rename from app/src/main/res/layout/calculation_type.xml rename to app/src/main/res/layout/statistics_mode_select_dialog.xml index 9b422beb9a..7918433d54 100644 --- a/app/src/main/res/layout/calculation_type.xml +++ b/app/src/main/res/layout/statistics_mode_select_dialog.xml @@ -6,14 +6,14 @@ android:padding="16dp"> + android:text="@string/statistics_mode_normal" /> + android:text="@string/statistics_mode_count_all" /> diff --git a/app/src/main/res/menu/statistics.xml b/app/src/main/res/menu/statistics.xml index bc36bbb38c..6ecc707077 100644 --- a/app/src/main/res/menu/statistics.xml +++ b/app/src/main/res/menu/statistics.xml @@ -3,9 +3,9 @@ xmlns:custom="http://schemas.android.com/apk/res-auto"> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index f0388b174f..7fa9448c6b 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -31,9 +31,9 @@ Total time of podcasts played: %1$d out of %2$d episodes started.\n\nPlayed %3$s out of %4$s. - Calculation type - The time you actually played podcasts, respecting playback speed - Sum up all played podcast durations, including those just marked as played + Statistics mode + The time you actually played podcasts, respecting playback speed + Sum up all played podcast durations, including those just marked as played Open menu From 4e7fef121173e398c2b15f20a20904366cc59e93 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 15 Apr 2017 15:41:54 +0200 Subject: [PATCH 3/5] Statistics calculation does not respect playback speed --- core/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 7fa9448c6b..d446597921 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -32,8 +32,8 @@ Total time of podcasts played: %1$d out of %2$d episodes started.\n\nPlayed %3$s out of %4$s. Statistics mode - The time you actually played podcasts, respecting playback speed - Sum up all played podcast durations, including those just marked as played + Duration that was actually played + Include podcasts that are just marked as played Open menu From 2f5fc1966d15054cf0674bc256f422c1ba1cc803 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 15 Apr 2017 15:52:46 +0200 Subject: [PATCH 4/5] Added more details to statistics mode description --- core/src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index d446597921..622d447b09 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -32,8 +32,8 @@ Total time of podcasts played: %1$d out of %2$d episodes started.\n\nPlayed %3$s out of %4$s. Statistics mode - Duration that was actually played - Include podcasts that are just marked as played + Calculate duration that was actually played. Playing twice counts twice, while marking as played does not count. + Sum up all podcasts marked as played Open menu From 8f226803cbfeaee628ca5b745bab03a7293c84d1 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 15 Apr 2017 15:59:12 +0200 Subject: [PATCH 5/5] Added notice that playback speed is not taken into account --- .../layout/statistics_mode_select_dialog.xml | 30 +++++++++++-------- core/src/main/res/values/strings.xml | 3 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/layout/statistics_mode_select_dialog.xml b/app/src/main/res/layout/statistics_mode_select_dialog.xml index 7918433d54..8f8e1e6574 100644 --- a/app/src/main/res/layout/statistics_mode_select_dialog.xml +++ b/app/src/main/res/layout/statistics_mode_select_dialog.xml @@ -1,19 +1,25 @@ + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:padding="16dp"> + + + android:id="@+id/statistics_mode_normal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/statistics_mode_normal"/> + android:id="@+id/statistics_mode_count_all" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/statistics_mode_count_all"/> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 622d447b09..5245c29656 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -32,8 +32,9 @@ Total time of podcasts played: %1$d out of %2$d episodes started.\n\nPlayed %3$s out of %4$s. Statistics mode - Calculate duration that was actually played. Playing twice counts twice, while marking as played does not count. + Calculate duration that was actually played. Playing twice is counted twice, while marking as played is not counted Sum up all podcasts marked as played + Notice: Playback speed is never taken into account. Open menu