mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2025-01-03 14:40:07 +02:00
Charts
This commit is contained in:
parent
c04a51f3b7
commit
74b107f1d3
4 changed files with 158 additions and 114 deletions
|
@ -15,34 +15,31 @@ package app.fedilab.android.mastodon.activities;
|
||||||
* see <http://www.gnu.org/licenses>. */
|
* see <http://www.gnu.org/licenses>. */
|
||||||
|
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.appcompat.widget.LinearLayoutCompat;
|
import androidx.appcompat.widget.LinearLayoutCompat;
|
||||||
|
|
||||||
import com.github.mikephil.charting.components.Description;
|
import com.github.mikephil.charting.components.Description;
|
||||||
|
import com.github.mikephil.charting.components.MarkerView;
|
||||||
import com.github.mikephil.charting.components.XAxis;
|
import com.github.mikephil.charting.components.XAxis;
|
||||||
import com.github.mikephil.charting.data.Entry;
|
import com.github.mikephil.charting.data.Entry;
|
||||||
import com.github.mikephil.charting.data.LineData;
|
import com.github.mikephil.charting.data.LineData;
|
||||||
import com.github.mikephil.charting.data.LineDataSet;
|
import com.github.mikephil.charting.data.LineDataSet;
|
||||||
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
|
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
|
||||||
|
import com.github.mikephil.charting.highlight.Highlight;
|
||||||
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
|
||||||
import com.github.mikephil.charting.renderer.XAxisRenderer;
|
|
||||||
import com.github.mikephil.charting.utils.MPPointF;
|
import com.github.mikephil.charting.utils.MPPointF;
|
||||||
import com.github.mikephil.charting.utils.Transformer;
|
|
||||||
import com.github.mikephil.charting.utils.Utils;
|
|
||||||
import com.github.mikephil.charting.utils.ViewPortHandler;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@ -52,7 +49,6 @@ import app.fedilab.android.databinding.ActivityCheckHomeCachetBinding;
|
||||||
import app.fedilab.android.mastodon.client.entities.api.Status;
|
import app.fedilab.android.mastodon.client.entities.api.Status;
|
||||||
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
|
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
|
||||||
import app.fedilab.android.mastodon.exception.DBException;
|
import app.fedilab.android.mastodon.exception.DBException;
|
||||||
import app.fedilab.android.mastodon.helper.Helper;
|
|
||||||
import app.fedilab.android.mastodon.helper.ThemeHelper;
|
import app.fedilab.android.mastodon.helper.ThemeHelper;
|
||||||
import es.dmoral.toasty.Toasty;
|
import es.dmoral.toasty.Toasty;
|
||||||
|
|
||||||
|
@ -62,6 +58,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||||
|
|
||||||
private ActivityCheckHomeCachetBinding binding;
|
private ActivityCheckHomeCachetBinding binding;
|
||||||
private List<Status> statuses;
|
private List<Status> statuses;
|
||||||
|
private ArrayList<String> xVals;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
@ -77,16 +74,6 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
binding.chart.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
||||||
@Override
|
|
||||||
public void onGlobalLayout() {
|
|
||||||
binding.chart.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
|
||||||
int height = (binding.chart.getWidth());
|
|
||||||
LinearLayoutCompat.LayoutParams params = new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
|
|
||||||
binding.chart.setLayoutParams(params);
|
|
||||||
binding.chart.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -95,83 +82,101 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||||
runOnUiThread(() -> binding.noAction.setVisibility(View.VISIBLE));
|
runOnUiThread(() -> binding.noAction.setVisibility(View.VISIBLE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
|
||||||
final ArrayList<String> xVals = new ArrayList<>();
|
binding.progress.setVisibility(View.GONE);
|
||||||
String xDate;
|
binding.chart.setVisibility(View.VISIBLE);
|
||||||
int inc = 0;
|
binding.chart.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
//We loop through cache
|
@Override
|
||||||
List<Entry> statusEntry = new ArrayList<>();
|
public void onGlobalLayout() {
|
||||||
int index = 0;
|
binding.chart.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
for (Status status : statuses) {
|
int height = (binding.chart.getWidth());
|
||||||
//We aggregate message in same hour range
|
LinearLayoutCompat.LayoutParams params = new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
|
||||||
boolean sameHourRange = true;
|
binding.chart.setLayoutParams(params);
|
||||||
int count = 0;
|
binding.chart.setVisibility(View.VISIBLE);
|
||||||
while (inc < statuses.size() && sameHourRange) {
|
}
|
||||||
Calendar currentStatusDate = Calendar.getInstance();
|
});
|
||||||
currentStatusDate.setTime(statuses.get(inc).created_at);
|
xVals = new ArrayList<>();
|
||||||
String xDateH = new SimpleDateFormat("hh", Locale.getDefault()).format(statuses.get(inc).created_at);
|
String xDate;
|
||||||
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
|
int inc = 0;
|
||||||
String xDateD = df.format(statuses.get(inc).created_at);
|
//We loop through cache
|
||||||
xDate = xDateD + " " + String.format(Locale.getDefault(), "%sh", xDateH);
|
List<Entry> statusEntry = new ArrayList<>();
|
||||||
if (inc + 1 < statuses.size()) {
|
int index = 0;
|
||||||
Calendar nextStatusDate = Calendar.getInstance();
|
for (Status status : statuses) {
|
||||||
nextStatusDate.setTime(statuses.get(inc + 1).created_at);
|
//We aggregate message in same hour range
|
||||||
if (currentStatusDate.get(Calendar.HOUR) != nextStatusDate.get(Calendar.HOUR)) {
|
boolean sameHourRange = true;
|
||||||
sameHourRange = false;
|
int count = 0;
|
||||||
statusEntry.add(new Entry(index, count));
|
while (inc < statuses.size() && sameHourRange) {
|
||||||
index++;
|
Calendar currentStatusDate = Calendar.getInstance();
|
||||||
xVals.add(xDate);
|
currentStatusDate.setTime(statuses.get(inc).created_at);
|
||||||
} else {
|
String xDateH = new SimpleDateFormat("hh", Locale.getDefault()).format(statuses.get(inc).created_at);
|
||||||
count++;
|
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
|
||||||
}
|
String xDateD = df.format(statuses.get(inc).created_at);
|
||||||
} else { //Last item
|
xDate = xDateD + " " + String.format(Locale.getDefault(), "%sh", xDateH);
|
||||||
count++;
|
if (inc + 1 < statuses.size()) {
|
||||||
statusEntry.add(new Entry(index, count));
|
Calendar nextStatusDate = Calendar.getInstance();
|
||||||
xVals.add(xDate);
|
nextStatusDate.setTime(statuses.get(inc + 1).created_at);
|
||||||
|
if (currentStatusDate.get(Calendar.HOUR) != nextStatusDate.get(Calendar.HOUR)) {
|
||||||
|
sameHourRange = false;
|
||||||
|
statusEntry.add(new Entry(index, count));
|
||||||
|
index++;
|
||||||
|
xVals.add(xDate);
|
||||||
|
} else {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} else { //Last item
|
||||||
|
count++;
|
||||||
|
statusEntry.add(new Entry(index, count));
|
||||||
|
xVals.add(xDate);
|
||||||
|
}
|
||||||
|
inc++;
|
||||||
}
|
}
|
||||||
inc++;
|
|
||||||
}
|
}
|
||||||
}
|
List<ILineDataSet> dataSets = new ArrayList<>();
|
||||||
List<ILineDataSet> dataSets = new ArrayList<>();
|
|
||||||
|
|
||||||
LineDataSet dataStatus = new LineDataSet(statusEntry, getString(R.string.cached_messages));
|
LineDataSet dataStatus = new LineDataSet(statusEntry, getString(R.string.cached_messages));
|
||||||
dataStatus.setDrawValues(false);
|
dataStatus.setDrawValues(false);
|
||||||
dataStatus.setDrawFilled(true);
|
dataStatus.setDrawFilled(true);
|
||||||
dataStatus.setDrawCircles(false);
|
dataStatus.setDrawCircles(false);
|
||||||
dataStatus.setDrawCircleHole(false);
|
dataStatus.setDrawCircleHole(false);
|
||||||
dataStatus.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
dataStatus.setMode(LineDataSet.Mode.CUBIC_BEZIER);
|
||||||
dataSets.add(dataStatus);
|
dataSets.add(dataStatus);
|
||||||
|
|
||||||
LineData data = new LineData(dataSets);
|
LineData data = new LineData(dataSets);
|
||||||
binding.chart.setData(data);
|
binding.chart.setData(data);
|
||||||
IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() {
|
IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() {
|
||||||
@Override
|
@Override
|
||||||
public String getFormattedValue(float value) {
|
public String getFormattedValue(float value) {
|
||||||
if (value < xVals.size()) {
|
if (value < xVals.size()) {
|
||||||
return xVals.get((int) value);
|
return xVals.get((int) value);
|
||||||
} else
|
} else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
binding.chart.setExtraBottomOffset(80);
|
|
||||||
// binding.chart.getXAxis().setGranularity(1f);
|
|
||||||
binding.chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
|
|
||||||
binding.chart.getXAxis().setLabelRotationAngle(-45f);
|
|
||||||
binding.chart.getXAxis().setValueFormatter(formatter);
|
|
||||||
binding.chart.getXAxis().setEnabled(true);
|
|
||||||
binding.chart.getXAxis().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
|
||||||
binding.chart.getAxisLeft().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
|
||||||
binding.chart.getAxisRight().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
|
||||||
binding.chart.getLegend().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
|
||||||
binding.chart.getAxisLeft().setAxisMinimum(0f);
|
|
||||||
binding.chart.getAxisRight().setAxisMinimum(0f);
|
|
||||||
binding.chart.getXAxis().setLabelCount(10, true);
|
|
||||||
binding.chart.getLegend().setEnabled(false);
|
|
||||||
|
|
||||||
Description description = binding.chart.getDescription();
|
binding.chart.setExtraBottomOffset(80);
|
||||||
description.setEnabled(false);
|
// binding.chart.getXAxis().setGranularity(1f);
|
||||||
|
binding.chart.getXAxis().setPosition(XAxis.XAxisPosition.BOTTOM);
|
||||||
|
binding.chart.getXAxis().setLabelRotationAngle(-45f);
|
||||||
|
binding.chart.getXAxis().setValueFormatter(formatter);
|
||||||
|
binding.chart.getXAxis().setEnabled(true);
|
||||||
|
binding.chart.getXAxis().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
||||||
|
binding.chart.getAxisLeft().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
||||||
|
binding.chart.getAxisRight().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
||||||
|
binding.chart.getLegend().setTextColor(ThemeHelper.getAttColor(CheckHomeCacheActivity.this, R.attr.colorOnBackground));
|
||||||
|
binding.chart.getAxisLeft().setAxisMinimum(0f);
|
||||||
|
binding.chart.getAxisRight().setAxisMinimum(0f);
|
||||||
|
binding.chart.getXAxis().setLabelCount(10, true);
|
||||||
|
binding.chart.getLegend().setEnabled(false);
|
||||||
|
binding.chart.setTouchEnabled(true);
|
||||||
|
Description description = binding.chart.getDescription();
|
||||||
|
description.setEnabled(false);
|
||||||
|
CustomMarkerView mv = new CustomMarkerView(CheckHomeCacheActivity.this, R.layout.custom_marker_view_layout);
|
||||||
|
binding.chart.setMarkerView(mv);
|
||||||
|
|
||||||
|
binding.chart.invalidate();
|
||||||
|
});
|
||||||
|
|
||||||
binding.chart.invalidate();
|
|
||||||
|
|
||||||
} catch (DBException | NegativeArraySizeException e) {
|
} catch (DBException | NegativeArraySizeException e) {
|
||||||
binding.noAction.setVisibility(View.VISIBLE);
|
binding.noAction.setVisibility(View.VISIBLE);
|
||||||
|
@ -182,6 +187,41 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class CustomMarkerView extends MarkerView {
|
||||||
|
|
||||||
|
private final TextView tvContent;
|
||||||
|
private MPPointF mOffset;
|
||||||
|
|
||||||
|
public CustomMarkerView(Context context, int layoutResource) {
|
||||||
|
super(context, layoutResource);
|
||||||
|
|
||||||
|
// find your layout components
|
||||||
|
tvContent = findViewById(R.id.tvContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbacks everytime the MarkerView is redrawn, can be used to update the
|
||||||
|
// content (user-interface)
|
||||||
|
@Override
|
||||||
|
public void refreshContent(Entry e, Highlight highlight) {
|
||||||
|
tvContent.setText(getString(R.string.messages, (int) e.getY()) + "\r\n" + xVals.get((int) e.getX()));
|
||||||
|
|
||||||
|
// this will perform necessary layouting
|
||||||
|
super.refreshContent(e, highlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPPointF getOffset() {
|
||||||
|
if (mOffset == null) {
|
||||||
|
// center the marker horizontally and vertically
|
||||||
|
mOffset = new MPPointF(-(getWidth() / 2), -getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
return mOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
if (item.getItemId() == android.R.id.home) {
|
if (item.getItemId() == android.R.id.home) {
|
||||||
|
@ -190,30 +230,4 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LineChartXAxisValueFormatter extends IndexAxisValueFormatter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormattedValue(float value) {
|
|
||||||
|
|
||||||
long emissionsMilliSince1970Time = ((long) value);
|
|
||||||
Log.v(Helper.TAG, "value: " + value);
|
|
||||||
Date timeMilliseconds = new Date(emissionsMilliSince1970Time);
|
|
||||||
DateFormat dateTimeFormat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
|
|
||||||
return dateTimeFormat.format(timeMilliseconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CustomXAxisRenderer extends XAxisRenderer {
|
|
||||||
public CustomXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {
|
|
||||||
super(viewPortHandler, xAxis, trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {
|
|
||||||
String[] line = formattedLabel.split("\n");
|
|
||||||
Utils.drawXAxisValue(c, line[0], x, y, mAxisLabelPaint, anchor, angleDegrees);
|
|
||||||
Utils.drawXAxisValue(c, line[1], x + mAxisLabelPaint.getTextSize(), y + mAxisLabelPaint.getTextSize(), mAxisLabelPaint, anchor, angleDegrees);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,16 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:indeterminate="true" />
|
||||||
|
|
||||||
<com.github.mikephil.charting.charts.LineChart
|
<com.github.mikephil.charting.charts.LineChart
|
||||||
android:id="@+id/chart"
|
android:id="@+id/chart"
|
||||||
|
android:visibility="gone"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:background="@color/black">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvContent"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginTop="7dp"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text=""
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
|
@ -1931,4 +1931,5 @@
|
||||||
<string name="set_autoplay_gif">Autoplay animated media</string>
|
<string name="set_autoplay_gif">Autoplay animated media</string>
|
||||||
<string name="no_cached_messages">No Home cached messages!</string>
|
<string name="no_cached_messages">No Home cached messages!</string>
|
||||||
<string name="check_home_cache">Check Home cache</string>
|
<string name="check_home_cache">Check Home cache</string>
|
||||||
|
<string name="messages">%1$d cached messages</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue