Added colorful dots to statistics

This commit is contained in:
ByteHamster 2020-01-12 10:35:32 +01:00
parent 2f0c627b15
commit f5e819f5dc
5 changed files with 101 additions and 49 deletions

View File

@ -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));
} }
} }

View File

@ -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));

View File

@ -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);
} }

View File

@ -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;
} }

View File

@ -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"/>