Commit c04a51f3 authored by Thomas's avatar Thomas
Browse files

Charts

parent 6019f512
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -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"
+219 −0
Original line number Diff line number Diff line
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);
        }
    }
}
+22 −0
Original line number Diff line number Diff line
@@ -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
     *
+12 −0
Original line number Diff line number Diff line
@@ -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;
            });
        }
    }


+11 −0
Original line number Diff line number Diff line
<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>
Loading