From b0a9c38dd9eac137330b5c7c97503bd19ade22e4 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Wed, 3 Jun 2020 23:01:07 +0200
Subject: [PATCH 01/31] Gradle upgrade
---
build.gradle | 2 +-
gradle/wrapper/gradle-wrapper.properties | 4 ++--
supla-android.iml | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/build.gradle b/build.gradle
index 6b80ead54..4dc1795ee 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.3'
+ classpath 'com.android.tools.build:gradle:4.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 815a3ac3a..fca5ea799 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed May 06 22:01:10 CEST 2020
+#Wed Jun 03 23:00:13 CEST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/supla-android.iml b/supla-android.iml
index 0b3e8c1cf..afac9ee08 100644
--- a/supla-android.iml
+++ b/supla-android.iml
@@ -1,5 +1,5 @@
-
+
From df83f8e9ffdac7f3816a820035d83702f3eaddaa Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Thu, 4 Jun 2020 22:38:42 +0200
Subject: [PATCH 02/31] ColorBrightnessPicker - Unused functionalities have
been removed. Added new ones not yet fully implemented.
---
.../android/SuplaColorBrightnessPicker.java | 284 ++++++------------
1 file changed, 100 insertions(+), 184 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 7f4d75dc9..7302090c5 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -10,11 +10,9 @@
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
-import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-
import java.util.ArrayList;
/*
@@ -33,10 +31,6 @@ of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Fragments of code based on:
- https://github.com/chiralcode/Android-Color-Picker/blob/master/src/com/chiralcode/colorpicker/ColorPicker.java
- https://github.com/LarsWerkman/HoloColorPicker/blob/master/libary/src/main/java/com/larswerkman/holocolorpicker/ColorPicker.java
*/
public class SuplaColorBrightnessPicker extends View {
@@ -60,8 +54,6 @@ public class SuplaColorBrightnessPicker extends View {
private RectF rectF = new RectF();
private float centerX;
private float centerY;
- private float wheelWidth;
- private float arrowHeight;
private float outerWheelWidth;
private double outerArrowHeight_a;
private double outerArrowHeight_b;
@@ -74,7 +66,6 @@ public class SuplaColorBrightnessPicker extends View {
private double innerWheelPointerAngle;
private int selectedColor;
private double selectedBrightness;
- private int selectedBrightnessColor;
private Path outerArrowPath;
private Paint outerArrowPaint;
private Path innerArrowPath;
@@ -86,17 +77,16 @@ public class SuplaColorBrightnessPicker extends View {
private Shader bwShader; // brightness wheel shader
private Matrix gradientRotationMatrix;
private boolean colorWheelVisible;
- private boolean bwBrightnessWheelVisible;
- private boolean colorBrightnessWheelVisible;
- private boolean percentVisible;
private boolean colorWheelMove;
private boolean brightnessWheelMove;
+ private boolean colorfulBrightnessWheel;
+ private boolean circleInsteadArrow;
private double lastTouchedAngle;
private OnColorBrightnessChangeListener mOnChangeListener;
private Rect bounds;
- private Paint textPaint;
private ArrayList ColorMarkers;
private ArrayList BrightnessMarkers;
+
public SuplaColorBrightnessPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
@@ -115,8 +105,6 @@ public SuplaColorBrightnessPicker(Context context) {
private void init() {
colorWheelVisible = true;
- bwBrightnessWheelVisible = false;
- colorBrightnessWheelVisible = false;
paint = new Paint();
@@ -141,7 +129,6 @@ private void init() {
innerArrowPaint = new Paint();
innerWheelPointerAngle = Math.toRadians(-90);
- selectedBrightnessColor = calculateColor((float) (innerWheelPointerAngle - m90d), BW);
selectedBrightness = 0;
gradientRotationMatrix = new Matrix();
@@ -150,18 +137,12 @@ private void init() {
colorWheelMove = false;
brightnessWheelMove = false;
-
- percentVisible = true;
+ colorfulBrightnessWheel = true;
+ circleInsteadArrow = false;
bounds = new Rect();
- textPaint = new Paint();
-
- textPaint.setAntiAlias(true);
- textPaint.setColor(Color.BLACK);
-
- setWheelWidth(100);
- setArrowHeight(100);
+ setBWcolor();
}
private int ave(int s, int d, float p) {
@@ -252,81 +233,91 @@ private void drawMarkers(Canvas canvas, float radius, float markerSize, ArrayLis
}
+ private void drawCirclePointer(Canvas canvas, double angle,
+ float wheelRadius, float wheelWidth) {
+
+ float x = (float)Math.cos(angle) * wheelRadius;
+ float y = (float)Math.sin(angle) * wheelRadius;
+
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+
+ canvas.drawCircle(x, y, wheelWidth * 0.47f, paint);
+ }
+
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(centerX, centerY);
-
if (colorWheelVisible) {
cwPaint.setShader(cwShader);
rectF.set(-outerWheelRadius, -outerWheelRadius, outerWheelRadius, outerWheelRadius);
canvas.drawOval(rectF, cwPaint);
- drawOuterPointerArrow(canvas, outerTop,
- outerWheelPointerAngle,
- outerWheelRadius,
- outerWheelWidth,
- -(outerArrowHeight_a / 4),
- outerArrowHeight_a,
- outerArrowHeight_b,
- selectedColor,
- outerArrowPath,
- outerArrowPaint);
+
+ if (circleInsteadArrow) {
+ drawCirclePointer(canvas, outerWheelPointerAngle,
+ outerWheelRadius, outerWheelWidth);
+ } else {
+ drawArrow(canvas, outerTop,
+ outerWheelPointerAngle,
+ outerWheelRadius,
+ outerWheelWidth,
+ -(outerArrowHeight_a / 4),
+ outerArrowHeight_a,
+ outerArrowHeight_b,
+ selectedColor,
+ outerArrowPath,
+ outerArrowPaint);
+ }
+
drawMarkers(canvas, outerWheelRadius,
outerWheelWidth / 6, ColorMarkers, false);
}
- if (bwBrightnessWheelVisible
- || colorBrightnessWheelVisible) {
+ bwPaint.setShader(bwShader);
+ rectF.set(-innerWheelRadius, -innerWheelRadius, innerWheelRadius, innerWheelRadius);
+ canvas.drawOval(rectF, bwPaint);
- bwPaint.setShader(bwShader);
- rectF.set(-innerWheelRadius, -innerWheelRadius, innerWheelRadius, innerWheelRadius);
- canvas.drawOval(rectF, bwPaint);
+ int negative;
+ double arrowOffset;
- int negative;
- double arrowOffset;
-
- if (colorWheelVisible) {
- negative = -1;
- arrowOffset = innerArrowHeight_a / 4 - innerWheelWidth;
- } else {
- negative = 1;
- arrowOffset = -(innerArrowHeight_a / 4);
- }
+ if (colorWheelVisible) {
+ negative = -1;
+ arrowOffset = innerArrowHeight_a / 4 - innerWheelWidth;
+ } else {
+ negative = 1;
+ arrowOffset = -(innerArrowHeight_a / 4);
+ }
- drawOuterPointerArrow(canvas, innerTop,
+ if (circleInsteadArrow) {
+ drawCirclePointer(canvas, innerWheelPointerAngle,
+ innerWheelRadius, innerWheelWidth);
+ } else {
+ drawArrow(canvas, innerTop,
innerWheelPointerAngle,
innerWheelRadius,
innerWheelWidth,
arrowOffset,
negative * innerArrowHeight_a,
negative * innerArrowHeight_b,
- selectedBrightnessColor,
+ calculateColor((float) (innerWheelPointerAngle - m90d), BW),
innerArrowPath,
innerArrowPaint);
-
- if (percentVisible) {
-
- String text = Integer.toString((int) selectedBrightness) + "%";
-
- textPaint.getTextBounds(text, 0, text.length(), bounds);
- canvas.drawText(text, -(bounds.width() / 2), bounds.height() / 2, textPaint);
- }
-
- drawMarkers(canvas, innerWheelRadius, innerWheelWidth / 6,
- BrightnessMarkers, true);
-
}
+ drawMarkers(canvas, innerWheelRadius, innerWheelWidth / 6,
+ BrightnessMarkers, true);
+
}
- private void drawOuterPointerArrow(Canvas canvas, PointerTop top, double topAngle,
- float wheelRadius, float wheelWidth, double arrowOffset,
- double arrowHeight_a, double arrowHeight_b,
- int color, Path arrowPath, Paint arrowPaint) {
+ private void drawArrow(Canvas canvas, PointerTop top, double topAngle,
+ float wheelRadius, float wheelWidth, double arrowOffset,
+ double arrowHeight_a, double arrowHeight_b,
+ int color, Path arrowPath, Paint arrowPaint) {
top.X = Math.cos(topAngle) * (wheelRadius + wheelWidth / 2 + arrowOffset);
top.Y = Math.sin(topAngle) * (wheelRadius + wheelWidth / 2 + arrowOffset);
@@ -370,7 +361,7 @@ private void drawOuterPointerArrow(Canvas canvas, PointerTop top, double topAngl
}
private void setBWcolor() {
- int color = colorBrightnessWheelVisible ? selectedColor : Color.WHITE;
+ int color = colorWheelVisible && colorfulBrightnessWheel ? selectedColor : Color.WHITE;
if (BW[1] != color) {
BW[1] = color;
@@ -383,6 +374,16 @@ private void setBWcolor() {
private void _onSizeChanged() {
+ float arrowHeight = 0;
+ float wheelWidth = this.getWidth() > this.getHeight() ? this.getHeight() : this.getWidth();
+
+ if (circleInsteadArrow) {
+ wheelWidth /= 7.0f;
+ } else {
+ wheelWidth /= 10.0f;
+ arrowHeight = wheelWidth * 0.9f;
+ }
+
outerWheelWidth = wheelWidth / 2;
outerArrowHeight_a = arrowHeight;
outerArrowHeight_b = outerArrowHeight_a * 0.6;
@@ -396,15 +397,15 @@ private void _onSizeChanged() {
centerX = this.getWidth() / 2;
centerY = this.getHeight() / 2;
- if (colorWheelVisible
- && (bwBrightnessWheelVisible || colorBrightnessWheelVisible)) {
+ if (colorWheelVisible && !circleInsteadArrow) {
outerWheelWidth = wheelWidth / 2;
} else {
outerWheelWidth = wheelWidth;
}
innerWheelWidth = outerWheelWidth;
- outerWheelRadius = Math.min(centerX, centerY) - outerWheelWidth / 2 - (int) (arrowHeight);
+ int margin = circleInsteadArrow ? 0 : (int) (arrowHeight);
+ outerWheelRadius = Math.min(centerX, centerY) - outerWheelWidth / 2 - margin;
if (colorWheelVisible) {
innerWheelRadius = outerWheelRadius - innerWheelWidth;
@@ -412,7 +413,6 @@ private void _onSizeChanged() {
innerWheelRadius = outerWheelRadius;
}
- textPaint.setTextSize((int) (innerWheelRadius * 0.4));
cwPaint.setStrokeWidth(outerWheelWidth);
bwPaint.setStrokeWidth(innerWheelWidth);
}
@@ -504,8 +504,7 @@ public boolean onTouchEvent(MotionEvent event) {
colorWheelMove = true;
brightnessWheelMove = false;
- } else if ((bwBrightnessWheelVisible || colorBrightnessWheelVisible)
- && Math.abs(innerTop.X - x) <= innerTop.Height
+ } else if (Math.abs(innerTop.X - x) <= innerTop.Height
&& Math.abs(innerTop.Y - y) <= innerTop.Height
&& ((colorWheelVisible
&& sqrt <= innerWheelRadius - innerWheelWidth / 2
@@ -521,7 +520,7 @@ public boolean onTouchEvent(MotionEvent event) {
lastTouchedAngle = inRads;
- if (!getMoving())
+ if (!isMoving())
return super.onTouchEvent(event);
break;
@@ -536,8 +535,8 @@ public boolean onTouchEvent(MotionEvent event) {
if (newColor != selectedColor) {
- selectedColor = newColor;
setBWcolor();
+ selectedColor = newColor;
invalidate();
if (mOnChangeListener != null)
@@ -584,11 +583,6 @@ public boolean onTouchEvent(MotionEvent event) {
}
- if ((colorWheelMove || brightnessWheelMove)
- && (bwBrightnessWheelVisible || colorBrightnessWheelVisible)) {
- selectedBrightnessColor = calculateColor((float) (innerWheelPointerAngle - m90d), BW);
- }
-
lastTouchedAngle = inRads;
break;
@@ -611,9 +605,7 @@ public void setColor(int color) {
color = 0xFFFFFFFF;
if (selectedColor != color) {
-
selectedColor = color;
- setBWcolor();
outerWheelPointerAngle = colorToAngle(color);
if (color == Color.WHITE)
@@ -621,10 +613,8 @@ public void setColor(int color) {
else
selectedColor = calculateColor((float) outerWheelPointerAngle, Colors);
- setBWcolor();
- setBrightnessValue(selectedBrightness);
+ invalidate();
}
-
}
public boolean getColorWheelVisible() {
@@ -632,29 +622,12 @@ public boolean getColorWheelVisible() {
}
public void setColorWheelVisible(boolean visible) {
-
if (visible != colorWheelVisible) {
-
- if (visible) {
- bwBrightnessWheelVisible = false;
- colorBrightnessWheelVisible = false;
- } else {
- bwBrightnessWheelVisible = true;
- colorBrightnessWheelVisible = false;
- }
-
colorWheelVisible = visible;
+ setBWcolor();
_onSizeChanged();
invalidate();
}
-
- }
-
- public void setPercentVisible(boolean visible) {
- if (percentVisible != visible) {
- percentVisible = visible;
- invalidate();
- }
}
public double getBrightnessValue() {
@@ -664,11 +637,9 @@ public double getBrightnessValue() {
public void setBrightnessValue(double value) {
innerWheelPointerAngle = brightnessToAngle(value);
- selectedBrightnessColor = calculateColor((float) (innerWheelPointerAngle - m90d), BW);
selectedBrightness = value;
invalidate();
-
}
private double brightnessToAngle(double value) {
@@ -696,82 +667,7 @@ else if (value > 100)
return result;
}
- public float getWheelWidth() {
- return wheelWidth;
- }
-
- public void setWheelWidth(float wheelWidth) {
- this.wheelWidth = wheelWidth;
- _onSizeChanged();
- invalidate();
- }
-
- public float getArrowHeight() {
- return arrowHeight;
- }
-
- public void setArrowHeight(float arrowHeight) {
- this.arrowHeight = arrowHeight;
- }
-
- public void setTextTypeface(Typeface typeface) {
-
- textPaint.setTypeface(typeface);
- invalidate();
- }
-
- public boolean getColorBrightnessWheelVisible() {
- return colorBrightnessWheelVisible;
- }
-
- public void setColorBrightnessWheelVisible(boolean visible) {
-
- if (visible != colorBrightnessWheelVisible) {
-
- if (visible) {
- colorWheelVisible = true;
- bwBrightnessWheelVisible = false;
- }
-
- colorBrightnessWheelVisible = visible;
-
- setBWcolor();
- selectedBrightnessColor = calculateColor((float) (innerWheelPointerAngle - m90d), BW);
-
- _onSizeChanged();
- invalidate();
- }
-
- }
-
- public boolean getBWBrightnessWheelVisible() {
- return bwBrightnessWheelVisible;
- }
-
- public void setBWBrightnessWheelVisible(boolean visible) {
-
- if (visible != bwBrightnessWheelVisible) {
-
- if (visible) {
- colorBrightnessWheelVisible = false;
- colorWheelVisible = false;
- } else {
- colorBrightnessWheelVisible = false;
- colorWheelVisible = true;
- }
-
- bwBrightnessWheelVisible = visible;
-
- setBWcolor();
- selectedBrightnessColor = calculateColor((float) (innerWheelPointerAngle - m90d), BW);
-
- _onSizeChanged();
- invalidate();
- }
-
- }
-
- public boolean getMoving() {
+ public boolean isMoving() {
return colorWheelMove || brightnessWheelMove;
}
@@ -793,6 +689,26 @@ public void setBrightnessMarkers(ArrayList brightnessMarkers) {
invalidate();
}
+ public boolean isColorfulBrightnessWheel() {
+ return colorfulBrightnessWheel;
+ }
+
+ public void setColorfulBrightnessWheel(boolean colorfulBrightnessWheel) {
+ this.colorfulBrightnessWheel = colorfulBrightnessWheel;
+ setBWcolor();
+ invalidate();
+ }
+
+ public boolean isCircleInsteadArrow() {
+ return circleInsteadArrow;
+ }
+
+ public void setCircleInsteadArrow(boolean circleInsteadArrow) {
+ this.circleInsteadArrow = circleInsteadArrow;
+ _onSizeChanged();
+ invalidate();
+ }
+
public interface OnColorBrightnessChangeListener {
void onColorChanged(SuplaColorBrightnessPicker scbPicker, int color);
From ad738151c4fae4c0a6bb74c85ca5a8c199665ddc Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Fri, 5 Jun 2020 18:19:07 +0200
Subject: [PATCH 03/31] =?UTF-8?q?Realizacja=20wska=C5=BAnik=C3=B3w=20w=20k?=
=?UTF-8?q?szta=C5=82cie=20ko=C5=82a?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../android/SuplaColorBrightnessPicker.java | 354 +++++++++---------
1 file changed, 171 insertions(+), 183 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 7302090c5..ac2c3f68c 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -6,7 +6,7 @@
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
-import android.graphics.Rect;
+import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
@@ -49,27 +49,26 @@ public class SuplaColorBrightnessPicker extends View {
Color.WHITE
};
- private PointerTop outerTop;
- private PointerTop innerTop;
+ private PointF colorPointerCenter;
+ private PointF brightnessPointerCenter;
private RectF rectF = new RectF();
private float centerX;
private float centerY;
- private float outerWheelWidth;
- private double outerArrowHeight_a;
- private double outerArrowHeight_b;
- private float outerWheelRadius;
- private double outerWheelPointerAngle;
- private double innerArrowHeight_a;
- private double innerArrowHeight_b;
- private float innerWheelWidth;
- private float innerWheelRadius;
- private double innerWheelPointerAngle;
+ private float colorWheelWidth;
+ private double pointerHeight;
+ private double arrowHeight_a;
+ private double arrowHeight_b;
+ private float colorWheelRadius;
+ private double colorWheelPointerAngle;
+ private float brightnessWheelWidth;
+ private float brightnessWheelRadius;
+ private double brightnessWheelPointerAngle;
private int selectedColor;
private double selectedBrightness;
- private Path outerArrowPath;
- private Paint outerArrowPaint;
- private Path innerArrowPath;
- private Paint innerArrowPaint;
+ private Path colorArrowPath;
+ private Paint colorArrowPaint;
+ private Path brightnessArrowPath;
+ private Paint brightnessArrowPaint;
private Paint paint;
private Paint cwPaint; // color wheel paint
private Shader cwShader; // color wheel shader
@@ -81,9 +80,8 @@ public class SuplaColorBrightnessPicker extends View {
private boolean brightnessWheelMove;
private boolean colorfulBrightnessWheel;
private boolean circleInsteadArrow;
- private double lastTouchedAngle;
+ private double touchAngleDiff;
private OnColorBrightnessChangeListener mOnChangeListener;
- private Rect bounds;
private ArrayList ColorMarkers;
private ArrayList BrightnessMarkers;
@@ -116,19 +114,19 @@ private void init() {
bwPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bwPaint.setStyle(Paint.Style.STROKE);
- outerArrowPath = new Path();
- outerArrowPaint = new Paint();
+ colorArrowPath = new Path();
+ colorArrowPaint = new Paint();
- outerTop = new PointerTop();
- innerTop = new PointerTop();
+ colorPointerCenter = new PointF();
+ brightnessPointerCenter = new PointF();
- outerWheelPointerAngle = Math.toRadians(-90);
- selectedColor = calculateColor((float) outerWheelPointerAngle, Colors);
+ colorWheelPointerAngle = Math.toRadians(-90);
+ selectedColor = calculateColor((float) colorWheelPointerAngle, Colors);
- innerArrowPath = new Path();
- innerArrowPaint = new Paint();
+ brightnessArrowPath = new Path();
+ brightnessArrowPaint = new Paint();
- innerWheelPointerAngle = Math.toRadians(-90);
+ brightnessWheelPointerAngle = Math.toRadians(-90);
selectedBrightness = 0;
gradientRotationMatrix = new Matrix();
@@ -140,8 +138,6 @@ private void init() {
colorfulBrightnessWheel = true;
circleInsteadArrow = false;
- bounds = new Rect();
-
setBWcolor();
}
@@ -191,11 +187,12 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(size, size);
}
- private void drawMarkers(Canvas canvas, float radius, float markerSize, ArrayList markers, boolean brightness) {
+ private void drawWheelMarkers(Canvas canvas, float radius, float markerSize,
+ ArrayList markers, boolean brightness) {
double angle;
paint.setAntiAlias(true);
- paint.setStrokeWidth(markerSize / 4);
+ paint.setStrokeWidth(markerSize / 5);
if (markers == null) {
return;
@@ -234,51 +231,64 @@ private void drawMarkers(Canvas canvas, float radius, float markerSize, ArrayLis
}
private void drawCirclePointer(Canvas canvas, double angle,
- float wheelRadius, float wheelWidth) {
+ float wheelRadius, int color, PointF center) {
+
+ center.x = (float) Math.cos(angle) * wheelRadius;
+ center.y = (float) Math.sin(angle) * wheelRadius;
+ float lw = (float) pointerHeight * 0.05f;
- float x = (float)Math.cos(angle) * wheelRadius;
- float y = (float)Math.sin(angle) * wheelRadius;
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(color);
+ canvas.drawCircle(center.x, center.y, (float) pointerHeight / 2 - lw / 2, paint);
+ paint.setStrokeWidth(lw);
paint.setStyle(Paint.Style.STROKE);
- paint.setColor(Color.BLACK);
+ paint.setColor(Color.WHITE);
- canvas.drawCircle(x, y, wheelWidth * 0.47f, paint);
+ canvas.drawCircle(center.x, center.y, (float) pointerHeight / 2 - lw * 1.5f, paint);
}
- @Override
- protected void onDraw(Canvas canvas) {
+ private float trimBrightnessColorAngle(float rad) {
+ if (rad >= 0 && rad <= 0.4f) {
+ rad = 0.4f;
+ } else if (rad >= 2.7 || rad < 0) {
+ rad = 2.7f;
+ }
+ return rad;
+ }
- canvas.translate(centerX, centerY);
+ private void drawWheel(Canvas canvas) {
if (colorWheelVisible) {
cwPaint.setShader(cwShader);
- rectF.set(-outerWheelRadius, -outerWheelRadius, outerWheelRadius, outerWheelRadius);
+ rectF.set(-colorWheelRadius, -colorWheelRadius, colorWheelRadius, colorWheelRadius);
canvas.drawOval(rectF, cwPaint);
if (circleInsteadArrow) {
- drawCirclePointer(canvas, outerWheelPointerAngle,
- outerWheelRadius, outerWheelWidth);
+ drawCirclePointer(canvas, colorWheelPointerAngle,
+ colorWheelRadius, selectedColor, colorPointerCenter);
} else {
- drawArrow(canvas, outerTop,
- outerWheelPointerAngle,
- outerWheelRadius,
- outerWheelWidth,
- -(outerArrowHeight_a / 4),
- outerArrowHeight_a,
- outerArrowHeight_b,
+ drawArrow(canvas, colorPointerCenter,
+ colorWheelPointerAngle,
+ colorWheelRadius,
+ colorWheelWidth,
+ -(arrowHeight_a / 4),
+ arrowHeight_a,
+ arrowHeight_b,
selectedColor,
- outerArrowPath,
- outerArrowPaint);
+ colorArrowPath,
+ colorArrowPaint);
}
-
- drawMarkers(canvas, outerWheelRadius,
- outerWheelWidth / 6, ColorMarkers, false);
+ drawWheelMarkers(canvas, colorWheelRadius,
+ colorWheelWidth / (circleInsteadArrow ? 9 : 6),
+ ColorMarkers, false);
}
bwPaint.setShader(bwShader);
- rectF.set(-innerWheelRadius, -innerWheelRadius, innerWheelRadius, innerWheelRadius);
+ rectF.set(-brightnessWheelRadius, -brightnessWheelRadius, brightnessWheelRadius, brightnessWheelRadius);
canvas.drawOval(rectF, bwPaint);
int negative;
@@ -286,51 +296,65 @@ protected void onDraw(Canvas canvas) {
if (colorWheelVisible) {
negative = -1;
- arrowOffset = innerArrowHeight_a / 4 - innerWheelWidth;
+ arrowOffset = arrowHeight_a / 4 - brightnessWheelWidth;
} else {
negative = 1;
- arrowOffset = -(innerArrowHeight_a / 4);
+ arrowOffset = -(arrowHeight_a / 4);
}
+
if (circleInsteadArrow) {
- drawCirclePointer(canvas, innerWheelPointerAngle,
- innerWheelRadius, innerWheelWidth);
+ float angle = (float) (brightnessWheelPointerAngle - m90d);
+ if (!colorfulBrightnessWheel || !colorWheelVisible) {
+ angle = trimBrightnessColorAngle(angle);
+ }
+ drawCirclePointer(canvas, brightnessWheelPointerAngle,
+ brightnessWheelRadius, calculateColor(angle, BW), brightnessPointerCenter);
} else {
- drawArrow(canvas, innerTop,
- innerWheelPointerAngle,
- innerWheelRadius,
- innerWheelWidth,
+ drawArrow(canvas, brightnessPointerCenter,
+ brightnessWheelPointerAngle,
+ brightnessWheelRadius,
+ brightnessWheelWidth,
arrowOffset,
- negative * innerArrowHeight_a,
- negative * innerArrowHeight_b,
- calculateColor((float) (innerWheelPointerAngle - m90d), BW),
- innerArrowPath,
- innerArrowPaint);
+ negative * arrowHeight_a,
+ negative * arrowHeight_b,
+ calculateColor((float) (brightnessWheelPointerAngle - m90d), BW),
+ brightnessArrowPath,
+ brightnessArrowPaint);
}
- drawMarkers(canvas, innerWheelRadius, innerWheelWidth / 6,
+ drawWheelMarkers(canvas, brightnessWheelRadius,
+ brightnessWheelWidth / (circleInsteadArrow ? 9 : 6),
BrightnessMarkers, true);
+ }
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.translate(centerX, centerY);
+ drawWheel(canvas);
}
- private void drawArrow(Canvas canvas, PointerTop top, double topAngle,
+ private void drawArrow(Canvas canvas, PointF center, double topAngle,
float wheelRadius, float wheelWidth, double arrowOffset,
double arrowHeight_a, double arrowHeight_b,
int color, Path arrowPath, Paint arrowPaint) {
- top.X = Math.cos(topAngle) * (wheelRadius + wheelWidth / 2 + arrowOffset);
- top.Y = Math.sin(topAngle) * (wheelRadius + wheelWidth / 2 + arrowOffset);
+ float hh = (float) (arrowHeight_a + arrowHeight_b) / 2.0f;
+ double radius = wheelRadius + wheelWidth / 2 + arrowOffset;
+ float x = (float) (Math.cos(topAngle) * radius);
+ float y = (float) (Math.sin(topAngle) * radius);
- top.Height = Math.abs(arrowHeight_a + arrowHeight_b);
+ center.x = (float) (Math.cos(topAngle) * (radius + hh));
+ center.y = (float) (Math.sin(topAngle) * (radius + hh));
double arrowRad = Math.toRadians(40);
- double leftX = top.X + Math.cos(topAngle + arrowRad) * arrowHeight_a;
- double leftY = top.Y + Math.sin(topAngle + arrowRad) * arrowHeight_a;
+ double leftX = x + Math.cos(topAngle + arrowRad) * arrowHeight_a;
+ double leftY = y + Math.sin(topAngle + arrowRad) * arrowHeight_a;
- double rightX = top.X + Math.cos(topAngle - arrowRad) * arrowHeight_a;
- double rightY = top.Y + Math.sin(topAngle - arrowRad) * arrowHeight_a;
+ double rightX = x + Math.cos(topAngle - arrowRad) * arrowHeight_a;
+ double rightY = y + Math.sin(topAngle - arrowRad) * arrowHeight_a;
double backLeftX = leftX + Math.cos(topAngle) * arrowHeight_b;
double backLeftY = leftY + Math.sin(topAngle) * arrowHeight_b;
@@ -339,11 +363,11 @@ private void drawArrow(Canvas canvas, PointerTop top, double topAngle,
double backRightY = rightY + Math.sin(topAngle) * arrowHeight_b;
arrowPath.reset();
- arrowPath.moveTo((float) top.X, (float) top.Y);
+ arrowPath.moveTo(x, y);
arrowPath.lineTo((float) leftX, (float) leftY);
arrowPath.lineTo((float) backLeftX, (float) backLeftY);
- arrowPath.moveTo((float) top.X, (float) top.Y);
+ arrowPath.moveTo(x, y);
arrowPath.lineTo((float) rightX, (float) rightY);
arrowPath.lineTo((float) backRightX, (float) backRightY);
arrowPath.lineTo((float) backLeftX, (float) backLeftY);
@@ -374,47 +398,44 @@ private void setBWcolor() {
private void _onSizeChanged() {
- float arrowHeight = 0;
float wheelWidth = this.getWidth() > this.getHeight() ? this.getHeight() : this.getWidth();
if (circleInsteadArrow) {
wheelWidth /= 7.0f;
+ pointerHeight = wheelWidth;
} else {
wheelWidth /= 10.0f;
- arrowHeight = wheelWidth * 0.9f;
+ pointerHeight = wheelWidth * 0.9f;
}
- outerWheelWidth = wheelWidth / 2;
- outerArrowHeight_a = arrowHeight;
- outerArrowHeight_b = outerArrowHeight_a * 0.6;
- outerArrowHeight_a -= outerArrowHeight_b;
+ colorWheelWidth = wheelWidth / 2f;
+ arrowHeight_a = pointerHeight;
+ arrowHeight_b = arrowHeight_a * 0.6;
+ arrowHeight_a -= arrowHeight_b;
- innerWheelWidth = outerWheelWidth;
- innerArrowHeight_a = arrowHeight;
- innerArrowHeight_b = innerArrowHeight_a * 0.6;
- innerArrowHeight_a -= innerArrowHeight_b;
+ brightnessWheelWidth = colorWheelWidth;
- centerX = this.getWidth() / 2;
- centerY = this.getHeight() / 2;
+ centerX = this.getWidth() / 2f;
+ centerY = this.getHeight() / 2f;
if (colorWheelVisible && !circleInsteadArrow) {
- outerWheelWidth = wheelWidth / 2;
+ colorWheelWidth = wheelWidth / 2f;
} else {
- outerWheelWidth = wheelWidth;
+ colorWheelWidth = wheelWidth;
}
- innerWheelWidth = outerWheelWidth;
- int margin = circleInsteadArrow ? 0 : (int) (arrowHeight);
- outerWheelRadius = Math.min(centerX, centerY) - outerWheelWidth / 2 - margin;
+ brightnessWheelWidth = colorWheelWidth;
+ int margin = circleInsteadArrow ? 0 : (int) (pointerHeight);
+ colorWheelRadius = Math.min(centerX, centerY) - colorWheelWidth / 2 - margin;
if (colorWheelVisible) {
- innerWheelRadius = outerWheelRadius - innerWheelWidth;
+ brightnessWheelRadius = colorWheelRadius - brightnessWheelWidth;
} else {
- innerWheelRadius = outerWheelRadius;
+ brightnessWheelRadius = colorWheelRadius;
}
- cwPaint.setStrokeWidth(outerWheelWidth);
- bwPaint.setStrokeWidth(innerWheelWidth);
+ cwPaint.setStrokeWidth(colorWheelWidth);
+ bwPaint.setStrokeWidth(brightnessWheelWidth);
}
@Override
@@ -424,40 +445,9 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
- private double calculateAngle(double pointerAngle, double inRads) {
-
- double delta;
-
- if (Math.abs(lastTouchedAngle - inRads) > Math.PI) {
-
- delta = 2 * Math.PI - Math.abs(lastTouchedAngle) - Math.abs(inRads);
-
- if (lastTouchedAngle > 0 && inRads < 0) {
- delta *= -1;
- }
-
- } else {
- delta = lastTouchedAngle - inRads;
- }
-
- double result = (pointerAngle - delta);
-
- if (Math.abs(result) > Math.PI) {
-
- result = Math.PI - (Math.abs(result) % Math.PI);
-
- if (lastTouchedAngle < inRads) {
- result *= -1;
- }
- }
-
-
- return result;
- }
-
private void calculateBrightness() {
- double d = Math.toDegrees(innerWheelPointerAngle) + 90;
+ double d = Math.toDegrees(brightnessWheelPointerAngle) + 90;
if (d < 0)
d = d + 360;
@@ -468,13 +458,21 @@ private void calculateBrightness() {
selectedBrightness = (d / 360) * 100;
}
+ private boolean touchOverPointer(PointF touchPoint, PointF pointerCenter,
+ double pointerHeight) {
+ return Math.sqrt(Math.pow(pointerCenter.x - touchPoint.x, 2)
+ + Math.pow(pointerCenter.y - touchPoint.y, 2)) <= pointerHeight / 2;
+ }
+
+ public double pointToRadians(PointF point) {
+ return Math.atan2(point.y, point.x);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
- float x = event.getX() - centerX;
- float y = event.getY() - centerY;
-
- double inRads = (float) Math.atan2(y, x);
+ PointF touchPoint = new PointF(event.getX() - centerX, event.getY() - centerY);
+ double inRads = pointToRadians(touchPoint);
int action = event.getAction();
@@ -492,34 +490,16 @@ public boolean onTouchEvent(MotionEvent event) {
case MotionEvent.ACTION_DOWN:
- double sqrt = Math.sqrt(x * x + y * y);
-
-
- if (colorWheelVisible
- && Math.abs(outerTop.X - x) <= outerTop.Height
- && Math.abs(outerTop.Y - y) <= outerTop.Height
- && sqrt >= outerWheelRadius - outerWheelWidth / 2
- && sqrt <= outerWheelRadius + (outerArrowHeight_a + outerArrowHeight_b) * 2) {
-
+ if (colorWheelVisible && touchOverPointer(touchPoint, colorPointerCenter, pointerHeight)) {
colorWheelMove = true;
brightnessWheelMove = false;
-
- } else if (Math.abs(innerTop.X - x) <= innerTop.Height
- && Math.abs(innerTop.Y - y) <= innerTop.Height
- && ((colorWheelVisible
- && sqrt <= innerWheelRadius - innerWheelWidth / 2
- && sqrt >= innerWheelRadius - (innerArrowHeight_a + innerArrowHeight_b) * 2)
- || (!colorWheelVisible
- && sqrt <= innerWheelRadius + (innerArrowHeight_a + innerArrowHeight_b) * 2
- && sqrt >= innerWheelRadius - innerWheelWidth / 2))) {
-
+ touchAngleDiff = pointToRadians(colorPointerCenter) - inRads;
+ } else if (touchOverPointer(touchPoint, brightnessPointerCenter, pointerHeight)) {
colorWheelMove = false;
brightnessWheelMove = true;
+ touchAngleDiff = pointToRadians(brightnessPointerCenter) - inRads;
}
-
- lastTouchedAngle = inRads;
-
if (!isMoving())
return super.onTouchEvent(event);
@@ -529,9 +509,9 @@ public boolean onTouchEvent(MotionEvent event) {
if (colorWheelMove) {
- outerWheelPointerAngle = calculateAngle(outerWheelPointerAngle, inRads);
+ colorWheelPointerAngle = inRads + touchAngleDiff; //calculateAngle(colorWheelPointerAngle, inRads);
- int newColor = calculateColor((float) outerWheelPointerAngle, Colors);
+ int newColor = calculateColor((float) colorWheelPointerAngle, Colors);
if (newColor != selectedColor) {
@@ -546,21 +526,21 @@ public boolean onTouchEvent(MotionEvent event) {
} else if (brightnessWheelMove) {
- double newAngle = calculateAngle(innerWheelPointerAngle, inRads);
+ double newAngle = inRads + touchAngleDiff;
if (newAngle >= m160d
&& newAngle <= m20d) {
- if (innerWheelPointerAngle > newAngle) {
+ if (brightnessWheelPointerAngle > newAngle) {
- if (innerWheelPointerAngle >= m90d
+ if (brightnessWheelPointerAngle >= m90d
&& newAngle < m90d) {
newAngle = m90d;
}
- } else if (innerWheelPointerAngle < newAngle) {
+ } else if (brightnessWheelPointerAngle < newAngle) {
- if (innerWheelPointerAngle <= m90_01d
+ if (brightnessWheelPointerAngle <= m90_01d
&& newAngle > m90_01d) {
newAngle = m90_01d;
}
@@ -569,9 +549,9 @@ public boolean onTouchEvent(MotionEvent event) {
}
- if (innerWheelPointerAngle != newAngle) {
+ if (brightnessWheelPointerAngle != newAngle) {
- innerWheelPointerAngle = newAngle;
+ brightnessWheelPointerAngle = newAngle;
calculateBrightness();
invalidate();
@@ -583,8 +563,6 @@ public boolean onTouchEvent(MotionEvent event) {
}
- lastTouchedAngle = inRads;
-
break;
}
@@ -606,12 +584,12 @@ public void setColor(int color) {
if (selectedColor != color) {
selectedColor = color;
- outerWheelPointerAngle = colorToAngle(color);
+ colorWheelPointerAngle = colorToAngle(color);
if (color == Color.WHITE)
selectedColor = color;
else
- selectedColor = calculateColor((float) outerWheelPointerAngle, Colors);
+ selectedColor = calculateColor((float) colorWheelPointerAngle, Colors);
invalidate();
}
@@ -636,7 +614,7 @@ public double getBrightnessValue() {
public void setBrightnessValue(double value) {
- innerWheelPointerAngle = brightnessToAngle(value);
+ brightnessWheelPointerAngle = brightnessToAngle(value);
selectedBrightness = value;
invalidate();
@@ -671,12 +649,28 @@ public boolean isMoving() {
return colorWheelMove || brightnessWheelMove;
}
- public ArrayList getColorMarkers() {
- return new ArrayList<>(ColorMarkers);
+ public ArrayList getColorMarkers() {
+ if (ColorMarkers != null && ColorMarkers.size() > 0) {
+ ArrayListresult = new ArrayList<>();
+ for(Double color: ColorMarkers) {
+ result.add(color.intValue());
+ }
+ return result;
+ }
+
+ return null;
}
- public void setColorMarkers(ArrayList colorMarkers) {
- ColorMarkers = colorMarkers == null ? null : new ArrayList<>(colorMarkers);
+ public void setColorMarkers(ArrayList colorMarkers) {
+ ColorMarkers = null;
+
+ if (colorMarkers != null && colorMarkers.size() > 0) {
+ ColorMarkers = new ArrayList<>();
+ for(Integer color: colorMarkers) {
+ ColorMarkers.add(color.doubleValue());
+ }
+ }
+
invalidate();
}
@@ -717,10 +711,4 @@ public interface OnColorBrightnessChangeListener {
void onChangeFinished();
}
- private class PointerTop {
- double X;
- double Y;
- double Height;
- }
-
}
From 989a7fc998860046607bf18f5150ba44fa91ed80 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sat, 6 Jun 2020 21:30:53 +0200
Subject: [PATCH 04/31] SuplaColorBrightnessPicker - slider added
---
.../android/SuplaColorBrightnessPicker.java | 287 ++++++++++++------
1 file changed, 198 insertions(+), 89 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index ac2c3f68c..13bbf67a2 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -13,6 +13,7 @@
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
+
import java.util.ArrayList;
/*
@@ -43,6 +44,7 @@ public class SuplaColorBrightnessPicker extends View {
final static private double m90d = Math.toRadians(-90);
final static private double m90_01d = Math.toRadians(-90.01);
final static private double m20d = Math.toRadians(-20);
+ final static private double p40d = Math.toRadians(40);
private int[] BW = new int[]{
Color.BLACK,
Color.WHITE,
@@ -74,16 +76,17 @@ public class SuplaColorBrightnessPicker extends View {
private Shader cwShader; // color wheel shader
private Paint bwPaint; // brightness wheel paint
private Shader bwShader; // brightness wheel shader
- private Matrix gradientRotationMatrix;
private boolean colorWheelVisible;
- private boolean colorWheelMove;
- private boolean brightnessWheelMove;
+ private boolean colorPointerMoving;
+ private boolean brightnessWheelPointerMoving;
private boolean colorfulBrightnessWheel;
private boolean circleInsteadArrow;
- private double touchAngleDiff;
+ private double touchDiff;
private OnColorBrightnessChangeListener mOnChangeListener;
private ArrayList ColorMarkers;
- private ArrayList BrightnessMarkers;
+ private ArrayList brightnessMarkers;
+ private boolean sliderVisible;
+ private RectF sliderRect;
public SuplaColorBrightnessPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
@@ -110,7 +113,6 @@ private void init() {
cwPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
cwPaint.setStyle(Paint.Style.STROKE);
- bwShader = new SweepGradient(0, 0, BW, null);
bwPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bwPaint.setStyle(Paint.Style.STROKE);
@@ -129,12 +131,8 @@ private void init() {
brightnessWheelPointerAngle = Math.toRadians(-90);
selectedBrightness = 0;
- gradientRotationMatrix = new Matrix();
- gradientRotationMatrix.preRotate(-90);
- bwShader.setLocalMatrix(gradientRotationMatrix);
-
- colorWheelMove = false;
- brightnessWheelMove = false;
+ colorPointerMoving = false;
+ brightnessWheelPointerMoving = false;
colorfulBrightnessWheel = true;
circleInsteadArrow = false;
@@ -187,17 +185,28 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(size, size);
}
- private void drawWheelMarkers(Canvas canvas, float radius, float markerSize,
- ArrayList markers, boolean brightness) {
-
- double angle;
+ private void drawMarker(Canvas canvas, float x, float y, float markerSize) {
paint.setAntiAlias(true);
paint.setStrokeWidth(markerSize / 5);
+ paint.setColor(Color.WHITE);
+ paint.setStyle(Paint.Style.FILL);
+
+ canvas.drawCircle(x, y, markerSize, paint);
+
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(Color.BLACK);
+
+ canvas.drawCircle(x, y, markerSize, paint);
+ }
+ private void drawWheelMarkers(Canvas canvas, float radius, float markerSize,
+ ArrayList markers, boolean brightness) {
if (markers == null) {
return;
}
+ double angle;
+
for (int a = 0; a < markers.size(); a++) {
double v = markers.get(a);
@@ -213,28 +222,32 @@ private void drawWheelMarkers(Canvas canvas, float radius, float markerSize,
angle = colorToAngle((int) v);
}
- float x = (float) Math.cos(angle) * radius;
- float y = (float) Math.sin(angle) * radius;
-
- paint.setColor(Color.WHITE);
- paint.setStyle(Paint.Style.FILL);
+ drawMarker(canvas,
+ (float) Math.cos(angle) * radius,
+ (float) Math.sin(angle) * radius,
+ markerSize);
- canvas.drawCircle(x, y, markerSize, paint);
- paint.setStyle(Paint.Style.STROKE);
- paint.setColor(Color.BLACK);
+ }
- canvas.drawCircle(x, y, markerSize, paint);
+ }
+ private void drawSliderMarkers(Canvas canvas, float markerSize) {
+ if (brightnessMarkers == null) {
+ return;
}
- }
+ float h = sliderRect.height() - (float) pointerHeight;
- private void drawCirclePointer(Canvas canvas, double angle,
- float wheelRadius, int color, PointF center) {
+ for (int a = 0; a < brightnessMarkers.size(); a++) {
+ drawMarker(canvas,
+ 0,
+ h / 2 - h * brightnessMarkers.get(a).floatValue() / 100f,
+ markerSize);
+ }
+ }
- center.x = (float) Math.cos(angle) * wheelRadius;
- center.y = (float) Math.sin(angle) * wheelRadius;
+ private void drawCirclePointer(Canvas canvas, int color, PointF center) {
float lw = (float) pointerHeight * 0.05f;
paint.setAntiAlias(true);
@@ -249,6 +262,15 @@ private void drawCirclePointer(Canvas canvas, double angle,
canvas.drawCircle(center.x, center.y, (float) pointerHeight / 2 - lw * 1.5f, paint);
}
+ private void drawCirclePointer(Canvas canvas, double angle,
+ float wheelRadius, int color, PointF center) {
+
+ center.x = (float) Math.cos(angle) * wheelRadius;
+ center.y = (float) Math.sin(angle) * wheelRadius;
+
+ drawCirclePointer(canvas, color, center);
+ }
+
private float trimBrightnessColorAngle(float rad) {
if (rad >= 0 && rad <= 0.4f) {
rad = 0.4f;
@@ -287,6 +309,7 @@ private void drawWheel(Canvas canvas) {
ColorMarkers, false);
}
+ bwPaint.setStyle(Paint.Style.STROKE);
bwPaint.setShader(bwShader);
rectF.set(-brightnessWheelRadius, -brightnessWheelRadius, brightnessWheelRadius, brightnessWheelRadius);
canvas.drawOval(rectF, bwPaint);
@@ -325,14 +348,61 @@ private void drawWheel(Canvas canvas) {
drawWheelMarkers(canvas, brightnessWheelRadius,
brightnessWheelWidth / (circleInsteadArrow ? 9 : 6),
- BrightnessMarkers, true);
+ brightnessMarkers, true);
}
+ private void drawSlider(Canvas canvas) {
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(2);
+
+ float height = getHeight() - (float) pointerHeight / 2;
+ float x = (float) pointerHeight / -2;
+ float y = height / -2;
+
+ Path path = new Path();
+ sliderRect = new RectF(x, y, x + (float) pointerHeight, y + height);
+ path.addRoundRect(sliderRect, 90, 90, Path.Direction.CW);
+ canvas.clipPath(path);
+
+ float[] hsv = new float[3];
+ Color.colorToHSV(Color.WHITE, hsv);
+
+ for (float a = 0; a < height; a++) {
+ hsv[2] = 1 - 1 * (a * 100f / height) / 100f;
+ paint.setColor(Color.HSVToColor(hsv));
+ canvas.drawLine(x, y + a, x + (float) pointerHeight, y + a, paint);
+ }
+
+
+ height -= pointerHeight;
+
+ brightnessPointerCenter.x = 0;
+ brightnessPointerCenter.y = height / 2 - height * (float) selectedBrightness / 100f;
+
+ float percent = (float) selectedBrightness;
+
+ if (percent > 85f) {
+ percent = 85f;
+ } else if (percent < 15f) {
+ percent = 15f;
+ }
+
+ hsv[2] = 1 * percent / 100f;
+ drawCirclePointer(canvas, Color.HSVToColor(hsv), brightnessPointerCenter);
+ drawSliderMarkers(canvas, (float) pointerHeight / 10f);
+ }
+
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(centerX, centerY);
- drawWheel(canvas);
+ if (sliderVisible) {
+ drawSlider(canvas);
+ } else {
+ drawWheel(canvas);
+ }
}
private void drawArrow(Canvas canvas, PointF center, double topAngle,
@@ -385,30 +455,36 @@ private void drawArrow(Canvas canvas, PointF center, double topAngle,
}
private void setBWcolor() {
- int color = colorWheelVisible && colorfulBrightnessWheel ? selectedColor : Color.WHITE;
+ int color = colorWheelVisible
+ && colorfulBrightnessWheel && !sliderVisible ? selectedColor : Color.WHITE;
if (BW[1] != color) {
BW[1] = color;
BW[2] = color;
bwShader = new SweepGradient(0, 0, BW, null);
+ Matrix gradientRotationMatrix = new Matrix();
+ gradientRotationMatrix.preRotate(-90);
bwShader.setLocalMatrix(gradientRotationMatrix);
+
}
}
private void _onSizeChanged() {
- float wheelWidth = this.getWidth() > this.getHeight() ? this.getHeight() : this.getWidth();
+ float w = this.getWidth() > this.getHeight() ? this.getHeight() : this.getWidth();
- if (circleInsteadArrow) {
- wheelWidth /= 7.0f;
- pointerHeight = wheelWidth;
+ if (sliderVisible) {
+ pointerHeight = w / 6.5f;
+ } else if (circleInsteadArrow) {
+ w /= 7.0f;
+ pointerHeight = w;
} else {
- wheelWidth /= 10.0f;
- pointerHeight = wheelWidth * 0.9f;
+ w /= 10.0f;
+ pointerHeight = w * 0.9f;
}
- colorWheelWidth = wheelWidth / 2f;
+ colorWheelWidth = w / 2f;
arrowHeight_a = pointerHeight;
arrowHeight_b = arrowHeight_a * 0.6;
arrowHeight_a -= arrowHeight_b;
@@ -419,9 +495,9 @@ private void _onSizeChanged() {
centerY = this.getHeight() / 2f;
if (colorWheelVisible && !circleInsteadArrow) {
- colorWheelWidth = wheelWidth / 2f;
+ colorWheelWidth = w / 2f;
} else {
- colorWheelWidth = wheelWidth;
+ colorWheelWidth = w;
}
brightnessWheelWidth = colorWheelWidth;
@@ -445,19 +521,6 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
- private void calculateBrightness() {
-
- double d = Math.toDegrees(brightnessWheelPointerAngle) + 90;
-
- if (d < 0)
- d = d + 360;
-
- if (d >= 359.99)
- d = 360;
-
- selectedBrightness = (d / 360) * 100;
- }
-
private boolean touchOverPointer(PointF touchPoint, PointF pointerCenter,
double pointerHeight) {
return Math.sqrt(Math.pow(pointerCenter.x - touchPoint.x, 2)
@@ -472,7 +535,7 @@ public double pointToRadians(PointF point) {
public boolean onTouchEvent(MotionEvent event) {
PointF touchPoint = new PointF(event.getX() - centerX, event.getY() - centerY);
- double inRads = pointToRadians(touchPoint);
+ double touchAngle = pointToRadians(touchPoint);
int action = event.getAction();
@@ -480,8 +543,8 @@ public boolean onTouchEvent(MotionEvent event) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- colorWheelMove = false;
- brightnessWheelMove = false;
+ colorPointerMoving = false;
+ brightnessWheelPointerMoving = false;
if (mOnChangeListener != null)
mOnChangeListener.onChangeFinished();
@@ -490,26 +553,52 @@ public boolean onTouchEvent(MotionEvent event) {
case MotionEvent.ACTION_DOWN:
- if (colorWheelVisible && touchOverPointer(touchPoint, colorPointerCenter, pointerHeight)) {
- colorWheelMove = true;
- brightnessWheelMove = false;
- touchAngleDiff = pointToRadians(colorPointerCenter) - inRads;
+ colorPointerMoving = false;
+ brightnessWheelPointerMoving = false;
+
+ if (!sliderVisible
+ && colorWheelVisible
+ && touchOverPointer(touchPoint, colorPointerCenter, pointerHeight)) {
+ colorPointerMoving = true;
+ touchDiff = pointToRadians(colorPointerCenter) - touchAngle;
} else if (touchOverPointer(touchPoint, brightnessPointerCenter, pointerHeight)) {
- colorWheelMove = false;
- brightnessWheelMove = true;
- touchAngleDiff = pointToRadians(brightnessPointerCenter) - inRads;
+ brightnessWheelPointerMoving = true;
+ if (sliderVisible) {
+ touchDiff = brightnessPointerCenter.y - touchPoint.y;
+ } else {
+ touchDiff = pointToRadians(brightnessPointerCenter) - touchAngle;
+ }
}
- if (!isMoving())
+ if (!isMoving()) {
return super.onTouchEvent(event);
-
+ }
break;
case MotionEvent.ACTION_MOVE:
- if (colorWheelMove) {
+ if (sliderVisible) {
+ if (brightnessWheelPointerMoving) {
+ float h = sliderRect.height() - (float) pointerHeight;
+ float brightness = 100 - ((h / 2) + (float) touchDiff + touchPoint.y) * 100 / h;
+
+ if (brightness > 100) {
+ brightness = 100;
+ } else if (brightness < 0) {
+ brightness = 0;
+ }
+
+ if (selectedBrightness != brightness) {
+ setBrightnessValue(brightness);
+
+ if (mOnChangeListener != null)
+ mOnChangeListener.onBrightnessChanged(this, selectedBrightness);
+ }
+
+ }
+ } else if (colorPointerMoving) {
- colorWheelPointerAngle = inRads + touchAngleDiff; //calculateAngle(colorWheelPointerAngle, inRads);
+ colorWheelPointerAngle = touchAngle + touchDiff;
int newColor = calculateColor((float) colorWheelPointerAngle, Colors);
@@ -524,43 +613,45 @@ public boolean onTouchEvent(MotionEvent event) {
}
- } else if (brightnessWheelMove) {
+ } else if (brightnessWheelPointerMoving) {
- double newAngle = inRads + touchAngleDiff;
+ double newAngle = touchAngle + touchDiff;
+ if (brightnessWheelPointerAngle >= m160d
+ && brightnessWheelPointerAngle <= m20d) {
- if (newAngle >= m160d
- && newAngle <= m20d) {
+ if (Math.abs(brightnessWheelPointerAngle - newAngle) > p40d) {
+ newAngle = brightnessWheelPointerAngle;
+ }
if (brightnessWheelPointerAngle > newAngle) {
-
if (brightnessWheelPointerAngle >= m90d
&& newAngle < m90d) {
newAngle = m90d;
}
-
} else if (brightnessWheelPointerAngle < newAngle) {
-
if (brightnessWheelPointerAngle <= m90_01d
&& newAngle > m90_01d) {
newAngle = m90_01d;
}
-
}
-
}
if (brightnessWheelPointerAngle != newAngle) {
+ double d = Math.toDegrees(newAngle) + 90;
- brightnessWheelPointerAngle = newAngle;
+ if (d < 0) {
+ d += 360;
+ }
- calculateBrightness();
- invalidate();
+ if (d >= 359.99) {
+ d = 360;
+ }
+
+ setBrightnessValue((d / 360) * 100);
if (mOnChangeListener != null)
mOnChangeListener.onBrightnessChanged(this, selectedBrightness);
-
}
-
}
break;
@@ -614,6 +705,12 @@ public double getBrightnessValue() {
public void setBrightnessValue(double value) {
+ if (value > 100) {
+ value = 100;
+ } else if (value < 0) {
+ value = 0;
+ }
+
brightnessWheelPointerAngle = brightnessToAngle(value);
selectedBrightness = value;
invalidate();
@@ -646,13 +743,13 @@ else if (value > 100)
}
public boolean isMoving() {
- return colorWheelMove || brightnessWheelMove;
+ return colorPointerMoving || brightnessWheelPointerMoving;
}
public ArrayList getColorMarkers() {
if (ColorMarkers != null && ColorMarkers.size() > 0) {
- ArrayListresult = new ArrayList<>();
- for(Double color: ColorMarkers) {
+ ArrayList result = new ArrayList<>();
+ for (Double color : ColorMarkers) {
result.add(color.intValue());
}
return result;
@@ -666,7 +763,7 @@ public void setColorMarkers(ArrayList colorMarkers) {
if (colorMarkers != null && colorMarkers.size() > 0) {
ColorMarkers = new ArrayList<>();
- for(Integer color: colorMarkers) {
+ for (Integer color : colorMarkers) {
ColorMarkers.add(color.doubleValue());
}
}
@@ -675,11 +772,12 @@ public void setColorMarkers(ArrayList colorMarkers) {
}
public ArrayList getBrightnessMarkers() {
- return new ArrayList<>(BrightnessMarkers);
+ return new ArrayList<>(brightnessMarkers);
}
public void setBrightnessMarkers(ArrayList brightnessMarkers) {
- BrightnessMarkers = brightnessMarkers == null ? null : new ArrayList<>(brightnessMarkers);
+ this.brightnessMarkers = brightnessMarkers == null ?
+ null : new ArrayList<>(brightnessMarkers);
invalidate();
}
@@ -703,6 +801,17 @@ public void setCircleInsteadArrow(boolean circleInsteadArrow) {
invalidate();
}
+ public boolean isSliderVisible() {
+ return sliderVisible;
+ }
+
+ public void setSliderVisible(boolean sliderVisible) {
+ this.sliderVisible = sliderVisible;
+ _onSizeChanged();
+ setBWcolor();
+ invalidate();
+ }
+
public interface OnColorBrightnessChangeListener {
void onColorChanged(SuplaColorBrightnessPicker scbPicker, int color);
From 7e418378fa787a88c0f008663d42cb452da4626b Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sat, 6 Jun 2020 22:32:35 +0200
Subject: [PATCH 05/31] SuplaColorBrightnessPicker - power button
implementation added
---
.../android/SuplaColorBrightnessPicker.java | 101 +++++++++++++++++-
1 file changed, 98 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 13bbf67a2..264d1fcf9 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -87,6 +87,13 @@ public class SuplaColorBrightnessPicker extends View {
private ArrayList brightnessMarkers;
private boolean sliderVisible;
private RectF sliderRect;
+ private boolean powerButtonVisible;
+ private boolean powerButtonEnabled;
+ private boolean powerButtonOn;
+ private int powerButtonColorOn;
+ private int powerButtonColorOff;
+ private float powerButtonRadius;
+ private boolean powerButtonTouched;
public SuplaColorBrightnessPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
@@ -135,6 +142,10 @@ private void init() {
brightnessWheelPointerMoving = false;
colorfulBrightnessWheel = true;
circleInsteadArrow = false;
+ powerButtonColorOn = Color.parseColor("#f7f0dc");
+ powerButtonColorOff = Color.parseColor("#404040");
+
+ powerButtonEnabled = true;
setBWcolor();
}
@@ -280,6 +291,27 @@ private float trimBrightnessColorAngle(float rad) {
return rad;
}
+ private void drawPowerButton(Canvas canvas, float wheelRadius) {
+ powerButtonRadius = wheelRadius * 0.3f;
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setColor(powerButtonOn ? powerButtonColorOn : powerButtonColorOff);
+ paint.setStrokeWidth(powerButtonRadius * 0.2f);
+
+ Path path = new Path();
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ RectF rect = new RectF(-powerButtonRadius, -powerButtonRadius,
+ powerButtonRadius, powerButtonRadius);
+ path.addArc(rect, -60f, 300f);
+ path.moveTo(0f, powerButtonRadius * -1f - powerButtonRadius * 0.15f);
+ path.lineTo(0f, powerButtonRadius * -1f + powerButtonRadius * 0.6f);
+
+ canvas.drawPath(path, paint);
+
+ }
+
private void drawWheel(Canvas canvas) {
if (colorWheelVisible) {
@@ -350,6 +382,9 @@ private void drawWheel(Canvas canvas) {
brightnessWheelWidth / (circleInsteadArrow ? 9 : 6),
brightnessMarkers, true);
+ if (powerButtonVisible) {
+ drawPowerButton(canvas, brightnessWheelRadius * 0.8f);
+ }
}
private void drawSlider(Canvas canvas) {
@@ -546,15 +581,24 @@ public boolean onTouchEvent(MotionEvent event) {
colorPointerMoving = false;
brightnessWheelPointerMoving = false;
+ if (powerButtonTouched) {
+ setPowerButtonOn(!isPowerButtonOn());
+
+ if (mOnChangeListener != null)
+ mOnChangeListener.onPowerButtonClick(this);
+ }
+
if (mOnChangeListener != null)
- mOnChangeListener.onChangeFinished();
+ mOnChangeListener.onChangeFinished(this);
+ powerButtonTouched = false;
break;
case MotionEvent.ACTION_DOWN:
colorPointerMoving = false;
brightnessWheelPointerMoving = false;
+ powerButtonTouched = false;
if (!sliderVisible
&& colorWheelVisible
@@ -568,9 +612,14 @@ && touchOverPointer(touchPoint, colorPointerCenter, pointerHeight)) {
} else {
touchDiff = pointToRadians(brightnessPointerCenter) - touchAngle;
}
+ } else if (powerButtonVisible
+ && powerButtonEnabled
+ && touchOverPointer(touchPoint, new PointF(0, 0),
+ powerButtonRadius * 2.2)) {
+ powerButtonTouched = true;
}
- if (!isMoving()) {
+ if (!isMoving() && !powerButtonTouched) {
return super.onTouchEvent(event);
}
break;
@@ -812,12 +861,58 @@ public void setSliderVisible(boolean sliderVisible) {
invalidate();
}
+ public boolean isPowerButtonVisible() {
+ return powerButtonVisible;
+ }
+
+ public void setPowerButtonVisible(boolean powerButtonVisible) {
+ this.powerButtonVisible = powerButtonVisible;
+ invalidate();
+ }
+
+ public boolean isPowerButtonEnabled() {
+ return powerButtonEnabled;
+ }
+
+ public void setPowerButtonEnabled(boolean powerButtonEnabled) {
+ this.powerButtonEnabled = powerButtonEnabled;
+ }
+
+ public boolean isPowerButtonOn() {
+ return powerButtonOn;
+ }
+
+ public void setPowerButtonOn(boolean powerButtonOn) {
+ this.powerButtonOn = powerButtonOn;
+ invalidate();
+ }
+
+ public int getPowerButtonColorOn() {
+ return powerButtonColorOn;
+ }
+
+ public void setPowerButtonColorOn(int powerButtonColorOn) {
+ this.powerButtonColorOn = powerButtonColorOn;
+ invalidate();
+ }
+
+ public int getPowerButtonColorOff() {
+ return powerButtonColorOff;
+ }
+
+ public void setPowerButtonColorOff(int powerButtonColorOff) {
+ this.powerButtonColorOff = powerButtonColorOff;
+ invalidate();
+ }
+
public interface OnColorBrightnessChangeListener {
void onColorChanged(SuplaColorBrightnessPicker scbPicker, int color);
void onBrightnessChanged(SuplaColorBrightnessPicker scbPicker, double brightness);
- void onChangeFinished();
+ void onChangeFinished(SuplaColorBrightnessPicker scbPicker);
+
+ void onPowerButtonClick(SuplaColorBrightnessPicker scbPicker);
}
}
From 18bb88bf13dafb3a54fa30064e2295bf8520ad9b Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:32:18 +0200
Subject: [PATCH 06/31] Color as Double. "get" replaced with "is"
---
.../android/SuplaColorBrightnessPicker.java | 30 +++++--------------
1 file changed, 8 insertions(+), 22 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 264d1fcf9..75067da4d 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -83,7 +83,7 @@ public class SuplaColorBrightnessPicker extends View {
private boolean circleInsteadArrow;
private double touchDiff;
private OnColorBrightnessChangeListener mOnChangeListener;
- private ArrayList ColorMarkers;
+ private ArrayList colorMarkers;
private ArrayList brightnessMarkers;
private boolean sliderVisible;
private RectF sliderRect;
@@ -338,7 +338,7 @@ private void drawWheel(Canvas canvas) {
drawWheelMarkers(canvas, colorWheelRadius,
colorWheelWidth / (circleInsteadArrow ? 9 : 6),
- ColorMarkers, false);
+ colorMarkers, false);
}
bwPaint.setStyle(Paint.Style.STROKE);
@@ -735,7 +735,7 @@ public void setColor(int color) {
}
}
- public boolean getColorWheelVisible() {
+ public boolean isColorWheelVisible() {
return colorWheelVisible;
}
@@ -795,27 +795,13 @@ public boolean isMoving() {
return colorPointerMoving || brightnessWheelPointerMoving;
}
- public ArrayList getColorMarkers() {
- if (ColorMarkers != null && ColorMarkers.size() > 0) {
- ArrayList result = new ArrayList<>();
- for (Double color : ColorMarkers) {
- result.add(color.intValue());
- }
- return result;
- }
-
- return null;
+ public ArrayList getColorMarkers() {
+ return new ArrayList<>(colorMarkers);
}
- public void setColorMarkers(ArrayList colorMarkers) {
- ColorMarkers = null;
-
- if (colorMarkers != null && colorMarkers.size() > 0) {
- ColorMarkers = new ArrayList<>();
- for (Integer color : colorMarkers) {
- ColorMarkers.add(color.doubleValue());
- }
- }
+ public void setColorMarkers(ArrayList colorMarkers) {
+ this.colorMarkers = colorMarkers == null ?
+ null : new ArrayList<>(colorMarkers);
invalidate();
}
From 1fe7dc847165f86e6817f7f6f888f3614727f3e0 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:33:13 +0200
Subject: [PATCH 07/31] rgbPicker renamed to cbPicker. rgb_wheel_width,
rgb_wheel_arrow_height removed
---
app/src/main/res/layout/detail_rgb.xml | 2 +-
app/src/main/res/values-sw600dp/dimens.xml | 2 --
app/src/main/res/values/dimens.xml | 2 --
3 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/app/src/main/res/layout/detail_rgb.xml b/app/src/main/res/layout/detail_rgb.xml
index be0af4d42..1533de884 100644
--- a/app/src/main/res/layout/detail_rgb.xml
+++ b/app/src/main/res/layout/detail_rgb.xml
@@ -31,7 +31,7 @@
android:layout_alignParentTop="false">
100dp
250dp
15dp
- 60dp
- 55dp
150dp
30dp
40dp
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 47105622d..284f3b431 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -27,8 +27,6 @@
50dp
150dp
15dp
- 35dp
- 30dp
80dp
15dp
25dp
From 8f6eeb1aeb910a93fdb5569a814f453ea5aaab42 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:34:28 +0200
Subject: [PATCH 08/31] ChannelDetailRGB has been adapted to the new version of
the picker
---
.../org/supla/android/ChannelDetailRGB.java | 110 +++++++++---------
1 file changed, 53 insertions(+), 57 deletions(-)
diff --git a/app/src/main/java/org/supla/android/ChannelDetailRGB.java b/app/src/main/java/org/supla/android/ChannelDetailRGB.java
index 084823cda..314952446 100644
--- a/app/src/main/java/org/supla/android/ChannelDetailRGB.java
+++ b/app/src/main/java/org/supla/android/ChannelDetailRGB.java
@@ -47,11 +47,13 @@ of the License, or (at your option) any later version.
import java.util.Timer;
import java.util.TimerTask;
-public class ChannelDetailRGB extends DetailLayout implements View.OnClickListener, SuplaColorBrightnessPicker.OnColorBrightnessChangeListener, SuplaColorListPicker.OnColorListTouchListener {
+public class ChannelDetailRGB extends DetailLayout implements View.OnClickListener,
+ SuplaColorBrightnessPicker.OnColorBrightnessChangeListener,
+ SuplaColorListPicker.OnColorListTouchListener {
final static private long MIN_REMOTE_UPDATE_PERIOD = 250;
final static private long MIN_UPDATE_DELAY = 2000;
- private SuplaColorBrightnessPicker rgbPicker;
+ private SuplaColorBrightnessPicker cbPicker;
private SuplaColorListPicker clPicker;
private Button tabRGB;
private Button tabDimmer;
@@ -108,12 +110,8 @@ protected void init() {
clPicker.addItem();
clPicker.setOnTouchListener(this);
- rgbPicker = findViewById(R.id.rgbPicker);
- rgbPicker.setPercentVisible(false);
- rgbPicker.setWheelWidth(r.getDimensionPixelSize(R.dimen.rgb_wheel_width));
- rgbPicker.setArrowHeight(r.getDimensionPixelSize(R.dimen.rgb_wheel_arrow_height));
-
- rgbPicker.setOnChangeListener(this);
+ cbPicker = findViewById(R.id.cbPicker);
+ cbPicker.setOnChangeListener(this);
tabRGB = findViewById(R.id.rgbTabBtn_RGB);
tabDimmer = findViewById(R.id.rgbTabBtn_Dimmer);
@@ -149,9 +147,7 @@ protected void init() {
private void showRGB() {
-
- rgbPicker.setColorWheelVisible(true);
- rgbPicker.setColorBrightnessWheelVisible(true);
+ cbPicker.setColorWheelVisible(true);
clPicker.setVisibility(View.VISIBLE);
channelDataToViews();
@@ -159,7 +155,7 @@ private void showRGB() {
private void showDimmer() {
- rgbPicker.setBWBrightnessWheelVisible(true);
+ cbPicker.setColorWheelVisible(false);
clPicker.setVisibility(View.GONE);
channelDataToViews();
@@ -217,8 +213,7 @@ public void setData(ChannelBase channel) {
break;
case SuplaConst.SUPLA_CHANNELFNC_DIMMERANDRGBLIGHTING:
- rgbPicker.setColorWheelVisible(true);
- rgbPicker.setColorBrightnessWheelVisible(true);
+ cbPicker.setColorWheelVisible(true);
onClick(tabRGB);
tabs.setVisibility(View.VISIBLE);
@@ -233,8 +228,8 @@ public void setData(ChannelBase channel) {
private void channelDataToViews() {
int id = 0;
- rgbPicker.setColorMarkers(null);
- rgbPicker.setBrightnessMarkers(null);
+ cbPicker.setColorMarkers(null);
+ cbPicker.setBrightnessMarkers(null);
if (isGroup()) {
ChannelGroup cgroup = (ChannelGroup) getChannelFromDatabase();
@@ -248,34 +243,30 @@ private void channelDataToViews() {
ArrayList markers;
- if (rgbPicker.getColorBrightnessWheelVisible()
- || rgbPicker.getBWBrightnessWheelVisible()) {
+ markers = cbPicker.isColorWheelVisible() ? cgroup.getColorBrightness()
+ : cgroup.getBrightness();
- markers = rgbPicker.getColorBrightnessWheelVisible() ? cgroup.getColorBrightness()
- : cgroup.getBrightness();
-
- if (markers != null) {
- if (markers.size() == 1) {
- if (markers.get(0).intValue() != (int) rgbPicker.getBrightnessValue()) {
- rgbPicker.setBrightnessValue(markers.get(0));
- }
- } else {
- rgbPicker.setBrightnessMarkers(markers);
+ if (markers != null) {
+ if (markers.size() == 1) {
+ if (markers.get(0).intValue() != (int) cbPicker.getBrightnessValue()) {
+ cbPicker.setBrightnessValue(markers.get(0));
}
+ } else {
+ cbPicker.setBrightnessMarkers(markers);
}
}
- if (rgbPicker.getColorWheelVisible()) {
+ if (cbPicker.isColorWheelVisible()) {
markers = cgroup.getColors();
if (markers != null) {
if (markers.size() == 1) {
- if (markers.get(0).intValue() != rgbPicker.getColor()) {
- rgbPicker.setColor(markers.get(0).intValue());
+ if (markers.get(0).intValue() != cbPicker.getColor()) {
+ cbPicker.setColor(markers.get(0).intValue());
}
} else {
- rgbPicker.setColorMarkers(markers);
+ cbPicker.setColorMarkers(markers);
}
}
}
@@ -290,16 +281,17 @@ private void channelDataToViews() {
stateImage.setVisibility(View.VISIBLE);
tvStateCaption.setVisibility(View.VISIBLE);
- if (rgbPicker.getColorBrightnessWheelVisible()
- && (int) rgbPicker.getBrightnessValue() != (int) channel.getColorBrightness())
- rgbPicker.setBrightnessValue(channel.getColorBrightness());
+ if (cbPicker.isColorWheelVisible()
+ && (int) cbPicker.getBrightnessValue() != (int) channel.getColorBrightness()) {
+ cbPicker.setBrightnessValue(channel.getColorBrightness());
- if (rgbPicker.getBWBrightnessWheelVisible()
- && (int) rgbPicker.getBrightnessValue() != (int) channel.getBrightness())
- rgbPicker.setBrightnessValue(channel.getBrightness());
+ } else if (!cbPicker.isColorWheelVisible()
+ && (int) cbPicker.getBrightnessValue() != (int) channel.getBrightness()) {
+ cbPicker.setBrightnessValue(channel.getBrightness());
+ }
- if (rgbPicker.getColorWheelVisible())
- rgbPicker.setColor(channel.getColor());
+ if (cbPicker.isColorWheelVisible())
+ cbPicker.setColor(channel.getColor());
}
@@ -340,12 +332,12 @@ private void setBtnBackground(Button btn, int id) {
@SuppressLint("SetTextI18n")
private void pickerToInfoPanel() {
- lastColor = rgbPicker.getColor();
+ lastColor = cbPicker.getColor();
- int brightness = (int) rgbPicker.getBrightnessValue();
+ int brightness = (int) cbPicker.getBrightnessValue();
stateImage.setImageResource(brightness > 0 ? R.drawable.poweron : R.drawable.poweroff);
- if (rgbPicker.getColorWheelVisible())
+ if (cbPicker.isColorWheelVisible())
lastColorBrightness = brightness;
else
lastBrightness = brightness;
@@ -423,10 +415,10 @@ public void onClick(View v) {
tabRGB.setTextColor(Color.BLACK);
tabDimmer.setTextColor(getResources().getColor(R.color.detail_rgb_gb));
} else if (v == stateImage) {
- rgbPicker.setBrightnessValue(rgbPicker.getBrightnessValue() > 0 ? 0 : 100);
+ cbPicker.setBrightnessValue(cbPicker.getBrightnessValue() > 0 ? 0 : 100);
pickerToInfoPanel();
sendNewValues(true, true);
- onChangeFinished();
+ onChangeFinished(cbPicker);
} else if (v == btnSettings
&& vlCalibrationTool != null) {
vlCalibrationTool.Show();
@@ -450,6 +442,11 @@ public void onBrightnessChanged(SuplaColorBrightnessPicker scbPicker, double bri
sendNewValues();
}
+ @Override
+ public void onPowerButtonClick(SuplaColorBrightnessPicker scbPicker) {
+
+ }
+
private void updateDelayed() {
if (delayTimer2 != null) {
@@ -458,7 +455,7 @@ private void updateDelayed() {
}
if (!isDetailVisible()
- || rgbPicker.getMoving())
+ || cbPicker.isMoving())
return;
if (System.currentTimeMillis() - changeFinishedTime >= MIN_UPDATE_DELAY) {
@@ -498,8 +495,7 @@ public void run() {
}
@Override
- public void onChangeFinished() {
-
+ public void onChangeFinished(SuplaColorBrightnessPicker scbPicker) {
changeFinishedTime = System.currentTimeMillis();
updateDelayed();
}
@@ -517,11 +513,11 @@ public void OnChannelDataChanged() {
@Override
public void onColorTouched(SuplaColorListPicker sclPicker, int color, short percent) {
- if (color != Color.TRANSPARENT && rgbPicker.getColorBrightnessWheelVisible()) {
- rgbPicker.setColor(color);
- rgbPicker.setBrightnessValue(percent);
+ if (color != Color.TRANSPARENT && cbPicker.isColorWheelVisible()) {
+ cbPicker.setColor(color);
+ cbPicker.setBrightnessValue(percent);
- onColorChanged(rgbPicker, color);
+ onColorChanged(cbPicker, color);
}
}
@@ -529,9 +525,9 @@ public void onColorTouched(SuplaColorListPicker sclPicker, int color, short perc
@Override
public void onEdit(SuplaColorListPicker sclPicker, int idx) {
- if (idx > 0 && rgbPicker.getColorBrightnessWheelVisible()) {
- sclPicker.setItemColor(idx, rgbPicker.getColor());
- sclPicker.setItemPercent(idx, (short) rgbPicker.getBrightnessValue());
+ if (idx > 0 && cbPicker.isColorWheelVisible()) {
+ sclPicker.setItemColor(idx, cbPicker.getColor());
+ sclPicker.setItemPercent(idx, (short) cbPicker.getBrightnessValue());
if (getRemoteId() != 0) {
@@ -539,8 +535,8 @@ public void onEdit(SuplaColorListPicker sclPicker, int idx) {
cli.setRemoteId(getRemoteId());
cli.setGroup(isGroup());
cli.setIdx(idx);
- cli.setColor(rgbPicker.getColor());
- cli.setBrightness((short) rgbPicker.getBrightnessValue());
+ cli.setColor(cbPicker.getColor());
+ cli.setBrightness((short) cbPicker.getBrightnessValue());
DBH.updateColorListItemValue(cli);
}
From ed440eeca7470d48829250089d77b823c763fae8 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:42:45 +0200
Subject: [PATCH 09/31] build-tools change to 29.0.3
---
.travis.yml | 2 +-
app/build.gradle | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 2475bcb7f..6ead9d428 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,6 @@ notifications:
android:
components:
- - build-tools-28.0.3
+ - build-tools-29.0.3
- android-28
- extra
diff --git a/app/build.gradle b/app/build.gradle
index 8e64d4554..5a131651a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -39,7 +39,7 @@ android {
lintOptions { checkReleaseBuilds false }
testOptions { unitTests.returnDefaultValues = true }
- buildToolsVersion '28.0.3'
+ buildToolsVersion '29.0.3'
}
repositories {
From 725669bed53da836637a5906ed5c847b4dab6f3f Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:48:06 +0200
Subject: [PATCH 10/31] SuplaColorBrightnessPickerTest class skeleton
---
.../SuplaColorBrightnessPickerTest.java | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
new file mode 100644
index 000000000..6058fdc0e
--- /dev/null
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -0,0 +1,19 @@
+package org.supla.android;
+
+import junit.framework.TestCase;
+
+import org.junit.After;
+import org.junit.Before;
+
+import static org.junit.Assert.*;
+
+public class SuplaColorBrightnessPickerTest extends TestCase {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
From b928145c6f24169bdd330bfd650c2ceea9faf230 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 17:50:23 +0200
Subject: [PATCH 11/31] License header
---
.../java/org/supla/android/EncryptionTest.java | 17 +++++++++++++++++
.../android/SuplaColorBrightnessPickerTest.java | 17 +++++++++++++++++
.../org/supla/android/SuplaCurtainsTest.java | 17 ++++++++---------
.../android/SuplaRangeCalibrationWheelTest.java | 3 +--
4 files changed, 43 insertions(+), 11 deletions(-)
diff --git a/app/src/test/java/org/supla/android/EncryptionTest.java b/app/src/test/java/org/supla/android/EncryptionTest.java
index 8357439b2..ab554b7d0 100644
--- a/app/src/test/java/org/supla/android/EncryptionTest.java
+++ b/app/src/test/java/org/supla/android/EncryptionTest.java
@@ -1,4 +1,21 @@
package org.supla.android;
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
import org.junit.Test;
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
index 6058fdc0e..236832dc9 100644
--- a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -1,4 +1,21 @@
package org.supla.android;
+/*
+ Copyright (C) AC SOFTWARE SP. Z O.O.
+
+ 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 2
+ of the License, or (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
import junit.framework.TestCase;
diff --git a/app/src/test/java/org/supla/android/SuplaCurtainsTest.java b/app/src/test/java/org/supla/android/SuplaCurtainsTest.java
index 5109b8d9a..eac54c7c2 100644
--- a/app/src/test/java/org/supla/android/SuplaCurtainsTest.java
+++ b/app/src/test/java/org/supla/android/SuplaCurtainsTest.java
@@ -1,13 +1,4 @@
package org.supla.android;
-
-import android.content.Context;
-import android.view.MotionEvent;
-
-import junit.framework.TestCase;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
/*
Copyright (C) AC SOFTWARE SP. Z O.O.
@@ -26,6 +17,14 @@ of the License, or (at your option) any later version.
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+import android.content.Context;
+import android.view.MotionEvent;
+
+import junit.framework.TestCase;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
public class SuplaCurtainsTest extends TestCase {
private SuplaCurtains curtains;
diff --git a/app/src/test/java/org/supla/android/SuplaRangeCalibrationWheelTest.java b/app/src/test/java/org/supla/android/SuplaRangeCalibrationWheelTest.java
index ee633b017..492804790 100644
--- a/app/src/test/java/org/supla/android/SuplaRangeCalibrationWheelTest.java
+++ b/app/src/test/java/org/supla/android/SuplaRangeCalibrationWheelTest.java
@@ -1,5 +1,4 @@
package org.supla.android;
-
/*
Copyright (C) AC SOFTWARE SP. Z O.O.
@@ -16,7 +15,7 @@ of the License, or (at your option) any later version.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
+*/
import junit.framework.TestCase;
From 0e4c2f1619b1cb0003b6702d60210e682a53132c Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 20:13:46 +0200
Subject: [PATCH 12/31] Small modifications
---
.../android/SuplaColorBrightnessPicker.java | 28 +++++--------------
1 file changed, 7 insertions(+), 21 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 75067da4d..3822f313b 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -129,25 +129,20 @@ private void init() {
colorPointerCenter = new PointF();
brightnessPointerCenter = new PointF();
- colorWheelPointerAngle = Math.toRadians(-90);
- selectedColor = calculateColor((float) colorWheelPointerAngle, Colors);
-
brightnessArrowPath = new Path();
brightnessArrowPaint = new Paint();
- brightnessWheelPointerAngle = Math.toRadians(-90);
- selectedBrightness = 0;
-
colorPointerMoving = false;
brightnessWheelPointerMoving = false;
colorfulBrightnessWheel = true;
circleInsteadArrow = false;
- powerButtonColorOn = Color.parseColor("#f7f0dc");
- powerButtonColorOff = Color.parseColor("#404040");
+ powerButtonColorOn = 0xfff7f0dc;
+ powerButtonColorOff = 0xff404040;
powerButtonEnabled = true;
- setBWcolor();
+ setBrightnessValue(0);
+ setColor(0xff00ff00);
}
private int ave(int s, int d, float p) {
@@ -718,19 +713,10 @@ public int getColor() {
}
public void setColor(int color) {
-
- if ((color & 0xFFFFFF) == 0xFFFFFF)
- color = 0xFFFFFFFF;
-
if (selectedColor != color) {
selectedColor = color;
colorWheelPointerAngle = colorToAngle(color);
-
- if (color == Color.WHITE)
- selectedColor = color;
- else
- selectedColor = calculateColor((float) colorWheelPointerAngle, Colors);
-
+ setBWcolor();
invalidate();
}
}
@@ -796,7 +782,7 @@ public boolean isMoving() {
}
public ArrayList getColorMarkers() {
- return new ArrayList<>(colorMarkers);
+ return colorMarkers == null ? null : new ArrayList<>(colorMarkers);
}
public void setColorMarkers(ArrayList colorMarkers) {
@@ -807,7 +793,7 @@ public void setColorMarkers(ArrayList colorMarkers) {
}
public ArrayList getBrightnessMarkers() {
- return new ArrayList<>(brightnessMarkers);
+ return brightnessMarkers == null ? null : new ArrayList<>(brightnessMarkers);
}
public void setBrightnessMarkers(ArrayList brightnessMarkers) {
From 9338809d513aada497b4687b4e9b907d386dde08 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 20:14:08 +0200
Subject: [PATCH 13/31] SuplaColorBrightnessPicker tests
---
.../SuplaColorBrightnessPickerTest.java | 140 ++++++++++++++++++
1 file changed, 140 insertions(+)
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
index 236832dc9..9caafd164 100644
--- a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -17,20 +17,160 @@ of the License, or (at your option) any later version.
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+import android.graphics.Color;
+
import junit.framework.TestCase;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
+import java.util.ArrayList;
+
import static org.junit.Assert.*;
public class SuplaColorBrightnessPickerTest extends TestCase {
+ private SuplaColorBrightnessPicker picker;
+
@Before
public void setUp() throws Exception {
+ picker = new SuplaColorBrightnessPicker(null);
}
@After
public void tearDown() throws Exception {
+ picker = null;
+ }
+
+ public void testColorWheelVisibleSetterAndGetter() {
+ Assert.assertTrue(picker.isColorWheelVisible());
+ picker.setColorWheelVisible(false);
+ Assert.assertFalse(picker.isColorWheelVisible());
+ picker.setColorWheelVisible(true);
+ Assert.assertTrue(picker.isColorWheelVisible());
+ }
+
+ public void testCircleInsteadArrowSetterAndGetter() {
+ Assert.assertFalse(picker.isCircleInsteadArrow());
+ picker.setCircleInsteadArrow(true);
+ Assert.assertTrue(picker.isCircleInsteadArrow());
+ picker.setCircleInsteadArrow(false);
+ Assert.assertFalse(picker.isCircleInsteadArrow());
+ }
+
+ public void testColorfulBrightnessWheelSetterAndGetter() {
+ Assert.assertTrue(picker.isColorfulBrightnessWheel());
+ picker.setColorfulBrightnessWheel(false);
+ Assert.assertFalse(picker.isColorfulBrightnessWheel());
+ picker.setColorfulBrightnessWheel(true);
+ Assert.assertTrue(picker.isColorfulBrightnessWheel());
+ }
+
+ public void testSliderVisibleSetterAndGetter() {
+ Assert.assertFalse(picker.isSliderVisible());
+ picker.setSliderVisible(true);
+ Assert.assertTrue(picker.isSliderVisible());
+ picker.setSliderVisible(false);
+ Assert.assertFalse(picker.isSliderVisible());
+ }
+
+ public void testPowerButtonVisibleSetterAndGetter() {
+ Assert.assertFalse(picker.isPowerButtonVisible());
+ picker.setPowerButtonVisible(true);
+ Assert.assertTrue(picker.isPowerButtonVisible());
+ picker.setPowerButtonVisible(false);
+ Assert.assertFalse(picker.isPowerButtonVisible());
+ }
+
+ public void testPowerButtonEnabledSetterAndGetter() {
+ Assert.assertTrue(picker.isPowerButtonEnabled());
+ picker.setPowerButtonEnabled(false);
+ Assert.assertFalse(picker.isPowerButtonEnabled());
+ picker.setPowerButtonEnabled(true);
+ Assert.assertTrue(picker.isPowerButtonEnabled());
+ }
+
+ public void testPowerButtonOnSetterAndGetter() {
+ Assert.assertFalse(picker.isPowerButtonOn());
+ picker.setPowerButtonOn(true);
+ Assert.assertTrue(picker.isPowerButtonOn());
+ picker.setPowerButtonOn(false);
+ Assert.assertFalse(picker.isPowerButtonOn());
+ }
+
+ public void testPowerButtonColorOnSetterAndGetter() {
+ Assert.assertEquals(0xfff7f0dc, picker.getPowerButtonColorOn());
+ picker.setPowerButtonColorOn(Color.BLUE);
+ Assert.assertEquals(Color.BLUE, picker.getPowerButtonColorOn());
+ }
+
+ public void testPowerButtonColorOffSetterAndGetter() {
+ Assert.assertEquals(0xff404040, picker.getPowerButtonColorOff());
+ picker.setPowerButtonColorOff(Color.BLUE);
+ Assert.assertEquals(Color.BLUE, picker.getPowerButtonColorOff());
+ }
+
+ public void testColorSetterAndGetter() {
+ Assert.assertEquals(0xff00ff00, picker.getColor());
+ picker.setColor(Color.BLUE);
+ Assert.assertEquals(Color.BLUE, picker.getColor());
+ }
+
+ public void testBrightnessSetterAndGetter() {
+ Assert.assertEquals(0f, picker.getBrightnessValue(), 0);
+ picker.setBrightnessValue(55.54);
+ Assert.assertEquals(55.54, picker.getBrightnessValue(), 0.001);
+ picker.setBrightnessValue(-1);
+ Assert.assertEquals(0, picker.getBrightnessValue(), 0);
+ picker.setBrightnessValue(80.88);
+ Assert.assertEquals(80.88, picker.getBrightnessValue(), 0.001);
+ picker.setBrightnessValue(110);
+ Assert.assertEquals(100, picker.getBrightnessValue(), 0);
+ }
+
+ public void testMovingGetter() {
+ Assert.assertFalse(picker.isMoving());
+ }
+
+ public void testBrightnessMarkersSetterAndGetter() {
+ Assert.assertNull(picker.getBrightnessMarkers());
+
+ ArrayList brigtness = new ArrayList<>();
+ brigtness.add(0.0);
+ brigtness.add(10.0);
+ brigtness.add(50.0);
+ brigtness.add(90.0);
+ brigtness.add(100.0);
+ picker.setBrightnessMarkers(brigtness);
+
+ Assert.assertNotNull(picker.getBrightnessMarkers());
+ Assert.assertEquals(5, picker.getBrightnessMarkers().size(), 0);
+ picker.setBrightnessMarkers(null);
+ Assert.assertNull(picker.getBrightnessMarkers());
+ }
+
+ public void testColorMarkersSetterAndGetter() {
+ Assert.assertNull(picker.getColorMarkers());
+
+ ArrayList colors = new ArrayList<>();
+ colors.add(new Double(Color.RED));
+ colors.add(new Double(Color.GREEN));
+ colors.add(new Double(Color.BLUE));
+ picker.setColorMarkers(colors);
+
+ Assert.assertNotNull(picker.getColorMarkers());
+ Assert.assertEquals(3, picker.getColorMarkers().size(), 0);
+ picker.setColorMarkers(null);
+ Assert.assertNull(picker.getColorMarkers());
+
+
+ Double d = new Double(Color.WHITE);
+ Assert.assertEquals(Color.WHITE, d, 0);
+ Assert.assertEquals(Color.WHITE, d.intValue(), 0);
+
+ d = new Double(Color.BLACK);
+ Assert.assertEquals(Color.BLACK, d, 0);
+ Assert.assertEquals(Color.BLACK, d.intValue(), 0);
}
}
\ No newline at end of file
From 0c55c81c90b74257b0cf85e3011b2f4cb31f086b Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 20:31:19 +0200
Subject: [PATCH 14/31] powerButtonVisible change the default value to true
---
.../java/org/supla/android/SuplaColorBrightnessPicker.java | 1 +
.../org/supla/android/SuplaColorBrightnessPickerTest.java | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 3822f313b..169027bc8 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -139,6 +139,7 @@ private void init() {
powerButtonColorOn = 0xfff7f0dc;
powerButtonColorOff = 0xff404040;
+ powerButtonVisible = true;
powerButtonEnabled = true;
setBrightnessValue(0);
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
index 9caafd164..01263e90f 100644
--- a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -76,11 +76,11 @@ public void testSliderVisibleSetterAndGetter() {
}
public void testPowerButtonVisibleSetterAndGetter() {
- Assert.assertFalse(picker.isPowerButtonVisible());
- picker.setPowerButtonVisible(true);
Assert.assertTrue(picker.isPowerButtonVisible());
picker.setPowerButtonVisible(false);
Assert.assertFalse(picker.isPowerButtonVisible());
+ picker.setPowerButtonVisible(true);
+ Assert.assertTrue(picker.isPowerButtonVisible());
}
public void testPowerButtonEnabledSetterAndGetter() {
From ff8c9da7b7dbd30675e992216a906802b9b836c6 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 20:32:34 +0200
Subject: [PATCH 15/31] circleInsteadArrow change the default value to true
---
.../java/org/supla/android/SuplaColorBrightnessPicker.java | 2 +-
.../org/supla/android/SuplaColorBrightnessPickerTest.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 169027bc8..0b9171709 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -135,7 +135,7 @@ private void init() {
colorPointerMoving = false;
brightnessWheelPointerMoving = false;
colorfulBrightnessWheel = true;
- circleInsteadArrow = false;
+ circleInsteadArrow = true;
powerButtonColorOn = 0xfff7f0dc;
powerButtonColorOff = 0xff404040;
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
index 01263e90f..bbce087ff 100644
--- a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -52,11 +52,11 @@ public void testColorWheelVisibleSetterAndGetter() {
}
public void testCircleInsteadArrowSetterAndGetter() {
- Assert.assertFalse(picker.isCircleInsteadArrow());
- picker.setCircleInsteadArrow(true);
Assert.assertTrue(picker.isCircleInsteadArrow());
picker.setCircleInsteadArrow(false);
Assert.assertFalse(picker.isCircleInsteadArrow());
+ picker.setCircleInsteadArrow(true);
+ Assert.assertTrue(picker.isCircleInsteadArrow());
}
public void testColorfulBrightnessWheelSetterAndGetter() {
From 07e61d8a6989c5f2e7f6016c1e55788eb7c82fed Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Sun, 7 Jun 2020 22:38:03 +0200
Subject: [PATCH 16/31] Trim when white color selected
---
.../java/org/supla/android/SuplaColorBrightnessPicker.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 0b9171709..9e2c77e14 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -356,7 +356,8 @@ private void drawWheel(Canvas canvas) {
if (circleInsteadArrow) {
float angle = (float) (brightnessWheelPointerAngle - m90d);
- if (!colorfulBrightnessWheel || !colorWheelVisible) {
+ if (!colorfulBrightnessWheel || !colorWheelVisible
+ || (colorWheelVisible && (selectedColor & 0xffffff) == 0xffffff )) {
angle = trimBrightnessColorAngle(angle);
}
drawCirclePointer(canvas, brightnessWheelPointerAngle,
From cd6bc4381d11f8bfa38fa2cac14603085ce6bdc2 Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Mon, 8 Jun 2020 19:44:08 +0200
Subject: [PATCH 17/31] powerButtonColorOn change the default value to white
---
.../main/java/org/supla/android/SuplaColorBrightnessPicker.java | 2 +-
.../java/org/supla/android/SuplaColorBrightnessPickerTest.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
index 9e2c77e14..065022b2c 100644
--- a/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorBrightnessPicker.java
@@ -136,7 +136,7 @@ private void init() {
brightnessWheelPointerMoving = false;
colorfulBrightnessWheel = true;
circleInsteadArrow = true;
- powerButtonColorOn = 0xfff7f0dc;
+ powerButtonColorOn = 0xffffffff;
powerButtonColorOff = 0xff404040;
powerButtonVisible = true;
diff --git a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
index bbce087ff..0719603ad 100644
--- a/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
+++ b/app/src/test/java/org/supla/android/SuplaColorBrightnessPickerTest.java
@@ -100,7 +100,7 @@ public void testPowerButtonOnSetterAndGetter() {
}
public void testPowerButtonColorOnSetterAndGetter() {
- Assert.assertEquals(0xfff7f0dc, picker.getPowerButtonColorOn());
+ Assert.assertEquals(0xffffffff, picker.getPowerButtonColorOn());
picker.setPowerButtonColorOn(Color.BLUE);
Assert.assertEquals(Color.BLUE, picker.getPowerButtonColorOn());
}
From da2ab3d76814ba107a8165f774a873ff2b39d0aa Mon Sep 17 00:00:00 2001
From: Przemek Zygmunt
Date: Mon, 8 Jun 2020 19:57:30 +0200
Subject: [PATCH 18/31] New RGBW controller layout
---
...lDetailRGB.java => ChannelDetailRGBW.java} | 184 ++++++++++------
.../java/org/supla/android/Preferences.java | 15 ++
.../supla/android/SuplaColorListPicker.java | 14 +-
.../org/supla/android/VLCalibrationTool.java | 4 +-
.../android/listview/ChannelListView.java | 6 +-
app/src/main/res/drawable/rgbwinfo.png | Bin 0 -> 15184 bytes
app/src/main/res/drawable/rgbwpoweroff.png | Bin 0 -> 18882 bytes
app/src/main/res/drawable/rgbwpoweron.png | Bin 0 -> 14089 bytes
app/src/main/res/drawable/rgbwsettings.png | Bin 0 -> 22190 bytes
.../res/drawable/rounded_rgb_left_btn.xml | 20 --
.../res/drawable/rounded_rgb_left_sel_btn.xml | 20 --
.../res/drawable/rounded_rgb_right_btn.xml | 20 --
.../drawable/rounded_rgb_right_sel_btn.xml | 20 --
.../res/drawable/rounded_rgbw_sel_btn.xml | 16 ++
.../drawable/rounded_rgbw_tab_background.xml | 16 ++
app/src/main/res/layout/detail_rgb.xml | 202 ------------------
app/src/main/res/layout/detail_rgbw.xml | 165 ++++++++++++++
app/src/main/res/values-pl/strings.xml | 2 +
app/src/main/res/values-sw600dp/dimens.xml | 4 +-
app/src/main/res/values/colors.xml | 2 +-
app/src/main/res/values/dimens.xml | 4 +-
app/src/main/res/values/strings.xml | 2 +
22 files changed, 351 insertions(+), 365 deletions(-)
rename app/src/main/java/org/supla/android/{ChannelDetailRGB.java => ChannelDetailRGBW.java} (74%)
create mode 100644 app/src/main/res/drawable/rgbwinfo.png
create mode 100644 app/src/main/res/drawable/rgbwpoweroff.png
create mode 100644 app/src/main/res/drawable/rgbwpoweron.png
create mode 100644 app/src/main/res/drawable/rgbwsettings.png
delete mode 100644 app/src/main/res/drawable/rounded_rgb_left_btn.xml
delete mode 100644 app/src/main/res/drawable/rounded_rgb_left_sel_btn.xml
delete mode 100644 app/src/main/res/drawable/rounded_rgb_right_btn.xml
delete mode 100644 app/src/main/res/drawable/rounded_rgb_right_sel_btn.xml
create mode 100644 app/src/main/res/drawable/rounded_rgbw_sel_btn.xml
create mode 100644 app/src/main/res/drawable/rounded_rgbw_tab_background.xml
delete mode 100644 app/src/main/res/layout/detail_rgb.xml
create mode 100644 app/src/main/res/layout/detail_rgbw.xml
diff --git a/app/src/main/java/org/supla/android/ChannelDetailRGB.java b/app/src/main/java/org/supla/android/ChannelDetailRGBW.java
similarity index 74%
rename from app/src/main/java/org/supla/android/ChannelDetailRGB.java
rename to app/src/main/java/org/supla/android/ChannelDetailRGBW.java
index 314952446..39fc03937 100644
--- a/app/src/main/java/org/supla/android/ChannelDetailRGB.java
+++ b/app/src/main/java/org/supla/android/ChannelDetailRGBW.java
@@ -30,9 +30,7 @@ of the License, or (at your option) any later version.
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
-import android.widget.TextView;
import org.supla.android.db.Channel;
import org.supla.android.db.ChannelBase;
@@ -47,7 +45,7 @@ of the License, or (at your option) any later version.
import java.util.Timer;
import java.util.TimerTask;
-public class ChannelDetailRGB extends DetailLayout implements View.OnClickListener,
+public class ChannelDetailRGBW extends DetailLayout implements View.OnClickListener,
SuplaColorBrightnessPicker.OnColorBrightnessChangeListener,
SuplaColorListPicker.OnColorListTouchListener {
@@ -57,13 +55,15 @@ public class ChannelDetailRGB extends DetailLayout implements View.OnClickListen
private SuplaColorListPicker clPicker;
private Button tabRGB;
private Button tabDimmer;
+ private Button tabWheel;
+ private Button tabSlider;
private ViewGroup tabs;
- private TextView tvTitle;
+ private ViewGroup pickerTypeTabs;
+ private ViewGroup llExtraButtons;
private Button btnSettings;
+ private Button btnInfo;
private RelativeLayout rlMain;
private VLCalibrationTool vlCalibrationTool = null;
- private TextView tvStateCaption;
- private ImageView stateImage;
private long remoteUpdateTime;
private long changeFinishedTime;
private Timer delayTimer1;
@@ -72,20 +72,21 @@ public class ChannelDetailRGB extends DetailLayout implements View.OnClickListen
private int lastColor;
private int lastColorBrightness;
private int lastBrightness;
+ private Button btnPowerOnOff;
- public ChannelDetailRGB(Context context, ChannelListView cLV) {
+ public ChannelDetailRGBW(Context context, ChannelListView cLV) {
super(context, cLV);
}
- public ChannelDetailRGB(Context context, AttributeSet attrs) {
+ public ChannelDetailRGBW(Context context, AttributeSet attrs) {
super(context, attrs);
}
- public ChannelDetailRGB(Context context, AttributeSet attrs, int defStyleAttr) {
+ public ChannelDetailRGBW(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
- public ChannelDetailRGB(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public ChannelDetailRGBW(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@@ -93,11 +94,12 @@ protected void init() {
super.init();
- tabs = findViewById(R.id.rlTabs);
+ tabs = findViewById(R.id.llTabs);
+ pickerTypeTabs = findViewById(R.id.llPickerTypeTabs);
Resources r = getResources();
- status = findViewById(R.id.rgbstatus);
+ status = findViewById(R.id.rgbwstatus);
status.setOnlineColor(getResources().getColor(R.color.channel_dot_on));
status.setOfflineColor(getResources().getColor(R.color.channel_dot_off));
@@ -115,29 +117,33 @@ protected void init() {
tabRGB = findViewById(R.id.rgbTabBtn_RGB);
tabDimmer = findViewById(R.id.rgbTabBtn_Dimmer);
+ tabWheel = findViewById(R.id.rgbTabBtn_Wheel);
+ tabSlider = findViewById(R.id.rgbTabBtn_Slider);
tabRGB.setOnClickListener(this);
tabDimmer.setOnClickListener(this);
+ tabWheel.setOnClickListener(this);
+ tabSlider.setOnClickListener(this);
- btnSettings = findViewById(R.id.rgbBtnSettings);
+ llExtraButtons = findViewById(R.id.llExtraButtons);
+ llExtraButtons.setVisibility(GONE);
+
+ btnInfo = findViewById(R.id.rgbwBtnInfo);
+ btnSettings = findViewById(R.id.rgbwBtnSettings);
+ btnInfo.setOnClickListener(this);
btnSettings.setOnClickListener(this);
- btnSettings.setVisibility(GONE);
- rlMain = findViewById(R.id.rlRgbMain);
+ rlMain = findViewById(R.id.rlRgbwMain);
rlMain.setVisibility(VISIBLE);
+ btnPowerOnOff = findViewById(R.id.rgbwBtnPowerOnOff);
+ btnPowerOnOff.setOnClickListener(this);
+
Typeface type = SuplaApp.getApp().getTypefaceOpenSansBold();
tabRGB.setTypeface(type);
tabDimmer.setTypeface(type);
-
- tvStateCaption = findViewById(R.id.rgbDetailStateCaption);
- tvStateCaption.setTypeface(type);
-
- tvTitle = findViewById(R.id.rgbDetailTitle);
- tvTitle.setTypeface(SuplaApp.getApp().getTypefaceQuicksandRegular());
-
- stateImage = findViewById(R.id.rgbDetailStateImage);
- stateImage.setOnClickListener(this);
+ tabWheel.setTypeface(type);
+ tabSlider.setTypeface(type);
remoteUpdateTime = 0;
changeFinishedTime = 0;
@@ -148,7 +154,11 @@ protected void init() {
private void showRGB() {
cbPicker.setColorWheelVisible(true);
+ cbPicker.setSliderVisible(false);
clPicker.setVisibility(View.VISIBLE);
+ pickerTypeTabs.setVisibility(GONE);
+ llExtraButtons.setVisibility(GONE);
+ btnPowerOnOff.setVisibility(GONE);
channelDataToViews();
}
@@ -157,7 +167,31 @@ private void showDimmer() {
cbPicker.setColorWheelVisible(false);
clPicker.setVisibility(View.GONE);
+ pickerTypeTabs.setVisibility(VISIBLE);
+
+ boolean varilight = false;
+
+ if (getChannelBase() instanceof Channel) {
+ Channel c = (Channel) getChannelBase();
+ if (c.getManufacturerID() == SuplaConst.SUPLA_MFR_DOYLETRATT
+ && c.getProductID() == 1) {
+ varilight = true;
+ }
+ }
+ if (varilight) {
+ vlCalibrationTool = new VLCalibrationTool(this);
+ llExtraButtons.setVisibility(VISIBLE);
+ }
+
+ Preferences prefs = new Preferences(getContext());
+
+ Boolean typeSlider = prefs.isBrightnessPickerTypeSlider();
+ if (typeSlider == null) {
+ typeSlider = varilight;
+ }
+
+ onClick(typeSlider ? tabSlider : tabWheel);
channelDataToViews();
}
@@ -184,27 +218,19 @@ public void onDetailShow() {
public void setData(ChannelBase channel) {
super.setData(channel);
- btnSettings.setVisibility(GONE);
+ llExtraButtons.setVisibility(GONE);
+ pickerTypeTabs.setVisibility(GONE);
+
+ if (vlCalibrationTool != null) {
+ vlCalibrationTool.Hide();
+ vlCalibrationTool = null;
+ }
switch (channel.getFunc()) {
case SuplaConst.SUPLA_CHANNELFNC_DIMMER:
showDimmer();
tabs.setVisibility(View.GONE);
-
- if (vlCalibrationTool != null) {
- vlCalibrationTool.Hide();
- vlCalibrationTool = null;
- }
-
- if (channel instanceof Channel) {
- Channel c = (Channel) channel;
- if (c.getManufacturerID() == SuplaConst.SUPLA_MFR_DOYLETRATT
- && c.getProductID() == 1) {
- vlCalibrationTool = new VLCalibrationTool(this);
- btnSettings.setVisibility(VISIBLE);
- }
- }
break;
case SuplaConst.SUPLA_CHANNELFNC_RGBLIGHTING:
@@ -233,10 +259,6 @@ private void channelDataToViews() {
if (isGroup()) {
ChannelGroup cgroup = (ChannelGroup) getChannelFromDatabase();
- tvTitle.setText(cgroup.getNotEmptyCaption(getContext()));
-
- stateImage.setVisibility(View.GONE);
- tvStateCaption.setVisibility(View.GONE);
status.setVisibility(View.VISIBLE);
status.setPercent(cgroup.getOnLinePercent());
@@ -275,12 +297,8 @@ private void channelDataToViews() {
} else {
Channel channel = (Channel) getChannelFromDatabase();
- tvTitle.setText(channel.getNotEmptyCaption(getContext()));
status.setVisibility(View.GONE);
- stateImage.setVisibility(View.VISIBLE);
- tvStateCaption.setVisibility(View.VISIBLE);
-
if (cbPicker.isColorWheelVisible()
&& (int) cbPicker.getBrightnessValue() != (int) channel.getColorBrightness()) {
cbPicker.setBrightnessValue(channel.getColorBrightness());
@@ -309,18 +327,18 @@ private void channelDataToViews() {
}
- pickerToInfoPanel();
+ pickerToUI();
}
@Override
public View inflateContentView() {
- return inflateLayout(R.layout.detail_rgb);
+ return inflateLayout(R.layout.detail_rgbw);
}
private void setBtnBackground(Button btn, int id) {
- Drawable d = getResources().getDrawable(id);
+ Drawable d = id == 0 ? null : getResources().getDrawable(id);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
btn.setBackground(d);
@@ -329,13 +347,17 @@ private void setBtnBackground(Button btn, int id) {
}
}
+ private void setPowerBtnOn(boolean on) {
+ cbPicker.setPowerButtonOn(on);
+ setBtnBackground(btnPowerOnOff, on ? R.drawable.rgbwpoweron : R.drawable.rgbwpoweroff);
+ }
+
@SuppressLint("SetTextI18n")
- private void pickerToInfoPanel() {
+ private void pickerToUI() {
lastColor = cbPicker.getColor();
-
int brightness = (int) cbPicker.getBrightnessValue();
- stateImage.setImageResource(brightness > 0 ? R.drawable.poweron : R.drawable.poweroff);
+ setPowerBtnOn(brightness > 0);
if (cbPicker.isColorWheelVisible())
lastColorBrightness = brightness;
@@ -397,54 +419,78 @@ private void sendNewValues() {
@Override
public void onClick(View v) {
-
if (v == tabRGB) {
showRGB();
- setBtnBackground(tabRGB, R.drawable.rounded_rgb_left_sel_btn);
- setBtnBackground(tabDimmer, R.drawable.rounded_rgb_right_btn);
+ setBtnBackground(tabRGB, R.drawable.rounded_rgbw_sel_btn);
+ setBtnBackground(tabDimmer, 0);
- tabRGB.setTextColor(getResources().getColor(R.color.detail_rgb_gb));
+ tabRGB.setTextColor(Color.WHITE);
tabDimmer.setTextColor(Color.BLACK);
} else if (v == tabDimmer) {
showDimmer();
- setBtnBackground(tabRGB, R.drawable.rounded_rgb_left_btn);
- setBtnBackground(tabDimmer, R.drawable.rounded_rgb_right_sel_btn);
+ setBtnBackground(tabDimmer, R.drawable.rounded_rgbw_sel_btn);
+ setBtnBackground(tabRGB, 0);
tabRGB.setTextColor(Color.BLACK);
- tabDimmer.setTextColor(getResources().getColor(R.color.detail_rgb_gb));
- } else if (v == stateImage) {
- cbPicker.setBrightnessValue(cbPicker.getBrightnessValue() > 0 ? 0 : 100);
- pickerToInfoPanel();
- sendNewValues(true, true);
- onChangeFinished(cbPicker);
+ tabDimmer.setTextColor(Color.WHITE);
+ } else if (v == tabWheel) {
+ setBtnBackground(tabWheel, R.drawable.rounded_rgbw_sel_btn);
+ setBtnBackground(tabSlider, 0);
+
+ tabWheel.setTextColor(Color.WHITE);
+ tabSlider.setTextColor(Color.BLACK);
+ btnPowerOnOff.setVisibility(GONE);
+
+ } else if (v == tabSlider) {
+ setBtnBackground(tabWheel, 0);
+ setBtnBackground(tabSlider, R.drawable.rounded_rgbw_sel_btn);
+
+ tabWheel.setTextColor(Color.BLACK);
+ tabSlider.setTextColor(Color.WHITE);
+ btnPowerOnOff.setVisibility(VISIBLE);
} else if (v == btnSettings
- && vlCalibrationTool != null) {
+ && vlCalibrationTool != null) {
vlCalibrationTool.Show();
+ } else if (v == btnPowerOnOff) {
+ cbPicker.setPowerButtonOn(!cbPicker.isPowerButtonOn());
+ onPowerButtonClick(cbPicker);
+ } else if (v == btnInfo) {
+
}
if (v == tabDimmer || v == tabRGB) {
channelDataToViews();
}
+ if (v == tabWheel || v == tabSlider) {
+ cbPicker.setSliderVisible(v == tabSlider);
+
+ Preferences prefs = new Preferences(getContext());
+ prefs.setBrightnessPickerTypeSlider(cbPicker.isSliderVisible());
+ }
+
}
@Override
public void onColorChanged(SuplaColorBrightnessPicker scbPicker, int color) {
- pickerToInfoPanel();
+ pickerToUI();
sendNewValues();
}
@Override
public void onBrightnessChanged(SuplaColorBrightnessPicker scbPicker, double brightness) {
- pickerToInfoPanel();
+ pickerToUI();
sendNewValues();
}
@Override
public void onPowerButtonClick(SuplaColorBrightnessPicker scbPicker) {
-
+ scbPicker.setBrightnessValue(scbPicker.isPowerButtonOn() ? 100 : 0);
+ pickerToUI();
+ sendNewValues(true, true);
+ onChangeFinished(scbPicker);
}
private void updateDelayed() {
diff --git a/app/src/main/java/org/supla/android/Preferences.java b/app/src/main/java/org/supla/android/Preferences.java
index 6c5b2932f..7de52127d 100644
--- a/app/src/main/java/org/supla/android/Preferences.java
+++ b/app/src/main/java/org/supla/android/Preferences.java
@@ -47,6 +47,8 @@ public class Preferences {
private static final String pref_wizard_selected_wifi = "pref_wizard_selected_wifi";
private static final String pref_hp_turbo_time = "pref_hp_turbo_time";
private static final String pref_hp_eco_reduction = "pref_hp_eco_reduction";
+ private static final String pref_brightness_picker_type_slider
+ = "pref_brightness_picker_type_slider";
private SharedPreferences _prefs;
private Context _context;
@@ -249,4 +251,17 @@ public void wizardSetSelectedWifi(String SSID) {
editor.putString(pref_wizard_selected_wifi, SSID);
editor.apply();
}
+
+ public void setBrightnessPickerTypeSlider(boolean slider) {
+ SharedPreferences.Editor editor = _prefs.edit();
+ editor.putBoolean(pref_brightness_picker_type_slider, slider);
+ editor.apply();
+ }
+
+ public Boolean isBrightnessPickerTypeSlider() {
+ if (_prefs.contains(pref_brightness_picker_type_slider)) {
+ return _prefs.getBoolean(pref_brightness_picker_type_slider, false);
+ }
+ return null;
+ }
}
diff --git a/app/src/main/java/org/supla/android/SuplaColorListPicker.java b/app/src/main/java/org/supla/android/SuplaColorListPicker.java
index 12ae69c34..f9c0dd313 100644
--- a/app/src/main/java/org/supla/android/SuplaColorListPicker.java
+++ b/app/src/main/java/org/supla/android/SuplaColorListPicker.java
@@ -38,7 +38,8 @@ public class SuplaColorListPicker extends View {
private ArrayList Items = null;
private float Space = 0;
private float BorderWidth = 0;
- private int BorderColor = Color.BLACK;
+ private int BorderColor = Color.WHITE;
+ private int BrightnessLevelColor = Color.BLACK;
private int BorderColorSelected = Color.YELLOW;
private ListItem TouchedItem = null;
private OnColorListTouchListener mOnTouchListener;
@@ -203,6 +204,15 @@ public void setBorderColorSelected(int borderColorSelected) {
invalidate();
}
+ public int getBrightnessLevelColor() {
+ return BrightnessLevelColor;
+ }
+
+ public void setBrightnessLevelColor(int brightnessLevelColor) {
+ BrightnessLevelColor = brightnessLevelColor;
+ invalidate();
+ }
+
@Override
protected void onDraw(Canvas canvas) {
@@ -239,7 +249,7 @@ protected void onDraw(Canvas canvas) {
if (i.getPercent() > 0) {
- p.setColor(BorderColor);
+ p.setColor(BrightnessLevelColor);
double rl_margin = width * 0.05;
double b_margin = width * 0.1;
diff --git a/app/src/main/java/org/supla/android/VLCalibrationTool.java b/app/src/main/java/org/supla/android/VLCalibrationTool.java
index 287b4a720..329aab53a 100644
--- a/app/src/main/java/org/supla/android/VLCalibrationTool.java
+++ b/app/src/main/java/org/supla/android/VLCalibrationTool.java
@@ -32,7 +32,7 @@ public class VLCalibrationTool implements View.OnClickListener, SuplaRangeCalibr
private final static int UI_REFRESH_LOCK_TIME = 2000;
private final static int MIN_SEND_DELAY_TIME = 500;
private final static int DISPLAY_DELAY_TIME = 1000;
- private ChannelDetailRGB detailRGB;
+ private ChannelDetailRGBW detailRGB;
private Button btnOK;
private Button btnRestore;
private Button btnCancel;
@@ -58,7 +58,7 @@ public class VLCalibrationTool implements View.OnClickListener, SuplaRangeCalibr
private long lastCalCfgTime = 0;
private Handler _sc_msg_handler = null;
- public VLCalibrationTool(ChannelDetailRGB detailRGB) {
+ public VLCalibrationTool(ChannelDetailRGBW detailRGB) {
this.detailRGB = detailRGB;
mainView = (RelativeLayout) detailRGB.inflateLayout(R.layout.vl_calibration);
diff --git a/app/src/main/java/org/supla/android/listview/ChannelListView.java b/app/src/main/java/org/supla/android/listview/ChannelListView.java
index 13034afc7..558ee48c7 100644
--- a/app/src/main/java/org/supla/android/listview/ChannelListView.java
+++ b/app/src/main/java/org/supla/android/listview/ChannelListView.java
@@ -36,7 +36,7 @@ of the License, or (at your option) any later version.
import org.supla.android.ChannelDetailEM;
import org.supla.android.ChannelDetailIC;
-import org.supla.android.ChannelDetailRGB;
+import org.supla.android.ChannelDetailRGBW;
import org.supla.android.ChannelDetailRS;
import org.supla.android.ChannelDetailTempHumidity;
import org.supla.android.ChannelDetailTemperature;
@@ -112,7 +112,7 @@ private DetailLayout getDetailLayout(ChannelBase cbase) {
case SuplaConst.SUPLA_CHANNELFNC_DIMMERANDRGBLIGHTING:
case SuplaConst.SUPLA_CHANNELFNC_RGBLIGHTING:
- if (!(mDetailLayout instanceof ChannelDetailRGB))
+ if (!(mDetailLayout instanceof ChannelDetailRGBW))
mDetailLayout = null;
break;
@@ -176,7 +176,7 @@ private DetailLayout getDetailLayout(ChannelBase cbase) {
case SuplaConst.SUPLA_CHANNELFNC_DIMMER:
case SuplaConst.SUPLA_CHANNELFNC_DIMMERANDRGBLIGHTING:
case SuplaConst.SUPLA_CHANNELFNC_RGBLIGHTING:
- mDetailLayout = new ChannelDetailRGB(getContext(), this);
+ mDetailLayout = new ChannelDetailRGBW(getContext(), this);
break;
case SuplaConst.SUPLA_CHANNELFNC_CONTROLLINGTHEROLLERSHUTTER:
mDetailLayout = new ChannelDetailRS(getContext(), this);
diff --git a/app/src/main/res/drawable/rgbwinfo.png b/app/src/main/res/drawable/rgbwinfo.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d59c98f1bd9555c92205aaafe76216b01263a55
GIT binary patch
literal 15184
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
LQKDANIOP8UH1oW7
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable/rgbwpoweron.png b/app/src/main/res/drawable/rgbwpoweron.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c09aae766cf67f217991cd0aee8a6b9bb376fb9
GIT binary patch
literal 14089
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