summaryrefslogtreecommitdiffstats
path: root/app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java')
-rw-r--r--app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java249
1 files changed, 249 insertions, 0 deletions
diff --git a/app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java b/app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java
new file mode 100644
index 000000000..33672f60c
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/helper/CirclesDrawingView.java
@@ -0,0 +1,249 @@
+package app.fedilab.android.helper;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.core.content.res.ResourcesCompat;
+
+import java.util.HashSet;
+import java.util.Random;
+
+import app.fedilab.android.R;
+
+//Original work at https://stackoverflow.com/a/17830245
+public class CirclesDrawingView extends View {
+
+
+ // Radius limit in pixels
+ private final static int RADIUS_LIMIT = 100;
+ private static final int CIRCLES_LIMIT = 1;
+ private final Random mRadiusGenerator = new Random();
+ /**
+ * All available circles
+ */
+ private final HashSet<CircleArea> mCircles = new HashSet<>(CIRCLES_LIMIT);
+ private final SparseArray<CircleArea> mCirclePointer = new SparseArray<>(CIRCLES_LIMIT);
+ /**
+ * Paint to draw circles
+ */
+ private Paint mCirclePaint;
+ private CircleArea touchedCircle;
+
+ /**
+ * Default constructor
+ *
+ * @param ct {@link android.content.Context}
+ */
+ public CirclesDrawingView(final Context ct) {
+ super(ct);
+ init(ct);
+ }
+
+ public CirclesDrawingView(final Context ct, final AttributeSet attrs) {
+ super(ct, attrs);
+ init(ct);
+ }
+
+ public CirclesDrawingView(final Context ct, final AttributeSet attrs, final int defStyle) {
+ super(ct, attrs, defStyle);
+ init(ct);
+ }
+
+ public CircleArea getTouchedCircle() {
+ return this.touchedCircle;
+ }
+
+ private void init(final Context ct) {
+ // Generate bitmap used for background
+ mCirclePaint = new Paint();
+
+ mCirclePaint.setColor(ResourcesCompat.getColor(getContext().getResources(), R.color.cyanea_accent, getContext().getTheme()));
+ mCirclePaint.setStrokeWidth(10);
+ mCirclePaint.setStyle(Paint.Style.STROKE);
+ }
+
+ @Override
+ public void onDraw(final Canvas canv) {
+ // background bitmap to cover all area
+ for (CircleArea circle : mCircles) {
+ canv.drawCircle(circle.centerX, circle.centerY, circle.radius, mCirclePaint);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(final MotionEvent event) {
+ boolean handled = false;
+
+
+ int xTouch;
+ int yTouch;
+ int pointerId;
+ int actionIndex = event.getActionIndex();
+
+ // get touch event coordinates and make transparent circle from it
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ // it's the first pointer, so clear all existing pointers data
+ clearCirclePointer();
+
+ xTouch = (int) event.getX(0);
+ yTouch = (int) event.getY(0);
+
+ // check if we've touched inside some circle
+ touchedCircle = obtainTouchedCircle(xTouch, yTouch);
+ touchedCircle.centerX = xTouch;
+ touchedCircle.centerY = yTouch;
+ mCirclePointer.put(event.getPointerId(0), touchedCircle);
+ invalidate();
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_POINTER_DOWN:
+ // It secondary pointers, so obtain their ids and check circles
+ pointerId = event.getPointerId(actionIndex);
+
+ xTouch = (int) event.getX(actionIndex);
+ yTouch = (int) event.getY(actionIndex);
+
+ // check if we've touched inside some circle
+ touchedCircle = obtainTouchedCircle(xTouch, yTouch);
+
+ mCirclePointer.put(pointerId, touchedCircle);
+ touchedCircle.centerX = xTouch;
+ touchedCircle.centerY = yTouch;
+ invalidate();
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final int pointerCount = event.getPointerCount();
+
+ for (actionIndex = 0; actionIndex < pointerCount; actionIndex++) {
+ // Some pointer has moved, search it by pointer id
+ pointerId = event.getPointerId(actionIndex);
+
+ xTouch = (int) event.getX(actionIndex);
+ yTouch = (int) event.getY(actionIndex);
+
+ touchedCircle = mCirclePointer.get(pointerId);
+
+ if (null != touchedCircle) {
+ touchedCircle.centerX = xTouch;
+ touchedCircle.centerY = yTouch;
+ }
+ }
+ invalidate();
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_UP:
+ clearCirclePointer();
+ invalidate();
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ // not general pointer was up
+ pointerId = event.getPointerId(actionIndex);
+
+ mCirclePointer.remove(pointerId);
+ invalidate();
+ handled = true;
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ handled = true;
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+
+ return super.onTouchEvent(event) || handled;
+ }
+
+ /**
+ * Clears all CircleArea - pointer id relations
+ */
+ private void clearCirclePointer() {
+
+ mCirclePointer.clear();
+ }
+
+ /**
+ * Search and creates new (if needed) circle based on touch area
+ *
+ * @param xTouch int x of touch
+ * @param yTouch int y of touch
+ * @return obtained {@link CircleArea}
+ */
+ private CircleArea obtainTouchedCircle(final int xTouch, final int yTouch) {
+ CircleArea touchedCircle = getTouchedCircle(xTouch, yTouch);
+
+ if (null == touchedCircle) {
+ touchedCircle = new CircleArea(xTouch, yTouch, mRadiusGenerator.nextInt(RADIUS_LIMIT) + RADIUS_LIMIT);
+
+ if (mCircles.size() == CIRCLES_LIMIT) {
+ // remove first circle
+ mCircles.clear();
+ }
+
+ mCircles.add(touchedCircle);
+ }
+
+ return touchedCircle;
+ }
+
+ /**
+ * Determines touched circle
+ *
+ * @param xTouch int x touch coordinate
+ * @param yTouch int y touch coordinate
+ * @return {@link CircleArea} touched circle or null if no circle has been touched
+ */
+ private CircleArea getTouchedCircle(final int xTouch, final int yTouch) {
+ CircleArea touched = null;
+
+ for (CircleArea circle : mCircles) {
+ if ((circle.centerX - xTouch) * (circle.centerX - xTouch) + (circle.centerY - yTouch) * (circle.centerY - yTouch) <= circle.radius * circle.radius) {
+ touched = circle;
+ break;
+ }
+ }
+
+ return touched;
+ }
+
+ @Override
+ protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ /**
+ * Stores data about single circle
+ */
+ public static class CircleArea {
+ public int centerX;
+ public int centerY;
+ int radius;
+
+ CircleArea(int centerX, int centerY, int radius) {
+ this.radius = radius;
+ this.centerX = centerX;
+ this.centerY = centerY;
+ }
+
+ @Override
+ public String toString() {
+ return "Circle[" + centerX + ", " + centerY + ", " + radius + "]";
+ }
+ }
+} \ No newline at end of file