Added colorful dots to statistics
This commit is contained in:
parent
2f0c627b15
commit
f5e819f5dc
@ -5,9 +5,10 @@ import android.content.Context;
|
|||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.storage.DBReader;
|
import de.danoeh.antennapod.core.storage.DBReader;
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
|
import de.danoeh.antennapod.view.PieChartView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter for the download statistics list
|
* Adapter for the download statistics list.
|
||||||
*/
|
*/
|
||||||
public class DownloadStatisticsListAdapter extends StatisticsListAdapter {
|
public class DownloadStatisticsListAdapter extends StatisticsListAdapter {
|
||||||
|
|
||||||
@ -21,25 +22,23 @@ public class DownloadStatisticsListAdapter extends StatisticsListAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onBindHeaderViewHolder(HeaderHolder holder) {
|
String getHeaderValue() {
|
||||||
long totalDownloadSize = 0;
|
return Converter.byteToString((long) pieChartData.getSum());
|
||||||
|
}
|
||||||
|
|
||||||
for (DBReader.StatisticsItem item: statisticsData.feeds) {
|
@Override
|
||||||
totalDownloadSize = totalDownloadSize + item.totalDownloadSize;
|
PieChartView.PieChartData generateChartData(DBReader.StatisticsData statisticsData) {
|
||||||
}
|
|
||||||
holder.totalTime.setText(Converter.byteToString(totalDownloadSize));
|
|
||||||
float[] dataValues = new float[statisticsData.feeds.size()];
|
float[] dataValues = new float[statisticsData.feeds.size()];
|
||||||
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
||||||
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
||||||
dataValues[i] = item.totalDownloadSize;
|
dataValues[i] = item.totalDownloadSize;
|
||||||
}
|
}
|
||||||
holder.pieChart.setData(dataValues);
|
return new PieChartView.PieChartData(dataValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onBindFeedViewHolder(StatisticsHolder holder, int position) {
|
void onBindFeedViewHolder(StatisticsHolder holder, DBReader.StatisticsItem item) {
|
||||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
holder.value.setText(Converter.byteToString(item.totalDownloadSize));
|
||||||
holder.value.setText(Converter.byteToString(statsItem.totalDownloadSize));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,10 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.core.storage.DBReader;
|
import de.danoeh.antennapod.core.storage.DBReader;
|
||||||
import de.danoeh.antennapod.core.util.Converter;
|
import de.danoeh.antennapod.core.util.Converter;
|
||||||
|
import de.danoeh.antennapod.view.PieChartView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter for the playback statistics list
|
* Adapter for the playback statistics list.
|
||||||
*/
|
*/
|
||||||
public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
|
public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
|
||||||
|
|
||||||
@ -28,20 +29,22 @@ public class PlaybackStatisticsListAdapter extends StatisticsListAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onBindHeaderViewHolder(HeaderHolder holder) {
|
String getHeaderValue() {
|
||||||
long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime;
|
return Converter.shortLocalizedDuration(context, (long) pieChartData.getSum());
|
||||||
holder.totalTime.setText(Converter.shortLocalizedDuration(context, time));
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
PieChartView.PieChartData generateChartData(DBReader.StatisticsData statisticsData) {
|
||||||
float[] dataValues = new float[statisticsData.feeds.size()];
|
float[] dataValues = new float[statisticsData.feeds.size()];
|
||||||
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
for (int i = 0; i < statisticsData.feeds.size(); i++) {
|
||||||
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
DBReader.StatisticsItem item = statisticsData.feeds.get(i);
|
||||||
dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
|
dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed;
|
||||||
}
|
}
|
||||||
holder.pieChart.setData(dataValues);
|
return new PieChartView.PieChartData(dataValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void onBindFeedViewHolder(StatisticsHolder holder, int position) {
|
void onBindFeedViewHolder(StatisticsHolder holder, DBReader.StatisticsItem statsItem) {
|
||||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
|
||||||
long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
|
long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed;
|
||||||
holder.value.setText(Converter.shortLocalizedDuration(context, time));
|
holder.value.setText(Converter.shortLocalizedDuration(context, time));
|
||||||
|
|
||||||
|
@ -18,13 +18,14 @@ import de.danoeh.antennapod.core.storage.DBReader;
|
|||||||
import de.danoeh.antennapod.view.PieChartView;
|
import de.danoeh.antennapod.view.PieChartView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent Adapter for the playback and download statistics list
|
* Parent Adapter for the playback and download statistics list.
|
||||||
*/
|
*/
|
||||||
public abstract 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_HEADER = 0;
|
||||||
private static final int TYPE_FEED = 1;
|
private static final int TYPE_FEED = 1;
|
||||||
final Context context;
|
final Context context;
|
||||||
DBReader.StatisticsData statisticsData;
|
private DBReader.StatisticsData statisticsData;
|
||||||
|
PieChartView.PieChartData pieChartData;
|
||||||
|
|
||||||
StatisticsListAdapter(Context context) {
|
StatisticsListAdapter(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -63,7 +64,9 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) {
|
||||||
if (getItemViewType(position) == TYPE_HEADER) {
|
if (getItemViewType(position) == TYPE_HEADER) {
|
||||||
onBindHeaderViewHolder((HeaderHolder) h);
|
HeaderHolder holder = (HeaderHolder) h;
|
||||||
|
holder.pieChart.setData(pieChartData);
|
||||||
|
holder.totalTime.setText(getHeaderValue());
|
||||||
} else {
|
} else {
|
||||||
StatisticsHolder holder = (StatisticsHolder) h;
|
StatisticsHolder holder = (StatisticsHolder) h;
|
||||||
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
DBReader.StatisticsItem statsItem = statisticsData.feeds.get(position - 1);
|
||||||
@ -78,12 +81,14 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
|
|||||||
.into(holder.image);
|
.into(holder.image);
|
||||||
|
|
||||||
holder.title.setText(statsItem.feed.getTitle());
|
holder.title.setText(statsItem.feed.getTitle());
|
||||||
onBindFeedViewHolder(holder, position);
|
holder.chip.setTextColor(pieChartData.getColorOfItem(position - 1));
|
||||||
|
onBindFeedViewHolder(holder, statsItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(DBReader.StatisticsData statistics) {
|
public void update(DBReader.StatisticsData statistics) {
|
||||||
this.statisticsData = statistics;
|
this.statisticsData = statistics;
|
||||||
|
pieChartData = generateChartData(statistics);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,18 +107,22 @@ public abstract class StatisticsListAdapter extends RecyclerView.Adapter<Recycle
|
|||||||
ImageView image;
|
ImageView image;
|
||||||
TextView title;
|
TextView title;
|
||||||
TextView value;
|
TextView value;
|
||||||
|
TextView chip;
|
||||||
|
|
||||||
StatisticsHolder(View itemView) {
|
StatisticsHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
image = itemView.findViewById(R.id.imgvCover);
|
image = itemView.findViewById(R.id.imgvCover);
|
||||||
title = itemView.findViewById(R.id.txtvTitle);
|
title = itemView.findViewById(R.id.txtvTitle);
|
||||||
value = itemView.findViewById(R.id.txtvValue);
|
value = itemView.findViewById(R.id.txtvValue);
|
||||||
|
chip = itemView.findViewById(R.id.chip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract int getHeaderCaptionResourceId();
|
abstract int getHeaderCaptionResourceId();
|
||||||
|
|
||||||
abstract void onBindHeaderViewHolder(HeaderHolder holder);
|
abstract String getHeaderValue();
|
||||||
|
|
||||||
abstract void onBindFeedViewHolder(StatisticsHolder holder, int position);
|
abstract PieChartView.PieChartData generateChartData(DBReader.StatisticsData statisticsData);
|
||||||
|
|
||||||
|
abstract void onBindFeedViewHolder(StatisticsHolder holder, DBReader.StatisticsItem item);
|
||||||
}
|
}
|
||||||
|
@ -39,14 +39,10 @@ public class PieChartView extends AppCompatImageView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set array od names, array of values and array of colors.
|
* Set of data values to display.
|
||||||
*/
|
*/
|
||||||
public void setData(float[] dataValues) {
|
public void setData(PieChartData data) {
|
||||||
drawable.dataValues = dataValues;
|
drawable.data = data;
|
||||||
drawable.valueSum = 0;
|
|
||||||
for (float datum : dataValues) {
|
|
||||||
drawable.valueSum += datum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -56,15 +52,50 @@ public class PieChartView extends AppCompatImageView {
|
|||||||
setMeasuredDimension(width, width / 2);
|
setMeasuredDimension(width, width / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PieChartDrawable extends Drawable {
|
public static class PieChartData {
|
||||||
private static final float MIN_DEGREES = 10f;
|
|
||||||
private static final float PADDING_DEGREES = 3f;
|
|
||||||
private static final float STROKE_SIZE = 15f;
|
|
||||||
private static final int[] COLOR_VALUES = new int[]{0xFF3775E6, 0xffe51c23, 0xffff9800, 0xff259b24, 0xff9c27b0,
|
private static final int[] COLOR_VALUES = new int[]{0xFF3775E6, 0xffe51c23, 0xffff9800, 0xff259b24, 0xff9c27b0,
|
||||||
0xff0099c6, 0xffdd4477, 0xff66aa00, 0xffb82e2e, 0xff316395,
|
0xff0099c6, 0xffdd4477, 0xff66aa00, 0xffb82e2e, 0xff316395,
|
||||||
0xff994499, 0xff22aa99, 0xffaaaa11, 0xff6633cc, 0xff0073e6};
|
0xff994499, 0xff22aa99, 0xffaaaa11, 0xff6633cc, 0xff0073e6};
|
||||||
private float[] dataValues;
|
|
||||||
private float valueSum;
|
private final float valueSum;
|
||||||
|
private final float[] values;
|
||||||
|
|
||||||
|
public PieChartData(float[] values) {
|
||||||
|
this.values = values;
|
||||||
|
float valueSum = 0;
|
||||||
|
for (float datum : values) {
|
||||||
|
valueSum += datum;
|
||||||
|
}
|
||||||
|
this.valueSum = valueSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSum() {
|
||||||
|
return valueSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPercentageOfItem(int index) {
|
||||||
|
if (valueSum == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return values[index] / valueSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLargeEnoughToDisplay(int index) {
|
||||||
|
return getPercentageOfItem(index) > 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColorOfItem(int index) {
|
||||||
|
if (!isLargeEnoughToDisplay(index)) {
|
||||||
|
return Color.GRAY;
|
||||||
|
}
|
||||||
|
return COLOR_VALUES[index % COLOR_VALUES.length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PieChartDrawable extends Drawable {
|
||||||
|
private static final float PADDING_DEGREES = 3f;
|
||||||
|
private static final float STROKE_SIZE = 15f;
|
||||||
|
private PieChartData data;
|
||||||
private final Paint paint;
|
private final Paint paint;
|
||||||
|
|
||||||
private PieChartDrawable() {
|
private PieChartDrawable() {
|
||||||
@ -78,22 +109,18 @@ public class PieChartView extends AppCompatImageView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(@NonNull Canvas canvas) {
|
public void draw(@NonNull Canvas canvas) {
|
||||||
if (valueSum == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
float radius = getBounds().height() - STROKE_SIZE;
|
float radius = getBounds().height() - STROKE_SIZE;
|
||||||
float center = getBounds().width() / 2.f;
|
float center = getBounds().width() / 2.f;
|
||||||
RectF arcBounds = new RectF(center - radius, STROKE_SIZE, center + radius, STROKE_SIZE + radius * 2);
|
RectF arcBounds = new RectF(center - radius, STROKE_SIZE, center + radius, STROKE_SIZE + radius * 2);
|
||||||
|
|
||||||
float startAngle = 180;
|
float startAngle = 180;
|
||||||
for (int i = 0; i < dataValues.length; i++) {
|
for (int i = 0; i < data.values.length; i++) {
|
||||||
float datum = dataValues[i];
|
if (!data.isLargeEnoughToDisplay(i)) {
|
||||||
float sweepAngle = (180f - PADDING_DEGREES) * (datum / valueSum);
|
|
||||||
if (sweepAngle < MIN_DEGREES) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
paint.setColor(COLOR_VALUES[i % COLOR_VALUES.length]);
|
paint.setColor(data.getColorOfItem(i));
|
||||||
float padding = i == 0 ? PADDING_DEGREES / 2 : PADDING_DEGREES;
|
float padding = i == 0 ? PADDING_DEGREES / 2 : PADDING_DEGREES;
|
||||||
|
float sweepAngle = (180f - PADDING_DEGREES) * data.getPercentageOfItem(i);
|
||||||
canvas.drawArc(arcBounds, startAngle + padding, sweepAngle - padding, false, paint);
|
canvas.drawArc(arcBounds, startAngle + padding, sweepAngle - padding, false, paint);
|
||||||
startAngle = startAngle + sweepAngle;
|
startAngle = startAngle + sweepAngle;
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,26 @@
|
|||||||
android:layout_marginLeft="16dp"
|
android:layout_marginLeft="16dp"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_toRightOf="@id/imgvCover"
|
android:layout_toRightOf="@id/imgvCover"
|
||||||
|
android:layout_toEndOf="@id/imgvCover"
|
||||||
android:layout_alignTop="@id/imgvCover"
|
android:layout_alignTop="@id/imgvCover"
|
||||||
android:layout_alignWithParentIfMissing="true"
|
android:layout_alignWithParentIfMissing="true"
|
||||||
tools:text="Feed title"/>
|
tools:text="Feed title"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/chip"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:layout_toEndOf="@+id/imgvCover"
|
||||||
|
android:layout_toRightOf="@+id/imgvCover"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_below="@+id/txtvTitle"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:text="⬤"
|
||||||
|
tools:ignore="HardcodedText"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/txtvValue"
|
android:id="@+id/txtvValue"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -47,10 +63,8 @@
|
|||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:textColor="?android:attr/textColorTertiary"
|
android:textColor="?android:attr/textColorTertiary"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:layout_toEndOf="@+id/imgvCover"
|
android:layout_toEndOf="@+id/chip"
|
||||||
android:layout_toRightOf="@+id/imgvCover"
|
android:layout_toRightOf="@+id/chip"
|
||||||
android:layout_marginLeft="16dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_below="@+id/txtvTitle"
|
android:layout_below="@+id/txtvTitle"
|
||||||
tools:text="23 hours"/>
|
tools:text="23 hours"/>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user