mirror of
https://codeberg.org/tom79/Fedilab.git
synced 2024-12-22 16:50:04 +02:00
Charts
This commit is contained in:
parent
6019f5129b
commit
c04a51f3b7
8 changed files with 332 additions and 1 deletions
|
@ -265,7 +265,11 @@
|
|||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/action_about"
|
||||
android:theme="@style/AppThemeBar" />
|
||||
|
||||
<activity
|
||||
android:name=".mastodon.activities.CheckHomeCacheActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:label="@string/home_cache"
|
||||
android:theme="@style/AppThemeBar" />
|
||||
<activity
|
||||
android:name=".mastodon.activities.admin.AdminDomainBlockActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
package app.fedilab.android.mastodon.activities;
|
||||
/* Copyright 2023 Thomas Schneider
|
||||
*
|
||||
* This file is a part of Fedilab
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import android.graphics.Canvas;
|
||||
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 androidx.appcompat.widget.LinearLayoutCompat;
|
||||
|
||||
import com.github.mikephil.charting.components.Description;
|
||||
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.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;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.activities.MainActivity;
|
||||
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;
|
||||
|
||||
|
||||
public class CheckHomeCacheActivity extends BaseBarActivity {
|
||||
|
||||
|
||||
private ActivityCheckHomeCachetBinding binding;
|
||||
private List<Status> statuses;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityCheckHomeCachetBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
if (MainActivity.currentAccount == null || MainActivity.currentAccount.mastodon_account == null) {
|
||||
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 {
|
||||
statuses = new StatusCache(this).getHome(MainActivity.currentAccount);
|
||||
if (statuses == null || statuses.size() < 2) {
|
||||
runOnUiThread(() -> binding.noAction.setVisibility(View.VISIBLE));
|
||||
return;
|
||||
}
|
||||
|
||||
final ArrayList<String> xVals = new ArrayList<>();
|
||||
String xDate;
|
||||
int inc = 0;
|
||||
//We loop through cache
|
||||
List<Entry> 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++;
|
||||
}
|
||||
}
|
||||
List<ILineDataSet> 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);
|
||||
|
||||
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);
|
||||
|
||||
Description description = binding.chart.getDescription();
|
||||
description.setEnabled(false);
|
||||
|
||||
binding.chart.invalidate();
|
||||
|
||||
} catch (DBException | NegativeArraySizeException e) {
|
||||
binding.noAction.setVisibility(View.VISIBLE);
|
||||
Toasty.error(this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -229,6 +229,28 @@ public class StatusCache {
|
|||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all cache messages for home
|
||||
*
|
||||
* @param baseAccount Status {@link BaseAccount}
|
||||
* @return List<Status>
|
||||
* @throws DBException Exception
|
||||
*/
|
||||
public List<Status> getHome(BaseAccount baseAccount) throws DBException {
|
||||
if (db == null) {
|
||||
throw new DBException("db is null. Wrong initialization.");
|
||||
}
|
||||
String selection = Sqlite.COL_INSTANCE + "='" + baseAccount.instance + "' AND " + Sqlite.COL_USER_ID + "= '" + baseAccount.user_id + "' AND " + Sqlite.COL_SLUG + "= '" + Timeline.TimeLineEnum.HOME.getValue() + "' ";
|
||||
try {
|
||||
Cursor c = db.query(Sqlite.TABLE_STATUS_CACHE, null, selection, null, Sqlite.COL_STATUS_ID, null, Sqlite.COL_STATUS_ID + " ASC", null);
|
||||
return cursorToListOfStatuses(c);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* count messages for other timelines
|
||||
*
|
||||
|
|
|
@ -15,10 +15,12 @@ package app.fedilab.android.mastodon.ui.fragment.settings;
|
|||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
@ -29,6 +31,7 @@ import androidx.work.WorkManager;
|
|||
import app.fedilab.android.BaseMainActivity;
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.activities.MainActivity;
|
||||
import app.fedilab.android.mastodon.activities.CheckHomeCacheActivity;
|
||||
import app.fedilab.android.mastodon.helper.Helper;
|
||||
import app.fedilab.android.mastodon.jobs.FetchHomeWorker;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
@ -65,6 +68,15 @@ public class FragmentHomeCacheSettings extends PreferenceFragmentCompat implemen
|
|||
String timeRefresh = sharedpreferences.getString(getString(R.string.SET_FETCH_HOME_DELAY_VALUE) + MainActivity.currentUserID + MainActivity.currentInstance, "60");
|
||||
SET_FETCH_HOME_DELAY_VALUE.setValue(timeRefresh);
|
||||
}
|
||||
|
||||
|
||||
Preference pref_category_show_data = findPreference(getString(R.string.pref_category_show_data));
|
||||
if (pref_category_show_data != null) {
|
||||
pref_category_show_data.setOnPreferenceClickListener(preference -> {
|
||||
startActivity(new Intent(requireActivity(), CheckHomeCacheActivity.class));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:autoMirrored="true"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3.5,18.49l6,-6.01 4,4L22,6.92l-1.41,-1.41 -7.09,7.97 -4,-4L2,16.99z" />
|
||||
</vector>
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright 2023 Thomas Schneider
|
||||
|
||||
This file is a part of Fedilab
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with Fedilab; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
-->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.github.mikephil.charting.charts.LineChart
|
||||
android:id="@+id/chart"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/no_action"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/no_action_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="@string/no_cached_messages"
|
||||
android:textSize="20sp" />
|
||||
</RelativeLayout>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
|
||||
</ScrollView>
|
|
@ -1645,6 +1645,8 @@
|
|||
<item>u+1f6a9</item>
|
||||
</string-array>
|
||||
<string name="pref_category_key_account" translatable="false">pref_category_account</string>
|
||||
<string name="pref_category_show_data" translatable="false">pref_category_show_data</string>
|
||||
|
||||
<string name="pref_category_key_timeline" translatable="false">pref_category_timeline</string>
|
||||
<string name="pref_category_key_notifications" translatable="false">pref_category_notifications</string>
|
||||
<string name="pref_category_key_interface" translatable="false">pref_category_interface</string>
|
||||
|
@ -1927,4 +1929,6 @@
|
|||
<string name="send_anyway">Send anyway</string>
|
||||
<string name="set_remove_battery">Ignore battery optimizations</string>
|
||||
<string name="set_autoplay_gif">Autoplay animated media</string>
|
||||
<string name="no_cached_messages">No Home cached messages!</string>
|
||||
<string name="check_home_cache">Check Home cache</string>
|
||||
</resources>
|
|
@ -23,4 +23,11 @@
|
|||
app:title="@string/type_of_home_delay_title"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<Preference
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:title="@string/check_home_cache"
|
||||
app:icon="@drawable/baseline_show_chart_24"
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="@string/pref_category_show_data" />
|
||||
</PreferenceScreen>
|
Loading…
Reference in a new issue