Show storage size of downloaded episodes
This commit is contained in:
parent
6d0b16461d
commit
6817c00491
|
@ -0,0 +1,45 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
|
||||
/**
|
||||
* Adapter for the download statistics list
|
||||
*/
|
||||
public class DownloadStatisticsListAdapter extends StatisticsListAdapter {
|
||||
|
||||
public DownloadStatisticsListAdapter(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getHeaderCaptionResourceId() {
|
||||
return R.string.total_size_downloaded_podcasts;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onBindHeaderViewHolder(HeaderHolder holder) {
|
||||
long totalDownloadSize = 0;
|
||||
|
||||
for (DBReader.StatisticsItem item: statisticsData.feeds) {
|
||||
totalDownloadSize = totalDownloadSize + item.totalDownloadSize;
|
||||
}
|
||||
holder.totalTime.setText(Converter.byteToString(totalDownloadSize));
|
||||
float[] dataValues = new float[statisticsData.feeds.size()];
|
||||
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
||||
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
||||
dataValues[i] = item.totalDownloadSize;
|
||||
}
|
||||
holder.pieChart.setData(dataValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onBindFeedViewHolder(StatisticsHolder holder, int position) {
|
||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
||||
holder.value.setText(Converter.byteToString(statsItem.totalDownloadSize));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
|
||||
/**
|
||||
* Adapter for the playback statistics list
|
||||
*/
|
||||
public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
|
||||
|
||||
boolean countAll = true;
|
||||
|
||||
public PlaybackStatisticsListAdapter(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setCountAll(boolean countAll) {
|
||||
this.countAll = countAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getHeaderCaptionResourceId() {
|
||||
return R.string.total_time_listened_to_podcasts;
|
||||
}
|
||||
|
||||
@Override
|
||||
void onBindHeaderViewHolder(HeaderHolder holder) {
|
||||
long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime;
|
||||
holder.totalTime.setText(Converter.shortLocalizedDuration(context, time));
|
||||
float[] dataValues = new float[statisticsData.feeds.size()];
|
||||
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
||||
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
||||
dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
|
||||
}
|
||||
holder.pieChart.setData(dataValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onBindFeedViewHolder(StatisticsHolder holder, int position) {
|
||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
||||
long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
|
||||
holder.value.setText(Converter.shortLocalizedDuration(context, time));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
||||
dialog.setTitle(statsItem.feed.getTitle());
|
||||
dialog.setMessage(context.getString(R.string.statistics_details_dialog,
|
||||
countAll ? statsItem.episodesStartedIncludingMarked : statsItem.episodesStarted,
|
||||
statsItem.episodes, Converter.shortLocalizedDuration(context,
|
||||
countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed),
|
||||
Converter.shortLocalizedDuration(context, statsItem.time)));
|
||||
dialog.setPositiveButton(android.R.string.ok, null);
|
||||
dialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -2,49 +2,44 @@ package de.danoeh.antennapod.adapter;
|
|||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.view.PieChartView;
|
||||
|
||||
/**
|
||||
* Adapter for the statistics list
|
||||
* Parent Adapter for the playback and download statistics list
|
||||
*/
|
||||
public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
public abstract class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private static final int TYPE_HEADER = 0;
|
||||
private static final int TYPE_FEED = 1;
|
||||
private final Context context;
|
||||
private DBReader.StatisticsData statisticsData;
|
||||
private boolean countAll = true;
|
||||
final Context context;
|
||||
DBReader.StatisticsData statisticsData;
|
||||
|
||||
public StatisticsListAdapter(Context context) {
|
||||
StatisticsListAdapter(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void setCountAll(boolean countAll) {
|
||||
this.countAll = countAll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return statisticsData.feedTime.size() + 1;
|
||||
return statisticsData.feeds.size() + 1;
|
||||
}
|
||||
|
||||
public DBReader.StatisticsItem getItem(int position) {
|
||||
if (position == 0) {
|
||||
return null;
|
||||
}
|
||||
return statisticsData.feedTime.get(position - 1);
|
||||
return statisticsData.feeds.get(position - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +52,10 @@ public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.Vie
|
|||
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_total_time, parent, false));
|
||||
View view = inflater.inflate(R.layout.statistics_listitem_total, parent, false);
|
||||
TextView totalText = view.findViewById(R.id.total_description);
|
||||
totalText.setText(getHeaderCaptionResourceId());
|
||||
return new HeaderHolder(view);
|
||||
}
|
||||
return new StatisticsHolder(inflater.inflate(R.layout.statistics_listitem, parent, false));
|
||||
}
|
||||
|
@ -65,18 +63,10 @@ public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.Vie
|
|||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
|
||||
if (getItemViewType(position) == TYPE_HEADER) {
|
||||
HeaderHolder holder = (HeaderHolder) h;
|
||||
long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime;
|
||||
holder.totalTime.setText(Converter.shortLocalizedDuration(context, time));
|
||||
float[] dataValues = new float[statisticsData.feedTime.size()];
|
||||
for (int i = 0; i < statisticsData.feedTime.size(); i++) {
|
||||
DBReader.StatisticsItem item = statisticsData.feedTime.get(i);
|
||||
dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
|
||||
}
|
||||
holder.pieChart.setData(dataValues);
|
||||
onBindHeaderViewHolder((HeaderHolder) h);
|
||||
} else {
|
||||
StatisticsHolder holder = (StatisticsHolder) h;
|
||||
DBReader.StatisticsItem statsItem = statisticsData.feedTime.get(position - 1);
|
||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
||||
Glide.with(context)
|
||||
.load(statsItem.feed.getImageLocation())
|
||||
.apply(new RequestOptions()
|
||||
|
@ -88,20 +78,7 @@ public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.Vie
|
|||
.into(holder.image);
|
||||
|
||||
holder.title.setText(statsItem.feed.getTitle());
|
||||
long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
|
||||
holder.time.setText(Converter.shortLocalizedDuration(context, time));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
|
||||
dialog.setTitle(statsItem.feed.getTitle());
|
||||
dialog.setMessage(context.getString(R.string.statistics_details_dialog,
|
||||
countAll ? statsItem.episodesStartedIncludingMarked : statsItem.episodesStarted,
|
||||
statsItem.episodes, Converter.shortLocalizedDuration(context,
|
||||
countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed),
|
||||
Converter.shortLocalizedDuration(context, statsItem.time)));
|
||||
dialog.setPositiveButton(android.R.string.ok, null);
|
||||
dialog.show();
|
||||
});
|
||||
onBindFeedViewHolder(holder, position);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,14 +101,19 @@ public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.Vie
|
|||
static class StatisticsHolder extends RecyclerView.ViewHolder {
|
||||
ImageView image;
|
||||
TextView title;
|
||||
TextView time;
|
||||
TextView value;
|
||||
|
||||
StatisticsHolder(View itemView) {
|
||||
super(itemView);
|
||||
image = itemView.findViewById(R.id.imgvCover);
|
||||
title = itemView.findViewById(R.id.txtvTitle);
|
||||
time = itemView.findViewById(R.id.txtvTime);
|
||||
value = itemView.findViewById(R.id.txtvValue);
|
||||
}
|
||||
}
|
||||
|
||||
abstract int getHeaderCaptionResourceId();
|
||||
|
||||
abstract void onBindHeaderViewHolder(HeaderHolder holder);
|
||||
|
||||
abstract void onBindFeedViewHolder(StatisticsHolder holder, int position);
|
||||
}
|
||||
|
|
|
@ -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.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.DownloadStatisticsListAdapter;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.util.comparator.CompareCompat;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Displays the 'download statistics' screen
|
||||
*/
|
||||
public class DownloadStatisticsFragment extends Fragment {
|
||||
private static final String TAG = DownloadStatisticsFragment.class.getSimpleName();
|
||||
|
||||
private Disposable disposable;
|
||||
private RecyclerView downloadStatisticsList;
|
||||
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) {
|
||||
View root = inflater.inflate(R.layout.statistics_activity, container, false);
|
||||
downloadStatisticsList = root.findViewById(R.id.statistics_list);
|
||||
progressBar = root.findViewById(R.id.progressBar);
|
||||
listAdapter = new DownloadStatisticsListAdapter(getContext());
|
||||
downloadStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
downloadStatisticsList.setAdapter(listAdapter);
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
refreshDownloadStatistics();
|
||||
}
|
||||
|
||||
private void refreshDownloadStatistics() {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
downloadStatisticsList.setVisibility(View.GONE);
|
||||
loadStatistics();
|
||||
}
|
||||
|
||||
private void loadStatistics() {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
|
||||
disposable =
|
||||
Observable.fromCallable(() -> {
|
||||
DBReader.StatisticsData statisticsData = DBReader.getStatistics();
|
||||
Collections.sort(statisticsData.feeds, (item1, item2) ->
|
||||
CompareCompat.compareLong(item1.totalDownloadSize, item2.totalDownloadSize));
|
||||
return statisticsData;
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
listAdapter.update(result);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
downloadStatisticsList.setVisibility(View.VISIBLE);
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
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.activity.PreferenceActivity;
|
||||
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.core.util.comparator.CompareCompat;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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(getContext());
|
||||
listAdapter.setCountAll(countAll);
|
||||
feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
feedStatisticsList.setAdapter(listAdapter);
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
|
||||
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(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(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 DBReader.StatisticsData fetchStatistics() {
|
||||
DBReader.StatisticsData statisticsData = DBReader.getStatistics();
|
||||
if (countAll) {
|
||||
Collections.sort(statisticsData.feeds, (item1, item2) ->
|
||||
CompareCompat.compareLong(item1.timePlayedCountAll, item2.timePlayedCountAll));
|
||||
} else {
|
||||
Collections.sort(statisticsData.feeds, (item1, item2) ->
|
||||
CompareCompat.compareLong(item1.timePlayed, item2.timePlayed));
|
||||
}
|
||||
return statisticsData;
|
||||
}
|
||||
}
|
|
@ -1,180 +1,96 @@
|
|||
package de.danoeh.antennapod.fragment.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
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 androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.PreferenceActivity;
|
||||
import de.danoeh.antennapod.adapter.StatisticsListAdapter;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import io.reactivex.Completable;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Displays the 'statistics' screen
|
||||
*/
|
||||
public class StatisticsFragment extends Fragment {
|
||||
private static final String TAG = StatisticsFragment.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 StatisticsListAdapter listAdapter;
|
||||
private boolean countAll = false;
|
||||
private SharedPreferences prefs;
|
||||
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 TabLayout tabLayout;
|
||||
private ViewPager viewPager;
|
||||
|
||||
@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 StatisticsListAdapter(getContext());
|
||||
listAdapter.setCountAll(countAll);
|
||||
feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
feedStatisticsList.setAdapter(listAdapter);
|
||||
return root;
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
View rootView = inflater.inflate(R.layout.pager_fragment, container, false);
|
||||
viewPager = rootView.findViewById(R.id.viewpager);
|
||||
viewPager.setAdapter(new StatisticsPagerAdapter(getChildFragmentManager(), getResources()));
|
||||
|
||||
// Give the TabLayout the ViewPager
|
||||
tabLayout = rootView.findViewById(R.id.sliding_tabs);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label);
|
||||
refreshStatistics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
}
|
||||
public static class StatisticsPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.statistics, menu);
|
||||
menu.findItem(R.id.statistics_reset).setEnabled(!countAll);
|
||||
}
|
||||
private final Resources resources;
|
||||
|
||||
@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);
|
||||
public StatisticsPagerAdapter(FragmentManager fm, Resources resources) {
|
||||
super(fm);
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
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();
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
if (position == 0) {
|
||||
return new PlaybackStatisticsFragment();
|
||||
} else {
|
||||
return new DownloadStatisticsFragment();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@Override
|
||||
public int getCount() {
|
||||
return TOTAL_COUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case POS_LISTENED_HOURS:
|
||||
return resources.getString(R.string.playback_statistics_label);
|
||||
case POS_SPACE_TAKEN:
|
||||
return resources.getString(R.string.download_statistics_label);
|
||||
default:
|
||||
return super.getPageTitle(position);
|
||||
}
|
||||
}
|
||||
disposable = Observable.fromCallable(() -> DBReader.getStatistics(countAll))
|
||||
.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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
|
@ -41,7 +41,7 @@
|
|||
tools:text="Feed title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvTime"
|
||||
android:id="@+id/txtvValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/total_time_description"
|
||||
android:id="@+id/total_description"
|
||||
android:textSize="14sp"
|
||||
android:text="@string/total_time_listened_to_podcasts"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_above="@+id/total_time"/>
|
||||
|
|
@ -870,12 +870,10 @@ public final class DBReader {
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
@NonNull
|
||||
public static StatisticsData getStatistics(boolean sortByCountAll) {
|
||||
public static StatisticsData getStatistics() {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
|
||||
|
@ -891,6 +889,7 @@ public final class DBReader {
|
|||
long episodes = 0;
|
||||
long episodesStarted = 0;
|
||||
long episodesStartedIncludingMarked = 0;
|
||||
long totalDownloadSize = 0;
|
||||
List<FeedItem> items = getFeed(feed.getId()).getItems();
|
||||
for (FeedItem item : items) {
|
||||
FeedMedia media = item.getMedia();
|
||||
|
@ -915,43 +914,24 @@ public final class DBReader {
|
|||
}
|
||||
|
||||
feedTotalTime += media.getDuration() / 1000;
|
||||
|
||||
if (media.isDownloaded()) {
|
||||
totalDownloadSize = totalDownloadSize + media.getSize();
|
||||
}
|
||||
|
||||
episodes++;
|
||||
}
|
||||
feedTime.add(new StatisticsItem(
|
||||
feed, feedTotalTime, feedPlayedTime, feedPlayedTimeCountAll, episodes,
|
||||
episodesStarted, episodesStartedIncludingMarked));
|
||||
episodesStarted, episodesStartedIncludingMarked, totalDownloadSize));
|
||||
totalTime += feedPlayedTime;
|
||||
totalTimeCountAll += feedPlayedTimeCountAll;
|
||||
}
|
||||
|
||||
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, 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
|
||||
|
@ -963,12 +943,12 @@ public final class DBReader {
|
|||
*/
|
||||
public final long totalTime;
|
||||
|
||||
public final List<StatisticsItem> feedTime;
|
||||
public final List<StatisticsItem> feeds;
|
||||
|
||||
public StatisticsData(long totalTime, long totalTimeCountAll, List<StatisticsItem> feedTime) {
|
||||
public StatisticsData(long totalTime, long totalTimeCountAll, List<StatisticsItem> feeds) {
|
||||
this.totalTime = totalTime;
|
||||
this.totalTimeCountAll = totalTimeCountAll;
|
||||
this.feedTime = feedTime;
|
||||
this.feeds = feeds;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -993,9 +973,14 @@ public final class DBReader {
|
|||
* 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;
|
||||
|
||||
public StatisticsItem(Feed feed, long time, long timePlayed, long timePlayedCountAll,
|
||||
long episodes, long episodesStarted, long episodesStartedIncludingMarked) {
|
||||
long episodes, long episodesStarted, long episodesStartedIncludingMarked,
|
||||
long totalDownloadSize) {
|
||||
this.feed = feed;
|
||||
this.time = time;
|
||||
this.timePlayed = timePlayed;
|
||||
|
@ -1003,6 +988,7 @@ public final class DBReader {
|
|||
this.episodes = episodes;
|
||||
this.episodesStarted = episodesStarted;
|
||||
this.episodesStartedIncludingMarked = episodesStartedIncludingMarked;
|
||||
this.totalDownloadSize = totalDownloadSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package de.danoeh.antennapod.core.util.comparator;
|
||||
|
||||
/**
|
||||
* Some compare() methods are not available before API 19.
|
||||
* This class provides fallbacks
|
||||
*/
|
||||
public class CompareCompat {
|
||||
|
||||
private CompareCompat() {
|
||||
// Must not be instantiated
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static int compareLong(long long1, long long2) {
|
||||
//noinspection UseCompareMethod
|
||||
if (long1 > long2) {
|
||||
return -1;
|
||||
} else if (long1 < long2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,8 @@
|
|||
<string name="gpodnet_auth_label">gpodder.net Login</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>
|
||||
|
||||
<!-- Statistics fragment -->
|
||||
<string name="total_time_listened_to_podcasts">Total time of podcasts played:</string>
|
||||
|
@ -40,6 +42,9 @@
|
|||
<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>
|
||||
|
||||
<!-- Download Statistics fragment -->
|
||||
<string name="total_size_downloaded_podcasts">Total size of downloaded podcasts:</string>
|
||||
|
||||
<!-- Main activity -->
|
||||
<string name="drawer_open">Open menu</string>
|
||||
<string name="drawer_close">Close menu</string>
|
||||
|
|
Loading…
Reference in New Issue