diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Croller.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Croller.java new file mode 100644 index 0000000..c566293 --- /dev/null +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/Croller.java @@ -0,0 +1,791 @@ +package de.tonifetzer.conductorswatch; + +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import de.tonifetzer.conductorswatch.R; +import de.tonifetzer.conductorswatch.utilities.Utils; + +public class Croller extends View { + + private float midx, midy; + private Paint textPaint, circlePaint, circlePaint2, linePaint; + private float currdeg = 0, deg = 3, downdeg = 0; + + private boolean isContinuous = false; + + private int backCircleColor = Color.parseColor("#222222"); + private int mainCircleColor = Color.parseColor("#000000"); + private int indicatorColor = Color.parseColor("#FFA036"); + private int progressPrimaryColor = Color.parseColor("#FFA036"); + private int progressSecondaryColor = Color.parseColor("#111111"); + + private float progressPrimaryCircleSize = -1; + private float progressSecondaryCircleSize = -1; + + private float progressPrimaryStrokeWidth = 25; + private float progressSecondaryStrokeWidth = 10; + + private float mainCircleRadius = -1; + private float backCircleRadius = -1; + private float progressRadius = -1; + + private float touchCircleRadiusMax = -1; + private float touchCircleRadiusMin = -1; + + private int max = 25; + private int min = 1; + + private float indicatorWidth = 7; + + private String label = "Label"; + private int labelSize = 40; + private int labelColor = Color.WHITE; + + private int startOffset = 30; + private int startOffset2 = 0; + private int sweepAngle = -1; + + private boolean isAntiClockwise = false; + + private boolean startEventSent = false; + + RectF oval; + + private onProgressChangedListener mProgressChangeListener; + private OnCrollerChangeListener mCrollerChangeListener; + + public interface onProgressChangedListener { + void onProgressChanged(int progress); + } + + public void setOnProgressChangedListener(onProgressChangedListener mProgressChangeListener) { + this.mProgressChangeListener = mProgressChangeListener; + } + + public void setOnCrollerChangeListener(OnCrollerChangeListener mCrollerChangeListener) { + this.mCrollerChangeListener = mCrollerChangeListener; + } + + public Croller(Context context) { + super(context); + init(); + } + + public Croller(Context context, AttributeSet attrs) { + super(context, attrs); + initXMLAttrs(context, attrs); + init(); + } + + public Croller(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initXMLAttrs(context, attrs); + init(); + } + + private void init() { + textPaint = new Paint(); + textPaint.setAntiAlias(true); + textPaint.setColor(labelColor); + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(labelSize); + textPaint.setFakeBoldText(true); + textPaint.setTextAlign(Paint.Align.CENTER); + + circlePaint = new Paint(); + circlePaint.setAntiAlias(true); + circlePaint.setColor(progressSecondaryColor); + circlePaint.setStrokeWidth(progressSecondaryStrokeWidth); + circlePaint.setStyle(Paint.Style.FILL); + + circlePaint2 = new Paint(); + circlePaint2.setAntiAlias(true); + circlePaint2.setColor(progressPrimaryColor); + circlePaint2.setStrokeWidth(progressPrimaryStrokeWidth); + circlePaint2.setStyle(Paint.Style.FILL); + + linePaint = new Paint(); + linePaint.setAntiAlias(true); + linePaint.setColor(indicatorColor); + linePaint.setStrokeWidth(indicatorWidth); + + oval = new RectF(); + + } + + private void initXMLAttrs(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Croller); + final int N = a.getIndexCount(); + for (int i = 0; i < N; ++i) { + int attr = a.getIndex(i); + if (attr == R.styleable.Croller_progress) { + setProgress(a.getInt(attr, 1)); + } else if (attr == R.styleable.Croller_label) { + setLabel(a.getString(attr)); + } else if (attr == R.styleable.Croller_back_circle_color) { + setBackCircleColor(a.getColor(attr, Color.parseColor("#222222"))); + } else if (attr == R.styleable.Croller_main_circle_color) { + setMainCircleColor(a.getColor(attr, Color.parseColor("#000000"))); + } else if (attr == R.styleable.Croller_indicator_color) { + setIndicatorColor(a.getColor(attr, Color.parseColor("#FFA036"))); + } else if (attr == R.styleable.Croller_progress_primary_color) { + setProgressPrimaryColor(a.getColor(attr, Color.parseColor("#FFA036"))); + } else if (attr == R.styleable.Croller_progress_secondary_color) { + setProgressSecondaryColor(a.getColor(attr, Color.parseColor("#111111"))); + } else if (attr == R.styleable.Croller_label_size) { + setLabelSize(a.getInteger(attr, 40)); + } else if (attr == R.styleable.Croller_label_color) { + setLabelColor(a.getColor(attr, Color.WHITE)); + } else if (attr == R.styleable.Croller_indicator_width) { + setIndicatorWidth(a.getFloat(attr, 7)); + } else if (attr == R.styleable.Croller_is_continuous) { + setIsContinuous(a.getBoolean(attr, false)); + } else if (attr == R.styleable.Croller_progress_primary_circle_size) { + setProgressPrimaryCircleSize(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_progress_secondary_circle_size) { + setProgressSecondaryCircleSize(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_progress_primary_stroke_width) { + setProgressPrimaryStrokeWidth(a.getFloat(attr, 25)); + } else if (attr == R.styleable.Croller_progress_secondary_stroke_width) { + setProgressSecondaryStrokeWidth(a.getFloat(attr, 10)); + } else if (attr == R.styleable.Croller_sweep_angle) { + setSweepAngle(a.getInt(attr, -1)); + } else if (attr == R.styleable.Croller_start_offset) { + setStartOffset(a.getInt(attr, 30)); + } else if (attr == R.styleable.Croller_max) { + setMax(a.getInt(attr, 25)); + } else if (attr == R.styleable.Croller_min) { + setMin(a.getInt(attr, 1)); + deg = min + 2; + } else if (attr == R.styleable.Croller_main_circle_radius) { + setMainCircleRadius(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_back_circle_radius) { + setBackCircleRadius(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_progress_radius) { + setProgressRadius(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_touch_circle_radius_max) { + setTouchCircleRadiusMax(a.getFloat(attr, -1)); + } else if (attr == R.styleable.Croller_touch_circle_radius_min) { + setTouchCircleRadiusMin(a.getFloat(attr, -1)); + }else if (attr == R.styleable.Croller_anticlockwise) { + setAntiClockwise(a.getBoolean(attr, false)); + } + } + a.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int minWidth = (int) Utils.convertDpToPixel(160, getContext()); + int minHeight = (int) Utils.convertDpToPixel(160, getContext()); + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + int width; + int height; + + if (widthMode == MeasureSpec.EXACTLY) { + width = widthSize; + } else if (widthMode == MeasureSpec.AT_MOST) { + width = Math.min(minWidth, widthSize); + } else { + // only in case of ScrollViews, otherwise MeasureSpec.UNSPECIFIED is never triggered + // If width is wrap_content i.e. MeasureSpec.UNSPECIFIED, then make width equal to height + width = heightSize; + } + + if (heightMode == MeasureSpec.EXACTLY) { + height = heightSize; + } else if (heightMode == MeasureSpec.AT_MOST) { + height = Math.min(minHeight, heightSize); + } else { + // only in case of ScrollViews, otherwise MeasureSpec.UNSPECIFIED is never triggered + // If height is wrap_content i.e. MeasureSpec.UNSPECIFIED, then make height equal to width + height = widthSize; + } + + if (widthMode == MeasureSpec.UNSPECIFIED && heightMode == MeasureSpec.UNSPECIFIED) { + width = minWidth; + height = minHeight; + } + + setMeasuredDimension(width, height); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mProgressChangeListener != null) + mProgressChangeListener.onProgressChanged((int) (deg - 2)); + + if (mCrollerChangeListener != null) + mCrollerChangeListener.onProgressChanged(this, (int) (deg - 2)); + + midx = canvas.getWidth() / 2; + midy = canvas.getHeight() / 2; + + if (!isContinuous) { + + startOffset2 = startOffset - 15; + + circlePaint.setColor(progressSecondaryColor); + circlePaint2.setColor(progressPrimaryColor); + linePaint.setStrokeWidth(indicatorWidth); + linePaint.setColor(indicatorColor); + textPaint.setColor(labelColor); + textPaint.setTextSize(labelSize); + + int radius = (int) (Math.min(midx, midy) * ((float) 14.5 / 16)); + + if (sweepAngle == -1) { + sweepAngle = 360 - (2 * startOffset2); + } + + if (mainCircleRadius == -1) { + mainCircleRadius = radius * ((float) 11 / 15); + } + if (backCircleRadius == -1) { + backCircleRadius = radius * ((float) 13 / 15); + } + if (progressRadius == -1) { + progressRadius = radius; + } + + if (touchCircleRadiusMax == -1) { + touchCircleRadiusMax = Math.max(mainCircleRadius, Math.max(backCircleRadius, progressRadius)); + } + + if (touchCircleRadiusMin == -1) { + touchCircleRadiusMin = 0; + } + + float x, y; + float deg2 = Math.max(3, deg); + float deg3 = Math.min(deg, max + 2); + for (int i = (int) (deg2); i < max + 3; i++) { + float tmp = ((float) startOffset2 / 360) + ((float) sweepAngle / 360) * (float) i / (max + 5); + + if (isAntiClockwise) { + tmp = 1.0f - tmp; + } + + x = midx + (float) (progressRadius * Math.sin(2 * Math.PI * (1.0 - tmp))); + y = midy + (float) (progressRadius * Math.cos(2 * Math.PI * (1.0 - tmp))); + circlePaint.setColor(progressSecondaryColor); + if (progressSecondaryCircleSize == -1) + canvas.drawCircle(x, y, ((float) radius / 30 * ((float) 20 / max) * ((float) sweepAngle / 270)), circlePaint); + else + canvas.drawCircle(x, y, progressSecondaryCircleSize, circlePaint); + } + for (int i = 3; i <= deg3; i++) { + float tmp = ((float) startOffset2 / 360) + ((float) sweepAngle / 360) * (float) i / (max + 5); + + if (isAntiClockwise) { + tmp = 1.0f - tmp; + } + + x = midx + (float) (progressRadius * Math.sin(2 * Math.PI * (1.0 - tmp))); + y = midy + (float) (progressRadius * Math.cos(2 * Math.PI * (1.0 - tmp))); + if (progressPrimaryCircleSize == -1) + canvas.drawCircle(x, y, (progressRadius / 15 * ((float) 20 / max) * ((float) sweepAngle / 270)), circlePaint2); + else + canvas.drawCircle(x, y, progressPrimaryCircleSize, circlePaint2); + } + + float tmp2 = ((float) startOffset2 / 360) + ((float) sweepAngle / 360) * deg / (max + 5); + + if (isAntiClockwise) { + tmp2 = 1.0f - tmp2; + } + + float x1 = midx + (float) (radius * ((float) 2 / 5) * Math.sin(2 * Math.PI * (1.0 - tmp2))); + float y1 = midy + (float) (radius * ((float) 2 / 5) * Math.cos(2 * Math.PI * (1.0 - tmp2))); + float x2 = midx + (float) (radius * ((float) 3 / 5) * Math.sin(2 * Math.PI * (1.0 - tmp2))); + float y2 = midy + (float) (radius * ((float) 3 / 5) * Math.cos(2 * Math.PI * (1.0 - tmp2))); + + circlePaint.setColor(backCircleColor); + canvas.drawCircle(midx, midy, backCircleRadius, circlePaint); + circlePaint.setColor(mainCircleColor); + canvas.drawCircle(midx, midy, mainCircleRadius, circlePaint); + canvas.drawText(label, midx, midy + (float) (radius * 1.1), textPaint); + canvas.drawLine(x1, y1, x2, y2, linePaint); + + } else { + + int radius = (int) (Math.min(midx, midy) * ((float) 14.5 / 16)); + + if (sweepAngle == -1) { + sweepAngle = 360 - (2 * startOffset); + } + + if (mainCircleRadius == -1) { + mainCircleRadius = radius * ((float) 11 / 15); + } + if (backCircleRadius == -1) { + backCircleRadius = radius * ((float) 13 / 15); + } + if (progressRadius == -1) { + progressRadius = radius; + } + + if (touchCircleRadiusMax == -1) { + touchCircleRadiusMax = Math.max(mainCircleRadius, Math.max(backCircleRadius, progressRadius)); + } + + if (touchCircleRadiusMin == -1) { + touchCircleRadiusMin = 0; + } + + circlePaint.setColor(progressSecondaryColor); + circlePaint.setStrokeWidth(progressSecondaryStrokeWidth); + circlePaint.setStyle(Paint.Style.STROKE); + circlePaint2.setColor(progressPrimaryColor); + circlePaint2.setStrokeWidth(progressPrimaryStrokeWidth); + circlePaint2.setStyle(Paint.Style.STROKE); + linePaint.setStrokeWidth(indicatorWidth); + linePaint.setColor(indicatorColor); + textPaint.setColor(labelColor); + textPaint.setTextSize(labelSize); + + float deg3 = Math.min(deg, max + 2); + + oval.set(midx - progressRadius, midy - progressRadius, midx + progressRadius, midy + progressRadius); + + canvas.drawArc(oval, (float) 90 + startOffset, (float) sweepAngle, false, circlePaint); + if (isAntiClockwise) { + canvas.drawArc(oval, (float) 90 - startOffset, -1 * ((deg3 - 2) * ((float) sweepAngle / max)), false, circlePaint2); + } else { + canvas.drawArc(oval, (float) 90 + startOffset, ((deg3 - 2) * ((float) sweepAngle / max)), false, circlePaint2); + } + + float tmp2 = ((float) startOffset / 360) + (((float) sweepAngle / 360) * ((deg - 2) / (max))); + + if (isAntiClockwise) { + tmp2 = 1.0f - tmp2; + } + + float x1 = midx + (float) (radius * ((float) 2 / 5) * Math.sin(2 * Math.PI * (1.0 - tmp2))); + float y1 = midy + (float) (radius * ((float) 2 / 5) * Math.cos(2 * Math.PI * (1.0 - tmp2))); + float x2 = midx + (float) (radius * ((float) 3 / 5) * Math.sin(2 * Math.PI * (1.0 - tmp2))); + float y2 = midy + (float) (radius * ((float) 3 / 5) * Math.cos(2 * Math.PI * (1.0 - tmp2))); + + circlePaint.setStyle(Paint.Style.FILL); + + circlePaint.setColor(backCircleColor); + canvas.drawCircle(midx, midy, backCircleRadius, circlePaint); + circlePaint.setColor(mainCircleColor); + canvas.drawCircle(midx, midy, mainCircleRadius, circlePaint); + canvas.drawText(label, midx, midy + (float) (radius * 1.1), textPaint); + canvas.drawLine(x1, y1, x2, y2, linePaint); + } + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + + float distancePointToMiddle = Utils.getDistance(e.getX(), e.getY(), midx, midy); + if ((distancePointToMiddle > touchCircleRadiusMax || distancePointToMiddle < touchCircleRadiusMin)) { + if (startEventSent && mCrollerChangeListener != null) { + mCrollerChangeListener.onStopTrackingTouch(this); + startEventSent = false; + } + return super.onTouchEvent(e); + } + + if (e.getAction() == MotionEvent.ACTION_DOWN) { + float dx = e.getX() - midx; + float dy = e.getY() - midy; + downdeg = (float) ((Math.atan2(dy, dx) * 180) / Math.PI); + downdeg -= 90; + if (downdeg < 0) { + downdeg += 360; + } + downdeg = (float) Math.floor((downdeg / 360) * (max + 5)); + + if (mCrollerChangeListener != null) { + mCrollerChangeListener.onStartTrackingTouch(this); + startEventSent = true; + } + + return true; + } + if (e.getAction() == MotionEvent.ACTION_MOVE) { + float dx = e.getX() - midx; + float dy = e.getY() - midy; + currdeg = (float) ((Math.atan2(dy, dx) * 180) / Math.PI); + currdeg -= 90; + if (currdeg < 0) { + currdeg += 360; + } + currdeg = (float) Math.floor((currdeg / 360) * (max + 5)); + + if ((currdeg / (max + 4)) > 0.75f && ((downdeg - 0) / (max + 4)) < 0.25f) { + if (isAntiClockwise) { + deg++; + if (deg > max + 2) { + deg = max + 2; + } + } else { + deg--; + if (deg < (min + 2)) { + deg = (min + 2); + } + } + } else if ((downdeg / (max + 4)) > 0.75f && ((currdeg - 0) / (max + 4)) < 0.25f) { + if (isAntiClockwise) { + deg--; + if (deg < (min + 2)) { + deg = (min + 2); + } + } else { + deg++; + if (deg > max + 2) { + deg = max + 2; + } + } + } else { + if (isAntiClockwise) { + deg -= (currdeg - downdeg); + } else { + deg += (currdeg - downdeg); + } + if (deg > max + 2) { + deg = max + 2; + } + if (deg < (min + 2)) { + deg = (min + 2); + } + } + + downdeg = currdeg; + + invalidate(); + return true; + + } + if (e.getAction() == MotionEvent.ACTION_UP) { + if (mCrollerChangeListener != null) { + mCrollerChangeListener.onStopTrackingTouch(this); + startEventSent = false; + } + return true; + } + return super.onTouchEvent(e); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + if (getParent() != null && event.getAction() == MotionEvent.ACTION_DOWN) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return super.dispatchTouchEvent(event); + } + + public int getProgress() { + return (int) (deg - 2); + } + + public void setProgress(int x) { + deg = x + 2; + invalidate(); + } + + public String getLabel() { + return label; + } + + public void setLabel(String txt) { + label = txt; + invalidate(); + } + + public int getBackCircleColor() { + return backCircleColor; + } + + public void setBackCircleColor(int backCircleColor) { + this.backCircleColor = backCircleColor; + invalidate(); + } + + public int getMainCircleColor() { + return mainCircleColor; + } + + public void setMainCircleColor(int mainCircleColor) { + this.mainCircleColor = mainCircleColor; + invalidate(); + } + + private ValueAnimator mainCircleAnimation; + public void setMainCircleColorAnimated(int startColor, int endColor, int duration) { + + mainCircleAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor); + mainCircleAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + + @Override + public void onAnimationUpdate(ValueAnimator animator) { + setMainCircleColor((Integer) animator.getAnimatedValue()); + } + + }); + + mainCircleAnimation.setDuration(duration); + mainCircleAnimation.start(); + } + + public void stopMainCircleColorAnimated(){ + if(mainCircleAnimation != null){ + if(mainCircleAnimation.isRunning()){ + mainCircleAnimation.reverse(); + } + } + } + + public void interruptMainCircleColorAnimated(){ + if(mainCircleAnimation != null){ + if(mainCircleAnimation.isRunning()){ + mainCircleAnimation.setDuration(0); + mainCircleAnimation.reverse(); + } + } + } + + private ValueAnimator backCircleAnimation; + public void setBackCircleColorAnimated(int startColor, int endColor, int duration) { + + backCircleAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), startColor, endColor); + backCircleAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + + @Override + public void onAnimationUpdate(ValueAnimator animator) { + setBackCircleColor((Integer) animator.getAnimatedValue()); + } + + }); + + backCircleAnimation.setDuration(duration); + backCircleAnimation.start(); + } + + public void stopBackCircleColorAnimated(){ + backCircleAnimation.reverse(); + } + + public int getIndicatorColor() { + return indicatorColor; + } + + public void setIndicatorColor(int indicatorColor) { + this.indicatorColor = indicatorColor; + invalidate(); + } + + public int getProgressPrimaryColor() { + return progressPrimaryColor; + } + + public void setProgressPrimaryColor(int progressPrimaryColor) { + this.progressPrimaryColor = progressPrimaryColor; + invalidate(); + } + + public int getProgressSecondaryColor() { + return progressSecondaryColor; + } + + public void setProgressSecondaryColor(int progressSecondaryColor) { + this.progressSecondaryColor = progressSecondaryColor; + invalidate(); + } + + public int getLabelSize() { + return labelSize; + } + + public void setLabelSize(int labelSize) { + this.labelSize = labelSize; + invalidate(); + } + + public int getLabelColor() { + return labelColor; + } + + public void setLabelColor(int labelColor) { + this.labelColor = labelColor; + invalidate(); + } + + public float getIndicatorWidth() { + return indicatorWidth; + } + + public void setIndicatorWidth(float indicatorWidth) { + this.indicatorWidth = indicatorWidth; + invalidate(); + } + + public boolean isContinuous() { + return isContinuous; + } + + public void setIsContinuous(boolean isContinuous) { + this.isContinuous = isContinuous; + invalidate(); + } + + public float getProgressPrimaryCircleSize() { + return progressPrimaryCircleSize; + } + + public void setProgressPrimaryCircleSize(float progressPrimaryCircleSize) { + this.progressPrimaryCircleSize = progressPrimaryCircleSize; + invalidate(); + } + + public float getProgressSecondaryCircleSize() { + return progressSecondaryCircleSize; + } + + public void setProgressSecondaryCircleSize(float progressSecondaryCircleSize) { + this.progressSecondaryCircleSize = progressSecondaryCircleSize; + invalidate(); + } + + public float getProgressPrimaryStrokeWidth() { + return progressPrimaryStrokeWidth; + } + + public void setProgressPrimaryStrokeWidth(float progressPrimaryStrokeWidth) { + this.progressPrimaryStrokeWidth = progressPrimaryStrokeWidth; + invalidate(); + } + + public float getProgressSecondaryStrokeWidth() { + return progressSecondaryStrokeWidth; + } + + public void setProgressSecondaryStrokeWidth(float progressSecondaryStrokeWidth) { + this.progressSecondaryStrokeWidth = progressSecondaryStrokeWidth; + invalidate(); + } + + public int getSweepAngle() { + return sweepAngle; + } + + public void setSweepAngle(int sweepAngle) { + this.sweepAngle = sweepAngle; + invalidate(); + } + + public int getStartOffset() { + return startOffset; + } + + public void setStartOffset(int startOffset) { + this.startOffset = startOffset; + invalidate(); + } + + public int getMax() { + return max; + } + + public void setMax(int max) { + if (max < min) { + this.max = min; + } else { + this.max = max; + } + invalidate(); + } + + public int getMin() { + return min; + } + + public void setMin(int min) { + if (min < 0) { + this.min = 0; + } else if (min > max) { + this.min = max; + } else { + this.min = min; + } + invalidate(); + } + + public float getMainCircleRadius() { + return mainCircleRadius; + } + + public void setMainCircleRadius(float mainCircleRadius) { + this.mainCircleRadius = mainCircleRadius; + invalidate(); + } + + public float getBackCircleRadius() { + return backCircleRadius; + } + + public void setBackCircleRadius(float backCircleRadius) { + this.backCircleRadius = backCircleRadius; + invalidate(); + } + + public float getProgressRadius() { + return progressRadius; + } + + public void setProgressRadius(float progressRadius) { + this.progressRadius = progressRadius; + invalidate(); + } + + public float getTouchCircleRadiusMax() { + return touchCircleRadiusMax; + } + + public void setTouchCircleRadiusMax(float touchCircleRadiusMax) { + this.touchCircleRadiusMax = touchCircleRadiusMax; + invalidate(); + } + + + public float getTouchCircleRadiusMin() { + return touchCircleRadiusMin; + } + + public void setTouchCircleRadiusMin(float touchCircleRadiusMin) { + this.touchCircleRadiusMin = touchCircleRadiusMin; + invalidate(); + } + + + public boolean isAntiClockwise() { + return isAntiClockwise; + } + + public void setAntiClockwise(boolean antiClockwise) { + isAntiClockwise = antiClockwise; + invalidate(); + } +} diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java index dc63f50..9bf830c 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/MainActivity.java @@ -28,6 +28,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF // display center private int mDisplayWidth; private int mDisplayHeight; + private Point mDisplayCenter; //parameter for long press to start the worker private Point mPreviousMovePoint; @@ -52,44 +53,26 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF args.putInt("bpm", mCroller.getProgress()); worker.setArguments(args); + //setter + worker.setCrollerWorker(mCroller); + worker.setTextViewWorker(mTextView); + //create fragment instance FragmentTransaction transaction = getFragmentManager().beginTransaction(); - transaction.replace(R.id.layout, worker); - transaction.addToBackStack(null); + transaction.replace(R.id.layout, worker, "Worker"); + transaction.addToBackStack("Worker"); transaction.commit(); } else { getFragmentManager().popBackStack(); + mCroller.interruptMainCircleColorAnimated(); + mCroller.setProgressPrimaryColor(Color.parseColor("#158b69")); + mCroller.setBackCircleColor(Color.parseColor("#158b69")); + mTextView.setTextColor(Color.parseColor("#158b69")); } } }; - private boolean onColorChanging(MotionEvent ev){ - Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); - - //only works within the maincircle of the scroller - float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, (float) (mDisplayWidth / 2.0f), (float) (mDisplayHeight / 2.0f)); - if ((distancePointToMiddle > mCroller.getMainCircleRadius())){ - return false; - } - - if(ev.getAction() == MotionEvent.ACTION_DOWN){ - //push down effect - mCroller.setBackCircleColorAnimated(Color.parseColor("#cccccc"), Color.parseColor("#158b69"),150); - - //make color of backgroundcircle brighter the longer we press - mCroller.setMainCircleColorAnimated(Color.parseColor("#ffffff"), Color.parseColor("#158b69"),1500); - } - - if(ev.getAction() == MotionEvent.ACTION_UP){ - //push_up effect - mCroller.setBackCircleColorAnimated(Color.parseColor("#158b69"), Color.parseColor("#cccccc"),150); - mCroller.stopMainCircleColorAnimated(); - } - - return false; - } - private boolean onLongPressCustomized(MotionEvent ev){ Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); @@ -140,6 +123,7 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF mDisplayWidth= this.getResources().getDisplayMetrics().widthPixels; mDisplayHeight= this.getResources().getDisplayMetrics().heightPixels; + mDisplayCenter = new Point((mDisplayWidth / 2), (mDisplayHeight / 2)); mModeRecord = false; @@ -176,10 +160,12 @@ public class MainActivity extends WearableActivity implements WorkerFragment.OnF //if record mode is on, we are not able to use the croller if(mModeRecord){ + + boolean changeColor = Utils.onColorChanging(ev, mCroller, mDisplayCenter, Color.parseColor("#EE693F")); return onLongPressCustomized(ev); } else { - boolean changeColor = onColorChanging(ev); + boolean changeColor = Utils.onColorChanging(ev, mCroller, mDisplayCenter, Color.parseColor("#158b69")); return onLongPressCustomized(ev) || super.dispatchTouchEvent(ev); } diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/OnCrollerChangeListener.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/OnCrollerChangeListener.java new file mode 100644 index 0000000..7b29b5a --- /dev/null +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/OnCrollerChangeListener.java @@ -0,0 +1,9 @@ +package de.tonifetzer.conductorswatch; + +public interface OnCrollerChangeListener { + void onProgressChanged(Croller croller, int progress); + + void onStartTrackingTouch(Croller croller); + + void onStopTrackingTouch(Croller croller); +} diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java index ebb4193..fb9436c 100644 --- a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/WorkerFragment.java @@ -1,18 +1,23 @@ package de.tonifetzer.conductorswatch; import android.content.Context; +import android.graphics.Color; +import android.graphics.Point; import android.os.Bundle; import android.app.Fragment; import android.os.Vibrator; import android.support.annotation.Nullable; import android.util.Log; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView; import java.util.Vector; +import de.tonifetzer.conductorswatch.utilities.Utils; + /** * A simple {@link Fragment} subclass. @@ -75,18 +80,22 @@ public class WorkerFragment extends Fragment implements Metronome.OnMetronomeLis this.getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_worker, container, false); + public void setCrollerWorker(Croller croller){ + mCroller = croller; + mCroller.interruptMainCircleColorAnimated(); + mCroller.setProgressPrimaryColor(Color.parseColor("#EE693F")); + mCroller.setBackCircleColor(Color.parseColor("#EE693F")); } + public void setTextViewWorker(TextView tw){ + mTextView = tw; + mTextView.setTextColor(Color.parseColor("#EE693F")); + } + @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState){ - mTextView = (TextView) getView().findViewById(R.id.bpmTextRed); - mCroller = (Croller) getView().findViewById(R.id.croller); + } @Override diff --git a/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java new file mode 100644 index 0000000..99698f1 --- /dev/null +++ b/android/ConductorsWatch/app/src/main/java/de/tonifetzer/conductorswatch/utilities/Utils.java @@ -0,0 +1,55 @@ +package de.tonifetzer.conductorswatch.utilities; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.util.DisplayMetrics; +import android.view.MotionEvent; + +import de.tonifetzer.conductorswatch.Croller; + +public class Utils { + public static float getDistance(float x1, float y1, float x2, float y2) { + return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + } + + public static float convertDpToPixel(float dp, Context context) { + Resources resources = context.getResources(); + DisplayMetrics metrics = resources.getDisplayMetrics(); + return dp * ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); + } + + public static float convertPixelsToDp(float px, Context context) { + Resources resources = context.getResources(); + DisplayMetrics metrics = resources.getDisplayMetrics(); + return px / ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); + } + + public static boolean onColorChanging(MotionEvent ev, Croller croller, Point center, int MainColor){ + Point currentPoint = new Point((int)ev.getX(), (int)ev.getY()); + + //only works within the maincircle of the scroller + float distancePointToMiddle = Utils.getDistance(currentPoint.x, currentPoint.y, center.x, center.y); + if ((distancePointToMiddle > croller.getMainCircleRadius())){ + return false; + } + + if(ev.getAction() == MotionEvent.ACTION_DOWN){ + //push down effect + croller.setBackCircleColorAnimated(Color.parseColor("#cccccc"), MainColor,150); + + //make color of backgroundcircle brighter the longer we press + croller.setMainCircleColorAnimated(Color.parseColor("#ffffff"), MainColor,1500); + } + + if(ev.getAction() == MotionEvent.ACTION_UP){ + //push_up effect + croller.setBackCircleColorAnimated(MainColor, Color.parseColor("#cccccc"),150); + croller.stopMainCircleColorAnimated(); + } + + return false; + } + +} diff --git a/android/ConductorsWatch/app/src/main/res/layout/fragment_worker.xml b/android/ConductorsWatch/app/src/main/res/layout/fragment_worker.xml index 86a6c5c..1e4a776 100644 --- a/android/ConductorsWatch/app/src/main/res/layout/fragment_worker.xml +++ b/android/ConductorsWatch/app/src/main/res/layout/fragment_worker.xml @@ -17,7 +17,7 @@