diff options
author | Thomas <tschneider.ac@gmail.com> | 2023-03-24 15:13:24 +0100 |
---|---|---|
committer | Thomas <tschneider.ac@gmail.com> | 2023-03-24 15:13:24 +0100 |
commit | 8ffd5b3a196c53b4b8b9424426420023afd57a06 (patch) | |
tree | ef7bd8668f183276a116a46214211f7307abe1e6 /colorPicker | |
parent | 4a8d20ed6b82bb086675008e5192c0bdd96f2994 (diff) |
some changes
Diffstat (limited to 'colorPicker')
52 files changed, 3906 insertions, 0 deletions
diff --git a/colorPicker/.gitignore b/colorPicker/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/colorPicker/.gitignore @@ -0,0 +1 @@ +/build diff --git a/colorPicker/build.gradle b/colorPicker/build.gradle new file mode 100644 index 000000000..0f3f1c23a --- /dev/null +++ b/colorPicker/build.gradle @@ -0,0 +1,39 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 33 + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 33 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + + +// Add a new configuration to hold your dependencies +configurations { + libConfig +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + //noinspection GradleCompatible + implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'androidx.preference:preference:1.2.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + +} + diff --git a/colorPicker/gradle.properties b/colorPicker/gradle.properties new file mode 100644 index 000000000..f81fb845d --- /dev/null +++ b/colorPicker/gradle.properties @@ -0,0 +1,19 @@ +VERSION_NAME=1.1.0 +VERSION_CODE=110 +GROUP=com.jaredrummler +ARTIFACT_ID=colorpicker +POM_NAME=colorpicker +POM_ARTIFACT_ID=colorpicker +POM_PACKAGING=aar +POM_DESCRIPTION=A simply good looking color picker component for Android +POM_URL=https://github.com/jaredrummler/ColorPicker +POM_SCM_URL=https://github.com/jaredrummler/ColorPicker +POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git +POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git +POM_LICENCE_NAME=The Apache Software License, Version 2.0 +POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt +POM_LICENCE_DIST=repo +POM_DEVELOPER_ID=jaredrummler +POM_DEVELOPER_NAME=Jared Rummler +SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots +RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2
\ No newline at end of file diff --git a/colorPicker/proguard-rules.pro b/colorPicker/proguard-rules.pro new file mode 100644 index 000000000..677edc8f4 --- /dev/null +++ b/colorPicker/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/colorPicker/src/main/AndroidManifest.xml b/colorPicker/src/main/AndroidManifest.xml new file mode 100644 index 000000000..c48f9fb9d --- /dev/null +++ b/colorPicker/src/main/AndroidManifest.xml @@ -0,0 +1 @@ +<manifest package="com.jaredrummler.android.colorpicker" /> diff --git a/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/AlphaPatternDrawable.java b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/AlphaPatternDrawable.java new file mode 100644 index 000000000..806ab027c --- /dev/null +++ b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/AlphaPatternDrawable.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2017 Jared Rummler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jaredrummler.android.colorpicker; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +/** + * This drawable will draw a simple white and gray chessboard pattern. + * It's the pattern you will often see as a background behind a partly transparent image in many applications. + */ +class AlphaPatternDrawable extends Drawable { + + private final Paint paint = new Paint(); + private final Paint paintWhite = new Paint(); + private final Paint paintGray = new Paint(); + private int rectangleSize = 10; + private int numRectanglesHorizontal; + private int numRectanglesVertical; + + /** + * Bitmap in which the pattern will be cached. + * This is so the pattern will not have to be recreated each time draw() gets called. + * Because recreating the pattern i rather expensive. I will only be recreated if the size changes. + */ + private Bitmap bitmap; + + AlphaPatternDrawable(int rectangleSize) { + this.rectangleSize = rectangleSize; + paintWhite.setColor(0xFFFFFFFF); + paintGray.setColor(0xFFCBCBCB); + } + + @Override + public void draw(Canvas canvas) { + if (bitmap != null && !bitmap.isRecycled()) { + canvas.drawBitmap(bitmap, null, getBounds(), paint); + } + } + + @Override + public int getOpacity() { + return 0; + } + + @Override + public void setAlpha(int alpha) { + throw new UnsupportedOperationException("Alpha is not supported by this drawable."); + } + + @Override + public void setColorFilter(ColorFilter cf) { + throw new UnsupportedOperationException("ColorFilter is not supported by this drawable."); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + int height = bounds.height(); + int width = bounds.width(); + numRectanglesHorizontal = (int) Math.ceil((width / rectangleSize)); + numRectanglesVertical = (int) Math.ceil(height / rectangleSize); + generatePatternBitmap(); + } + + /** + * This will generate a bitmap with the pattern as big as the rectangle we were allow to draw on. + * We do this to chache the bitmap so we don't need to recreate it each time draw() is called since it takes a few + * milliseconds + */ + private void generatePatternBitmap() { + if (getBounds().width() <= 0 || getBounds().height() <= 0) { + return; + } + + bitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + + Rect r = new Rect(); + boolean verticalStartWhite = true; + for (int i = 0; i <= numRectanglesVertical; i++) { + boolean isWhite = verticalStartWhite; + for (int j = 0; j <= numRectanglesHorizontal; j++) { + r.top = i * rectangleSize; + r.left = j * rectangleSize; + r.bottom = r.top + rectangleSize; + r.right = r.left + rectangleSize; + canvas.drawRect(r, isWhite ? paintWhite : paintGray); + isWhite = !isWhite; + } + verticalStartWhite = !verticalStartWhite; + } + } +} diff --git a/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPaletteAdapter.java b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPaletteAdapter.java new file mode 100644 index 000000000..8e960d547 --- /dev/null +++ b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPaletteAdapter.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2017 Jared Rummler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jaredrummler.android.colorpicker; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; + +import androidx.core.graphics.ColorUtils; + +class ColorPaletteAdapter extends BaseAdapter { + + /*package*/ final OnColorSelectedListener listener; + /*package*/ final int[] colors; + /*package*/ int selectedPosition; + /*package*/ int colorShape; + + ColorPaletteAdapter(OnColorSelectedListener listener, int[] colors, int selectedPosition, + @ColorShape int colorShape) { + this.listener = listener; + this.colors = colors; + this.selectedPosition = selectedPosition; + this.colorShape = colorShape; + } + + @Override + public int getCount() { + return colors.length; + } + + @Override + public Object getItem(int position) { + return colors[position]; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final ViewHolder holder; + if (convertView == null) { + holder = new ViewHolder(parent.getContext()); + convertView = holder.view; + } else { + holder = (ViewHolder) convertView.getTag(); + } + holder.setup(position); + return convertView; + } + + void selectNone() { + selectedPosition = -1; + notifyDataSetChanged(); + } + + interface OnColorSelectedListener { + + void onColorSelected(int color); + } + + private final class ViewHolder { + + View view; + ColorPanelView colorPanelView; + ImageView imageView; + int originalBorderColor; + + ViewHolder(Context context) { + int layoutResId; + if (colorShape == ColorShape.SQUARE) { + layoutResId = R.layout.cpv_color_item_square; + } else { + layoutResId = R.layout.cpv_color_item_circle; + } + view = View.inflate(context, layoutResId, null); + colorPanelView = view.findViewById(R.id.cpv_color_panel_view); + imageView = view.findViewById(R.id.cpv_color_image_view); + originalBorderColor = colorPanelView.getBorderColor(); + view.setTag(this); + } + + void setup(int position) { + int color = colors[position]; + int alpha = Color.alpha(color); + colorPanelView.setColor(color); + imageView.setImageResource(selectedPosition == position ? R.drawable.cpv_preset_checked : 0); + if (alpha != 255) { + if (alpha <= ColorPickerDialog.ALPHA_THRESHOLD) { + colorPanelView.setBorderColor(color | 0xFF000000); + imageView.setColorFilter(/*color | 0xFF000000*/Color.BLACK, PorterDuff.Mode.SRC_IN); + } else { + colorPanelView.setBorderColor(originalBorderColor); + imageView.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); + } + } else { + setColorFilter(position); + } + setOnClickListener(position); + } + + private void setOnClickListener(final int position) { + colorPanelView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedPosition != position) { + selectedPosition = position; + notifyDataSetChanged(); + } + listener.onColorSelected(colors[position]); + } + }); + colorPanelView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + colorPanelView.showHint(); + return true; + } + }); + } + + private void setColorFilter(int position) { + if (position == selectedPosition && ColorUtils.calculateLuminance(colors[position]) >= 0.65) { + imageView.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + } else { + imageView.setColorFilter(null); + } + } + } +}
\ No newline at end of file diff --git a/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPanelView.java b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPanelView.java new file mode 100644 index 000000000..ad047682d --- /dev/null +++ b/colorPicker/src/main/java/com/jaredrummler/android/colorpicker/ColorPanelView.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2017 Jared Rummler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jaredrummler.android.colorpicker; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.Toast; + +import androidx.annotation.ColorInt; +import androidx.core.view.GravityCompat; +import androidx.core.view.ViewCompat; + +import java.util.Locale; + +/** + * This class draws a panel which which will be filled with a color which can be set. It can be used to show the + * currently selected color which you will get from the {@link ColorPickerView}. + */ +public class ColorPanelView extends View { + + private final static int DEFAULT_BORDER_COLOR = 0xFF6E6E6E; + + private Drawable alphaPattern; + private Paint borderPaint; + private Paint colorPaint; + private Paint alphaPaint; + private Paint originalPaint; + private Rect drawingRect; + private Rect colorRect; + private RectF centerRect = new RectF(); + private boolean showOldColor; + + /* The width in pixels of the border surrounding the color panel. */ + private int borderWidthPx; + private int borderColor = DEFAULT_BORDER_COLOR; + private int color = Color.BLACK; + private int shape; + + public ColorPanelView(Context context) { + this(context, null); + } + + public ColorPanelView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ColorPanelView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + @Override + public Parcelable onSaveInstanceState() { + Bundle state = new Bundle(); + state.putParcelable("instanceState", super.onSaveInstanceState()); + state.putInt("color", color); + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + color = bundle.getInt("color"); + state = bundle.getParcelable("instanceState"); + } + super.onRestoreInstanceState(state); + } + + private void init(Context context, AttributeSet attrs) { + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPanelView); + shape = a.getInt(R.styleable.ColorPanelView_cpv_colorShape, ColorShape.CIRCLE); + showOldColor = a.getBoolean(R.styleable.ColorPanelView_cpv_showOldColor, false); + if (showOldColor && shape != ColorShape.CIRCLE) { + throw new IllegalStateException("Color preview is only available in circle mode"); + } + borderColor = a.getColor(R.styleable.ColorPanelView_cpv_borderColor, DEFAULT_BORDER_COLOR); + a.recycle(); + if (borderColor == DEFAULT_BORDER_COLOR) { + // If no specific border color has been set we take the default secondary text color as border/slider color. + // Thus it will adopt to theme changes automatically. + final TypedValue value = new TypedValue(); + TypedArray typedArray = + context.obtainStyledAttributes(value.data, new int[]{android.R.attr.textColorSecondary}); + borderColor = typedArray.getColor(0, borderColor); + typedArray.recycle(); + } + borderWidthPx = DrawingUtils.dpToPx(context, 1); + borderPaint = new Paint(); + borderPaint.setAntiAlias(true); + colorPaint = new Paint(); + colorPaint.setAntiAlias(true); + if (showOldColor) { + originalPaint = new Paint(); + } + if (shape == ColorShape.CIRCLE) { + Bitmap bitmap = ((BitmapDrawable) context.getResources().getDrawable(R.drawable.cpv_alpha)).getBitmap(); + alphaPaint = new Paint(); + alphaPaint.setAntiAlias(true); + BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); + alphaPaint.setShader(shader); + } + } + + @Override + protected void onDraw(Canvas canvas) { + borderPaint.setColor(borderColor); + colorPaint.setColor(color); + if (shape == ColorShape.SQUARE) { + if (borderWidthPx > 0) { + canvas.drawRect(drawingRect, borderPaint); + } + if (alphaPattern != null) { + alphaPattern.draw(canvas); + } + canvas.drawRect(colorRect, colorPaint); + } else if (shape == ColorShape.CIRCLE) { + final int outerRadius = getMeasuredWidth() / 2; + if (borderWidthPx > 0) { + canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius, borderPaint); + } + if (Color.alpha(color) < 255) { + canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, alphaPaint); + } + if (showOldColor) { + canvas.drawArc(centerRect, 90, 180, true, originalPaint); + canvas.drawArc(centerRect, 270, 180, true, colorPaint); + } else { + canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, outerRadius - borderWidthPx, colorPaint); + } + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (shape == ColorShape.SQUARE) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(width, height); + } else if (shape == ColorShape.CIRCLE) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (shape == ColorShape.SQUARE || showOldColor) { + drawingRect = new Rect(); + drawingRect.left = getPaddingLeft(); + drawingRect.right = w - getPaddingRight(); + drawingRect.top = getPaddin |