From 74b107f1d38ca412e38efa44c8233e75a2faacf2 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 4 Mar 2023 18:28:59 +0100 Subject: [PATCH] Charts --- .../activities/CheckHomeCacheActivity.java | 242 +++++++++--------- .../layout/activity_check_home_cachet.xml | 8 + .../layout/custom_marker_view_layout.xml | 21 ++ app/src/main/res/values/strings.xml | 1 + 4 files changed, 158 insertions(+), 114 deletions(-) create mode 100644 app/src/main/res/layouts/mastodon/layout/custom_marker_view_layout.xml diff --git a/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java b/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java index 1fdc505b..ada8ea43 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java +++ b/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java @@ -15,34 +15,31 @@ package app.fedilab.android.mastodon.activities; * see . */ -import android.graphics.Canvas; +import android.content.Context; import android.os.Bundle; -import android.util.Log; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.widget.TextView; import androidx.appcompat.widget.LinearLayoutCompat; 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.data.Entry; import com.github.mikephil.charting.data.LineData; import com.github.mikephil.charting.data.LineDataSet; 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.renderer.XAxisRenderer; 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.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.List; 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.app.StatusCache; import app.fedilab.android.mastodon.exception.DBException; -import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.ThemeHelper; import es.dmoral.toasty.Toasty; @@ -62,6 +58,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity { private ActivityCheckHomeCachetBinding binding; private List statuses; + private ArrayList xVals; @Override protected void onCreate(Bundle savedInstanceState) { @@ -77,16 +74,6 @@ public class CheckHomeCacheActivity extends BaseBarActivity { finish(); 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(() -> { try { @@ -95,83 +82,101 @@ public class CheckHomeCacheActivity extends BaseBarActivity { runOnUiThread(() -> binding.noAction.setVisibility(View.VISIBLE)); return; } + runOnUiThread(() -> { - final ArrayList xVals = new ArrayList<>(); - String xDate; - int inc = 0; - //We loop through cache - List statusEntry = new ArrayList<>(); - int index = 0; - for (Status status : statuses) { - //We aggregate message in same hour range - boolean sameHourRange = true; - int count = 0; - while (inc < statuses.size() && sameHourRange) { - Calendar currentStatusDate = Calendar.getInstance(); - currentStatusDate.setTime(statuses.get(inc).created_at); - String xDateH = new SimpleDateFormat("hh", Locale.getDefault()).format(statuses.get(inc).created_at); - SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); - String xDateD = df.format(statuses.get(inc).created_at); - xDate = xDateD + " " + String.format(Locale.getDefault(), "%sh", xDateH); - if (inc + 1 < statuses.size()) { - Calendar nextStatusDate = Calendar.getInstance(); - 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); + binding.progress.setVisibility(View.GONE); + binding.chart.setVisibility(View.VISIBLE); + 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); + } + }); + xVals = new ArrayList<>(); + String xDate; + int inc = 0; + //We loop through cache + List statusEntry = new ArrayList<>(); + int index = 0; + for (Status status : statuses) { + //We aggregate message in same hour range + boolean sameHourRange = true; + int count = 0; + while (inc < statuses.size() && sameHourRange) { + Calendar currentStatusDate = Calendar.getInstance(); + currentStatusDate.setTime(statuses.get(inc).created_at); + String xDateH = new SimpleDateFormat("hh", Locale.getDefault()).format(statuses.get(inc).created_at); + SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); + String xDateD = df.format(statuses.get(inc).created_at); + xDate = xDateD + " " + String.format(Locale.getDefault(), "%sh", xDateH); + if (inc + 1 < statuses.size()) { + Calendar nextStatusDate = Calendar.getInstance(); + 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 dataSets = new ArrayList<>(); + List dataSets = new ArrayList<>(); - LineDataSet dataStatus = new LineDataSet(statusEntry, getString(R.string.cached_messages)); - dataStatus.setDrawValues(false); - dataStatus.setDrawFilled(true); - dataStatus.setDrawCircles(false); - dataStatus.setDrawCircleHole(false); - dataStatus.setMode(LineDataSet.Mode.CUBIC_BEZIER); - dataSets.add(dataStatus); + LineDataSet dataStatus = new LineDataSet(statusEntry, getString(R.string.cached_messages)); + dataStatus.setDrawValues(false); + dataStatus.setDrawFilled(true); + dataStatus.setDrawCircles(false); + dataStatus.setDrawCircleHole(false); + dataStatus.setMode(LineDataSet.Mode.CUBIC_BEZIER); + dataSets.add(dataStatus); - LineData data = new LineData(dataSets); - binding.chart.setData(data); - IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() { - @Override - public String getFormattedValue(float value) { - if (value < xVals.size()) { - return xVals.get((int) value); - } else - 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); + LineData data = new LineData(dataSets); + binding.chart.setData(data); + IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() { + @Override + public String getFormattedValue(float value) { + if (value < xVals.size()) { + return xVals.get((int) value); + } else + return ""; + } + }; - Description description = binding.chart.getDescription(); - description.setEnabled(false); + 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); + 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) { 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 public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { @@ -190,30 +230,4 @@ public class CheckHomeCacheActivity extends BaseBarActivity { } 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); - } - } } diff --git a/app/src/main/res/layouts/mastodon/layout/activity_check_home_cachet.xml b/app/src/main/res/layouts/mastodon/layout/activity_check_home_cachet.xml index a0a27860..e0814ce6 100644 --- a/app/src/main/res/layouts/mastodon/layout/activity_check_home_cachet.xml +++ b/app/src/main/res/layouts/mastodon/layout/activity_check_home_cachet.xml @@ -25,8 +25,16 @@ android:layout_height="wrap_content" android:orientation="vertical"> + + diff --git a/app/src/main/res/layouts/mastodon/layout/custom_marker_view_layout.xml b/app/src/main/res/layouts/mastodon/layout/custom_marker_view_layout.xml new file mode 100644 index 00000000..3b85e1ff --- /dev/null +++ b/app/src/main/res/layouts/mastodon/layout/custom_marker_view_layout.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8267c0c2..04dc1a0c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1931,4 +1931,5 @@ Autoplay animated media No Home cached messages! Check Home cache + %1$d cached messages \ No newline at end of file