summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod/view/LineChartView.java
blob: 0eb225e8e005e498474cb1c943e9dcf52dcccce9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package de.danoeh.antennapod.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.ThemeUtils;
import de.danoeh.antennapod.R;
import io.reactivex.annotations.Nullable;

public class LineChartView extends AppCompatImageView {
    private LineChartDrawable drawable;

    public LineChartView(Context context) {
        super(context);
        setup();
    }

    public LineChartView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        setup();
    }

    public LineChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setup();
    }

    @SuppressLint("ClickableViewAccessibility")
    private void setup() {
        drawable = new LineChartDrawable();
        setImageDrawable(drawable);
    }

    /**
     * Set of data values to display.
     */
    public void setData(LineChartData data) {
        drawable.data = data;
    }

    public static class LineChartData {
        private final long valueMax;
        private final long[] values;
        private final long[] verticalLines;

        public LineChartData(long[] values, long[] verticalLines) {
            this.values = values;
            long valueMax = 0;
            for (long datum : values) {
                valueMax = Math.max(datum, valueMax);
            }
            this.valueMax = valueMax;
            this.verticalLines = verticalLines;
        }

        public float getHeight(int item) {
            return (float) values[item] / valueMax;
        }
    }

    private class LineChartDrawable extends Drawable {
        private LineChartData data;
        private final Paint paintLine;
        private final Paint paintBackground;
        private final Paint paintVerticalLines;

        private LineChartDrawable() {
            paintLine = new Paint();
            paintLine.setFlags(Paint.ANTI_ALIAS_FLAG);
            paintLine.setStyle(Paint.Style.STROKE);
            paintLine.setStrokeJoin(Paint.Join.ROUND);
            paintLine.setStrokeCap(Paint.Cap.ROUND);
            paintLine.setColor(ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorAccent));
            paintBackground = new Paint();
            paintBackground.setStyle(Paint.Style.FILL);
            paintVerticalLines = new Paint();
            paintVerticalLines.setStyle(Paint.Style.STROKE);
            paintVerticalLines.setPathEffect(new DashPathEffect(new float[] {10f, 10f}, 0f));
            paintVerticalLines.setColor(0x66777777);
        }

        @Override
        public void draw(@NonNull Canvas canvas) {
            float width = getBounds().width();
            float height = getBounds().height();
            float usableHeight = height * 0.9f;
            float stepSize = width / (data.values.length + 1);

            paintVerticalLines.setStrokeWidth(height * 0.005f);
            for (long line : data.verticalLines) {
                canvas.drawLine((line + 1) * stepSize, 0, (line + 1) * stepSize, height, paintVerticalLines);
            }

            paintLine.setStrokeWidth(height * 0.015f);
            Path path = new Path();
            for (int i = 0; i < data.values.length; i++) {
                if (i == 0) {
                    path.moveTo((i + 1) * stepSize, (1 - data.getHeight(i)) * usableHeight + height * 0.05f);
                } else {
                    path.lineTo((i + 1) * stepSize, (1 - data.getHeight(i)) * usableHeight + height * 0.05f);
                }
            }
            canvas.drawPath(path, paintLine);

            path.lineTo(data.values.length * stepSize, height);
            path.lineTo(stepSize, height);
            paintBackground.setShader(new LinearGradient(0, 0, 0, height,
                    (ThemeUtils.getThemeAttrColor(getContext(), R.attr.colorAccent) & 0xffffff) + 0x66000000,
                    Color.TRANSPARENT, Shader.TileMode.CLAMP));
            canvas.drawPath(path, paintBackground);
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }

        @Override
        public void setAlpha(int alpha) {
        }

        @Override
        public void setColorFilter(ColorFilter cf) {
        }
    }
}