From 41f807402bd289c530dcc6de2979d2e9c69e7935 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 29 Oct 2018 11:19:14 -0400 Subject: [PATCH 01/31] update dependencies / androidx migration --- app/build.gradle | 20 +++--- .../colorpickerdialogsample/MainActivity.java | 2 +- app/src/main/res/layout/activity_main.xml | 8 +-- build.gradle | 9 +-- colorpickerdialog/build.gradle | 40 ++--------- .../activities/ImagePickerActivity.java | 2 +- .../dialogs/ColorPickerDialog.java | 8 +-- .../dialogs/ImageColorPickerDialog.java | 2 +- .../dialogs/PreferenceDialog.java | 2 +- .../colorpickerdialog/utils/ColorUtils.java | 5 +- .../colorpickerdialog/utils/ImageUtils.java | 3 +- .../views/CircleImageView.java | 6 +- .../views/ColorPickerImageView.java | 4 +- .../main/res/layout/dialog_color_picker.xml | 14 ++-- gradle.properties | 2 + gradlew | 72 +++++++++++-------- gradlew.bat | 14 ++-- 17 files changed, 94 insertions(+), 119 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f743e88..9405255 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 28 + buildToolsVersion "28.0.3" defaultConfig { applicationId "james.colorpickerdialogsample" minSdkVersion 16 - targetSdkVersion 25 + targetSdkVersion 28 versionCode 2 versionName "1.1" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -20,11 +20,7 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) - compile 'com.android.support:appcompat-v7:25.1.0' - compile project(path: ':colorpickerdialog') - testCompile 'junit:junit:4.12' -} + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation project(path: ':colorpickerdialog') +} \ No newline at end of file diff --git a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java b/app/src/main/java/james/colorpickerdialogsample/MainActivity.java index 266b247..e225e04 100644 --- a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/james/colorpickerdialogsample/MainActivity.java @@ -2,10 +2,10 @@ import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; import james.colorpickerdialog.dialogs.ColorPickerDialog; import james.colorpickerdialog.dialogs.PreferenceDialog; diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 85264d2..264878d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - extends AppCompatDialog { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java index ab1cc75..9b01bed 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java @@ -2,8 +2,9 @@ import android.graphics.Color; import android.graphics.PorterDuff; -import android.support.annotation.ColorInt; -import android.support.v7.widget.AppCompatSeekBar; + +import androidx.annotation.ColorInt; +import androidx.appcompat.widget.AppCompatSeekBar; public class ColorUtils { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java index dd5aa44..b4e996e 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java @@ -6,7 +6,8 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.support.graphics.drawable.VectorDrawableCompat; + +import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat; public class ImageUtils { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java index 13f930a..3e09129 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java @@ -5,11 +5,11 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.media.ThumbnailUtils; -import android.support.v4.graphics.drawable.RoundedBitmapDrawable; -import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.core.graphics.drawable.RoundedBitmapDrawable; +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; import james.colorpickerdialog.utils.ImageUtils; public class CircleImageView extends AppCompatImageView { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java index 8df5c32..c770225 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java @@ -8,12 +8,12 @@ import android.graphics.Rect; import android.os.Handler; import android.os.Looper; -import android.support.annotation.ColorInt; -import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewTreeObserver; +import androidx.annotation.ColorInt; +import androidx.appcompat.widget.AppCompatImageView; import james.colorpickerdialog.utils.ColorUtils; public class ColorPickerImageView extends AppCompatImageView { diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index d19ab63..68d6433 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -16,7 +16,7 @@ android:layout_height="0dp" android:layout_weight="1"> - - - - - - - \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282..f955316 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line From 6da50fdd83d66be7bded3717bbbadfdf8546144c Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Sat, 3 Nov 2018 14:46:22 -0400 Subject: [PATCH 02/31] start removing mostly useless PreferenceDialog --- .../colorpickerdialogsample/MainActivity.java | 1 - .../dialogs/ColorPickerDialog.java | 94 ++++++++++++++++--- .../dialogs/ImageColorPickerDialog.java | 2 +- .../dialogs/PreferenceDialog.java | 90 ------------------ 4 files changed, 82 insertions(+), 105 deletions(-) delete mode 100644 colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/PreferenceDialog.java diff --git a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java b/app/src/main/java/james/colorpickerdialogsample/MainActivity.java index e225e04..4dc3b10 100644 --- a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/james/colorpickerdialogsample/MainActivity.java @@ -7,7 +7,6 @@ import androidx.appcompat.app.AppCompatActivity; import james.colorpickerdialog.dialogs.ColorPickerDialog; -import james.colorpickerdialog.dialogs.PreferenceDialog; public class MainActivity extends AppCompatActivity implements View.OnClickListener, PreferenceDialog.OnPreferenceListener { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java index a4ea974..2747209 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -4,6 +4,7 @@ import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Color; @@ -20,6 +21,7 @@ import java.io.IOException; import androidx.annotation.ColorInt; +import androidx.appcompat.app.AppCompatDialog; import androidx.appcompat.widget.AppCompatEditText; import androidx.appcompat.widget.AppCompatSeekBar; import androidx.core.content.ContextCompat; @@ -28,8 +30,10 @@ import james.colorpickerdialog.activities.ImagePickerActivity; import james.colorpickerdialog.utils.ColorUtils; -public class ColorPickerDialog extends PreferenceDialog implements ColorPicker - .OnActivityResultListener { +public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener { + + private Integer preference, defaultPreference; + private OnColorListener listener; private ColorPicker picker; private TextWatcher textWatcher; @@ -45,6 +49,13 @@ public class ColorPickerDialog extends PreferenceDialog implements Colo public ColorPickerDialog(Context context) { super(context); setTitle(R.string.color_picker_name); + + setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialogInterface) { + cancel(); + } + }); } @Override @@ -55,17 +66,17 @@ protected void onCreate(Bundle savedInstanceState) { picker = (ColorPicker) getContext().getApplicationContext(); picker.addListener(this); - colorImage = (ImageView) findViewById(R.id.color); - colorHex = (AppCompatEditText) findViewById(R.id.colorHex); - red = (AppCompatSeekBar) findViewById(R.id.red); + colorImage = findViewById(R.id.color); + colorHex = findViewById(R.id.colorHex); + red = findViewById(R.id.red); ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.red)); - redInt = (TextView) findViewById(R.id.redInt); - green = (AppCompatSeekBar) findViewById(R.id.green); + redInt = findViewById(R.id.redInt); + green = findViewById(R.id.green); ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.green)); - greenInt = (TextView) findViewById(R.id.greenInt); - blue = (AppCompatSeekBar) findViewById(R.id.blue); + greenInt = findViewById(R.id.greenInt); + blue = findViewById(R.id.blue); ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.blue)); - blueInt = (TextView) findViewById(R.id.blueInt); + blueInt = findViewById(R.id.blueInt); imagePicker = findViewById(R.id.image); reset = findViewById(R.id.reset); @@ -275,20 +286,77 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } if (bitmap != null) { - new ImageColorPickerDialog(getContext(), bitmap).setDefaultPreference(Color.BLACK).setListener(new PreferenceDialog.OnPreferenceListener() { + new ImageColorPickerDialog(getContext(), bitmap).setDefaultPreference(Color.BLACK).setListener(new OnColorListener() { @Override - public void onPreference(PreferenceDialog dialog, Integer preference) { + public void onColorPicked(ColorPickerDialog dialog, @ColorInt int preference) { setColor(preference, false); setPreference(preference); } @Override - public void onCancel(PreferenceDialog dialog) { + public void onCancel(ColorPickerDialog dialog) { } }).show(); } } + public void confirm() { + if (hasListener()) { + getListener().onColorPicked(this, getPreference()); + setListener(null); + } + + if (isShowing()) dismiss(); + } + + public void cancel() { + if (hasListener()) { + getListener().onCancel(this); + setListener(null); + } + + if (isShowing()) dismiss(); + } + + public ColorPickerDialog setPreference(@ColorInt int preference) { + this.preference = preference; + return this; + } + + @ColorInt + public int getPreference() { + return preference != null ? preference : getDefaultPreference(); + } + + public ColorPickerDialog setDefaultPreference(@ColorInt int preference) { + defaultPreference = preference; + return this; + } + + @ColorInt + public int getDefaultPreference() { + return defaultPreference; + } + + public ColorPickerDialog setListener(OnColorListener listener) { + this.listener = listener; + return this; + } + + public boolean hasListener() { + return listener != null; + } + + public OnColorListener getListener() { + return listener; + } + + public interface OnColorListener { + void onColorPicked(ColorPickerDialog dialog, @ColorInt int color); + + void onCancel(ColorPickerDialog dialog); + } + @Override public void dismiss() { picker.removeListener(this); diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java index 838c516..59cccfc 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java @@ -9,7 +9,7 @@ import james.colorpickerdialog.R; import james.colorpickerdialog.views.ColorPickerImageView; -public class ImageColorPickerDialog extends PreferenceDialog { +public class ImageColorPickerDialog extends androidx.appcompat.app.AppCompatDialog { private Bitmap bitmap; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/PreferenceDialog.java b/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/PreferenceDialog.java deleted file mode 100644 index 74f13fe..0000000 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/PreferenceDialog.java +++ /dev/null @@ -1,90 +0,0 @@ -package james.colorpickerdialog.dialogs; - -import android.content.Context; -import android.content.DialogInterface; - -import androidx.appcompat.app.AppCompatDialog; -import james.colorpickerdialog.R; - -public abstract class PreferenceDialog extends AppCompatDialog { - - private T preference, defaultPreference; - private OnPreferenceListener listener; - - public PreferenceDialog(Context context) { - super(context, R.style.DialogTheme); - - setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialogInterface) { - cancel(); - } - }); - } - - public PreferenceDialog(Context context, int theme) { - super(context, theme); - - setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialogInterface) { - cancel(); - } - }); - } - - public void confirm() { - if (hasListener()) { - getListener().onPreference(this, getPreference()); - setListener(null); - } - - if (isShowing()) dismiss(); - } - - public void cancel() { - if (hasListener()) { - getListener().onCancel(this); - setListener(null); - } - - if (isShowing()) dismiss(); - } - - public PreferenceDialog setPreference(T preference) { - this.preference = preference; - return this; - } - - public T getPreference() { - return preference != null ? preference : getDefaultPreference(); - } - - public PreferenceDialog setDefaultPreference(T preference) { - defaultPreference = preference; - return this; - } - - public T getDefaultPreference() { - return defaultPreference; - } - - public PreferenceDialog setListener(OnPreferenceListener listener) { - this.listener = listener; - return this; - } - - public boolean hasListener() { - return listener != null; - } - - public OnPreferenceListener getListener() { - return listener; - } - - public interface OnPreferenceListener { - void onPreference(PreferenceDialog dialog, T preference); - - void onCancel(PreferenceDialog dialog); - } -} From c7cc97129090b4ff92c6afc127014d6119dc1851 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 13:12:28 -0500 Subject: [PATCH 03/31] refactor packages --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 4 ++-- .../jfenn}/colorpickerdialogsample/MainActivity.java | 4 ++-- colorpickerdialog/src/main/AndroidManifest.xml | 6 +++--- .../jfenn}/colorpickerdialog/ColorPicker.java | 2 +- .../activities/ImagePickerActivity.java | 4 ++-- .../colorpickerdialog/dialogs/ColorPickerDialog.java | 10 +++++----- .../dialogs/ImageColorPickerDialog.java | 9 +++++---- .../jfenn}/colorpickerdialog/utils/ColorUtils.java | 2 +- .../jfenn}/colorpickerdialog/utils/ImageUtils.java | 2 +- .../colorpickerdialog/views/CircleImageView.java | 4 ++-- .../colorpickerdialog/views/ColorPickerImageView.java | 4 ++-- .../src/main/res/layout/dialog_image_color_picker.xml | 2 +- 13 files changed, 28 insertions(+), 27 deletions(-) rename app/src/main/java/{james => me/jfenn}/colorpickerdialogsample/MainActivity.java (94%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/ColorPicker.java (96%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/activities/ImagePickerActivity.java (90%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/dialogs/ColorPickerDialog.java (98%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/dialogs/ImageColorPickerDialog.java (85%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/utils/ColorUtils.java (95%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/utils/ImageUtils.java (96%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/views/CircleImageView.java (94%) rename colorpickerdialog/src/main/java/{james => me/jfenn}/colorpickerdialog/views/ColorPickerImageView.java (98%) diff --git a/app/build.gradle b/app/build.gradle index 9405255..c4b2e5d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,7 +4,7 @@ android { compileSdkVersion 28 buildToolsVersion "28.0.3" defaultConfig { - applicationId "james.colorpickerdialogsample" + applicationId "me.jfenn.colorpickerdialogsample" minSdkVersion 16 targetSdkVersion 28 versionCode 2 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 690bae0..5ae28ed 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ + package="me.jfenn.colorpickerdialogsample"> - + diff --git a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java similarity index 94% rename from app/src/main/java/james/colorpickerdialogsample/MainActivity.java rename to app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java index 4dc3b10..e981300 100644 --- a/app/src/main/java/james/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java @@ -1,4 +1,4 @@ -package james.colorpickerdialogsample; +package me.jfenn.colorpickerdialogsample; import android.graphics.Color; import android.os.Bundle; @@ -6,7 +6,7 @@ import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; -import james.colorpickerdialog.dialogs.ColorPickerDialog; +import me.jfenn.colorpickerdialog.dialogs.ColorPickerDialog; public class MainActivity extends AppCompatActivity implements View.OnClickListener, PreferenceDialog.OnPreferenceListener { diff --git a/colorpickerdialog/src/main/AndroidManifest.xml b/colorpickerdialog/src/main/AndroidManifest.xml index 0433579..692e156 100644 --- a/colorpickerdialog/src/main/AndroidManifest.xml +++ b/colorpickerdialog/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ + package="me.jfenn.colorpickerdialog"> - + diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/ColorPicker.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/ColorPicker.java similarity index 96% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/ColorPicker.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/ColorPicker.java index 7e2a20a..9eb39bb 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/ColorPicker.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/ColorPicker.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog; +package me.jfenn.colorpickerdialog; import android.app.Application; import android.content.Intent; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/activities/ImagePickerActivity.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/activities/ImagePickerActivity.java similarity index 90% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/activities/ImagePickerActivity.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/activities/ImagePickerActivity.java index 0f9e04f..233d30b 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/activities/ImagePickerActivity.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/activities/ImagePickerActivity.java @@ -1,11 +1,11 @@ -package james.colorpickerdialog.activities; +package me.jfenn.colorpickerdialog.activities; import android.content.Intent; import android.os.Bundle; import android.widget.FrameLayout; import androidx.appcompat.app.AppCompatActivity; -import james.colorpickerdialog.ColorPicker; +import me.jfenn.colorpickerdialog.ColorPicker; public class ImagePickerActivity extends AppCompatActivity { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java similarity index 98% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 2747209..16bd5c1 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.dialogs; +package me.jfenn.colorpickerdialog.dialogs; import android.animation.Animator; import android.animation.ArgbEvaluator; @@ -25,10 +25,10 @@ import androidx.appcompat.widget.AppCompatEditText; import androidx.appcompat.widget.AppCompatSeekBar; import androidx.core.content.ContextCompat; -import james.colorpickerdialog.ColorPicker; -import james.colorpickerdialog.R; -import james.colorpickerdialog.activities.ImagePickerActivity; -import james.colorpickerdialog.utils.ColorUtils; +import me.jfenn.colorpickerdialog.ColorPicker; +import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; +import me.jfenn.colorpickerdialog.utils.ColorUtils; public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener { diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java similarity index 85% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java index 59cccfc..0b24fff 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/dialogs/ImageColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.dialogs; +package me.jfenn.colorpickerdialog.dialogs; import android.content.Context; import android.graphics.Bitmap; @@ -6,10 +6,11 @@ import android.view.View; import androidx.annotation.ColorInt; -import james.colorpickerdialog.R; -import james.colorpickerdialog.views.ColorPickerImageView; +import androidx.appcompat.app.AppCompatDialog; +import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.views.ColorPickerImageView; -public class ImageColorPickerDialog extends androidx.appcompat.app.AppCompatDialog { +public class ImageColorPickerDialog extends AppCompatDialog { private Bitmap bitmap; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java similarity index 95% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 9b01bed..267b44d 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.utils; +package me.jfenn.colorpickerdialog.utils; import android.graphics.Color; import android.graphics.PorterDuff; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ImageUtils.java similarity index 96% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ImageUtils.java index b4e996e..5c8af4d 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/utils/ImageUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ImageUtils.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.utils; +package me.jfenn.colorpickerdialog.utils; import android.graphics.Bitmap; import android.graphics.Canvas; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleImageView.java similarity index 94% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleImageView.java index 3e09129..de6f9f7 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/CircleImageView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleImageView.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.views; +package me.jfenn.colorpickerdialog.views; import android.content.Context; import android.graphics.Bitmap; @@ -10,7 +10,7 @@ import androidx.appcompat.widget.AppCompatImageView; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; -import james.colorpickerdialog.utils.ImageUtils; +import me.jfenn.colorpickerdialog.utils.ImageUtils; public class CircleImageView extends AppCompatImageView { Paint paint; diff --git a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerImageView.java similarity index 98% rename from colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerImageView.java index c770225..efa36ff 100644 --- a/colorpickerdialog/src/main/java/james/colorpickerdialog/views/ColorPickerImageView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerImageView.java @@ -1,4 +1,4 @@ -package james.colorpickerdialog.views; +package me.jfenn.colorpickerdialog.views; import android.content.Context; import android.graphics.Bitmap; @@ -14,7 +14,7 @@ import androidx.annotation.ColorInt; import androidx.appcompat.widget.AppCompatImageView; -import james.colorpickerdialog.utils.ColorUtils; +import me.jfenn.colorpickerdialog.utils.ColorUtils; public class ColorPickerImageView extends AppCompatImageView { diff --git a/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml index 62e2b64..2beca49 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml @@ -3,7 +3,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - Date: Mon, 5 Nov 2018 16:33:00 -0500 Subject: [PATCH 04/31] add color / rgb picker views & layouts --- .../views/ColorPickerView.java | 191 ++++++++++++++++++ .../views/RGBPickerView.java | 99 +++++++++ .../src/main/res/layout/layout_hsb_picker.xml | 164 +++++++++++++++ .../src/main/res/layout/layout_rgb_picker.xml | 164 +++++++++++++++ .../src/main/res/values/strings.xml | 4 + 5 files changed, 622 insertions(+) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java create mode 100644 colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml create mode 100644 colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java new file mode 100644 index 0000000..aa29855 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -0,0 +1,191 @@ +package me.jfenn.colorpickerdialog.views; + +import android.animation.ObjectAnimator; +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Color; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.widget.LinearLayout; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatSeekBar; +import me.jfenn.colorpickerdialog.R; + +public abstract class ColorPickerView extends LinearLayout { + + private OnColorPickedListener listener; + + private float alpha; + private TextView alphaInt; + private AppCompatSeekBar alphaBar; + private View alphaLayout; + + private boolean isTrackingTouch; + + public ColorPickerView(Context context) { + super(context); + init(); + postInit(); + } + + public ColorPickerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + postInit(); + } + + public ColorPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + postInit(); + } + + @TargetApi(21) + public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + postInit(); + } + + abstract void init(); + + private void postInit() { + alphaInt = findViewById(R.id.alphaInt); + alphaBar = findViewById(R.id.alpha); + alphaLayout = findViewById(R.id.alphaLayout); + + if (alphaBar != null) { + alphaBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + alphaInt.setText(String.format("%s", (float) i / 255)); + onColorPicked(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + isTrackingTouch = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + isTrackingTouch = false; + } + }); + } + } + + /** + * Set the picker's color. Changes to values will not be animated. + * + * @param color The picker's color. + */ + public void setColor(@ColorInt int color) { + setColor(color, false); + } + + /** + * Set the picker's color. + * + * @param color The picker's color. + * @param animate Whether to animate changes in values. + */ + public void setColor(@ColorInt int color, boolean animate) { + setAlpha(((float) (int) Color.alpha(color) / 255), animate); + } + + /** + * Get the current color value. + * + * @return The current color value. + */ + @ColorInt + public abstract int getColor(); + + /** + * Set whether the color's alpha value can be changed. + * + * @param isAlpha Whether the color's alpha value can be changed. + */ + public void setAlphaEnabled(boolean isAlpha) { + if (alphaLayout == null) + return; + + if (isAlpha) { + alphaLayout.setVisibility(View.VISIBLE); + } else { + alphaLayout.setVisibility(View.GONE); + } + } + + /** + * Determine whether the color's alpha value can be modified. + * + * @return Whether the color's alpha value can be modified. + */ + public boolean isAlphaEnabled() { + return alphaLayout != null && alphaLayout.getVisibility() == View.VISIBLE; + } + + /** + * Set the color's alpha, between 0-1 (inclusive). Change in values + * will not be animated. + * + * @param alpha The color's alpha, between 0-1 (inclusive). + */ + public void setAlpha(float alpha) { + setAlpha(alpha, false); + } + + /** + * Set the color's alpha, between 0-1 (inclusive). + * + * @param alpha The color's alpha, between 0-1 (inclusive). + * @param animate Whether to animate the change in values. + */ + public void setAlpha(float alpha, boolean animate) { + this.alpha = alpha; + + if (animate && !isTrackingTouch) { + ObjectAnimator animator = ObjectAnimator.ofInt(alphaBar, "progress", 0, (int) (alpha * 255)); + animator.setInterpolator(new DecelerateInterpolator()); + animator.start(); + } else { + alphaBar.setProgress((int) (alpha * 255)); + } + } + + /** + * Gets the color's alpha, between 0-1 (inclusive). + * + * @return The color's alpha, between 0-1 (inclusive). + */ + public float getAlpha() { + return alpha; + } + + protected void onColorPicked() { + if (listener != null) + listener.onColorPicked(getColor()); + } + + /** + * Set an interface to receive updates to color values. This may + * be called multiple times in succession if a slider is dragged + * or animated; be wary of performance. + * + * @param listener An interface to receive color updates. + */ + public void setListener(OnColorPickedListener listener) { + this.listener = listener; + } + + private interface OnColorPickedListener { + void onColorPicked(@ColorInt int color); + } +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java new file mode 100644 index 0000000..f441754 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -0,0 +1,99 @@ +package me.jfenn.colorpickerdialog.views; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.DecelerateInterpolator; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatSeekBar; +import me.jfenn.colorpickerdialog.R; + +public class RGBPickerView extends ColorPickerView { + + private AppCompatSeekBar red, green, blue; + private TextView redInt, greenInt, blueInt; + private boolean isTrackingTouch; + + public RGBPickerView(Context context) { + super(context); + } + + public RGBPickerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public RGBPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public RGBPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + void init() { + inflate(getContext(), R.layout.layout_rgb_picker, this); + red = findViewById(R.id.red); + redInt = findViewById(R.id.redInt); + green = findViewById(R.id.green); + greenInt = findViewById(R.id.greenInt); + blue = findViewById(R.id.blue); + blueInt = findViewById(R.id.blueInt); + + SeekBar.OnSeekBarChangeListener listener = new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + if (seekBar.getId() == R.id.red) { + redInt.setText(String.format("%s", i)); + } else if (seekBar.getId() == R.id.green) { + greenInt.setText(String.format("%s", i)); + } else if (seekBar.getId() == R.id.blue) { + blueInt.setText(String.format("%s", i)); + } + onColorPicked(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + isTrackingTouch = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + isTrackingTouch = false; + } + }; + + red.setOnSeekBarChangeListener(listener); + green.setOnSeekBarChangeListener(listener); + blue.setOnSeekBarChangeListener(listener); + } + + @Override + public void setColor(int color, boolean animate) { + super.setColor(color, animate); + SeekBar[] bars = new SeekBar[]{red, green, blue}; + int[] offsets = new int[]{16, 8, 0}; + for (int i = 0; i < bars.length; i++) { + int value = (color >> offsets[i]) & 0xFF; + if (animate && !isTrackingTouch) { + ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, value); + animator.setInterpolator(new DecelerateInterpolator()); + animator.start(); + } else { + bars[i].setProgress(value); + } + } + } + + @Override + public int getColor() { + return (32 << (0xFF & (int) (isAlphaEnabled() ? getAlpha() * 255 : 255))) + + (0xFF & red.getProgress()) << 16 + + (0xFF & green.getProgress()) << 8 + + (0xFF & blue.getProgress()); + } +} diff --git a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml new file mode 100644 index 0000000..5b380cc --- /dev/null +++ b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml new file mode 100644 index 0000000..6643839 --- /dev/null +++ b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/colorpickerdialog/src/main/res/values/strings.xml b/colorpickerdialog/src/main/res/values/strings.xml index 98d804d..35b69ef 100644 --- a/colorpickerdialog/src/main/res/values/strings.xml +++ b/colorpickerdialog/src/main/res/values/strings.xml @@ -9,4 +9,8 @@ Blue Green Image + Alpha + Hue + Saturation + Brightness From d7dc71dd7b5a09d068f0e8abeb6022e6ad2b4a80 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 17:01:04 -0500 Subject: [PATCH 05/31] begun implementing pager stuff --- .../adapters/ColorPickerPagerAdapter.java | 62 +++++++++++++++++++ .../views/ColorPickerView.java | 2 +- .../src/main/res/values/strings.xml | 2 + 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java new file mode 100644 index 0000000..c2ff486 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -0,0 +1,62 @@ +package me.jfenn.colorpickerdialog.adapters; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.PagerAdapter; +import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.views.ColorPickerView; +import me.jfenn.colorpickerdialog.views.RGBPickerView; + +public class ColorPickerPagerAdapter extends PagerAdapter { + + private Context context; + private ColorPickerView.OnColorPickedListener listener; + + public ColorPickerPagerAdapter(Context context, ColorPickerView.OnColorPickedListener listener) { + this.context = context; + this.listener = listener; + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + ColorPickerView view; + switch (position) { + case 0: + view = new RGBPickerView(context); + break; + default: + return new View(context); + } + + view.setListener(listener); + container.addView(view); + return view; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView((View) object); + } + + @Override + public int getCount() { + return 2; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + + @Nullable + @Override + public CharSequence getPageTitle(int position) { + return context.getString(new int[]{R.string.rgb, R.string.hsb}[position]); + } + +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index aa29855..9cdb6f9 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -185,7 +185,7 @@ public void setListener(OnColorPickedListener listener) { this.listener = listener; } - private interface OnColorPickedListener { + public interface OnColorPickedListener { void onColorPicked(@ColorInt int color); } } diff --git a/colorpickerdialog/src/main/res/values/strings.xml b/colorpickerdialog/src/main/res/values/strings.xml index 35b69ef..89b96b8 100644 --- a/colorpickerdialog/src/main/res/values/strings.xml +++ b/colorpickerdialog/src/main/res/values/strings.xml @@ -13,4 +13,6 @@ Hue Saturation Brightness + RGB + HSB From 5b341e503bb382b866959509aff5ac39b8a3bf46 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 21:29:22 -0500 Subject: [PATCH 06/31] did things --- .../colorpickerdialogsample/MainActivity.java | 30 +- colorpickerdialog/build.gradle | 1 + .../dialogs/ColorPickerDialog.java | 325 +----------------- .../dialogs/ImageColorPickerDialog.java | 11 +- .../views/ColorPickerView.java | 4 +- .../views/HSBPickerView.java | 99 ++++++ .../views/RGBPickerView.java | 6 + .../main/res/layout/dialog_color_picker.xml | 119 +------ .../src/main/res/layout/layout_hsb_picker.xml | 29 +- .../src/main/res/layout/layout_rgb_picker.xml | 39 ++- .../src/main/res/values/strings.xml | 14 +- 11 files changed, 188 insertions(+), 489 deletions(-) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java diff --git a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java index e981300..b58a895 100644 --- a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java @@ -3,12 +3,11 @@ import android.graphics.Color; import android.os.Bundle; import android.view.View; -import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import me.jfenn.colorpickerdialog.dialogs.ColorPickerDialog; -public class MainActivity extends AppCompatActivity implements View.OnClickListener, PreferenceDialog.OnPreferenceListener { +public class MainActivity extends AppCompatActivity implements View.OnClickListener { private int preference = Color.BLUE; @@ -26,33 +25,6 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onClick(View v) { ColorPickerDialog dialog = new ColorPickerDialog(this); - dialog.setPreference(preference); - dialog.setListener(this); - - switch (v.getId()) { - case R.id.defaultAndImage: - dialog.setDefaultPreference(Color.BLACK); - case R.id.noDefaultAndImage: - dialog.setImagePickerEnabled(true); - break; - case R.id.defaultAndNoImage: - dialog.setDefaultPreference(Color.BLACK); - case R.id.noDefaultAndNoImage: - dialog.setImagePickerEnabled(false); - break; - } - dialog.show(); } - - @Override - public void onPreference(PreferenceDialog dialog, Integer preference) { - Toast.makeText(MainActivity.this, String.format("#%06X", (0xFFFFFF & preference)), Toast.LENGTH_SHORT).show(); - this.preference = preference; - } - - @Override - public void onCancel(PreferenceDialog dialog) { - Toast.makeText(MainActivity.this, "Cancelled", Toast.LENGTH_SHORT).show(); - } } diff --git a/colorpickerdialog/build.gradle b/colorpickerdialog/build.gradle index cffc11a..007703c 100644 --- a/colorpickerdialog/build.gradle +++ b/colorpickerdialog/build.gradle @@ -25,4 +25,5 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'com.google.android.material:material:1.0.0' } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 16bd5c1..38b5724 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -1,61 +1,31 @@ package me.jfenn.colorpickerdialog.dialogs; -import android.animation.Animator; -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.provider.MediaStore; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.widget.ImageView; -import android.widget.SeekBar; -import android.widget.TextView; + +import com.google.android.material.tabs.TabLayout; import java.io.IOException; -import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatDialog; -import androidx.appcompat.widget.AppCompatEditText; -import androidx.appcompat.widget.AppCompatSeekBar; -import androidx.core.content.ContextCompat; +import androidx.viewpager.widget.ViewPager; import me.jfenn.colorpickerdialog.ColorPicker; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; -import me.jfenn.colorpickerdialog.utils.ColorUtils; - -public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener { - - private Integer preference, defaultPreference; - private OnColorListener listener; +import me.jfenn.colorpickerdialog.adapters.ColorPickerPagerAdapter; +import me.jfenn.colorpickerdialog.views.ColorPickerView; - private ColorPicker picker; - private TextWatcher textWatcher; +public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener, ColorPickerView.OnColorPickedListener { - private ImageView colorImage; - private AppCompatEditText colorHex; - private TextView redInt, greenInt, blueInt; - private AppCompatSeekBar red, green, blue; - private View reset, imagePicker; - - private boolean isTrackingTouch, isImagePickerEnabled = true; + private TabLayout tabLayout; + private ViewPager slidersPager; public ColorPickerDialog(Context context) { super(context); setTitle(R.string.color_picker_name); - - setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialogInterface) { - cancel(); - } - }); } @Override @@ -63,213 +33,11 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_color_picker); - picker = (ColorPicker) getContext().getApplicationContext(); - picker.addListener(this); - - colorImage = findViewById(R.id.color); - colorHex = findViewById(R.id.colorHex); - red = findViewById(R.id.red); - ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.red)); - redInt = findViewById(R.id.redInt); - green = findViewById(R.id.green); - ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.green)); - greenInt = findViewById(R.id.greenInt); - blue = findViewById(R.id.blue); - ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.blue)); - blueInt = findViewById(R.id.blueInt); - imagePicker = findViewById(R.id.image); - reset = findViewById(R.id.reset); - - textWatcher = new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - try { - int color = Color.parseColor(colorHex.getText().toString()); - setColor(color, true); - setPreference(color); - } catch (Exception ignored) { - } - } - - @Override - public void afterTextChanged(Editable s) { - } - }; - - colorHex.addTextChangedListener(textWatcher); - - red.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - int color = getPreference(); - color = Color.rgb(i, Color.green(color), Color.blue(color)); - setColor(color, false); - setPreference(color); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - isTrackingTouch = true; - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - isTrackingTouch = false; - } - }); - - green.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - int color = getPreference(); - color = Color.rgb(Color.red(color), i, Color.blue(color)); - setColor(color, false); - setPreference(color); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - isTrackingTouch = true; - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - isTrackingTouch = false; - } - }); - - blue.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - int color = getPreference(); - color = Color.rgb(Color.red(color), Color.green(color), i); - setColor(color, false); - setPreference(color); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - isTrackingTouch = true; - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - isTrackingTouch = false; - } - }); - - setColor(getPreference(), false); - - imagePicker.setVisibility(isImagePickerEnabled ? View.VISIBLE : View.GONE); - imagePicker.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getContext().startActivity(new Intent(getContext(), ImagePickerActivity.class)); - } - }); - - Integer preference = getPreference(); - Integer defaultPreference = getDefaultPreference(); - reset.setVisibility(defaultPreference != null && !preference.equals(defaultPreference) ? View.VISIBLE : View.GONE); - - reset.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int color = getDefaultPreference(); - setColor(color, true); - setPreference(color); - } - }); - - findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - cancel(); - } - }); - - findViewById(R.id.confirm).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - confirm(); - } - }); - } - - private void setColor(@ColorInt int color, boolean animate) { - if (!isTrackingTouch && animate) { - ValueAnimator animator = ValueAnimator.ofObject(new ArgbEvaluator(), getPreference(), color); - animator.setDuration(250); - animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int color = (int) animation.getAnimatedValue(); - red.setProgress(Color.red(color)); - green.setProgress(Color.green(color)); - blue.setProgress(Color.blue(color)); - } - }); - animator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - isTrackingTouch = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - isTrackingTouch = false; - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - }); - animator.start(); - } else { - colorImage.setImageDrawable(new ColorDrawable(color)); - colorHex.removeTextChangedListener(textWatcher); - colorHex.setText(String.format("#%06X", (0xFFFFFF & color))); - colorHex.setTextColor(ContextCompat.getColor(getContext(), ColorUtils.isColorDark(color) ? R.color.textColorPrimaryInverse : R.color.textColorPrimary)); - colorHex.addTextChangedListener(textWatcher); - redInt.setText(String.valueOf(Color.red(color))); - greenInt.setText(String.valueOf(Color.green(color))); - blueInt.setText(String.valueOf(Color.blue(color))); - - if (red.getProgress() != Color.red(color)) red.setProgress(Color.red(color)); - if (green.getProgress() != Color.green(color)) green.setProgress(Color.green(color)); - if (blue.getProgress() != Color.blue(color)) blue.setProgress(Color.blue(color)); - } - } - - @Override - public ColorPickerDialog setDefaultPreference(Integer preference) { - return (ColorPickerDialog) super.setDefaultPreference(preference); - } - - @Override - public ColorPickerDialog setPreference(@ColorInt Integer preference) { - Integer defaultPreference = getDefaultPreference(); - if (reset != null) - reset.setVisibility(!preference.equals(defaultPreference) ? View.VISIBLE : View.GONE); - - return (ColorPickerDialog) super.setPreference(preference); - } - - public ColorPickerDialog setImagePickerEnabled(boolean isImagePickerEnabled) { - this.isImagePickerEnabled = isImagePickerEnabled; + tabLayout = findViewById(R.id.tabLayout); + slidersPager = findViewById(R.id.slidersPager); - if (imagePicker != null) - imagePicker.setVisibility(isImagePickerEnabled ? View.VISIBLE : View.GONE); - - return this; + slidersPager.setAdapter(new ColorPickerPagerAdapter(getContext(), this)); + tabLayout.setupWithViewPager(slidersPager); } @Override @@ -286,80 +54,21 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } if (bitmap != null) { - new ImageColorPickerDialog(getContext(), bitmap).setDefaultPreference(Color.BLACK).setListener(new OnColorListener() { + /*new ImageColorPickerDialog(getContext(), bitmap).setDefaultPreference(Color.BLACK).setListener(new OnColorListener() { @Override public void onColorPicked(ColorPickerDialog dialog, @ColorInt int preference) { - setColor(preference, false); - setPreference(preference); + //TODO: set color } @Override public void onCancel(ColorPickerDialog dialog) { } - }).show(); - } - } - - public void confirm() { - if (hasListener()) { - getListener().onColorPicked(this, getPreference()); - setListener(null); - } - - if (isShowing()) dismiss(); - } - - public void cancel() { - if (hasListener()) { - getListener().onCancel(this); - setListener(null); + }).show();*/ } - - if (isShowing()) dismiss(); - } - - public ColorPickerDialog setPreference(@ColorInt int preference) { - this.preference = preference; - return this; - } - - @ColorInt - public int getPreference() { - return preference != null ? preference : getDefaultPreference(); - } - - public ColorPickerDialog setDefaultPreference(@ColorInt int preference) { - defaultPreference = preference; - return this; - } - - @ColorInt - public int getDefaultPreference() { - return defaultPreference; - } - - public ColorPickerDialog setListener(OnColorListener listener) { - this.listener = listener; - return this; - } - - public boolean hasListener() { - return listener != null; - } - - public OnColorListener getListener() { - return listener; - } - - public interface OnColorListener { - void onColorPicked(ColorPickerDialog dialog, @ColorInt int color); - - void onCancel(ColorPickerDialog dialog); } @Override - public void dismiss() { - picker.removeListener(this); - super.dismiss(); + public void onColorPicked(int color) { + } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java index 0b24fff..8bc7940 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java @@ -3,12 +3,9 @@ import android.content.Context; import android.graphics.Bitmap; import android.os.Bundle; -import android.view.View; -import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatDialog; import me.jfenn.colorpickerdialog.R; -import me.jfenn.colorpickerdialog.views.ColorPickerImageView; public class ImageColorPickerDialog extends AppCompatDialog { @@ -26,7 +23,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_image_color_picker); - ColorPickerImageView imageView = (ColorPickerImageView) findViewById(R.id.image); + /*ColorPickerImageView imageView = (ColorPickerImageView) findViewById(R.id.image); imageView.setOnColorChangedListener(new ColorPickerImageView.OnColorChangedListener() { @Override public void onColorChanged(@ColorInt int color) { @@ -48,11 +45,11 @@ public void onClick(View view) { public void onClick(View view) { confirm(); } - }); + });*/ } - @Override + /*@Override public ImageColorPickerDialog setDefaultPreference(Integer preference) { return (ImageColorPickerDialog) super.setDefaultPreference(preference); - } + }*/ } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index 9cdb6f9..0d5727a 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -11,6 +11,8 @@ import android.widget.SeekBar; import android.widget.TextView; +import java.util.Locale; + import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; @@ -63,7 +65,7 @@ private void postInit() { alphaBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - alphaInt.setText(String.format("%s", (float) i / 255)); + alphaInt.setText(String.format(Locale.getDefault(), "%.2f", (float) i / 255)); onColorPicked(); } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java new file mode 100644 index 0000000..b65ac35 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java @@ -0,0 +1,99 @@ +package me.jfenn.colorpickerdialog.views; + +import android.animation.ObjectAnimator; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.DecelerateInterpolator; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatSeekBar; +import me.jfenn.colorpickerdialog.R; + +public class HSBPickerView extends ColorPickerView { + + private AppCompatSeekBar red, green, blue; + private TextView redInt, greenInt, blueInt; + private boolean isTrackingTouch; + + public HSBPickerView(Context context) { + super(context); + } + + public HSBPickerView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public HSBPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public HSBPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + void init() { + inflate(getContext(), R.layout.layout_rgb_picker, this); + red = findViewById(R.id.hue); + redInt = findViewById(R.id.hueInt); + green = findViewById(R.id.brightness); + greenInt = findViewById(R.id.brightnessInt); + blue = findViewById(R.id.saturation); + blueInt = findViewById(R.id.saturationInt); + + SeekBar.OnSeekBarChangeListener listener = new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int i, boolean b) { + if (seekBar.getId() == R.id.red) { + redInt.setText(String.format("%s", i)); + } else if (seekBar.getId() == R.id.green) { + greenInt.setText(String.format("%s", i)); + } else if (seekBar.getId() == R.id.blue) { + blueInt.setText(String.format("%s", i)); + } + onColorPicked(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + isTrackingTouch = true; + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + isTrackingTouch = false; + } + }; + + red.setOnSeekBarChangeListener(listener); + green.setOnSeekBarChangeListener(listener); + blue.setOnSeekBarChangeListener(listener); + } + + @Override + public void setColor(int color, boolean animate) { + super.setColor(color, animate); + SeekBar[] bars = new SeekBar[]{red, green, blue}; + int[] offsets = new int[]{16, 8, 0}; + for (int i = 0; i < bars.length; i++) { + int value = (color >> offsets[i]) & 0xFF; + if (animate && !isTrackingTouch) { + ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, value); + animator.setInterpolator(new DecelerateInterpolator()); + animator.start(); + } else { + bars[i].setProgress(value); + } + } + } + + @Override + public int getColor() { + return (32 << (0xFF & (int) (isAlphaEnabled() ? getAlpha() * 255 : 255))) + + (0xFF & red.getProgress()) << 16 + + (0xFF & green.getProgress()) << 8 + + (0xFF & blue.getProgress()); + } +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index f441754..4b10a5e 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -9,7 +9,9 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; +import androidx.core.content.ContextCompat; import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.utils.ColorUtils; public class RGBPickerView extends ColorPickerView { @@ -70,6 +72,10 @@ public void onStopTrackingTouch(SeekBar seekBar) { red.setOnSeekBarChangeListener(listener); green.setOnSeekBarChangeListener(listener); blue.setOnSeekBarChangeListener(listener); + + ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.red)); + ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.green)); + ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.blue)); } @Override diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 68d6433..19d8712 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -99,122 +99,15 @@ - - - - - - - - - - - - - + android:layout_height="wrap_content" /> - - - - - - - - - - - - - - - + android:layout_height="wrap_content" /> diff --git a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml index 5b380cc..5ea5641 100644 --- a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml @@ -1,5 +1,6 @@ @@ -15,7 +16,7 @@ + android:textStyle="bold" + tools:text="255" /> @@ -54,7 +58,7 @@ + android:textStyle="bold" + tools:text="255" /> @@ -93,7 +100,7 @@ + android:textStyle="bold" + tools:text="255" /> @@ -133,7 +143,7 @@ + android:textStyle="bold" + tools:text="1.0" /> diff --git a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml index 6643839..0b25c51 100644 --- a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml @@ -1,16 +1,17 @@ + android:orientation="horizontal"> + android:textStyle="bold" + tools:text="255" /> @@ -47,9 +51,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> + android:textStyle="bold" + tools:text="255" /> @@ -86,9 +91,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> + android:textStyle="bold" + tools:text="255" /> @@ -126,9 +132,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> + android:textStyle="bold" + tools:text="1.0" /> diff --git a/colorpickerdialog/src/main/res/values/strings.xml b/colorpickerdialog/src/main/res/values/strings.xml index 89b96b8..35a2356 100644 --- a/colorpickerdialog/src/main/res/values/strings.xml +++ b/colorpickerdialog/src/main/res/values/strings.xml @@ -5,14 +5,14 @@ Reset Pick Color from Image - Red - Blue - Green + R + B + G Image - Alpha - Hue - Saturation - Brightness + A + H + S + B RGB HSB From c8e522e1c04614da6b37011c2969321175eaef61 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 21:54:54 -0500 Subject: [PATCH 07/31] fixed viewpager / seekbar touch areas --- .../adapters/ColorPickerPagerAdapter.java | 4 ++ .../views/ColorPickerView.java | 4 ++ .../views/HeightableViewPager.java | 46 +++++++++++++++++++ .../main/res/layout/dialog_color_picker.xml | 12 +++-- .../src/main/res/layout/layout_hsb_picker.xml | 36 ++++++--------- .../src/main/res/layout/layout_rgb_picker.xml | 43 +++++++++-------- .../src/main/res/values/colors.xml | 1 + 7 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HeightableViewPager.java diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index c2ff486..34c386c 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -9,6 +9,7 @@ import androidx.viewpager.widget.PagerAdapter; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.views.ColorPickerView; +import me.jfenn.colorpickerdialog.views.HSBPickerView; import me.jfenn.colorpickerdialog.views.RGBPickerView; public class ColorPickerPagerAdapter extends PagerAdapter { @@ -29,6 +30,9 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) { case 0: view = new RGBPickerView(context); break; + case 1: + view = new HSBPickerView(context); + break; default: return new View(context); } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index 0d5727a..8fff2cd 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -16,7 +16,9 @@ import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; +import androidx.core.content.ContextCompat; import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.utils.ColorUtils; public abstract class ColorPickerView extends LinearLayout { @@ -79,6 +81,8 @@ public void onStopTrackingTouch(SeekBar seekBar) { isTrackingTouch = false; } }); + + ColorUtils.setProgressBarColor(alphaBar, ContextCompat.getColor(getContext(), R.color.neutral)); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HeightableViewPager.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HeightableViewPager.java new file mode 100644 index 0000000..6da54a9 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HeightableViewPager.java @@ -0,0 +1,46 @@ +package me.jfenn.colorpickerdialog.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.viewpager.widget.ViewPager; + +public class HeightableViewPager extends ViewPager { + + public HeightableViewPager(@NonNull Context context) { + super(context); + } + + public HeightableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + return false; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = 0; + for (int i = 0; i < getChildCount(); i++) { + View v = getChildAt(i); + v.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + height = Math.max(height, v.getMeasuredHeight()); + } + + if (height != 0) + heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } +} diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 19d8712..91ed67d 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -2,7 +2,8 @@ + android:layout_height="match_parent" + android:minWidth="350dp"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + app:tabIndicatorHeight="0dp" + app:tabMode="scrollable"/> - diff --git a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml index 5ea5641..84a4016 100644 --- a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml @@ -3,15 +3,15 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingLeft="26dp" + android:paddingRight="26dp"> + android:orientation="horizontal"> @@ -36,9 +36,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="true" android:ellipsize="none" android:gravity="end" + android:singleLine="true" android:textAllCaps="true" android:textColor="@color/textColorSecondary" android:textSize="14sp" @@ -51,9 +51,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> @@ -78,9 +76,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="true" android:ellipsize="none" android:gravity="end" + android:singleLine="true" android:textAllCaps="true" android:textColor="@color/textColorSecondary" android:textSize="14sp" @@ -93,9 +91,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> @@ -120,9 +116,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:singleLine="true" android:ellipsize="none" android:gravity="end" + android:singleLine="true" android:textAllCaps="true" android:textColor="@color/textColorSecondary" android:textSize="14sp" @@ -136,9 +132,7 @@ android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center_vertical" - android:orientation="horizontal" - android:paddingLeft="15dp" - android:paddingRight="15dp"> + android:orientation="horizontal"> @@ -163,9 +157,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:ellipsize="none" android:gravity="end" android:singleLine="true" - android:ellipsize="none" android:textAllCaps="true" android:textColor="@color/textColorSecondary" android:textSize="14sp" diff --git a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml index 0b25c51..be02a53 100644 --- a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml @@ -1,11 +1,10 @@ + android:paddingRight="26dp"> + android:textStyle="bold" /> @@ -66,9 +66,10 @@ + android:textStyle="bold" /> @@ -106,9 +107,10 @@ + android:textStyle="bold" /> @@ -147,9 +149,10 @@ + android:textStyle="bold" /> diff --git a/colorpickerdialog/src/main/res/values/colors.xml b/colorpickerdialog/src/main/res/values/colors.xml index 8f16ec1..ca0c5c8 100644 --- a/colorpickerdialog/src/main/res/values/colors.xml +++ b/colorpickerdialog/src/main/res/values/colors.xml @@ -13,5 +13,6 @@ #D32F2F #388E3C #1976D2 + #000000 From 510f96a4f105fcda0c5195842b0f4c571a41322c Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 22:20:28 -0500 Subject: [PATCH 08/31] finish HSB picker (#5) --- .../views/ColorPickerView.java | 2 +- .../views/HSBPickerView.java | 58 ++++++++++--------- .../src/main/res/layout/layout_hsb_picker.xml | 18 +++--- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index 8fff2cd..dbe9f36 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -67,7 +67,7 @@ private void postInit() { alphaBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - alphaInt.setText(String.format(Locale.getDefault(), "%.2f", (float) i / 255)); + alphaInt.setText(String.format(Locale.getDefault(), "%.2f", i / 255f)); onColorPicked(); } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java index b65ac35..adf3355 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java @@ -2,19 +2,22 @@ import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.Color; import android.util.AttributeSet; import android.view.animation.DecelerateInterpolator; import android.widget.SeekBar; import android.widget.TextView; +import java.util.Locale; + import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; import me.jfenn.colorpickerdialog.R; public class HSBPickerView extends ColorPickerView { - private AppCompatSeekBar red, green, blue; - private TextView redInt, greenInt, blueInt; + private AppCompatSeekBar hue, saturation, brightness; + private TextView hueInt, saturationInt, brightnessInt; private boolean isTrackingTouch; public HSBPickerView(Context context) { @@ -35,23 +38,23 @@ public HSBPickerView(Context context, AttributeSet attrs, int defStyleAttr, int @Override void init() { - inflate(getContext(), R.layout.layout_rgb_picker, this); - red = findViewById(R.id.hue); - redInt = findViewById(R.id.hueInt); - green = findViewById(R.id.brightness); - greenInt = findViewById(R.id.brightnessInt); - blue = findViewById(R.id.saturation); - blueInt = findViewById(R.id.saturationInt); + inflate(getContext(), R.layout.layout_hsb_picker, this); + hue = findViewById(R.id.hue); + hueInt = findViewById(R.id.hueInt); + saturation = findViewById(R.id.saturation); + saturationInt = findViewById(R.id.saturationInt); + brightness = findViewById(R.id.brightness); + brightnessInt = findViewById(R.id.brightnessInt); SeekBar.OnSeekBarChangeListener listener = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { - if (seekBar.getId() == R.id.red) { - redInt.setText(String.format("%s", i)); - } else if (seekBar.getId() == R.id.green) { - greenInt.setText(String.format("%s", i)); - } else if (seekBar.getId() == R.id.blue) { - blueInt.setText(String.format("%s", i)); + if (seekBar.getId() == R.id.hue) { + hueInt.setText(String.format("%s", i)); + } else if (seekBar.getId() == R.id.saturation) { + saturationInt.setText(String.format(Locale.getDefault(), "%.2f", i / 255f)); + } else if (seekBar.getId() == R.id.brightness) { + brightnessInt.setText(String.format(Locale.getDefault(), "%.2f", i / 255f)); } onColorPicked(); } @@ -67,33 +70,34 @@ public void onStopTrackingTouch(SeekBar seekBar) { } }; - red.setOnSeekBarChangeListener(listener); - green.setOnSeekBarChangeListener(listener); - blue.setOnSeekBarChangeListener(listener); + hue.setOnSeekBarChangeListener(listener); + saturation.setOnSeekBarChangeListener(listener); + brightness.setOnSeekBarChangeListener(listener); } @Override public void setColor(int color, boolean animate) { super.setColor(color, animate); - SeekBar[] bars = new SeekBar[]{red, green, blue}; - int[] offsets = new int[]{16, 8, 0}; + SeekBar[] bars = new SeekBar[]{hue, saturation, brightness}; + float[] values = new float[3]; + Color.colorToHSV(color, values); + values[1] *= 255; + values[2] *= 255; + for (int i = 0; i < bars.length; i++) { - int value = (color >> offsets[i]) & 0xFF; if (animate && !isTrackingTouch) { - ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, value); + ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, (int) values[i]); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); } else { - bars[i].setProgress(value); + bars[i].setProgress((int) values[i]); } } + } @Override public int getColor() { - return (32 << (0xFF & (int) (isAlphaEnabled() ? getAlpha() * 255 : 255))) - + (0xFF & red.getProgress()) << 16 - + (0xFF & green.getProgress()) << 8 - + (0xFF & blue.getProgress()); + return Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, brightness.getProgress() / 255f}); } } diff --git a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml index 84a4016..5906718 100644 --- a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml @@ -28,7 +28,8 @@ android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="4" - android:max="255" + android:max="360" + android:progress="0" android:theme="@style/Widget.AppCompat.SeekBar" /> + android:textStyle="bold" /> @@ -69,6 +70,7 @@ android:layout_height="match_parent" android:layout_weight="4" android:max="255" + android:progress="0" android:theme="@style/Widget.AppCompat.SeekBar" /> + android:textStyle="bold" /> @@ -109,6 +111,7 @@ android:layout_height="match_parent" android:layout_weight="4" android:max="255" + android:progress="0" android:theme="@style/Widget.AppCompat.SeekBar" /> + android:textStyle="bold" /> @@ -150,6 +153,7 @@ android:layout_height="match_parent" android:layout_weight="4" android:max="255" + android:progress="255" android:theme="@style/Widget.AppCompat.SeekBar" /> Date: Mon, 5 Nov 2018 22:57:11 -0500 Subject: [PATCH 09/31] implement new / more efficient color view --- .../dialogs/ColorPickerDialog.java | 5 +- .../utils/CanvasRenderTask.java | 45 +++++++++++ .../utils/ConversionUtils.java | 15 ++++ .../views/CircleColorView.java | 68 ++++++++++++++++ .../views/ColorPickerView.java | 37 ++++----- .../colorpickerdialog/views/ColorView.java | 61 +++++++++++++++ .../views/HSBPickerView.java | 3 +- .../views/RGBPickerView.java | 6 +- .../views/RenderableView.java | 78 +++++++++++++++++++ .../main/res/layout/dialog_color_picker.xml | 2 +- 10 files changed, 293 insertions(+), 27 deletions(-) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/CanvasRenderTask.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ConversionUtils.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleColorView.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorView.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RenderableView.java diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 38b5724..11c9e43 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -17,9 +17,11 @@ import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; import me.jfenn.colorpickerdialog.adapters.ColorPickerPagerAdapter; import me.jfenn.colorpickerdialog.views.ColorPickerView; +import me.jfenn.colorpickerdialog.views.ColorView; public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener, ColorPickerView.OnColorPickedListener { + private ColorView colorView; private TabLayout tabLayout; private ViewPager slidersPager; @@ -33,6 +35,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_color_picker); + colorView = findViewById(R.id.color); tabLayout = findViewById(R.id.tabLayout); slidersPager = findViewById(R.id.slidersPager); @@ -69,6 +72,6 @@ public void onCancel(ColorPickerDialog dialog) { @Override public void onColorPicked(int color) { - + colorView.setColor(color); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/CanvasRenderTask.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/CanvasRenderTask.java new file mode 100644 index 0000000..dec431c --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/CanvasRenderTask.java @@ -0,0 +1,45 @@ +package me.jfenn.colorpickerdialog.utils; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.os.AsyncTask; + +import java.lang.ref.WeakReference; + +import androidx.annotation.Nullable; + +public class CanvasRenderTask extends AsyncTask { + + private final WeakReference reference; + + public CanvasRenderTask(Renderable renderable) { + reference = new WeakReference<>(renderable); + } + + @Override + protected Bitmap doInBackground(Integer... integers) { + if (integers[0] == null || integers[0] < 1 || integers[1] == null || integers[1] < 1) + return null; + + Bitmap bitmap = Bitmap.createBitmap(integers[0], integers[1], Bitmap.Config.ARGB_8888); + Renderable renderable = reference.get(); + if (renderable != null) + renderable.render(new Canvas(bitmap)); + + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + Renderable renderable = reference.get(); + if (renderable != null) + renderable.onRendered(bitmap); + } + + public interface Renderable { + void render(Canvas canvas); + + void onRendered(@Nullable Bitmap bitmap); + } + +} \ No newline at end of file diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ConversionUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ConversionUtils.java new file mode 100644 index 0000000..e58d469 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ConversionUtils.java @@ -0,0 +1,15 @@ +package me.jfenn.colorpickerdialog.utils; + +import android.content.res.Resources; + +public class ConversionUtils { + + public static float getPixelsFromDp(int dp) { + return dp * Resources.getSystem().getDisplayMetrics().density; + } + + public static float getDpFromPixels(int px) { + return px / Resources.getSystem().getDisplayMetrics().density; + } + +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleColorView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleColorView.java new file mode 100644 index 0000000..13f6fca --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/CircleColorView.java @@ -0,0 +1,68 @@ +package me.jfenn.colorpickerdialog.views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.util.AttributeSet; + +import androidx.annotation.ColorInt; +import me.jfenn.colorpickerdialog.utils.ColorUtils; + +public class CircleColorView extends ColorView { + + Paint outlinePaint; + + public CircleColorView(Context context) { + super(context); + } + + public CircleColorView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CircleColorView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + void setUp() { + super.setUp(); + + outlinePaint = new Paint(); + outlinePaint.setAntiAlias(true); + outlinePaint.setDither(true); + outlinePaint.setStyle(Paint.Style.STROKE); + outlinePaint.setStrokeWidth(outlineSize); + outlinePaint.setColor(Color.BLACK); + } + + @Override + public void setColor(@ColorInt int color) { + outlinePaint.setColor(ColorUtils.isColorDark(color) ? Color.TRANSPARENT : Color.BLACK); + super.setColor(color); + } + + @Override + public void render(Canvas canvas) { + int size = Math.min(canvas.getWidth(), canvas.getHeight()); + + Path path = new Path(); + path.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, size / 2, Path.Direction.CW); + canvas.clipPath(path); + + super.render(canvas); + + canvas.drawCircle(getWidth() / 2, getHeight() / 2, (size / 2) - (outlineSize / 2), outlinePaint); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int size = getMeasuredWidth(); + setMeasuredDimension(size, size); + } + +} \ No newline at end of file diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index dbe9f36..fb442d7 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -24,9 +24,8 @@ public abstract class ColorPickerView extends LinearLayout { private OnColorPickedListener listener; - private float alpha; private TextView alphaInt; - private AppCompatSeekBar alphaBar; + private AppCompatSeekBar alpha; private View alphaLayout; private boolean isTrackingTouch; @@ -60,11 +59,11 @@ public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr, in private void postInit() { alphaInt = findViewById(R.id.alphaInt); - alphaBar = findViewById(R.id.alpha); + alpha = findViewById(R.id.alpha); alphaLayout = findViewById(R.id.alphaLayout); - if (alphaBar != null) { - alphaBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + if (alpha != null) { + alpha.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int i, boolean b) { alphaInt.setText(String.format(Locale.getDefault(), "%.2f", i / 255f)); @@ -82,7 +81,7 @@ public void onStopTrackingTouch(SeekBar seekBar) { } }); - ColorUtils.setProgressBarColor(alphaBar, ContextCompat.getColor(getContext(), R.color.neutral)); + ColorUtils.setProgressBarColor(alpha, ContextCompat.getColor(getContext(), R.color.neutral)); } } @@ -102,7 +101,7 @@ public void setColor(@ColorInt int color) { * @param animate Whether to animate changes in values. */ public void setColor(@ColorInt int color, boolean animate) { - setAlpha(((float) (int) Color.alpha(color) / 255), animate); + setColorAlpha(Color.alpha(color), animate); } /** @@ -139,13 +138,13 @@ public boolean isAlphaEnabled() { } /** - * Set the color's alpha, between 0-1 (inclusive). Change in values + * Set the color's alpha, from 0-255. Change in values * will not be animated. * - * @param alpha The color's alpha, between 0-1 (inclusive). + * @param alpha The color's alpha, from 0-255. */ - public void setAlpha(float alpha) { - setAlpha(alpha, false); + public void setColorAlpha(int alpha) { + setColorAlpha(alpha, false); } /** @@ -154,25 +153,23 @@ public void setAlpha(float alpha) { * @param alpha The color's alpha, between 0-1 (inclusive). * @param animate Whether to animate the change in values. */ - public void setAlpha(float alpha, boolean animate) { - this.alpha = alpha; - + public void setColorAlpha(int alpha, boolean animate) { if (animate && !isTrackingTouch) { - ObjectAnimator animator = ObjectAnimator.ofInt(alphaBar, "progress", 0, (int) (alpha * 255)); + ObjectAnimator animator = ObjectAnimator.ofInt(this.alpha, "progress", 0, alpha); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); } else { - alphaBar.setProgress((int) (alpha * 255)); + this.alpha.setProgress(alpha); } } /** - * Gets the color's alpha, between 0-1 (inclusive). + * Gets the color's alpha, from 0-255. * - * @return The color's alpha, between 0-1 (inclusive). + * @return The color's alpha, from 0-255. */ - public float getAlpha() { - return alpha; + public int getColorAlpha() { + return alpha.getProgress(); } protected void onColorPicked() { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorView.java new file mode 100644 index 0000000..2ff6a15 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorView.java @@ -0,0 +1,61 @@ +package me.jfenn.colorpickerdialog.views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; + +import androidx.annotation.ColorInt; +import me.jfenn.colorpickerdialog.utils.ConversionUtils; + +public class ColorView extends RenderableView { + + @ColorInt + int color = Color.BLACK; + float outlineSize; + Paint tilePaint; + + public ColorView(final Context context) { + super(context); + setUp(); + } + + public ColorView(Context context, AttributeSet attrs) { + super(context, attrs); + setUp(); + } + + public ColorView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setUp(); + } + + void setUp() { + outlineSize = ConversionUtils.getPixelsFromDp(2); + + tilePaint = new Paint(); + tilePaint.setAntiAlias(true); + tilePaint.setStyle(Paint.Style.FILL); + tilePaint.setColor(Color.LTGRAY); + } + + public void setColor(@ColorInt int color) { + this.color = color; + startRender(); + } + + @Override + public void render(Canvas canvas) { + if (Color.alpha(color) < 255) { + int outline = Math.round(outlineSize) * 4; + for (int x = 0; x < canvas.getWidth(); x += outline) { + for (int y = x % (outline * 2) == 0 ? 0 : outline; y < canvas.getWidth(); y += (outline * 2)) { + canvas.drawRect(x, y, x + outline, y + outline, tilePaint); + } + } + } + + canvas.drawColor(color); + } +} \ No newline at end of file diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java index adf3355..66061bb 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java @@ -98,6 +98,7 @@ public void setColor(int color, boolean animate) { @Override public int getColor() { - return Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, brightness.getProgress() / 255f}); + int color = Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, brightness.getProgress() / 255f}); + return (getColorAlpha() << 24) | (color & 0x00ffffff); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index 4b10a5e..98c5c37 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -2,6 +2,7 @@ import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.Color; import android.util.AttributeSet; import android.view.animation.DecelerateInterpolator; import android.widget.SeekBar; @@ -97,9 +98,6 @@ public void setColor(int color, boolean animate) { @Override public int getColor() { - return (32 << (0xFF & (int) (isAlphaEnabled() ? getAlpha() * 255 : 255))) - + (0xFF & red.getProgress()) << 16 - + (0xFF & green.getProgress()) << 8 - + (0xFF & blue.getProgress()); + return Color.argb(getColorAlpha(), red.getProgress(), green.getProgress(), blue.getProgress()); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RenderableView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RenderableView.java new file mode 100644 index 0000000..a87138f --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RenderableView.java @@ -0,0 +1,78 @@ +package me.jfenn.colorpickerdialog.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.os.AsyncTask; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.Nullable; +import me.jfenn.colorpickerdialog.utils.CanvasRenderTask; + +public abstract class RenderableView extends View implements CanvasRenderTask.Renderable { + + private Paint paint; + private Bitmap render; + private AsyncTask task; + + private int width, height; + + public RenderableView(Context context) { + super(context); + init(); + } + + public RenderableView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public RenderableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + @TargetApi(21) + public RenderableView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + void init() { + paint = new Paint(); + paint.setDither(true); + paint.setAntiAlias(true); + } + + public void startRender() { + if (task != null) + task.cancel(true); + + task = new CanvasRenderTask(this).execute(width, height); + } + + @Override + public void onRendered(@Nullable Bitmap bitmap) { + if (render != null && render != bitmap) + render.recycle(); + + task = null; + render = bitmap; + postInvalidate(); + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + width = canvas.getWidth(); + height = canvas.getHeight(); + + if (render != null) + canvas.drawBitmap(render, 0, 0, paint); + else if (task == null) + startRender(); + } +} \ No newline at end of file diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 91ed67d..242bf7e 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -17,7 +17,7 @@ android:layout_height="0dp" android:layout_weight="1"> - Date: Mon, 5 Nov 2018 23:12:09 -0500 Subject: [PATCH 10/31] update color states between pages --- .../adapters/ColorPickerPagerAdapter.java | 36 ++++++++++++++++--- .../dialogs/ColorPickerDialog.java | 6 ++-- .../views/ColorPickerView.java | 4 +-- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index 34c386c..dc6b0c0 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -7,15 +7,20 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.views.ColorPickerView; import me.jfenn.colorpickerdialog.views.HSBPickerView; import me.jfenn.colorpickerdialog.views.RGBPickerView; -public class ColorPickerPagerAdapter extends PagerAdapter { +public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPickerView.OnColorPickedListener, ViewPager.OnPageChangeListener { private Context context; private ColorPickerView.OnColorPickedListener listener; + private int color; + + private RGBPickerView rgbPicker; + private HSBPickerView hsbPicker; public ColorPickerPagerAdapter(Context context, ColorPickerView.OnColorPickedListener listener) { this.context = context; @@ -28,16 +33,17 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) { ColorPickerView view; switch (position) { case 0: - view = new RGBPickerView(context); + view = rgbPicker = new RGBPickerView(context); break; case 1: - view = new HSBPickerView(context); + view = hsbPicker = new HSBPickerView(context); break; default: return new View(context); } - view.setListener(listener); + view.setListener(this); + view.setColor(color); container.addView(view); return view; } @@ -63,4 +69,26 @@ public CharSequence getPageTitle(int position) { return context.getString(new int[]{R.string.rgb, R.string.hsb}[position]); } + @Override + public void onColorPicked(ColorPickerView pickerView, int color) { + this.color = color; + if (listener != null) + listener.onColorPicked(pickerView, color); + } + + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + if (position == 0 && rgbPicker != null) + rgbPicker.setColor(color); + if (position == 1 && hsbPicker != null) + hsbPicker.setColor(color); + } + + @Override + public void onPageScrollStateChanged(int state) { + } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 11c9e43..ddddefe 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -39,7 +39,9 @@ protected void onCreate(Bundle savedInstanceState) { tabLayout = findViewById(R.id.tabLayout); slidersPager = findViewById(R.id.slidersPager); - slidersPager.setAdapter(new ColorPickerPagerAdapter(getContext(), this)); + ColorPickerPagerAdapter adapter = new ColorPickerPagerAdapter(getContext(), this); + slidersPager.setAdapter(adapter); + slidersPager.addOnPageChangeListener(adapter); tabLayout.setupWithViewPager(slidersPager); } @@ -71,7 +73,7 @@ public void onCancel(ColorPickerDialog dialog) { } @Override - public void onColorPicked(int color) { + public void onColorPicked(ColorPickerView pickerView, int color) { colorView.setColor(color); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index fb442d7..32bc77e 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -174,7 +174,7 @@ public int getColorAlpha() { protected void onColorPicked() { if (listener != null) - listener.onColorPicked(getColor()); + listener.onColorPicked(this, getColor()); } /** @@ -189,6 +189,6 @@ public void setListener(OnColorPickedListener listener) { } public interface OnColorPickedListener { - void onColorPicked(@ColorInt int color); + void onColorPicked(ColorPickerView pickerView, @ColorInt int color); } } From d640d43be2b106e40637edba98256e4f3d331d1d Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Mon, 5 Nov 2018 23:18:54 -0500 Subject: [PATCH 11/31] remove nonfunctional buttons --- .../main/res/layout/dialog_color_picker.xml | 71 ++----------------- 1 file changed, 4 insertions(+), 67 deletions(-) diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 242bf7e..4f96ed8 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -35,71 +35,6 @@ - - - - - - - - - - - - - - - - - - - - + android:textSize="14sp" + android:textStyle="bold"/> + android:textSize="14sp" + android:textStyle="bold"/> From 4abca8018d537ebcf64e146c07b7456cd6621a63 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 10:41:44 -0500 Subject: [PATCH 12/31] added color setters / listeners --- .../adapters/ColorPickerPagerAdapter.java | 12 +++++- .../dialogs/ColorPickerDialog.java | 43 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index dc6b0c0..b9a0634 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -1,9 +1,11 @@ package me.jfenn.colorpickerdialog.adapters; import android.content.Context; +import android.graphics.Color; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.viewpager.widget.PagerAdapter; @@ -17,7 +19,9 @@ public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPicker private Context context; private ColorPickerView.OnColorPickedListener listener; - private int color; + + @ColorInt + private int color = Color.BLACK; private RGBPickerView rgbPicker; private HSBPickerView hsbPicker; @@ -27,6 +31,10 @@ public ColorPickerPagerAdapter(Context context, ColorPickerView.OnColorPickedLis this.listener = listener; } + public void setColor(@ColorInt int color) { + this.color = color; + } + @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { @@ -70,7 +78,7 @@ public CharSequence getPageTitle(int position) { } @Override - public void onColorPicked(ColorPickerView pickerView, int color) { + public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { this.color = color; if (listener != null) listener.onColorPicked(pickerView, color); diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index ddddefe..087d33c 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -3,13 +3,16 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.Color; import android.os.Bundle; import android.provider.MediaStore; +import android.view.View; import com.google.android.material.tabs.TabLayout; import java.io.IOException; +import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatDialog; import androidx.viewpager.widget.ViewPager; import me.jfenn.colorpickerdialog.ColorPicker; @@ -25,11 +28,25 @@ public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.On private TabLayout tabLayout; private ViewPager slidersPager; + @ColorInt + private int color = Color.BLACK; + private OnColorPickedListener listener; + public ColorPickerDialog(Context context) { super(context); setTitle(R.string.color_picker_name); } + public ColorPickerDialog withListener(OnColorPickedListener listener) { + this.listener = listener; + return this; + } + + public ColorPickerDialog withColor(@ColorInt int color) { + this.color = color; + return this; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -40,9 +57,28 @@ protected void onCreate(Bundle savedInstanceState) { slidersPager = findViewById(R.id.slidersPager); ColorPickerPagerAdapter adapter = new ColorPickerPagerAdapter(getContext(), this); + adapter.setColor(color); + slidersPager.setAdapter(adapter); slidersPager.addOnPageChangeListener(adapter); tabLayout.setupWithViewPager(slidersPager); + + findViewById(R.id.confirm).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listener != null) + listener.onColorPicked(ColorPickerDialog.this, color); + + dismiss(); + } + }); + + findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + } + }); } @Override @@ -73,7 +109,12 @@ public void onCancel(ColorPickerDialog dialog) { } @Override - public void onColorPicked(ColorPickerView pickerView, int color) { + public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { + this.color = color; colorView.setColor(color); } + + public interface OnColorPickedListener { + void onColorPicked(ColorPickerDialog dialog, @ColorInt int color); + } } From 7531258e6fa026fd7002eafd694171cfd4a2e2e8 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 11:33:35 -0500 Subject: [PATCH 13/31] set seekbar background gradients --- .../colorpickerdialog/utils/ColorUtils.java | 27 +++++++++ .../utils/SeekBarBackgroundDrawable.java | 56 +++++++++++++++++++ .../utils/SeekBarDrawable.java | 39 +++++++++++++ .../views/HSBPickerView.java | 43 ++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarBackgroundDrawable.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarDrawable.java diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 267b44d..bb6278a 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -2,8 +2,11 @@ import android.graphics.Color; import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatSeekBar; public class ColorUtils { @@ -24,4 +27,28 @@ public static void setProgressBarColor(AppCompatSeekBar seekbar, @ColorInt int c seekbar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN); } + public static void setProgressBarDrawable(AppCompatSeekBar seekbar, @NonNull Drawable drawable) { + Drawable background = new SeekBarBackgroundDrawable(drawable.mutate().getConstantState().newDrawable()); + background.setAlpha(127); + + LayerDrawable layers = new LayerDrawable(new Drawable[]{ + new SeekBarDrawable(drawable), + background + }); + + layers.setId(0, android.R.id.progress); + layers.setId(1, android.R.id.background); + seekbar.setProgressDrawable(layers); + + seekbar.getThumb().setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + } + + public static int[] getColorWheelArr() { + int[] arr = new int[36]; + for (int i = 0; i < 36; i++) + arr[i] = Color.HSVToColor(new float[]{i * 10, 0.7f, 0.9f}); + + return arr; + } + } \ No newline at end of file diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarBackgroundDrawable.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarBackgroundDrawable.java new file mode 100644 index 0000000..121b86f --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarBackgroundDrawable.java @@ -0,0 +1,56 @@ +package me.jfenn.colorpickerdialog.utils; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class SeekBarBackgroundDrawable extends Drawable { + + private Drawable drawable; + private float height; + private Paint paint; + + public SeekBarBackgroundDrawable(Drawable drawable) { + this.drawable = drawable; + height = ConversionUtils.getPixelsFromDp(2); + paint = new Paint(); + } + + @Override + public void draw(@NonNull Canvas canvas) { + Bitmap bitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.RGB_565); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(new Canvas(bitmap)); + + Rect bounds = getBounds(); + canvas.clipRect(new Rect( + bounds.left, + (int) (bounds.centerY() - height / 2), + bounds.right, + (int) (bounds.centerY() + height / 2) + )); + + canvas.drawBitmap(bitmap, 0, 0, paint); + } + + @Override + public void setAlpha(int alpha) { + paint.setAlpha(alpha); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarDrawable.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarDrawable.java new file mode 100644 index 0000000..baf0c0a --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/SeekBarDrawable.java @@ -0,0 +1,39 @@ +package me.jfenn.colorpickerdialog.utils; + +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.Drawable; +import android.view.Gravity; + +public class SeekBarDrawable extends ClipDrawable { + + private float height; + private Rect rect; + + public SeekBarDrawable(Drawable drawable) { + super(drawable, Gravity.START, ClipDrawable.HORIZONTAL); + height = ConversionUtils.getPixelsFromDp(2); + } + + @Override + public void draw(Canvas canvas) { + if (rect == null) { + Rect bounds = getBounds(); + setBounds(rect = new Rect( + bounds.left, + (int) (bounds.centerY() - height / 2), + bounds.right, + (int) (bounds.centerY() + height / 2) + )); + } + + super.draw(canvas); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java index 66061bb..72e251f 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java @@ -3,6 +3,7 @@ import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Color; +import android.graphics.drawable.GradientDrawable; import android.util.AttributeSet; import android.view.animation.DecelerateInterpolator; import android.widget.SeekBar; @@ -13,6 +14,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; import me.jfenn.colorpickerdialog.R; +import me.jfenn.colorpickerdialog.utils.ColorUtils; public class HSBPickerView extends ColorPickerView { @@ -73,6 +75,11 @@ public void onStopTrackingTouch(SeekBar seekBar) { hue.setOnSeekBarChangeListener(listener); saturation.setOnSeekBarChangeListener(listener); brightness.setOnSeekBarChangeListener(listener); + + ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + ColorUtils.getColorWheelArr() + )); } @Override @@ -94,6 +101,21 @@ public void setColor(int color, boolean animate) { } } + ColorUtils.setProgressBarDrawable(saturation, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + new int[]{ + Color.HSVToColor(new float[]{hue.getProgress(), 0, brightness.getProgress() / 255f}), + Color.HSVToColor(new float[]{hue.getProgress(), 1, brightness.getProgress() / 255f}) + } + )); + + ColorUtils.setProgressBarDrawable(brightness, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + new int[]{ + Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 0}), + Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 1}) + } + )); } @Override @@ -101,4 +123,25 @@ public int getColor() { int color = Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, brightness.getProgress() / 255f}); return (getColorAlpha() << 24) | (color & 0x00ffffff); } + + @Override + protected void onColorPicked() { + super.onColorPicked(); + + ColorUtils.setProgressBarDrawable(saturation, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + new int[]{ + Color.HSVToColor(new float[]{hue.getProgress(), 0, brightness.getProgress() / 255f}), + Color.HSVToColor(new float[]{hue.getProgress(), 1, brightness.getProgress() / 255f}) + } + )); + + ColorUtils.setProgressBarDrawable(brightness, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + new int[]{ + Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 0}), + Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 1}) + } + )); + } } From 84d5133234d38579e3dfe3ebad59cd5814b8d4ef Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 13:36:33 -0500 Subject: [PATCH 14/31] make color stuff do the thing --- .../jfenn/colorpickerdialog/utils/ColorUtils.java | 4 ++-- .../colorpickerdialog/views/HSBPickerView.java | 15 ++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index bb6278a..387b82d 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -43,10 +43,10 @@ public static void setProgressBarDrawable(AppCompatSeekBar seekbar, @NonNull Dra seekbar.getThumb().setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); } - public static int[] getColorWheelArr() { + public static int[] getColorWheelArr(float saturation, float brightness) { int[] arr = new int[36]; for (int i = 0; i < 36; i++) - arr[i] = Color.HSVToColor(new float[]{i * 10, 0.7f, 0.9f}); + arr[i] = Color.HSVToColor(new float[]{i * 10, saturation, brightness}); return arr; } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java index 72e251f..878ce1a 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java @@ -75,11 +75,6 @@ public void onStopTrackingTouch(SeekBar seekBar) { hue.setOnSeekBarChangeListener(listener); saturation.setOnSeekBarChangeListener(listener); brightness.setOnSeekBarChangeListener(listener); - - ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, - ColorUtils.getColorWheelArr() - )); } @Override @@ -101,6 +96,11 @@ public void setColor(int color, boolean animate) { } } + ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + ColorUtils.getColorWheelArr(saturation.getProgress() / 255f, brightness.getProgress() / 255f) + )); + ColorUtils.setProgressBarDrawable(saturation, new GradientDrawable( GradientDrawable.Orientation.LEFT_RIGHT, new int[]{ @@ -128,6 +128,11 @@ public int getColor() { protected void onColorPicked() { super.onColorPicked(); + ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, + ColorUtils.getColorWheelArr(saturation.getProgress() / 255f, brightness.getProgress() / 255f) + )); + ColorUtils.setProgressBarDrawable(saturation, new GradientDrawable( GradientDrawable.Orientation.LEFT_RIGHT, new int[]{ From 83e6950f6fcc5fc7cb21d29be30992d669b87871 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 15:43:35 -0500 Subject: [PATCH 15/31] refactor HSB to HSV, random other improvements --- .../adapters/ColorPickerPagerAdapter.java | 8 ++--- ...{HSBPickerView.java => HSVPickerView.java} | 36 ++++++------------- .../views/RGBPickerView.java | 2 +- ...t_hsb_picker.xml => layout_hsv_picker.xml} | 13 ++++--- .../src/main/res/layout/layout_rgb_picker.xml | 8 ++--- .../src/main/res/values/strings.xml | 4 +-- 6 files changed, 27 insertions(+), 44 deletions(-) rename colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/{HSBPickerView.java => HSVPickerView.java} (76%) rename colorpickerdialog/src/main/res/layout/{layout_hsb_picker.xml => layout_hsv_picker.xml} (95%) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index b9a0634..cb46327 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -12,7 +12,7 @@ import androidx.viewpager.widget.ViewPager; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.views.ColorPickerView; -import me.jfenn.colorpickerdialog.views.HSBPickerView; +import me.jfenn.colorpickerdialog.views.HSVPickerView; import me.jfenn.colorpickerdialog.views.RGBPickerView; public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPickerView.OnColorPickedListener, ViewPager.OnPageChangeListener { @@ -24,7 +24,7 @@ public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPicker private int color = Color.BLACK; private RGBPickerView rgbPicker; - private HSBPickerView hsbPicker; + private HSVPickerView hsbPicker; public ColorPickerPagerAdapter(Context context, ColorPickerView.OnColorPickedListener listener) { this.context = context; @@ -44,7 +44,7 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) { view = rgbPicker = new RGBPickerView(context); break; case 1: - view = hsbPicker = new HSBPickerView(context); + view = hsbPicker = new HSVPickerView(context); break; default: return new View(context); @@ -74,7 +74,7 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { @Nullable @Override public CharSequence getPageTitle(int position) { - return context.getString(new int[]{R.string.rgb, R.string.hsb}[position]); + return context.getString(new int[]{R.string.rgb, R.string.hsv}[position]); } @Override diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java similarity index 76% rename from colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java rename to colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java index 878ce1a..a7e8200 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java @@ -16,31 +16,31 @@ import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.utils.ColorUtils; -public class HSBPickerView extends ColorPickerView { +public class HSVPickerView extends ColorPickerView { private AppCompatSeekBar hue, saturation, brightness; private TextView hueInt, saturationInt, brightnessInt; private boolean isTrackingTouch; - public HSBPickerView(Context context) { + public HSVPickerView(Context context) { super(context); } - public HSBPickerView(Context context, @Nullable AttributeSet attrs) { + public HSVPickerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } - public HSBPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + public HSVPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } - public HSBPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public HSVPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override void init() { - inflate(getContext(), R.layout.layout_hsb_picker, this); + inflate(getContext(), R.layout.layout_hsv_picker, this); hue = findViewById(R.id.hue); hueInt = findViewById(R.id.hueInt); saturation = findViewById(R.id.saturation); @@ -96,26 +96,7 @@ public void setColor(int color, boolean animate) { } } - ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, - ColorUtils.getColorWheelArr(saturation.getProgress() / 255f, brightness.getProgress() / 255f) - )); - - ColorUtils.setProgressBarDrawable(saturation, new GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, - new int[]{ - Color.HSVToColor(new float[]{hue.getProgress(), 0, brightness.getProgress() / 255f}), - Color.HSVToColor(new float[]{hue.getProgress(), 1, brightness.getProgress() / 255f}) - } - )); - - ColorUtils.setProgressBarDrawable(brightness, new GradientDrawable( - GradientDrawable.Orientation.LEFT_RIGHT, - new int[]{ - Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 0}), - Color.HSVToColor(new float[]{hue.getProgress(), saturation.getProgress() / 255f, 1}) - } - )); + updateProgressBars(); } @Override @@ -127,7 +108,10 @@ public int getColor() { @Override protected void onColorPicked() { super.onColorPicked(); + updateProgressBars(); + } + private void updateProgressBars() { ColorUtils.setProgressBarDrawable(hue, new GradientDrawable( GradientDrawable.Orientation.LEFT_RIGHT, ColorUtils.getColorWheelArr(saturation.getProgress() / 255f, brightness.getProgress() / 255f) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index 98c5c37..17ccfbd 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -98,6 +98,6 @@ public void setColor(int color, boolean animate) { @Override public int getColor() { - return Color.argb(getColorAlpha(), red.getProgress(), green.getProgress(), blue.getProgress()); + return Color.argb(getColorAlpha(), red.getProgress(), green.getProgress(), blue.getProgress()); } } diff --git a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml similarity index 95% rename from colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml rename to colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml index 5906718..376750b 100644 --- a/colorpickerdialog/src/main/res/layout/layout_hsb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml @@ -1,6 +1,5 @@ @@ -50,7 +49,7 @@ @@ -91,7 +90,7 @@ @@ -133,7 +132,7 @@ @@ -164,11 +163,11 @@ android:ellipsize="none" android:gravity="end" android:singleLine="true" + android:text="1.0" android:textAllCaps="true" android:textColor="@color/textColorSecondary" android:textSize="14sp" - android:textStyle="bold" - tools:text="1.0" /> + android:textStyle="bold" /> diff --git a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml index be02a53..13ae1a5 100644 --- a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml @@ -8,7 +8,7 @@ @@ -49,7 +49,7 @@ @@ -90,7 +90,7 @@ @@ -132,7 +132,7 @@ diff --git a/colorpickerdialog/src/main/res/values/strings.xml b/colorpickerdialog/src/main/res/values/strings.xml index 35a2356..d940909 100644 --- a/colorpickerdialog/src/main/res/values/strings.xml +++ b/colorpickerdialog/src/main/res/values/strings.xml @@ -12,7 +12,7 @@ A H S - B + V RGB - HSB + HSV From 7d283c986f4fa2f17cb3a3fb2af5e69b3e0b6a40 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 16:44:07 -0500 Subject: [PATCH 16/31] Update README.md --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c52e699..9c9c5b1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ColorPickerDialog is a simple dialog making it quick and easy to add a color picker functionality to any app. +[![](https://jitpack.io/v/me.jfenn/ColorPickerDialog.svg)](https://jitpack.io/#me.jfenn/ColorPickerDialog) + For testing and experimentation purposes, a sample apk can be downloaded [here](https://jfenn.me/projects/colorpickerdialog). |Color Picker|Image Color Picker| @@ -10,9 +12,21 @@ For testing and experimentation purposes, a sample apk can be downloaded [here]( ### Setup -The Gradle dependency is available through jCenter, which is used by default in Android Studio. To add the module to your project, copy this line into the dependencies section of your build.gradle file. +This project is published on [JitPack](https://jitpack.io), which you can add to your project by copying the following to your root build.gradle at the end of "repositories". + +```gradle +allprojects { + repositories { + ... + maven { url 'https://jitpack.io' } + } +} +``` + +To add the dependency, copy this line into your app module's build.gradle file. + ``` gradle -compile 'james.colorpickerdialog:colorpickerdialog:0.0.4' +implementation 'me.jfenn:ColorPickerDialog:1.2.0' ``` ### Creating a Dialog From 757527dd69c94fae57fcb85b308f45222084f13f Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 17:42:40 -0500 Subject: [PATCH 17/31] fixed tabs --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c9c5b1..b021ddb 100644 --- a/README.md +++ b/README.md @@ -16,10 +16,10 @@ This project is published on [JitPack](https://jitpack.io), which you can add to ```gradle allprojects { - repositories { - ... - maven { url 'https://jitpack.io' } - } + repositories { + ... + maven { url 'https://jitpack.io' } + } } ``` From 023a7254827baf3de0dcdd55697449261cdb2231 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Tue, 6 Nov 2018 23:12:20 -0500 Subject: [PATCH 18/31] smoother / faster color preview updates --- .../dialogs/ColorPickerDialog.java | 4 +- .../utils/AlphaColorDrawable.java | 79 +++++++++++++++++++ .../views/SmoothColorView.java | 68 ++++++++++++++++ .../main/res/layout/dialog_color_picker.xml | 10 +-- 4 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java create mode 100644 colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 087d33c..a3c6f08 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -20,11 +20,11 @@ import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; import me.jfenn.colorpickerdialog.adapters.ColorPickerPagerAdapter; import me.jfenn.colorpickerdialog.views.ColorPickerView; -import me.jfenn.colorpickerdialog.views.ColorView; +import me.jfenn.colorpickerdialog.views.SmoothColorView; public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener, ColorPickerView.OnColorPickedListener { - private ColorView colorView; + private SmoothColorView colorView; private TabLayout tabLayout; private ViewPager slidersPager; diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java new file mode 100644 index 0000000..25c7845 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java @@ -0,0 +1,79 @@ +package me.jfenn.colorpickerdialog.utils; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.ColorUtils; + +public class AlphaColorDrawable extends Drawable { + + private Paint bitmapPaint; + private Paint paint; + private Bitmap tile; + + public AlphaColorDrawable(@ColorInt int color) { + this(color, null); + } + + public AlphaColorDrawable(@ColorInt int color, @Nullable AlphaColorDrawable drawable) { + int size = (int) ConversionUtils.getPixelsFromDp(8); + bitmapPaint = new Paint(); + bitmapPaint.setColor(Color.LTGRAY); + + if (drawable != null) + tile = drawable.tile; + else { + tile = Bitmap.createBitmap(size * 4, size * 4, Bitmap.Config.RGB_565); + Canvas canvas = new Canvas(tile); + canvas.drawColor(Color.WHITE); + for (int x = 0; x < canvas.getWidth(); x += size) { + for (int y = x % (size * 2) == 0 ? 0 : size; y < canvas.getWidth(); y += size * 2) { + canvas.drawRect(x, y, x + size, y + size, bitmapPaint); + } + } + } + + paint = new Paint(); + paint.setColor(color); + } + + + + @Override + public void draw(@NonNull Canvas canvas) { + Rect b = getBounds(); + + if (paint.getAlpha() < 255) { + for (int x = b.left; x < b.right; x += tile.getWidth()) { + for (int y = b.top; y < b.bottom; y += tile.getHeight()) { + canvas.drawBitmap(tile, x, y, bitmapPaint); + } + } + } + + canvas.drawRect(b.left, b.top, b.right, b.bottom, paint); + } + + @Override + public void setAlpha(int alpha) { + bitmapPaint.setColor(ColorUtils.setAlphaComponent(bitmapPaint.getColor(), alpha)); + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java new file mode 100644 index 0000000..d3b34b3 --- /dev/null +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java @@ -0,0 +1,68 @@ +package me.jfenn.colorpickerdialog.views; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.TransitionDrawable; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.ColorInt; +import androidx.annotation.Nullable; +import me.jfenn.colorpickerdialog.utils.AlphaColorDrawable; + +public class SmoothColorView extends View { + + private AlphaColorDrawable previous; + + public SmoothColorView(Context context) { + super(context); + init(); + } + + public SmoothColorView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public SmoothColorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + @TargetApi(21) + public SmoothColorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(); + } + + private void init() { + previous = new AlphaColorDrawable(Color.BLACK); + setBackground(previous); + } + + public void setColor(@ColorInt int color) { + setColor(color, false); + } + + public void setColor(@ColorInt int color, boolean animate) { + AlphaColorDrawable current = new AlphaColorDrawable(color, previous); + + if (previous != null && animate) { + TransitionDrawable transition = new TransitionDrawable(new Drawable[]{previous, current}); + setBackground(transition); + transition.startTransition(100); + } else setBackground(current); + + previous = current; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int height = (int) (getMeasuredWidth() * 0.5625); + setMeasuredDimension(getMeasuredWidth(), height); + } +} diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 4f96ed8..6253940 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -14,16 +14,12 @@ + android:layout_height="wrap_content"> - + android:layout_height="wrap_content" /> Date: Tue, 6 Nov 2018 23:41:20 -0500 Subject: [PATCH 19/31] set input hex code / text color --- .../colorpickerdialog/dialogs/ColorPickerDialog.java | 10 ++++++++++ .../me/jfenn/colorpickerdialog/utils/ColorUtils.java | 10 ++++++++++ .../src/main/res/layout/dialog_color_picker.xml | 1 + 3 files changed, 21 insertions(+) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index a3c6f08..ae5ddaa 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -7,6 +7,7 @@ import android.os.Bundle; import android.provider.MediaStore; import android.view.View; +import android.widget.EditText; import com.google.android.material.tabs.TabLayout; @@ -19,17 +20,21 @@ import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; import me.jfenn.colorpickerdialog.adapters.ColorPickerPagerAdapter; +import me.jfenn.colorpickerdialog.utils.ColorUtils; import me.jfenn.colorpickerdialog.views.ColorPickerView; import me.jfenn.colorpickerdialog.views.SmoothColorView; public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener, ColorPickerView.OnColorPickedListener { private SmoothColorView colorView; + private EditText colorHex; private TabLayout tabLayout; private ViewPager slidersPager; @ColorInt private int color = Color.BLACK; + private boolean isAlphaEnabled = true; + private OnColorPickedListener listener; public ColorPickerDialog(Context context) { @@ -53,6 +58,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.dialog_color_picker); colorView = findViewById(R.id.color); + colorHex = findViewById(R.id.colorHex); tabLayout = findViewById(R.id.tabLayout); slidersPager = findViewById(R.id.slidersPager); @@ -79,6 +85,8 @@ public void onClick(View v) { dismiss(); } }); + + onColorPicked(null, color); } @Override @@ -112,6 +120,8 @@ public void onCancel(ColorPickerDialog dialog) { public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { this.color = color; colorView.setColor(color); + colorHex.setText(String.format(isAlphaEnabled ? "#%08X" : "#%06X", isAlphaEnabled ? color : (0xFFFFFF & color))); + colorHex.setTextColor(ColorUtils.isColorDark(ColorUtils.withBackground(color, Color.WHITE)) ? Color.WHITE : Color.BLACK); } public interface OnColorPickedListener { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 387b82d..64a7a46 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -22,6 +22,16 @@ private static double getColorDarkness(@ColorInt int color) { (color)) / 255); } + @ColorInt + public static int withBackground(@ColorInt int color, @ColorInt int background) { + float alpha = Color.alpha(color) / 255f; + return Color.rgb( + (int) ((Color.red(color) * alpha) + (Color.red(background) * (1 - alpha))), + (int) ((Color.green(color) * alpha) + (Color.green(background) * (1 - alpha))), + (int) ((Color.blue(color) * alpha) + (Color.blue(background) * (1 - alpha))) + ); + } + public static void setProgressBarColor(AppCompatSeekBar seekbar, @ColorInt int color) { seekbar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN); seekbar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN); diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 6253940..f95c715 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -27,6 +27,7 @@ android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@android:color/white" + android:textCursorDrawable="@null" android:textSize="24sp" /> From a67ec1eae1b06fa9443ffbdd99291f33d2e918cb Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 20:37:15 -0500 Subject: [PATCH 20/31] improved darkness detection accuracy --- .../colorpickerdialog/dialogs/ColorPickerDialog.java | 12 +++++++++--- .../me/jfenn/colorpickerdialog/utils/ColorUtils.java | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index ae5ddaa..e5d7e78 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -2,12 +2,13 @@ import android.content.Context; import android.content.Intent; +import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.Color; +import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; import android.view.View; -import android.widget.EditText; import com.google.android.material.tabs.TabLayout; @@ -15,6 +16,7 @@ import androidx.annotation.ColorInt; import androidx.appcompat.app.AppCompatDialog; +import androidx.appcompat.widget.AppCompatEditText; import androidx.viewpager.widget.ViewPager; import me.jfenn.colorpickerdialog.ColorPicker; import me.jfenn.colorpickerdialog.R; @@ -27,7 +29,7 @@ public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.OnActivityResultListener, ColorPickerView.OnColorPickedListener { private SmoothColorView colorView; - private EditText colorHex; + private AppCompatEditText colorHex; private TabLayout tabLayout; private ViewPager slidersPager; @@ -121,7 +123,11 @@ public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { this.color = color; colorView.setColor(color); colorHex.setText(String.format(isAlphaEnabled ? "#%08X" : "#%06X", isAlphaEnabled ? color : (0xFFFFFF & color))); - colorHex.setTextColor(ColorUtils.isColorDark(ColorUtils.withBackground(color, Color.WHITE)) ? Color.WHITE : Color.BLACK); + + int textColor = ColorUtils.isColorDark(ColorUtils.withBackground(color, Color.WHITE)) ? Color.WHITE : Color.BLACK; + colorHex.setTextColor(textColor); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + colorHex.setBackgroundTintList(ColorStateList.valueOf(textColor)); } public interface OnColorPickedListener { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 64a7a46..2a05cc5 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -18,8 +18,7 @@ public static boolean isColorDark(@ColorInt int color) { private static double getColorDarkness(@ColorInt int color) { if (color == Color.BLACK) return 1.0; else if (color == Color.WHITE || color == Color.TRANSPARENT) return 0.0; - return (1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue - (color)) / 255); + return (1 - (0.259 * Color.red(color) + 0.667 * Color.green(color) + 0.074 * Color.blue(color)) / 255); } @ColorInt From 0f9df07c8bf5a9c10ffdad59c5611834351b4540 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 21:06:40 -0500 Subject: [PATCH 21/31] implement proper hex editing / animations --- .../adapters/ColorPickerPagerAdapter.java | 9 +++++ .../dialogs/ColorPickerDialog.java | 40 +++++++++++++++++-- .../views/ColorPickerView.java | 2 +- .../views/HSVPickerView.java | 2 +- .../views/RGBPickerView.java | 2 +- 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index cb46327..b32b4d0 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -22,6 +22,7 @@ public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPicker @ColorInt private int color = Color.BLACK; + private int position; private RGBPickerView rgbPicker; private HSVPickerView hsbPicker; @@ -35,6 +36,13 @@ public void setColor(@ColorInt int color) { this.color = color; } + public void updateColor(@ColorInt int color, boolean animate) { + if (position == 0 && rgbPicker != null) + rgbPicker.setColor(color, animate); + if (position == 1 && hsbPicker != null) + hsbPicker.setColor(color, animate); + } + @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { @@ -90,6 +98,7 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse @Override public void onPageSelected(int position) { + this.position = position; if (position == 0 && rgbPicker != null) rgbPicker.setColor(color); if (position == 1 && hsbPicker != null) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index e5d7e78..ed5bf52 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -8,6 +8,9 @@ import android.os.Build; import android.os.Bundle; import android.provider.MediaStore; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; import android.view.View; import com.google.android.material.tabs.TabLayout; @@ -32,10 +35,12 @@ public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.On private AppCompatEditText colorHex; private TabLayout tabLayout; private ViewPager slidersPager; + private ColorPickerPagerAdapter slidersAdapter; @ColorInt private int color = Color.BLACK; private boolean isAlphaEnabled = true; + private boolean shouldIgnoreNextHex = false; private OnColorPickedListener listener; @@ -64,13 +69,38 @@ protected void onCreate(Bundle savedInstanceState) { tabLayout = findViewById(R.id.tabLayout); slidersPager = findViewById(R.id.slidersPager); - ColorPickerPagerAdapter adapter = new ColorPickerPagerAdapter(getContext(), this); - adapter.setColor(color); + slidersAdapter = new ColorPickerPagerAdapter(getContext(), this); + slidersAdapter.setColor(color); - slidersPager.setAdapter(adapter); - slidersPager.addOnPageChangeListener(adapter); + slidersPager.setAdapter(slidersAdapter); + slidersPager.addOnPageChangeListener(slidersAdapter); tabLayout.setupWithViewPager(slidersPager); + colorHex.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + Editable editable = colorHex.getText(); + if (editable != null && !shouldIgnoreNextHex) { + String str = editable.toString(); + Log.d("TextChange", str); + if (str.length() == (isAlphaEnabled ? 9 : 7)) { + try { + slidersAdapter.updateColor(Color.parseColor(str), true); + } catch (Exception ignored) { + } + } + } else shouldIgnoreNextHex = false; + } + }); + findViewById(R.id.confirm).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -122,6 +152,8 @@ public void onCancel(ColorPickerDialog dialog) { public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { this.color = color; colorView.setColor(color); + + shouldIgnoreNextHex = true; colorHex.setText(String.format(isAlphaEnabled ? "#%08X" : "#%06X", isAlphaEnabled ? color : (0xFFFFFF & color))); int textColor = ColorUtils.isColorDark(ColorUtils.withBackground(color, Color.WHITE)) ? Color.WHITE : Color.BLACK; diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index 32bc77e..c19e825 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -155,7 +155,7 @@ public void setColorAlpha(int alpha) { */ public void setColorAlpha(int alpha, boolean animate) { if (animate && !isTrackingTouch) { - ObjectAnimator animator = ObjectAnimator.ofInt(this.alpha, "progress", 0, alpha); + ObjectAnimator animator = ObjectAnimator.ofInt(this.alpha, "progress", alpha); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); } else { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java index a7e8200..238a837 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/HSVPickerView.java @@ -88,7 +88,7 @@ public void setColor(int color, boolean animate) { for (int i = 0; i < bars.length; i++) { if (animate && !isTrackingTouch) { - ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, (int) values[i]); + ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", (int) values[i]); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); } else { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index 17ccfbd..42ecfc2 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -87,7 +87,7 @@ public void setColor(int color, boolean animate) { for (int i = 0; i < bars.length; i++) { int value = (color >> offsets[i]) & 0xFF; if (animate && !isTrackingTouch) { - ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", 0, value); + ObjectAnimator animator = ObjectAnimator.ofInt(bars[i], "progress", value); animator.setInterpolator(new DecelerateInterpolator()); animator.start(); } else { From dc90552b74d6d1998a4edd202bd956ae78669b0f Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 21:23:21 -0500 Subject: [PATCH 22/31] corrected input options and stuff --- .../colorpickerdialogsample/MainActivity.java | 20 +++++++---- app/src/main/res/layout/activity_main.xml | 36 +++++-------------- .../src/main/AndroidManifest.xml | 7 ++-- .../dialogs/ColorPickerDialog.java | 6 ++++ .../main/res/layout/dialog_color_picker.xml | 31 ++++++++++------ 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java index b58a895..4c7eed7 100644 --- a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java @@ -9,22 +9,28 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListener { - private int preference = Color.BLUE; + private int color = Color.BLUE; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - findViewById(R.id.defaultAndImage).setOnClickListener(this); - findViewById(R.id.noDefaultAndImage).setOnClickListener(this); - findViewById(R.id.defaultAndNoImage).setOnClickListener(this); - findViewById(R.id.noDefaultAndNoImage).setOnClickListener(this); + findViewById(R.id.normal).setOnClickListener(this); + findViewById(R.id.normalAlpha).setOnClickListener(this); } @Override public void onClick(View v) { - ColorPickerDialog dialog = new ColorPickerDialog(this); - dialog.show(); + new ColorPickerDialog(this) + .withColor(color) + .withAlphaEnabled(v.getId() == R.id.normalAlpha) + .withListener(new ColorPickerDialog.OnColorPickedListener() { + @Override + public void onColorPicked(ColorPickerDialog dialog, int color) { + MainActivity.this.color = color; + } + }) + .show(); } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 264878d..2fd287e 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,38 +1,20 @@ - + android:layout_height="match_parent" + android:orientation="vertical" + android:gravity="center"> + android:id="@+id/normal" /> + android:id="@+id/normalAlpha" /> - - - - - + diff --git a/colorpickerdialog/src/main/AndroidManifest.xml b/colorpickerdialog/src/main/AndroidManifest.xml index 692e156..246aea6 100644 --- a/colorpickerdialog/src/main/AndroidManifest.xml +++ b/colorpickerdialog/src/main/AndroidManifest.xml @@ -1,13 +1,12 @@ - + - + diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index ed5bf52..d06c142 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -59,6 +59,11 @@ public ColorPickerDialog withColor(@ColorInt int color) { return this; } + public ColorPickerDialog withAlphaEnabled(boolean isAlphaEnabled) { + this.isAlphaEnabled = isAlphaEnabled; + return this; + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -155,6 +160,7 @@ public void onColorPicked(ColorPickerView pickerView, @ColorInt int color) { shouldIgnoreNextHex = true; colorHex.setText(String.format(isAlphaEnabled ? "#%08X" : "#%06X", isAlphaEnabled ? color : (0xFFFFFF & color))); + colorHex.clearFocus(); int textColor = ColorUtils.isColorDark(ColorUtils.withBackground(color, Color.WHITE)) ? Color.WHITE : Color.BLACK; colorHex.setTextColor(textColor); diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index f95c715..8337c7f 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -1,6 +1,7 @@ @@ -8,8 +9,8 @@ + android:textSize="24sp" + tools:text="#000000" /> @@ -38,7 +47,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" app:tabIndicatorHeight="0dp" - app:tabMode="scrollable"/> + app:tabMode="scrollable" /> + android:textStyle="bold" /> + android:textStyle="bold" /> From 6a0f4ade7faeff67208343c73ec34e4508f04457 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 22:05:36 -0500 Subject: [PATCH 23/31] moved to static tile bitmap - performance improvements --- .../me/jfenn/colorpickerdialogsample/MainActivity.java | 2 ++ .../colorpickerdialog/dialogs/ColorPickerDialog.java | 7 +++++++ .../colorpickerdialog/utils/AlphaColorDrawable.java | 10 ++-------- .../me/jfenn/colorpickerdialog/utils/ColorUtils.java | 6 +++--- .../jfenn/colorpickerdialog/views/SmoothColorView.java | 2 +- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java index 4c7eed7..5c200d7 100644 --- a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java @@ -3,6 +3,7 @@ import android.graphics.Color; import android.os.Bundle; import android.view.View; +import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import me.jfenn.colorpickerdialog.dialogs.ColorPickerDialog; @@ -29,6 +30,7 @@ public void onClick(View v) { @Override public void onColorPicked(ColorPickerDialog dialog, int color) { MainActivity.this.color = color; + Toast.makeText(MainActivity.this, String.format("#%08X", color), Toast.LENGTH_SHORT).show(); } }) .show(); diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index d06c142..87b5850 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -25,6 +25,7 @@ import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.activities.ImagePickerActivity; import me.jfenn.colorpickerdialog.adapters.ColorPickerPagerAdapter; +import me.jfenn.colorpickerdialog.utils.AlphaColorDrawable; import me.jfenn.colorpickerdialog.utils.ColorUtils; import me.jfenn.colorpickerdialog.views.ColorPickerView; import me.jfenn.colorpickerdialog.views.SmoothColorView; @@ -126,6 +127,12 @@ public void onClick(View v) { onColorPicked(null, color); } + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + AlphaColorDrawable.tile.recycle(); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { Bitmap bitmap = null; diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java index 25c7845..4aa8ff4 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/AlphaColorDrawable.java @@ -18,20 +18,14 @@ public class AlphaColorDrawable extends Drawable { private Paint bitmapPaint; private Paint paint; - private Bitmap tile; + public static Bitmap tile; public AlphaColorDrawable(@ColorInt int color) { - this(color, null); - } - - public AlphaColorDrawable(@ColorInt int color, @Nullable AlphaColorDrawable drawable) { int size = (int) ConversionUtils.getPixelsFromDp(8); bitmapPaint = new Paint(); bitmapPaint.setColor(Color.LTGRAY); - if (drawable != null) - tile = drawable.tile; - else { + if (tile == null || tile.isRecycled()) { tile = Bitmap.createBitmap(size * 4, size * 4, Bitmap.Config.RGB_565); Canvas canvas = new Canvas(tile); canvas.drawColor(Color.WHITE); diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 2a05cc5..9750e8e 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -53,9 +53,9 @@ public static void setProgressBarDrawable(AppCompatSeekBar seekbar, @NonNull Dra } public static int[] getColorWheelArr(float saturation, float brightness) { - int[] arr = new int[36]; - for (int i = 0; i < 36; i++) - arr[i] = Color.HSVToColor(new float[]{i * 10, saturation, brightness}); + int[] arr = new int[13]; + for (int i = 0; i <= 12; i++) + arr[i] = Color.HSVToColor(new float[]{i * 30, saturation, brightness}); return arr; } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java index d3b34b3..5d4d0a9 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/SmoothColorView.java @@ -47,7 +47,7 @@ public void setColor(@ColorInt int color) { } public void setColor(@ColorInt int color, boolean animate) { - AlphaColorDrawable current = new AlphaColorDrawable(color, previous); + AlphaColorDrawable current = new AlphaColorDrawable(color); if (previous != null && animate) { TransitionDrawable transition = new TransitionDrawable(new Drawable[]{previous, current}); From ad7fa9eb796219c0a56698aa07371df5adce4085 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 22:33:24 -0500 Subject: [PATCH 24/31] enabled basic theming --- .../colorpickerdialogsample/MainActivity.java | 5 ++-- app/src/main/res/layout/activity_main.xml | 6 ++++ app/src/main/res/values/styles.xml | 4 +++ .../adapters/ColorPickerPagerAdapter.java | 2 +- .../dialogs/ColorPickerDialog.java | 8 +++++- .../dialogs/ImageColorPickerDialog.java | 2 +- .../views/ColorPickerView.java | 2 +- .../views/RGBPickerView.java | 6 ++-- .../src/main/res/drawable/ic_image.xml | 9 ------ .../src/main/res/drawable/ic_reset.xml | 9 ------ .../main/res/layout/dialog_color_picker.xml | 4 +-- .../res/layout/dialog_image_color_picker.xml | 4 +-- .../src/main/res/layout/layout_hsv_picker.xml | 24 ++++++++-------- .../src/main/res/layout/layout_rgb_picker.xml | 24 ++++++++-------- .../src/main/res/values/colors.xml | 16 +++-------- .../src/main/res/values/strings.xml | 28 +++++++++---------- .../src/main/res/values/styles.xml | 6 ---- 17 files changed, 72 insertions(+), 87 deletions(-) delete mode 100644 colorpickerdialog/src/main/res/drawable/ic_image.xml delete mode 100644 colorpickerdialog/src/main/res/drawable/ic_reset.xml delete mode 100644 colorpickerdialog/src/main/res/values/styles.xml diff --git a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java index 5c200d7..dcaa556 100644 --- a/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java +++ b/app/src/main/java/me/jfenn/colorpickerdialogsample/MainActivity.java @@ -19,13 +19,14 @@ protected void onCreate(Bundle savedInstanceState) { findViewById(R.id.normal).setOnClickListener(this); findViewById(R.id.normalAlpha).setOnClickListener(this); + findViewById(R.id.dark).setOnClickListener(this); } @Override public void onClick(View v) { - new ColorPickerDialog(this) + new ColorPickerDialog(this, v.getId() == R.id.dark ? R.style.ColorDialog_Dark : 0) .withColor(color) - .withAlphaEnabled(v.getId() == R.id.normalAlpha) + .withAlphaEnabled(v.getId() != R.id.normal) .withListener(new ColorPickerDialog.OnColorPickedListener() { @Override public void onColorPicked(ColorPickerDialog dialog, int color) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 2fd287e..a345e2f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -17,4 +17,10 @@ android:layout_height="wrap_content" android:id="@+id/normalAlpha" /> + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index db4a141..ccfe56b 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -7,4 +7,8 @@ @color/colorAccent + + diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index b32b4d0..534dbaf 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -82,7 +82,7 @@ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { @Nullable @Override public CharSequence getPageTitle(int position) { - return context.getString(new int[]{R.string.rgb, R.string.hsv}[position]); + return context.getString(new int[]{R.string.colorPickerDialog_rgb, R.string.colorPickerDialog_hsv}[position]); } @Override diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 87b5850..735395f 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -18,6 +18,7 @@ import java.io.IOException; import androidx.annotation.ColorInt; +import androidx.annotation.StyleRes; import androidx.appcompat.app.AppCompatDialog; import androidx.appcompat.widget.AppCompatEditText; import androidx.viewpager.widget.ViewPager; @@ -47,7 +48,12 @@ public class ColorPickerDialog extends AppCompatDialog implements ColorPicker.On public ColorPickerDialog(Context context) { super(context); - setTitle(R.string.color_picker_name); + setTitle(R.string.colorPickerDialog_dialogName); + } + + public ColorPickerDialog(Context context, @StyleRes int style) { + super(context, style); + setTitle(R.string.colorPickerDialog_dialogName); } public ColorPickerDialog withListener(OnColorPickedListener listener) { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java index 8bc7940..ae8ee99 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ImageColorPickerDialog.java @@ -15,7 +15,7 @@ public ImageColorPickerDialog(Context context, Bitmap bitmap) { super(context); this.bitmap = bitmap; - setTitle(R.string.action_pick_image_color); + setTitle(R.string.colorPickerDialog_imageColorPicker); } @Override diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index c19e825..d0bdd8f 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -81,7 +81,7 @@ public void onStopTrackingTouch(SeekBar seekBar) { } }); - ColorUtils.setProgressBarColor(alpha, ContextCompat.getColor(getContext(), R.color.neutral)); + ColorUtils.setProgressBarColor(alpha, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_neutral)); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index 42ecfc2..aa8b88d 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -74,9 +74,9 @@ public void onStopTrackingTouch(SeekBar seekBar) { green.setOnSeekBarChangeListener(listener); blue.setOnSeekBarChangeListener(listener); - ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.red)); - ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.green)); - ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.blue)); + ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_red)); + ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_green)); + ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_blue)); } @Override diff --git a/colorpickerdialog/src/main/res/drawable/ic_image.xml b/colorpickerdialog/src/main/res/drawable/ic_image.xml deleted file mode 100644 index bd03e2e..0000000 --- a/colorpickerdialog/src/main/res/drawable/ic_image.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/colorpickerdialog/src/main/res/drawable/ic_reset.xml b/colorpickerdialog/src/main/res/drawable/ic_reset.xml deleted file mode 100644 index e68bc65..0000000 --- a/colorpickerdialog/src/main/res/drawable/ic_reset.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml index 8337c7f..e0b28d4 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_color_picker.xml @@ -75,7 +75,7 @@ android:paddingBottom="8dp" android:text="@android:string/cancel" android:textAllCaps="true" - android:textColor="@color/textColorPrimary" + android:textColor="?android:attr/textColorPrimary" android:textSize="14sp" android:textStyle="bold" /> @@ -90,7 +90,7 @@ android:paddingBottom="8dp" android:text="@android:string/ok" android:textAllCaps="true" - android:textColor="@color/textColorPrimary" + android:textColor="?android:attr/textColorPrimary" android:textSize="14sp" android:textStyle="bold" /> diff --git a/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml b/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml index 2beca49..c41738d 100644 --- a/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml +++ b/colorpickerdialog/src/main/res/layout/dialog_image_color_picker.xml @@ -32,7 +32,7 @@ android:paddingRight="12dp" android:paddingTop="8dp" android:text="@android:string/cancel" - android:textColor="@color/textColorPrimary" + android:textColor="?android:attr/textColorPrimary" android:textAllCaps="true" android:textSize="16sp" /> @@ -46,7 +46,7 @@ android:paddingRight="12dp" android:paddingTop="8dp" android:text="@android:string/ok" - android:textColor="@color/textColorPrimary" + android:textColor="?android:attr/textColorPrimary" android:textAllCaps="true" android:textSize="16sp" /> diff --git a/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml b/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml index 376750b..17f2bc6 100644 --- a/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_hsv_picker.xml @@ -16,9 +16,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/hue" + android:text="@string/colorPickerDialog_hue" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -41,7 +41,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -57,9 +57,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/saturation" + android:text="@string/colorPickerDialog_saturation" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -82,7 +82,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -98,9 +98,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/brightness" + android:text="@string/colorPickerDialog_brightness" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -123,7 +123,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -140,9 +140,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/alpha" + android:text="@string/colorPickerDialog_alpha" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -165,7 +165,7 @@ android:singleLine="true" android:text="1.0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> diff --git a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml index 13ae1a5..d41cb04 100644 --- a/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml +++ b/colorpickerdialog/src/main/res/layout/layout_rgb_picker.xml @@ -16,9 +16,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/red" + android:text="@string/colorPickerDialog_red" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -41,7 +41,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -57,9 +57,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/green" + android:text="@string/colorPickerDialog_green" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -82,7 +82,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -98,9 +98,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/blue" + android:text="@string/colorPickerDialog_blue" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -123,7 +123,7 @@ android:singleLine="true" android:text="0" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -140,9 +140,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@string/alpha" + android:text="@string/colorPickerDialog_alpha" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> @@ -165,7 +165,7 @@ android:singleLine="true" android:text="1.00" android:textAllCaps="true" - android:textColor="@color/textColorSecondary" + android:textColor="?android:attr/textColorSecondary" android:textSize="14sp" android:textStyle="bold" /> diff --git a/colorpickerdialog/src/main/res/values/colors.xml b/colorpickerdialog/src/main/res/values/colors.xml index ca0c5c8..5c4c4ab 100644 --- a/colorpickerdialog/src/main/res/values/colors.xml +++ b/colorpickerdialog/src/main/res/values/colors.xml @@ -2,17 +2,9 @@ - #DE000000 - #8A000000 - #61000000 - - #FFFFFF - #B3FFFFFF - #80FFFFFF - - #D32F2F - #388E3C - #1976D2 - #000000 + #D32F2F + #388E3C + #1976D2 + #000000 diff --git a/colorpickerdialog/src/main/res/values/strings.xml b/colorpickerdialog/src/main/res/values/strings.xml index d940909..1249313 100644 --- a/colorpickerdialog/src/main/res/values/strings.xml +++ b/colorpickerdialog/src/main/res/values/strings.xml @@ -1,18 +1,18 @@ - Color Picker - Image Picker + Color Picker + Image Picker - Reset - Pick Color from Image + Reset + Pick Color from Image - R - B - G - Image - A - H - S - V - RGB - HSV + R + B + G + Image + A + H + S + V + RGB + HSV diff --git a/colorpickerdialog/src/main/res/values/styles.xml b/colorpickerdialog/src/main/res/values/styles.xml deleted file mode 100644 index a0d1527..0000000 --- a/colorpickerdialog/src/main/res/values/styles.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java index 9750e8e..17a552d 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/utils/ColorUtils.java @@ -1,13 +1,19 @@ package me.jfenn.colorpickerdialog.utils; +import android.content.Context; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; +import android.util.TypedValue; +import androidx.annotation.AttrRes; import androidx.annotation.ColorInt; +import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatSeekBar; +import androidx.core.content.ContextCompat; +import me.jfenn.colorpickerdialog.R; public class ColorUtils { @@ -31,6 +37,32 @@ public static int withBackground(@ColorInt int color, @ColorInt int background) ); } + @ColorInt + public static int fromAttr(Context context, @AttrRes int attr, @ColorInt int defaultColor) { + TypedValue out = new TypedValue(); + try { + context.getTheme().resolveAttribute(attr, out, true); + if (out.resourceId == 0) + return out.data == 0 ? defaultColor : out.data; + else return ContextCompat.getColor(context, out.resourceId); + } catch (Exception e) { + return defaultColor; + } + } + + @ColorInt + public static int fromAttrRes(Context context, @AttrRes int attr, @ColorRes int defaultColorRes) { + TypedValue out = new TypedValue(); + try { + context.getTheme().resolveAttribute(attr, out, true); + if (out.resourceId == 0) + return out.data == 0 ? ContextCompat.getColor(context, defaultColorRes) : out.data; + else return ContextCompat.getColor(context, out.resourceId); + } catch (Exception e) { + return ContextCompat.getColor(context, defaultColorRes); + } + } + public static void setProgressBarColor(AppCompatSeekBar seekbar, @ColorInt int color) { seekbar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN); seekbar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN); @@ -49,7 +81,11 @@ public static void setProgressBarDrawable(AppCompatSeekBar seekbar, @NonNull Dra layers.setId(1, android.R.id.background); seekbar.setProgressDrawable(layers); - seekbar.getThumb().setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + seekbar.getThumb().setColorFilter( + fromAttr(seekbar.getContext(), R.attr.neutralColor, + fromAttrRes(seekbar.getContext(), android.R.attr.textColorPrimary, R.color.colorPickerDialog_neutral)), + PorterDuff.Mode.SRC_IN + ); } public static int[] getColorWheelArr(float saturation, float brightness) { diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java index d0bdd8f..7ad8fda 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/ColorPickerView.java @@ -16,7 +16,6 @@ import androidx.annotation.ColorInt; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; -import androidx.core.content.ContextCompat; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.utils.ColorUtils; @@ -81,7 +80,11 @@ public void onStopTrackingTouch(SeekBar seekBar) { } }); - ColorUtils.setProgressBarColor(alpha, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_neutral)); + ColorUtils.setProgressBarColor( + alpha, + ColorUtils.fromAttr(getContext(), R.attr.neutralColor, + ColorUtils.fromAttrRes(getContext(), android.R.attr.textColorPrimary, R.color.colorPickerDialog_neutral)) + ); } } diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java index aa8b88d..c03eaa9 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/views/RGBPickerView.java @@ -10,7 +10,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatSeekBar; -import androidx.core.content.ContextCompat; import me.jfenn.colorpickerdialog.R; import me.jfenn.colorpickerdialog.utils.ColorUtils; @@ -74,9 +73,20 @@ public void onStopTrackingTouch(SeekBar seekBar) { green.setOnSeekBarChangeListener(listener); blue.setOnSeekBarChangeListener(listener); - ColorUtils.setProgressBarColor(red, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_red)); - ColorUtils.setProgressBarColor(green, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_green)); - ColorUtils.setProgressBarColor(blue, ContextCompat.getColor(getContext(), R.color.colorPickerDialog_blue)); + ColorUtils.setProgressBarColor( + red, + ColorUtils.fromAttrRes(getContext(), R.attr.redColor, R.color.colorPickerDialog_red) + ); + + ColorUtils.setProgressBarColor( + green, + ColorUtils.fromAttrRes(getContext(), R.attr.greenColor, R.color.colorPickerDialog_green) + ); + + ColorUtils.setProgressBarColor( + blue, + ColorUtils.fromAttrRes(getContext(), R.attr.blueColor, R.color.colorPickerDialog_blue) + ); } @Override diff --git a/colorpickerdialog/src/main/res/values/attrs.xml b/colorpickerdialog/src/main/res/values/attrs.xml new file mode 100644 index 0000000..2ec6a1c --- /dev/null +++ b/colorpickerdialog/src/main/res/values/attrs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file From e3866a19682b8dc2c0fcbf60f2ab207145e5e490 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:13:56 -0500 Subject: [PATCH 26/31] update version numbers --- colorpickerdialog/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/colorpickerdialog/build.gradle b/colorpickerdialog/build.gradle index 007703c..000a9ff 100644 --- a/colorpickerdialog/build.gradle +++ b/colorpickerdialog/build.gradle @@ -7,8 +7,8 @@ android { defaultConfig { minSdkVersion 16 targetSdkVersion 28 - versionCode 4 - versionName "0.0.4" + versionCode 5 + versionName "0.1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true From 6b33171927f0593349d1598e610c0124846dda6e Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:24:37 -0500 Subject: [PATCH 27/31] Update README.md --- README.md | 66 ++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index b021ddb..aa46201 100644 --- a/README.md +++ b/README.md @@ -25,56 +25,52 @@ allprojects { To add the dependency, copy this line into your app module's build.gradle file. -``` gradle -implementation 'me.jfenn:ColorPickerDialog:1.2.0' +```gradle +implementation 'me.jfenn:ColorPickerDialog:0.1.0' ``` ### Creating a Dialog -The basic requirements for the dialog are a context, color, and listener. You must handle storage of the color yourself, as the library will not do it for you. - -``` java -new ColorPickerDialog(this) //context - .setPreference(color) //the current stored color value - .setListener(new PreferenceDialog.OnPreferenceListener() { - @Override - public void onPreference(PreferenceDialog dialog, Integer preference) { - //called when a color is chosen - this is where you would update a stored value - } +The basic requirements for the dialog are a context, color, and listener, though none of them _have_ to be specified. If you don't specify a listener, though, you can't do anything with the color picked by the dialog, which is not very good. +```java +new ColorPickerDialog(this) // context + .withColor(color) // the default / initial color + .withListener(new ColorPickerDialog.OnColorPickedListener() { @Override - public void onCancel(PreferenceDialog dialog) { - //called if the dialog is dismissed + public void onColorPicked(ColorPickerDialog dialog, int color) { + // a color has been picked; use it } }) .show(); ``` -### Image Picker +### Alpha -By default, the dialog will allow the user to pick a color from an image. To enable or disable this feature, use the `ColorPickerDialog.setImagePickerEnabled(boolean)` method. +You can also call `.withAlpha(boolean)` to specify whether you want the colors' alpha to be configurable by the user (if not, all output colors will be fully opaque). This option is enabled by default. A somewhat unnecessary example: -### Default Colors - -To add a default color, use the `ColorPickerDialog.setDefaultPreference(Integer)` method. This will cause a reset button to display when the current preference isn't equal to the default one. If a current preference isn't specified, the dialog will use the default one, but if neither are specified it will cause a `NullPointerException`. +```java +new ColorPickerDialog(this) + .withAlphaEnabled(false) // disable the alpha + .withListener(...) + .show(); +``` -### Using The Image Picker Dialog Separately +### Theming -The image picker function included in this library is currently limited to getting images from the gallery on the device. To use the dialog with a different image, you can create the dialog manually like below. +You can theme this dialog the same as any other: by passing a second parameter (a style resource) to its constructor. Full "runtime" theming will come later, but now is not later, so you can't do that yet. Here's an example of a `ColorPickerDialog` with a basic dark theme, demonstrating all of the options you can specify. -``` java -new ImageColorPickerDialog(getContext(), bitmap) //context, image - .setDefaultPreference(Color.BLACK) //default color in case the user doesn't pick a value - .setListener(new PreferenceDialog.OnPreferenceListener() { - @Override - public void onPreference(PreferenceDialog dialog, Integer preference) { - //called when a color is chosen - } +```java +new ColorPickerDialog(this, R.style.ColorPickerTheme).show(); +``` - @Override - public void onCancel(PreferenceDialog dialog) { - //called if the dialog is dismissed - } - }) - .show(); +```xml + ``` + +The `redColor`, `greenColor`, and `blueColor` attributes affect the RGB sliders, and the `neutralColor` attribute changes the "neutral" colors of the others, including the alpha slider and the handles of the sliders in the HSL picker. From f8bc5418874801f5e6abdeff411657a522c3fe4e Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:30:55 -0500 Subject: [PATCH 28/31] fixed alpha settings --- .../colorpickerdialog/adapters/ColorPickerPagerAdapter.java | 6 ++++++ .../jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java | 1 + 2 files changed, 7 insertions(+) diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java index 534dbaf..268ffd1 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/adapters/ColorPickerPagerAdapter.java @@ -22,6 +22,7 @@ public class ColorPickerPagerAdapter extends PagerAdapter implements ColorPicker @ColorInt private int color = Color.BLACK; + private boolean isAlphaEnabled = true; private int position; private RGBPickerView rgbPicker; @@ -36,6 +37,10 @@ public void setColor(@ColorInt int color) { this.color = color; } + public void setAlphaEnabled(boolean isAlphaEnabled) { + this.isAlphaEnabled = isAlphaEnabled; + } + public void updateColor(@ColorInt int color, boolean animate) { if (position == 0 && rgbPicker != null) rgbPicker.setColor(color, animate); @@ -59,6 +64,7 @@ public Object instantiateItem(@NonNull ViewGroup container, int position) { } view.setListener(this); + view.setAlphaEnabled(isAlphaEnabled); view.setColor(color); container.addView(view); return view; diff --git a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java index 735395f..09d15a9 100644 --- a/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java +++ b/colorpickerdialog/src/main/java/me/jfenn/colorpickerdialog/dialogs/ColorPickerDialog.java @@ -82,6 +82,7 @@ protected void onCreate(Bundle savedInstanceState) { slidersPager = findViewById(R.id.slidersPager); slidersAdapter = new ColorPickerPagerAdapter(getContext(), this); + slidersAdapter.setAlphaEnabled(isAlphaEnabled); slidersAdapter.setColor(color); slidersPager.setAdapter(slidersAdapter); From 6adc9e1513ef42ac8363bb4cc058be4cab4b0f65 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:33:04 -0500 Subject: [PATCH 29/31] update screenshots --- .github/images/darktheme.png | Bin 0 -> 53550 bytes .github/images/dialog.png | Bin 50253 -> 53113 bytes .github/images/noalpha.png | Bin 0 -> 54474 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/images/darktheme.png create mode 100644 .github/images/noalpha.png diff --git a/.github/images/darktheme.png b/.github/images/darktheme.png new file mode 100644 index 0000000000000000000000000000000000000000..21486fbfcddd0f2c503f508264220b83812a5b25 GIT binary patch literal 53550 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

O%)WDJ2J_lr1#SGjjhTlR>UM z#aH0}XHKM+(5^7`P}-^xM^pPM%!?RBA5}}wFTeN?Hh@xu-3d_!R2PnmpGlbKXG_D4M1Wmc1j*ZIRc!Mnpc=FWT8jaV3{`}-ZCYVD?~(1#tNrxv5WFaxxz zziP^XhRmDyB{Mmh%W9?s5}Y}$W-RWmj&5#lREp&@xgCrWTn_21H-E+k!J)GDG3j@- zO~FdcRq2ARQa99iNUf0M>%{dDu?DO40cpq|6$TKWoe`-4)JD981cXh?sgR~5+LjE_zPL@~I zeUJq^K<*=5ngh>vit#9X3dVd1#-pvrQ($TG|LY;%yr@BVuv z&5IiaK`vo8J1Oz;`AXB@5EEI=$1?OE&ypd$I+gtDd7WWT@QL>hAGLBYnlfcL4r8rH znZB^m!L))9>h(ckvR>=mF%aBfZ5}7jv-NhaN{q8{2%{tX-M@H246)TgA&F7IPr;t0 zPU8VIIo)Qfo}@d-2KTpCHY;?2SKkMS4>}gWHb}byywTq@|h7?kzeM zFyQv;NW0EVZd4$_FF8ayhHm%7_nL3|4PcY!&sxx`*GYTrmCQGj&0H{q1>pC(vKggM zZ1~c99xgndB|yMsTM@|_j?0`S&+D>ZGS9W@eco|*jGU0&yM?Ro{oM*gkJ`VjSIM&Q>9}Qw zSY~^#I2-N#5N*2F*~5vS{(%Yr+}PkYxF#|!R(*W)Jr=@<7fN2SyG|c2wK!F`Uuiva z;z4MGx#cW~4f1=X;*sgU0thqfD1*@jfqBfja3-{>>N$Gj$6q$DPsDh1ECE ztBTy^r0Vap!NYhESk{hBSbJ1cSgNc7G-59{+K>~L7xaC)TOIz*iBWx7A)m>s>(GbI ziZn@`lgZ}>$NGi2&=E!_9*0`$oT-&1hf{T}v^dKOcUV?l*UC(cFAff!*!z5x3+SST z(rT~&?HS6%h{FV~9$L;^3<1hke2y4uwaBee6}(nF4=PEHA6m|a7?v}*mh44@A=GrL zqm`WKFa}_;-r?jdWLUFETwMcDQiT8;lJv=D<8@D4Bsx4h*&9UyDCtFj*Cj|J#15rb zvbls7h(UdhAIejy*RoK5vmhTq^ipmQrAyNubQj!wV9g1{GcXxM} zuR({jG)PHzr_$Zs-5}kt?^pcqIdf*t*)#jw-t+tDypPYipS#wzuC>+$8^p1*GJfWJ zP344*_~4}4-z_UD0-M3)IKncA#@?W=*JD#~qaG)#3ZjJo@io$A7#;++mDP}U*q9|PwfLO^-aP*nzy6GH2K0Mle zCF?rDz7HcKkiMp4w*SY&6qjMqOi85o*{Itqf>+V|;JR!295G~9Nx12+;c?KKBVjpE zo`roI?7)36*pdxM+oN54pYg8sT3n;$hie>JPv$%N|A9N$2P) zYW?=Qnx2nS-d$|=?LH*NVAu?c%>D{4mxEBI>Z0D)-U1akaXdxLkMZ{T@2-#D2RJ_e z*u!1c+de~%)i-TbD^*b==<`H22-`57GgC4av#x^55|M@ntR`|hTs4#^-|;`#JD z&Y*F#z|IuaZ~Ql#GQDxE5jTZ;WtVA6ozZMIwe<2(dJUAnH}6mgxMn&GJ z-cyqa2W?Cgr&Y^_3&pEKzHXeTxr-Pwrnm%uqD*qp%l<@`!*q8T)A%Z%jfIG8Te^~A zia*cwE4YoSz53_8t}GK-myH5($J`<;R3*cMjPH(;?+{8%ne#CS0%ArjiAS}}+Dj7Z z<0N_ocn(^y_8adSq*$R^^=_sz0Z0;IJh$h|&?iG&!ZuWMNrqS*@-H2rKmNuO9};0C z)voE3t{mL}t~KLXqS@0X#HXvp`l(s1vQgB@q)BSmVsf%LS}v*lq1ORE50!eYm$@-N0%d)w}1ez1)3i=E`%$p`b5 zF%}-cq|cTo8K#z0RM4~1{?3a5vr)6YB6eA}1b6A-jAw-!`=BoU;>okw?SgZY(|7y_ z$Sem=*7^MS*?%DjG3-R~KYFcPQ0Ba4s9bBXd!WxYM^x12-(^(Ek6?w=QVVZPoK-Ce za<{J!-ft z%qI7mG5n#EU?IOTY4%=ft=(l(2OZ;)sP4uK97|@|94~GAURK~2Jc+ZWEi4~7oy|P5 zi|cl2Fw{4q_?x2h`RhR7zPYBb4vkcdg6%+}r3(M(NzvmBHTm~vsOo!6`g7BT+Whzo z8G6kJ5Rk>u(tM7!-}g!tC&MsbE%VJGy&C`(;s)Qvh%MI#Zx@?vZGqTDDY^NHcrO2G z_&vagjCc^z82*^5ANSPAGCXJ3vs<>?E#M7R`_Jft8$OHc7^!S_^*qCo#9Jlqm+m5fY%}N_yY~*2NwW?o1{t));8%FWtGiulWM)HJ z&arl@%3W@MMqXq_?7^RiSxyAUsb#sG%{s&5{*D13tRW%P=5ab{>_q8@ouomjlZnf9 zEbWtFcaoaSYChIt5zl)2?TEg1RH$babyo4s4!n?byo3+018?C@ZNYX$@}&K z>O%h)k~YbJ&APrUF}j8l%saJi%4DkgemU0R^BVI?;Jd=*xH9jRFcF8#IJ(u7aqUX@ zB+^y7X^Kwu(?YM4*UQL~`l&s91+{xz=Hxjs`$g)K?uGcGLa|mC&k3*%UJoji|Jg!U z*5@Kq;xdpfn30M|rxEAf(b8f$e!oLD{G?sR>kz9_WREm3X#pOMhqzx~II<&2m`gB% zYKVaAMf;1Tsx!=c2#*G5!NFrAE)%X_V4Uo!^w{!6_k;YTgxYn=wZsy^$j=h&VqVOw zzPiu+#Rp;uFT-Nfwen^O(eWrG99eY(r9fK#k2umbSfg=QQzNLLoTP93#)3iij1eym8>u<=GEBFBCzeWfi3SD$`WP%>$3$JT91(EO=S)E<(8@|flT zBfj7(5Geo#u<412YjU~t**A7`XJ(-uO#X`%tV9BA>7nfHxK8Kga)E^$R642|hheF) zk&#|p29N+-9#w=pz}sQnszrF!2Wf6}ik$I0n?+(1=IhSSV(r!1c;n_A^KGL#^CgYE z>&({3%R~pPes`5mmc;llo05R1_FM2b_wMTVI%S^x=EEz$DWswFg9~1=J*Ax|Sd&|` z9J=)DG0}*u!PrPsnOMfAriT1k5`3p#1s}+`=l%RmYN(cK@30!mqmx0Rw?q+>!qqCp zMf~g3FVrY#=h;^RpPKgGTmsXlH9yZvhc_{jpyi3`g7_wj!Z?Elrumkd|t##o9iw`DOn zsohg5Q9=vJQZ%`1h+Bp}WDvh+aQ_I3kI4@{HTVCIetUpGN(@fs15%;?gLZ8 z$@BYVegH)T3rG4<6yttdz#*OkGT_?dZ!-%lY$S$&g+e5j`#&>MUOT&UK`TC=jjW->r?y3*b1jMCpSSC%a9bWb+RHZ4!B z+{t22qsV14r+66!o9LGpU_UduX-H9vQpgWNt*{E;>Q{gXwIe^JP;meQ|5U z(d-dBgQgY34Rj6u%JFinxVqj=bj5J|HFlm^TdqjLQe&V3q5&d^EPQxOYE&OVg1H>u z48QpLTFGku+y30-PkndIy{QVz-Y=b29-~jpZ&Ow~7Aq{}Uizavbyw~YQ0mP~Sd*G2 za7(#8;W+E52Kr#z$#(&_a|^Mswewy^oF)Z+0Z)iQK!|9z()u zAKx4}Ni`uX^=7;hJu8*&#~<-NE@yxEOtDnctp0FsuDUc*E=RyFDsXG&x&pFLmgPqZFOk8{`_vI!*^(X6g_52{;k zlVPZ>$O|d1J__}@4?r_tW4Nu?rQ)#wl(E@DMuVnsE0V7NhLay0ojq^dOdBx|F z*!#3M*38EmL#t=Xbi(k7o`yCqH;@x~V1}Tz@60uj5t!UBU zQ-`XVDnC?(6h zcrMT1yrCA~%VjQ2qSE(e`u1<@hXafeOG?~s|KyS1U8&f;`k;^;=>3XOm$WiZjd^j- zH^%!kqjz|>Hp`S;RERqB;$wp+{bj0gX3Lx*{E%@z+DlUgtS1iqS3z(wng*79ELY`b zJ?Ep#6gkcp_G{IT1dy;r*$@?!LF}`2X|Sn$h=Av~X<+3f^1hX&_?^KV#CwzJR&*wh zL`!y+_WcoK+|Zk^`%^XfO40{cm3g$RqV2hiS{^Cn;APwM0sW0bIdbF7($OE@ltO}Q z9SEG384PDJ=|%LbDU>DaB)R!(569v7xGOCZj~DdSI=5_Q!n!j3W9hS!Syp9aYJ{?* z3$l_8^qj0F4_8qu^OMB9)SjPGcup5|9dS5X>MD2s$GA8y`H@fPgWN(&SX( z&ViIL|-^$~eeP8+A<6Wnt_H#8fq@9RR*L=PH&?XF3djt;e6mu zMDKRxiB&LL^fpFbW~MQyN*TWJ+*Df2o;=rb`*fV~U~lj;BwEL8tiY0~r@Wk&~-s5j#Wv`5C&t;rZ2Zu`0KlIBb0A19)FX=}*)v z5YxNTM_NSRiESXr?Pe$hmM3)JGc~ojLo7o%RPc=@A5D(#&1h_NT12?rF1S}{OWdA? z)lPS;!PpWN5FrPGCguR771WnHnZxY6`&hrNG{bb?*5MrI2!6=yH5A>RylIW>Z-*>_!+}&*602&{Ao%XI0k`gGYBqnYX>}7mkf2>ml`@ zJ)J%;S!V3Xq|uWzOMdNEcH?m}3DIrNt6meH{82;R^2D6fplKB+ev){ySo&_8U(X0d z#EB=>pg=UU1Z&@$B>@VOwoT+8QGF#o+q7YP3*tC$n6I5>qwozF6mG}T@@k_P&C@(= z|Dl=4re(dNt>GNlEAI#)4B_r#5tbA5qJE}zz4v%Gl-{X>#9Nh#F!6S!p+IP8=c2G- z^t9-+r0k&x)5$^BtR8%fl^n4}<>=2<=&M@q^pTr_lC9Cq7qbP`*bi6g={`idPu>j? zb&JL5u{e`+W3qQ*S#j$5%|0tVZtmxqw&(f!4FMVi>YzJ*wo4g*Mksqw$Qr4$lVl$3 z;q=Fzx#MzZuEf%tfzYZ#{7LtRwAP}xnQ-O}u?B7L=nPEsn#$^CF&>N1bFAc>1L*>z zy>!`iX}nFWvN4CZrfyb6EWD!aQRHKb|XO}7S3nD96E4M0I-67^t z3raL?{N=>_jDq(>PYRXHuc1|Zqn@$o%{}A9F!rC?#c%^j{r*mmz=dDA(YW95zUl}o zo&vqKfT>$~JKQ^gP*#7$?;EvKrtq{rCi%GS$c{Btd8JaCv%P*@y^uFo^9fV%^}Z>8 zkx#IdPY#xq`#DJ_quF}+8D9yi`k%GhDQYtx!TK>U#cT|ky4ziyui5IPu0_NR|1i*3 z8l`sg-K-2J6YNb zvMjVpB)K)xS9X5HQ)@Hp_FkS0Hdgo&U9T2e)5$MZdTr? zaiob?Q~9s$oRa*eI=cE!>r~>E_NHoBEixCJh^ya~(F~@m8_V|vFf=-?>l~BPn~N`_ zrJel5C{a3KZ?cpm)lK|mRI2KZg1`KztU7JkzkSEQGn{y!lk9NV@F|h(%2elY+q`RI z{QQ?y-(FGF3wKNBl~f7-YnFuemX7U>hF6@UekWOUJGQ z{SO14+Zei|0BoKF-R&J!_1pH+}_^AiFs zn$vIxo`VS!x12zIQnw{n`X_xdPYjKJks=Dus%)Gr&<<~vB(ZoWtslGL zBB`%VF`YJqJK60=Me&Q9oMmJ8MDK!-$k*itOadu*SX5rI%b=|14FaC?t^wrGXOpRO zcd%E(DxtC|xX^5I32XX{YdxAxjrBBM0Hr)fkB)v;mh&53b@x)tRXx8^%B*|T#@%5u zNrv8a%9s5xSwGhImW&1|A&#i)rjAWT@K!hF+`rK6wNl4j*T2hqEB-EPPnI?q>&llf zs@}`UIlru^ZM@vwUo};b6T4f9H<;Pq11@zrZubr6DjDlswxgBo7m^Rbfa1(KXwEP< zr1-F;@6eyu;9h$20K>*QOP%R6BD)yASl*RFzFw8})?$xgaCWR__ne-l z_2dh7;@K2*Q? z6B660v)dy1?;Lkqs1M|%uA^DaZ*aq@(r=1IzB92-7X9gU){icXLZsuO5*vPChn-Zl z?*BcbI&89UEo|4FFun%YLgh+a#(bI}`>k-4^!JawG_cYpeT{HNntb7}B$+4*Y+{nlj6gw`> zkw#wQdGga*1=nT?#{7Ld>)K4eSqm!_`Qs7~2mNrwm~!;p_@edDyktJ+lvoS+6}Y_l3>>^P zX+m4f)CC(OFB&V#8>1(|r{0KclFXkF93PJ+A<4*-UY_D!o#D z6`!~L)KICO>rg6N*rwwnnN3;Y>E=cgj{HuKv6kon73IK_GrOB7$;yn5T{V=&C{BC3 zUr7GXjEw2Gk8SzUWWJLVdA$4WH6u!G!+fs8ZLf8%wYDA5*u8doom)%Q9rp8!im=J@ zu)=(HrwPxlwU-qw`|-^OD#}AJR8I%j5A33;wXD=FZ+}0}wct2tO1~nqWVLg-8EZY1 zzB18sLmR#wlA*7yIJ;PP;92~>lqPw~$J#4l`rNc_xZg^vrmp!wBvu?nxxmRh=K0sY zJa)$IOljx-0Q=G?JSUu>opy>jO}i1@nTQe7kq>B8nYX_<(I$l#A! zA-jmXbJVV3ip*ol!nVf^E@|&(@L#jjdZSgqmFOdWXPQVC5NLLK^-1tF=M+_ouTUu% z7w0Ecn1qy0-b?mWm$YDwqV>E$p#7fgrsPHnpu!blAS~c$wIY!Dp9s@KC}E_Rw0Evsy-eik~2#v ziBm_&dbjrMiD~8+!msKUvQaNhJpXin1)vyw5-ZhlnR+b(b>O;iad)cYv1psY4;MX} z;Y4C)T&R|i$vM~Ey-RZ>oeuw)Yo|}9S7J_*xp&LnR##%R6GbCycvuzHHZ89&F>U-u zR-w#t*9~9h0VEb=?ZQlD5^nd%-rN>E-ubE(DC4^SyuNVj#hG(|%|P4hl(U5$-U2%Q zn~Opg&3y{RM4K#3ezjJ*xVwG!$^!Lu>-gy4pjw*h=^?eA9^<65bq3b*?n;?5SBLMh zsIOC`(#iJE^8uG&D7>UZ=JdEwT`gOe`Rxx2w@4CaE!B* zlGP4O;~2B`ma99BoYapz^5x+-T`%DgU3Y1-7B=h$L*sTF6-n_sT^Z`v?8cA9hUa+8 zQ&L2^#TJZgngQKW6f-?$S+s}%zZ=5Ub9tk2JtqQZ&C2~nG0pDG zUuG}SsSsUGfj#FqZ1iGzxGj+zdF|4aSsy!BEY8O$P(B#%FcOa$Eer;Yo7!TwX?ZaD2==bk2iPAh{ZQb@JlBv{j}1y0Mo%nVPTsxgU%Ygq~i$Joi=4lQ@a>_U6m{V3Ye=#^sl}wfd1vHFarH z%M4RI+SdH)ad;Y>p(uVnnQJBKZ*)-XDRDz?|t__T&ObiD4Xb=~x~$oh-?6cTw-;<*vO9;5tul+}Jyn)X+8Wr(95I@;z* z*=j5HOYyZtL8^(-7E^?dKPNfTemr$Q4z;7&V^ge%<BrfW21P%mcB}FYCxnxk^F7V&>aoIYT ziaqY}IwdE(TNBQts@q6Bi{I*)WR_99P-`DF5cb6inPTw{8wuytno!8^Et9{yu6)M& zS&!r!J@|ml!*mm4WTcIoi8_BPt&*O6qtMc$rTWa)zP{X?R_%Dfr!1DIRm{%Zt3EMa zf3h8GCvPXnmXV&GMeC^S%~49nUWDQ}P>H=Uy))0RFj0Nmo*0>+8y%G)J2~rMRw8jE zW_j)HegxcLF%5zTIhgSjF=WZ349#J(j*-S)sGGIX`xPGjr*el0DTby4`Q6W@!*epIz>m zw$%6VzUkX{72(3gP&RMFN#%7tdvp1vNSxzu;!g##x)+MxeizRxIg0hg-MXHR9&XbM zUXAah?y7a$1Xso>v|CRVHm)GhmYBZo zEn}_~8nj77BPx$f?0Jna}>X&fd0Z8yz2U_7=sOE=g67Jv_L^n=M7|j zX20WCUWXdulcxFn5B&} z{v9{*06IDc_{(WX_ft0ozIe*SQS$F>fd7XO;`2rM?>7jfu)#so*whHIU>^tvK?VOJ zS&aHSGw4611QvbU?b~F_C zZ{)yNZ@~AG{(ICKJZi0__Rq(Af=v7WD?ifS&Ab3iD=PFW3Qj@wT3m4Uy0&tj%E3lj zD7|V)y2@lp-3e%ZtX_>q!KQV&K4|wo$<^isEqob9y@~v1Gxni8haI4+P}7VPDdK3o zU%SjiHpt=Pa5a?oRORTKvbN_5=pGfi!II%A1`UvMpB=|Fog<{!{2$4HPAo#_8H}r+ z6FLV=t@dj?cMQ5cmX-T@BA^A3dy3~`B_g64B|xtW;Swy=rG4o$C=Q`b6CBa?!sB=n zQo$L}kp_!S(7ex^*QyIWcguaszMIZdNIK;1&^Ilh+>k0P5QtTOBpskbUGSsdKJgD76XHW9G%YE)BsjQLj?xKI* zuA9y^8UhEIMd8R8s*j3BsKNA;nXcWfnD*s6PF>?TH1<9T~SHZ za6QraHooy99&{?$bUkko*^Q~+G4wuB_I5n%q?DO-`HfHDb-oB|v|_YG5bdxoZpDVR z20Bj~#;n+buDPstBZW0vIlU&edo|`$+Gq3Ljb(#7X+8omkPsUOqzqhW1;lyIb-l9T zB%g&lWUifiGK72YMFi+QZ7KA=*|zq+nl>HV2JNfkb!)7$UZ4kLd7)j#`*N5AyX0am zp2&Ttc-p$rGl7)@bkQyM?l1ZhN$(Et&$!mD=YyFAU7gMef&O+LnXulpLNE$F{Z(4@ z$2?0D!UC-%!LJLdNOhJqBp)NVySx8d3Lk)O_z z$7qCei+wdoMlO?JqCh%+1c`Q>A37<}R)ClZP6GyNWG%oy@Z;h%2K=I7OQ!s=B* zHog_qoP!r0&EMV3n~w2<9Ss_Y>OiAlaOo@Cs2&Nhg^2FX+ZkU=XTIk|=H4k1q_(jr z`t@k@g;-0=5@+F3O(YWfhHw*glvQLI$v}LQbK}))S(7lnWhAmMp_59@Zf1AAvBhTR4Ar&BEKe36yrnS6)u-@$s7#qluSF8%I5_x}=O)JpPA z!7oi@b7{CvlrPy1oEui>sCa4+s%3m6Bap{56-Y6LawvyK`=h**UnFO66{A@>tI*4` z^&$TxI?__BQ`}(4**BGb30i#%4dJ6mzF8aj4=dV2EobV(RlUj%DP@F7=nsSOze3oa zzHdEYX(hv*euX-g|G!!Qt6EDl-1Z*ieNPBBsx9rmN+S~Vn1B5*uum`%jWw9!ATY}%XM!ypy{-il0h#$3`UpaR*ch&$J zv#XBaQa$Ww`f^qZmf}Jkf@q%7w$62)AR{0ilPnQBbBoHeq&BM`vdfBOhgQkhsfCjB$&fz$I!{*}F@4$p?~WV~uLMj6f}BNSF) zQfH+rLQ6DI*mdN}gj}q{6Pu%gwF-79m9t75>s$m$0;T|abC8bhv}Gls>q;2xhSASP z4_wc0m6@qOj7Yvtcd#`f2n@(&AsuMZO`k}$wKUBm#g=?69x$hj#ckIq#{Bk&0oo)Em3D(t;bVtx{bvhc;2mE(O{H9C=Z~WkI z58m>;R5-cIyN31V+INdlwY*KtEvU(HO}AYXO1L#C2&FVma9xYFRU&_>g^6RI-mOjA z)H*95OP?448}Tp651mUSaBR)kCjVjIc%4`>ne=#(5wsd!=}NgL>B zw*k%P7hAy!MAmBAA9yq{`dfnVS=0FXqFUhYMpBNs3;27{E<{V`ZuXqp$#|FOgU)$P zt-si6EkEWzf9p?0vCOv^4J9iNS{A;mJf!TCX(iJjTM-ftn!&EjU0Dwn?gne+PJ*dR z@X)`rN}q~Q%0J%7UQ3ejQtG3?|6KeZ2z37Tv@-c-$5>vmE<)(3-~0h>Hwr`Do65lE z6CfI3EQyU~x{~GG;;vrX6z1OXwQ8MI2_s@tcdlBC1m*ogV0(3&fyRz%oj5zD@O8`A zN(^c}qE_25y#+sf^(8g1buhyi!Tvp>rVGtpaRldbAVc6nJeMA4IOqX18lrvCr94!g zVEcf-K&8i$zVZ4{A>^@S>y>K3e%iOfxsI=VT)6u}OH{4XbEg%RjW@g2uHEW!B6v7X z>0N7tVf&Z?>pmGBnC?fH+lAJ9?@bgcyNuimMRv}{mk{2bpMbCcm&!VIXAaa=NwZ- za-4@1RCHE$M{_ZXeH18!NM|3@Wb#6(5tiQmD0CamU3%AAweqHchn8QNMY^_yte@;t z-Ch^Y_Uj=|i*sfRd9v--w_kh`@a;rwOSeI5eiEfT z$)17hw)(tUPEhChqi7E#(IXAkgI*_FPb(fMUC2wJkABJFVj9KMhZI3zJ+2@#j9rRq|x~a(UIUaj($XGh0|wZPmpI%(~9# z+TR9NI(T3I6*)*fQz- zw}Ssax9E3fs6HFmg>AwM9j-@C@yy2Ylckl3yxfl*mrMKSj(1Ae8MI&C1^2!{{nF$D z@WOI2QShgx7Ni}1=RJ2E+6kK|9D>Z?35+`-A=dg^Zu`4JMv#j?JH z*st}dI*uwPyDa(hBwQS=GpLnO$yCtt0AUlDe2%RWZOLl1dO^jM84%Q|-3D#cjd!<8 z8mp$@Kn^2#4C?w4RscB~_A|`bW$5FVRhL`2{Q$bJRhuEAZ>Z~Zm4&(U>E2$eGPn(H zGKpa0*8V;P_#enjSb|6fXrvs3dL5_nG-x`{o>VP|bVtykgi%U!@0PKcCpwO~j^=7T zukY1zwW3#?1EB#-Y62FXLXD1um9F>m@5qmo_yq7(#To)_KPPEBd*9J`1P&-|FF z6GJT{qeI%1d5(hYUz116CI@+IoK5J5f&j`2VEVXQl`(Dao67oKOCS?N?^q53w1z#$ z!a(?!prv2eG`jPiK$xOGTmWbjpn68`zS5TYjXc$Z#VsLqi{e&U5yBIou~WaRX9Qe# zxd6f3M$PU%z*H|GB84V`(*Um29VPAuQGL6GT2>|k3668R%9$ZMt1nR;53x#N_;6&Q zgDkYibQuIuRY!f?<0|^WgiaGAAx?QET{HmrZLG#7U{UURXS_`OArXN5mmy%SGn%(!p2)zI3s_N0_10| z|1_r&C~vl=KBH8^>~`>KT!8FvIv7lbH^G#baBR}M{0Q+air!{J#UKc7&nG-r9}jEA z1e`wZNt|w%!^V|{b|BjlEX~;W^MZZpKKmQAlC#sMSj0^y%z|BBys=n`HCPUCrN z_DL`M{LZH|X`40Ru~LknRR^pE@KUd74x{T!MbHjU?&GDG0`E_Tgz}^Yng9ArhSI?ZsQwZ042r+3{s)8P>}L z39R@uz_+&$sAU8H{jvLoE6W%WAjl^ToNU?700RZ1-MWWi}82R0#9WNY69pZcrY z+%5CprWv|N@q&1Q*H&tfqYp(mkVE8!cS`oAAR6y0OUYCtHfX`aB@8W*yt>i4ZE~;i zKkHAekHy)vcF({K;LzX>C>|UQo42*UTI&lhPRErS4x?ZaR%Jo!csqb#8P~9vs?8X2 zre3I+piiwa!v097t)@qR<6#iLiE28Fp{uoCEj`IJJO6Z1 z?B{D!Ct&cKVo9Ji$$c;O5#i%EH9SI?Xsq6V2N{+-*f>UF&NZxph|uL-811=0+JP2< zMmLv(xDM&V%X7U*KI~Z0sbWG0k6A??P8J^=G~`-<)x?*Bvb++9&L@FFQK0=%Y)qA7 zhDzZ~GGGXkr=Ll{1d%q6#mfS*e1T-n!84TaAewN7*yb(8*YlLI<8jvw67Eh^Oqmzf z4^3D#-kh$jC${5g3ayFq17S89CBNli>dg1OFb+kdaG(;rm3{UZ%GzfF+Z$O8Cl(>| zQos|a5r?Qa#B%Ag z?L^5hCtk#OuAp$o;V2K+gZI`eTGK6~u{6L@(P7E#hn~+&9|E3oK#N$fMI_0ir1^w^ z@im?({w@-wp){Y#!JlTdO80Bw8HpEXT@+z1O(q7BE&*~LN^l8jnFXW%9y7>5V83_!(5CrV(=w0>6g{5RCeLECJq#LA`?Zscicy;qYdD zh~Y9EiR}-{yB3^kgo!Dj-gNJ?(Ir#t}JU{iPyH82$gGeA~mY$XP9&>sCT={1g zOa1*{(Ag#pplhwBnZP~hJO`o5;xuK2-(S=jln79#Q|-vdd(is_9Ioa{84HYiE8M`! zj#D<={SX$x5PYnYCrIzDH~}jYyK?aNLudv=crwpdEOc*W2Usbd&Ukb`1RohNga%K& zz0pQ1nT_|o`B8F_}_>Azj;N!Gdqzn5kufHRXqMYMRA%lxQ*T}s2O!D?#i-u z)!EEP<8vLP3)S{G`dHBfP#p0aF0i*Yc3!J4{udo-f4E zHr^Fq^`Bp0>50gS#6E!f1tu0i1d*@1l+vYmV# zP#!Xs->mc=eR4&x(Dj^KdFIZVe}ABd7J{&atpY%)vbtrtlesHM8N|@3W8Y~2Z2D6( zUf~XC@$p=4q$N&&=gt7Tm0Y$G74Xc-09C+j^rGac6fXf8K5l>~3aXX@G_v0eLF6-o zd1}hFYOey7Vjb^r`np*GQTRkE5r~=9uWF3Y(2oCHg zbbV(5_wPJo+dkrH%Gd(2bx9k~50u~quw}4}@I&=(NL!#B)+ z`c~P29I=>4X(O5jTalbgkf9;k2y*Cd69H$o8GfD@;@yZl_6t~ zlxxdvO*kKiz?eMSIQP$}Y<|O3AcJ8{P_|K5aPI2~!-rWsUhnGqM%=%#Ood6jc+VVpy4Ev;7<*uSgV_F@{Z zSHUKn)#YA(bxxDZeLGZ*T}}e#3_d?sF-~+m zL@-j3#c3(J>Pw{p)Ngn&qb zNhb4mJKt$BxkNM=pAmFB^zP2i6%j?<>pB<)4%ujvocR_-Dy~2>6S|4g(%5;h(F!0t zH!>`#22w=mHet(K}!JO)J`|>aHM=vL6$22wN4geQ$b!clGIX{}Hsws`X z+A5KKZ+1J4BbxtDm9Nbc4{cQvs5Ina#Hj(oP#Mzh(RvgyWZ+@q0o26~X}@lQWnk27 z2C*xhBgXpmDTqinos2I?us4{NOC`pt6`Qv)fwETV2Um(j2K(v$o_SaTX0j z{I{r~)<68J4~Rbl3CN#Sk%z}13;_cr7qX2|+#+wFGO3*Py5s$U5q+e6>Y%KDL4xk5 z{~RsZ(eMl(GnjC0BS}I6GK$<%?r^XWd_D>EaF@;V<<>#isLw?~7}2`Uk_lekuHaYt zW;e+>3GaN?7wkFDlzN>o4ld_D&UFIM<3U;c#~Y;bL=FRQ4-{&vsHhvV`1n=W5ACk& zbi}a8sJ;PYdGy>WjE!LK#V=lqh;|X;hD`1s!Yv`^F(8#H6Jq?P&9@0;V7N3Ji9*e2 z37aRtox4o5%W?}uX&pR>eT-g}9$n<5PNrM2r(c+;R7xn#(kH3o9Owb%PtXl~?jM-2 zT(eP?PL@m@)VNcXL&m>Ww{@~@odS{3^12#Qf2mP)<5Q{}KX2D+JKI*D%(K3@e`-UU zZpcrAgbqNR20b1US%VVkt!jw;90tWwK#jwlj>mN%T7WH%MDg8u_@#p+SJKjXu(d}T zhq+4^NKR~ZoyE@I1fX_DR3{+QQKm7CR=$qhQkTx`;`8GEJ@{BHP{`}NnW&AVs>+@F zrC+?&f^_iGc{@k~KbtSM1F>PbisYyXa*KcXIYUDfT>~ZgUX)a2cbjMFf%Z(q5=)oK zo}xOh59EO12!wE0l(j&eb=gHVliqo*Ny{SB_DIC=%K&m^T~5K0a1@8?i^gSH=Hjmhm0F7Zm#~Th zz-%uCDv;W@l!UPfUoLACeD3sRk^9mW!C0dp{WUs5Hg;?Jx%dekrMw|gBjMr(eEu-0 zt!Q(0gfwUr0*H12V*5GQUE^_qmR4%5LKkV~Uv~2WvZ`%;NW@UId-)4#Y< zAjJ;Q4t8>cnDNr(Wldo&?I{wv3HJBOwJ>|-X~(FG=^oW0%O20QZ2V+(x8cKf29?u^ zi{9W-SkQJ2LY;%@EMXQ6h`sW>_oC0fs^OeZYp)xh6YT_>T*oKFGy3W??HGP~r)RDp z@BTs%L{&B1j*CFT7n_#q^bklbgR&Ka$r8g>@zu^}DpiB->xG^kzQrQws$~~xK(J58&Jd&4WS}G@d^KrUjjwfY2QtboZJB z8q5|T(`>c3+DVyQ2Plk!y2CDTd6u~r#EGGQXRs59^($^Qb$kk0POad&|!dUJ1@daDNn@~6n?)hR(0e*5BV3DZ4 zI9Bu0UN-mP__;EGD4!VNw|UWp*eFy70`bsaK!@EbN>RzbEUdqDr>Oa9SX@82_-Mw{ z3sZ6Yn(^zc^fk5)eg<;7DGn!n`6HD4zghr+*HC~q>t@6J{V-sqI&;n-nV%^%4v->; z5+M>9#qz>2j7bBtaTd1+}B}@0A{v{ zEQEvf=Am`vtP?~8*E}z4*=#^@&1zs9ec3I9qhk>=q%~VcIY4VO+m*a_3FO^x>8xEP zM%oqeU<|KW5il+E+s{s8)D{$0%-OaR%Fa2@dji^fg9=ukQ9J_FM3eEZW-DQybXcl* z0Y+4EEQH~;!i7?+#q(-`EjFFs2-mCLtQvK@0uqj|p?(eVe89J$F>c!3dl5S+z>L~JtlininGV$ zd@_IYS@d%g%fo2?+gh1F!#l9; zt?Wu0>Hx#W7Yu*OEo^W*Fk1&?Q-!?w5vV^m>Yx58do2D@pcP_kXmUyLLWC(GOB58) z#E+E$0JTK3{6r#7l2Rj}H1g_i37mOt2cTi_j+W54?i|}#(}4u`Gb}EA z0Ih;2hY^_p-qC^PL4ksS5xuL__$&-RGJ!8JVcTq^AoO@mPXs`RIF5PbG!l=;uI{c; zu*MDEw1?4Y&drSY+0O7moxSfb5i8&61+c&iAK{0>f;eRDfJT2%6L#n<1u}u+-Vlc) zrZ3Bn_NsL=5ETRsdmY%rYJP@Ay+O@`LN$daYUMqPX%pHrhVeoST4m=A1}g^oR7aK9 z?a9eFzlY75K-0Q3oySy-SIt9~^15K>4=})O$gq3_NA8mDx}qAIvvzlKo!wlV$Z>Hn zz@4zV!|!s$w;0m>!k~VEzG~r<+*K7{nSy*=Ldo0g`p#&GRiI_3+*`wzKo40tg2j$X zO~rw7dLJ#FNwRrws|(M1DmTQ9u1frd&^z`BTUmB)RkkdzGt%rfgjFTh1zaiR7TOVE^BojLYDU@72~W zXGXca7r9O&tZYnj7!m^!uY7`fXDDLeevl=uypKbZV4W&NB#PS@#H+ott(L{0iq1K1 zdsOn1K#Sk1j0Udu%Gh46;!;iU`t*5Uh1j|Io3>c=2@v`ZnGu1ywxMPA!!?-dH>{`+ z{Cxp@sQ&Hs1q>r6m4mB9wg}_HJq2=jA=Osny%aIa}HOzw`2bxvh@W_laav z;E+Xu4VrBaCx=4eqm;3bI$HbsAs)@vp+al6h_MURQLI7PT=y^cJl9Y>5@T! zLSd|(61dNF_kduJ+1R@Go;cJ4-qe3`^pW^qWM~Aq%kP}-=JyZ}iwrO#Jq2tZ?g>bH zz-;tPsx#l4cmYi4Ih8~I!bWH;;3|#!=Hl*6v;b#_Rho+$`IqzTNdWfk|Bv>*D=Mm` z>sAquh=QOo@2Xv^R;@MHoKBkF$H9U*FOE(6B-r;Gn>qZoVn5{DRKQX$nfk!q|s#0fzxg8T|u18N%Lv)e2; zFB6_heEt`*isxQ?{nGGtckXw4gzaizU4D0|r3h~2cvz>K5dki59bs{jhL4!pkUXV{ z{Rq(uCCcY)0mAnwc!zycVFD2ng5UvrxeX4onC{9ndXUG4+>y#-c>4#P?VZjvmAS#X zd?*4-`dY%mG&dNcyqhTHHp13#gU76vmO;qpNm@uD-v1K-AoF5tjTbf_oCjV7j@?Zm5D9iSz9_(?V(VeQCb(&JQ4p(AD|JWkoLZw)|45jqKkWOrC}V*NW24> zXK(LID5NQ*3Zvb*GPhMMmtMxy83DW6Rc$@E#Q_gPAaJ_Y9w0)WwE=Fqw$=oR1z>f5 z1WxaVfj2eCaXcdd>Q2mia>5ps9*r!ILi`dDmuxodgRg7~p;6r;d-1{W%}#>nw5DZz zm+Fi=EYP{dk9?44YOqr}i}q^kQFB{n-M_?KGTEN8M}X#khZA3rW$UYn{c43CL^5lD zieU)azEH%2V^@~oFXB46%JPfveR}lN#wkBI$IY(Joal5@qlLT~YJdQ^dOf1Rzomo-2i1E`r}1zg895S3v-Kr86gP9(Y9Vo=+%uX! zzcD7tk;}L3I(+c2l^NqgQU2-0=Fz&Tb(U*jfg5l#hHORHc+{i8mi+Cfch$xiaCm3c=@Rj4*Xcze5)O$(~AU)@hmaj;}0Wm9R!PFo1)t5f^PEU zK4gF`A|S}f_5Qc-2l-mdkpqJO1~;?-40$AehW11b)Rbykj)&A$Yf@8g=`j7xWIWIP zQ*y@aRoG<#TahG}>0Fy4wsB%z-2@wMz&#xYS@!+vJ?1;)~wA4=Uh5?a=K){XW+d9%i~G zpX}WK2Iz#2d?kr#%i{O5SqYWYV*q0u%YUdny6Hac`?lQG{?k847enGV24D~T<@8ph zjPMZuh8u=%n8eu3RmBfafa9_joIg>U@LfTr*Zwv67p|jV@fF3OU``d!&sSIV(%Y9P zWqw6qLi(wPuXhXuA47>IWphLBLVTk)ac=}J_23C?^}QAZ&Jp1 zZ`(WQ%4!Mh1t+C^>G#3Mv2^AXn*WTQXKjK1CcN^<(3<9U+R)(-SP+h#j~CE|{&S%v zuP-9J_uL9c6;W1vEt9LA4C^^Yy6MTt#tS>S%zgdi-=2&H-rFQoBPe3#O()vUZc({h z%{)~)EPOhgwza)IaMH&I$dOySm8!ho^NQi%u13opIE|=3XAJ@b&=q%42Rl_=6z^)d z!TQ5v0B`XSY8cP%?s#p-wR>~<*iQf_|Fo`4`0UIG{jvsk5=~!o14ERzfv)#G2g2w6 zdDH79wOnO%YLZ!HlN<(<@0i=S?dJK1^G=s+`I5Q1VUc3gHJSkW#mI1PPN6oQ>$G?% zQ-|0L2HbAI)@FQCecxnUT6c!L4bC}p|9H>)l$mVh&w3z91026sfQ1MU6bAg;?!zL& zX&p#W!6$XsH!|trAg^}Dq|dIeYC6pe(UIe~rcYXV>qWo_-l{y!eyvC$ktZ-^LyPSm z#fY2t77rWS>?rrVM&Qk}h0d`R!Ht6RKvr;Vl0q3RmJAE~ZQ`3~UofN86OA<1Ppc9F zoU!4-j@^0@vH|c)RcIccjeYQiH+!W*>&2R@<$YJD{{;Z@rHROYDJfUAfvG|jtAH+N z6s@u$5VjYbrPcsVkZ7}48!QL6v6T6s+hG8;Siw&xY{A^jyH_{!zYE%X-YKx&6ieo1 z7jpnX!*)Nqs^y^?j_49{tea?{vun_m`1aig@ASAkiwC0mwCBXiIs3KXCpCH}@^lWM z!8Ew)xpn~R*+Cp>ce|JO0MrBCWf0?+{YdSJf*`1!1oNd2bkRX@rKd!UFsX7>04IEA zlzs3`J-`X=KoGD`&@6*suZBRXcGt;O>R6O#;jyCfM)*b+@F!#&tU$TCGr~n%(;En z^WWxBKw`VH?-8|PYubSP(9D(4k|eVZ3cISAH+ig(O0*ql3rReuM52(H+0BinB)8wox65OJXVPOZH6)^xTe#gDD8SR`7_MX>dq5xVLd4(}if z@t!eAxhjT8V-V#8&E!LzM!gXYUHf?d8$?dY6)ZTs(I6rByXFY4_1alV`JLYqmH$#i zO5AOYj~4$0cxD9<`95dAVv-J-Is)>^Jm7tlZXn?B8n)Uer$MrUY4p{Xsd*VwohLOX zPqaXuOT!J{x*VL zWv6w0MMQ*bgx@cgHF6#*^#cq(463SZ^JS=n_#&Dz2pYQ!inc6{ChAWcX?a1LWQD1? z#VnTN`#6K44}w41yT&Q?&NRx7WT?`NumFkL%Y52FU78R{t5rSvq!H3~GwBIS2dZ&( z@j_tRfEqLfGZP%;>hlg@RqWRU(Woz$WVaz2kM<(JY6o(Uf zhI;S!GDGHjlj}E>L-e5hkP?v2Vk@~%16hGYx(i0RF*GUHSCF~&AI;H| znv4@jRV45yB(9;F%9_l;as9N)@0Sb=`>uTup?7D-xVmCvB-lXe#|h2WpeU%Hm}xbb zUv&2R_AO{N6E&P*ICF1|>(QWXc4;f3jz(aGL4x-U9>r$7#aeOKkSN1FYXrA83|qds z_xsddM{(SjX)>TFvRuKRX1|CdLFm|w-i!UJ69K2b;>-jPWN~w*zWnFtM1pfz?di^2 zP?7h8RGcw}g@$Qz38`$jCp9AZJz@$7GMj89u!7adeSz@h0fFIPqs8VZbMk#X=_r+U zWAHsVm=aHp;PikJox?Zm&fM8cm)}Y^WS|T3{dI@U3l7ZGbkx$Z1T?SeH7mrj%4qN6 z>hU|QgMoFs7*KhK<1}N0LN!T8{&^~?Pz>3gYAe7!141s|(5OM181oT6|BVn<q-GjL943wr1Jin0Aii|5gsb;j~}I%{HRsH>1iwaBKTc$_xi` z7=UW@8OYHL19JIENV(M6g(}t4wI^jNm^Tj}V~#L^48JT=JS|bTv96QgeNHhK>k(Ur zka!Fku!E|iykhE6yN>$!0@XZ`WGqI!e8r>G@TQi()D4R}jU32mo!k*2VBN4tPe95ZOUyzh3kxu(1;PX zwr=%j3^gON&Pf@2)OZd}viDN6dm5jj>9V*p;Qly~DYT zkO2#eUrVk6yw*qQ3c$^QB*3_{lwM0NsNtcmT<}>4)}&4snb!|gbI-tS^4@k0w;!U_ zGvVYKy;4|vL~3NMZEw4JFW6Ke-9}E#;8#YtHlL7O#d!G;C+pnVZ)|-(RN47i8Uh*< z$6l9J{tyqFtxJ~~S&A>eEN;^9Bk(CRg1L{yR;GSlIa+b$wB)YXG#a9rQO<~zd8+m2 zV@$eTheodmvv!?ba9fP}L6$BjC($U#mvnUGe8`RBf}K zM3lCx_I>X{ZCmytVSQ~g@~FaC-uHpWQW~v?bQ9X$R07i*W)H7(@IoG z+*Xg_Y4Cz#>mET;B$5mfTdx(Cr*mpgJSyMW2;JCW!DD=pI!sU1`0L;hrWBlJyI^Zc z8kNslsYbnxTE)&=XCHn`hOG&SYAJa=j+d50oh2~KvO4PnUt-ojG%ytO{9NhQZC}TM zs-7CbFx5*=eru4)6mjsXTZ0$RNU}&4D)}i=P8Z?%rR?oYrgMp3DWGq{O4U78-kYr^ z@bis!rorN=#&|=P_PkL2eO7B81+)RDt3us zF>|v=7Z2se#c=uUfp+ori?Q(m_K~$CUe;C*Tq8J~7U5y09EtVIQe8^s>2d|v0)2Ws zy%4+zkwz~(?)#8-Q&v@6I^+dL+%M93Qm4fcF#6IcJp_N?B_*s{?uoU%%xLd+?X(*5 z*EeIIe;m5NsGSl!it6;n+siKG^$SFg+Q#y_)L9R$4xV#Sev0VrU5mM@j+Nn3=3&Sj z7Qc4L=8cYPrEHwQoyPn|Wa^i+iaKXcAc|Z9o)<-)4*-gG6|pO7P}8Z_&^Q>Qk#h zg%lrPN$7f6=uyuPggo2L=v$E&mzHxa;Ee1^_byaDb_k`JsC-{4Z(G|Ax1ny_fX(q9 z<6r~q%sxnpx9znztlPnAUiD9PE11m_Zv-|LXEvy@JTQ#Wv=z^+$=_J3 zOI=b!k#JDESc*=HQn7<~rlYiflyBqp@n*CCixiZkKTX`Agy%$^gm1kr?xAY-3zw+B zMya!PDx|zbVnd5C0)S^_T_dLFq%*Mj+RV#dVPeW30m-!1>;32%+I9hQ@C$jC&`e0Y z*+GRCr-)2QxXjUnj9>G5^+CoDIK9X-p=BD5Lx-r6HI)B0gl#R5kFLc4x)77^dyu#b zu)A23A0^%{RS433p_{u0$v@PSn`nTsi)8o;<^V337jGRv4aHAtB6(@{KRJZ1fZV^r zdUc;(NlIpY7|mh8vyTcKCV2prtq09BF~k-&!9D&zbn;Kf{vRWjPAv%$c<;%JaLW9| zRk8h%yd`k-E^O4&HOd%T)A`Z^Fj&D^BVxsH@eD$(Q9otpe?-mtV=wSkd(I52@2&QG zAm%~;M4_@<(5&2Leh7EuhOti`J-XzytDFrKJ_6a3Oq-*MPSFaQ(3GIGbIsTillRR_ z;X6qtKl#XXt1(I?-Pw2 z#0|%(oc=p1D8ytZ%n7n@01oh@>+aK47Gp6`;WHD6M?w{B+Ozz{7s z8|+8~ziM2_MXR4>#!qbhJ4C>kiZQB5{v*j&%7a;s7&Myri#UO9$&%{-QmWi8gUY&5?F(n>@C+_kC(_JY0Z{d&`zt)A{%Na;Bj1xcY2EJ{E_Hp#Jh3s>dIdoalUq)VozgA-lWc(i+W*7!dU zj42=dBrEftR$ZqWs0g?DU>S_rH-}U?^p3^XVZJP!hadl3WlzLkVG}ue`5NP9Q71BA ztNP?NaPGSedOh?`7KYqY7NCAPAiZM8+ z+n^JK+M0e>+d}-5gR{fq-uCX{?VP|lUD$_H-;=CSG9%ltB8GgWtBlc8!hJZ9*q~b* zM^(2dochCEXj~1X`e;tzWOw|8-bd_vkQF{EXSdCy0>h@L&U-~evwSm7@*(K-fjq+~ z?(~jgGi*Fz-|lK|kq&-RfGGsRAI216n{Dn2e|4!CFp4)|cS=Wa{^?QHAD_M zF6ii8AaHhR%q7e<70n?qsDc*FQ+j&d(g|~-9;X+!r5_5qOmL7F|03C>5TY}o+=QyToft=b~Qf6{Hm3quBSuHB{uUe)M(GV)(kPb5UfC zrxOgFf0F%!ao!P}MK&jm4{>xX(1_M}Uz&D5ab}l@E~g81ENKfG(cX);yBek9KcZj1 zwe@B7uP~?gG7V;5$USpK^ZMEQloPu2FYycK5a&1;OSX1k1`{nbw za<|8Ay2pP1%$i$F*tZPB^BqeRLdFw{`TWrd_FZ?!w#;&@m!%(xOx1LH+6TEQo#PHP z(-FnVm9b?QyPk+9Ht-}l%`jmw`ku@3)jU>=y`;(2Xg-*jD4ZxO5cCko^Xq8P!qa-x zN!e=o3B@ARUp98~pQ(>H$+1V;#ox0DkmaZA%8w0Ew2;NNN7pkR^g*0tn&q8jBBfYs z$9i^H9igls?<{VW^gWQQ7M;5B5Ev}*aTjJ7JVlHx7R z54>5QoUR?1FNqb!AKcd*J%O#1#b8R}`GdvkQS;fj4x5sRqo!ZsUrh?Q#4DsIX!wK2 zdz9R?d(>>=zYUqXI@yg%5Iu}Bdgpn+Yz=IA5pN|W{H<7|{cXm@)S6Bw(>wlB(lq#7 zA4Wf?Yrit$vTRC5&J#-@w=#~#4{u+swH-*kaZ?}$^VX{vQ$sy!>$~lI^CqJOUR)y^ zS36;&DaJ+Yk3U()`j?4M@AHJ;I}Bvm*tq6e;LAwElEu$IH#~VJvw6sf)w9SoIge=R zT-VsErQS1p**e)4kDp&Pq7-$hyJp((OyB3U?SKgTRg1a!UbU=y#CiUdBy;@}#LCYnNnp6qC&kvbfDD#z8D&Ti< z@6V#Qz|%)QH;?ZvE>@bnOVk`T)7+0^HM!1}LRm6%DF2d6o%+@3*9nJ9&G^z+I&Vwx z_a1ESo1@?x?C^s?SrX4Q8Bf4`3C8mG&`VlH7j+79D1O)~jke91qZJ6vuqn}JIxy}; z(ySIzABkAhrz(b73T75@{^vbX{27-XIi1<q$%G4XF?b#mULv2cRWQvMTy1n%X53l>w zMd7snxRBJ9Hpy{y8SH}Wqc3gQ4v5V%QP)mUQA@WwN8& z-Mveq=Af+`mtMO1^d6t%lY^C@g5>g&xbz(~$C?4-yV|qq+uZhe#4K->lHTRC<4lV? z$!vR~F06CwPFdOh(h)>*nO^L4U(2zuQWmR59>V6}J}Had7tIjP7; z;(%U-tK)Smc9g yg>0rbVJ7m=MVB{4eDdBqSOnSqU)>PvpG}jP!KL+hEz|({-rNAq0%4)*b)?{40Xwp|GP(i98W0fIEqVy zg#7s7p`QZCsM1sTama{g|BO7woqKri&$TY&rFQUB}>*_xQIH^2efXrCdVUpO{hVPI76I=K!qe<~z! z^+VahjBnbOVY<|(c9=4)fP1RYF5smqE+#}!EC2w(q?K0Td`exce>PIF8?5Ue-3uY#jezNoip3U*8DkJ*XpxOTR%8mT=uw-&qt6WdN`_vR`wGEoDGq4G_ zu}gpMa;sgT$3jyPH$7~Q^%Te5lmnsn$@)OlmozdGxpZ97wyqgWcW2mwsK9q16*UTT#G zNra+DRW`vt&$=WQMM|#G2j5pE-7UeVW2pTFxX4tIzy0L9`{_p(H){E-nOdn-B|~DI zLl_R56!yG7*ve=UuZ4QUa0?jAR#dXA1u`~RwAghadcP)(o={Ebp}$%dysx@%^}k;2 z)^0awGf}MRBD^YnYQ0$V>r)#m#DkTHp1z>0V6sc=7rd$2dQyPMa_(C}Y6{e`xv+fBrIRwmt`X61c* zH5GCyU+H`8i$xm(%5T3Oro2A0&aA@P9MnJRWLc*B_|+1ES^;rAHwdoN_Rq7wOVt-n z=CljF4p+tIJJn_uBP2{RYCKUApF0HPFCMZj?OP_bBzjAcIo$oaTZGTw^@n@3-YHZ2 z@|l!+k>dCjvtNuaX1(gD$VjE~bF6%HzVCh$N`rTu3r=%lm{cCQi5AW6!co~~AGX=X(p9&UlJv}>sb#q6-g7GLY`|>wH%UN6L z0-jMBf^x<(Om}BN=dqI7pFrbD=_jSreja@lB}oQBb@w~U^*+C;jUZ4u-S?NfYj+hG z(uO{lR4`X|A^##HBY3^=k)kIKD}}#C`-4QlTo{{Ud6a>L{H8r-rq^~k=-vKAD zH1IvaNHVC3oA@Dn&nxQk(z@p;?l89q9>_>BseESheTjkmP=&Dox>Nb>?dEUckz0?| zA5p&CJ_j{G2cj&c#HHbk_V*B%X5{j<@#)j?bt`kd1w!gFsDpZe?#>hD=hddy3`w`n zmgP^vhBfHrRp8|!Ld^+=o(EMd75*Np4dJn0yQonlWkgR-r|;cIw%Ju~!&+`~Gm3`Z zb2@8Wx?V&@?c5L421`j3>emPd(pS z@4U56Xa31|+B`#lpBgE?yTjkY)=2GdeL`*wQpmFmwr~{z@wsoZJ_=t4NVkoqhKd+8 zjI4;+t>@_y4COm42&o8b=G*aYj8kXGPnxjbZYW{w&BO27qptShhZ$bS?y>4*!58P) zYrTpK`C+*!u-;z?hEREbP~pT9yKkni)#_x!N1CiW+#R88hk@ny*GiK~ zi;X*$s*WHh`hb zYXNhaZNaS<_o{K?v`HX}FzO&n!7)F%jW6xefj{$NWTxpvt8u+m`kd(C8D{a-sqb=$ zx$h9=%~nC^TwaWvL>-oI{9%*@c0IA2%lhV@4y*@Ht-qrr+2|kd>Hhm0WF^BfU+LYQPR)hMh>x2y#da@s*r@>~uO+`jv3`ur_1s_4hfMD;Jw-P^-z2VkOy%ia0VQF`; zqQ0*E$-ETjbU}xvLM~ftkRZ5I%KWHvfMj;X%VJG+T=~i^$Khg-;UJ0eGe~~K@2Y!G zj;^>bzSVuVEJW*#cc?;E-Dzr?$c^hl=s z$Ilo8>g~wvo1IwW!zzugMjYNV9yNf>f1o#vKMjA|?8B{FuZ4w6!?qXTwrP?r)|-hnFR_9Fav?drSwFHrQft8c$g zL1VC=vraQ(z{8pDE-%J)xhz=6lMI&)H{?G;_2xh+@#Ob6)w~VPy^pf$Y{o~|EBNu< zpfL8yjV%9J@`m@V4P^6^Ne6dvS?%$1PfM0zhyHI3{KM7hn?$j{tvL3mjOUfZ^b17a!h?yIoWHPn~Se3uX2snQpdSj{#UeYdYk@ zi>M=$L0+VN2VbiD8=P%xl{%H26-5|eP6yZX#kIl5HEn4o6w089f3gbpk zdRWdmjTR5|WlP8Xk7{-a69vNq*G|S;A3e7+X+c!NX_v7*v)&&xPbxK%yY-zIH4b=fTR_ zhiTq{Fg|!_v652hOET^<&!W;K=guagh>yu1<_dCs(=4(=hzZ{wuTO7f^5{65wF@=B zyInN`t~!*cK$M#bZ}9gN5&V)s5znez*fm`&{=)M$;pYG#)ko8lhHB2VW$S zCxu%J?H$^CE2qiX#(%->hDL{`76-8bP?8*X6+1(ET;{&fr?$;H1-oA%k1;2v9g-MJ zubP?=jg-E|itHDgu+Dff-!LgEd7~4#ba(Tu!$5#LVPf>%Red@6++%P0%j(-~p5u6` zvUJj}K+zZY(N`j?>z29n(6P84bry^~hlnUCcK3NctlZuaDLb;-3109e=H$U6J1bcs z-~Epq`0&eO`lZ$Zh?UQW2e-^PI zt`*}s#*ZQ!uP9A@Mo(| z-tYzX%WpGT9)aSe4tviW6fo)8(H-V{A_?^CjProe;`#{^L!{SL>`sV;YaVEjrb}8B z@VzK&88+Rpo$hs9uNPl5Vm@TOt6lz)K}j#az#l!G=XUprbc93u`H?G*5o3PJn_Jv{ zvb67Hs?+WyM5gpwSMq9QNO`j_q+w*cD zy~J7&y#Oo7^4x-eqTgvk+odi_Pf;eEtsI#HSFtC>Aj6u+svLKsQ%!Nn>Xqa?m0PZq zUJ(dZs+mWNpff9^b%0y5-fA{@ir;E%P$Y{gZdFc)_p5C){RG&dxU)tcXx)+M{=uv- z^M>qKG;p+%3J24>fEywvB0^TrEOPJP$Lt%YTlY&2hg{WJM_+r8Ol>#x5egn2G7jgm z<3=V~RunU1Th*6C-5G~6^tqkMx+3L@vZ@O+W^U-IWM)Z`bAhE#7bgkW z=EAe#r0Ru9)bk}TC~yMy>eVrbO03o(se{m`@%A%SV=S&Wcd?6+j_$Z=zsZ96SY7m0 z0bgA=*^OfCh{)E^Wz2V@$%Q37&{2c+zDXImt(GMkZNE*d>>1{Il+UEMf*w~tdMFGc zc94-iUqxgOybyihP>)UU#5_X;ry&ebJUSO;n+q=we5`AHQS1$u;Q-TQ(o)fBq4e*{W3@-xU#2%uRYO zeDn3-1jgVj!ngz;YK zp^%AOoVZ=@xH906vR@&h)C%6j?49`^elz30n>L2=1uVWdy1lD)0^)#zr1r|fj==X? z$!+iMU|T-`IxmAGYr)qq;P|$LpsxN$(;#%$Eb(NK+Li#kEai) zhMwM?!(}1EtO=5!o|5#NQe5xj33@H?jw*{O@oPPhulU)P5DXMRu{c%1-M!?-zeAi; z5-1*52Qd@F9v&a!)Aj5#o=mZ#X81Pox#w;EyZ0G6vz%OY>8~k~CnMDRmR6qzn9yc- zm@W31wPApHe)p3vhi7uo2;~fg1%1;BopW(@pM6`E6QX6;h~dv9$GpRm>`uQOkHUYd z3PcNL3*$;D5%~>>KH6Hoq01hg6!I1|9brx5{q4ua_?A#X@X?gRE0HkoelX|!Wp|Ql zfZJkrXYq-;l)VSdh!f#+D*w$BfmV&8qUGQ7LT(H@SqGP9u+xIVYhHb;Q=(J_K$lrL zJ1^EO**@BM?qZ(uZIp4v=OASv;4HZ$0P5#x2+;x5tJ&o=jJwDZa4sR*K8nAud7?ihRDMIU8E{9lNq4 zi(P7DGU9~nmr5y=`nE_NnBNIzQGV2NJXR$)a!?@9qNOKc&yF^ZCmoe?ct_`H?D<8s z8ozPJ!^dhdovBWEI`VCP!yN?g?)Jvhj%>n#LKgYb=s27bj#E;Na~m{gzFn9SkDoQf zsoL_neLY3)3i3m}NSv%A$9~PhgQ|>hin}Fe5sN_=$E?sNpfU7kJO7JpqiGR=JFB$1 z{2nVtT!D?501KfSxUwh1OagC<$FSABzmUCO7D zZC~|4UfPa3ufv>@XKs;&+M20kucPOpXCa#&%RFtv4R^3%M1}4mc>tP1l!T;bv4Oyp}J|l{sVXF~ZUyPjwskyb0uCinObb zDb^ro)`!R~o2kX$UV%q5a0?V+b4d1qYA;d)RbM9H)!GX*zEF`tt*0FACzj3<+G)LOKr+ew=a9RBg)nZ7qLy zJ_yYN(%LR9}J%SH<3q5fD(=H0o;F^bKp{BkZCWE7*}Aat@t z_LR3Jh!ou6vzq^P&NzFw7eH2YrTD-&5kf7pb*fa%h{Sv^#+_D3x-`mWcYb4WO^ks`gQqOIY%S8h4v!K}*%@}XG5W-I_7>if z92csYfOqvlqf_k(PnGsP@$P=PsD>c#Dajp8)j)FlKDJc$n_{zlYp9x?P|?{b|GKQL)-0(I7BvAmRj6Cu|#8W zEPFiCU}R#^`s>qM7uV$_)~0gpO-ZhJbLK`j=@&_JuEU2MeoS!D z)1hLeiFV4X5fJN!-6IN!g#%^RaQg~>c$)X=jF;ih?G7VQQDr{BxwKuct;7xu<_ws! zi+Xm#xyoUHQmR!siBXE%B*$w~*eP!fEHpCs#M_WNukKb<$ZsJ_F1MfZ0klZ(u9syjH86%b;4)dY6OescGYw)60yp}Z$jIJU4?Hy*6Svl z2FloNdj$71Gryg9EgQSB1ev>t^6<^g^WyGd@iKmwxHePF$#dVXiGoF6m&0BqNKHZN zk9?#x=7}hO6X1{5aN>Nn`A%EHqu_`p<30$?JterXy3^mWVaBM7`J`mt>Pqp64X;`d zmpM%#VHM;swGeiv$AzewuI%&fc|fZlfn!D6C+l3lr(Lm{Rs?pJS39A~;yumw=CWO!>7)>lL=yn2LzJGoHmn~#2P~U&1%I5GKGF7ZOy; z-JC<1(Bs#zG9@^Gu|8yQMpis+F`#jv#<2q|TLo?P)Y;6d$O8bS&bLH9)+b-tawY+g zS+(pq9@nA7&G+uhO?kPmS^)i~%2C`7iZ3-UwbcX2KDFO;X3)D*`CF6`QESR_F*?<) zYF?(&Gm)V}8(K6zyi+#KB(}23=ta|R@w$$ZQXgPjws@tCJEXi zavC;Y=}ftK^xmKA9mW3B`=|-`DDXXR+{UiY`0e zy&@$6+GSe{`))d6FTGg=NJMhEVQYY0HlpEGGCk_nF;@rnl=W_A;ohnMMKGx+0T}~$ z%7Nj9chZ5gs!hiWXB-z05G=DXQy0zskd?}un+*h zS-lxp`nh)$pDH`%U~7fOYeb36n6TmnK{i={p@Aj7U?!#7Vb`+k-AwMzV_v^Q4NsOZs?-MAKkHJj?og{$uwk7WDsP2pMSh= z^mKeKJkRf#+NJF`^0n(E+4ET%tBbk$WdoOi;8Ya(ZBWZI)#ZDFa70l>-+v>|>zj?k z?I;)R9S2f}F&53&9Q>v`Up*j&B#Ks4YRSZQVh{ijYKkth8s4w}2N%T)7+DtPCdDW( zYC1g3%k*}C&vUh7mZCM*?ohe;=(-MCsOTGNZDL^Q(-^#=&2bbMRl%k?ZoRbS{Z2Xj zormyrndT3nr$cRF9;mc@3LN=d`KjwMN(w&8-7{4w0($(v(5*g-Cch(> z1NK+rOXcj6Eys0#%xb*hNAcCDH~!xP(Jm;DBh$5!(f=XE zSXrVG?gmepZ`9P@{h1vhz|L}?@FUY#8D0Jkh&thkIzE#YQkVO8uY^g%=Ny(b_@MoW zX}ZObI#em(3QYg*`RNhpF_RzX--A4UhJiquohG;nzWl|P*W-}_X^SrUDE{tPg#xj` zZq<=^g1`6C>JJXUpIsP!I3r1UfhR0A_8k&R6TOOWV4h*?oSoiOsZphSh5+|;<#Ltx z5aesPHoHzE=h}wDc!^)Qg_~jxOPi6lU0|Nim7<1`+o zo$)*n0h4~s)h=c@0`8}lWe|#r+$W!?Xtlz#=|44Rab|5LcsW-!6r@=?#eVO%4|&#~ z<|NT%&AOvWm-8T*UzD>2P#jn zr`~a_#7vUKQ=$(mQslurj$)b_IG!Gkm-%eUr4@Ti}peV6Oo}e3W zqQI0^UhL5(0(IduJ;OTDT}D7w(@LqIfgex+RvJbASx{9YcJQyy?yn7NuF?(@8zrOD zt)Y!d*Y!BCL|d{R;A{&5P$*bqV5{$FBWeBMG;19Z`1*Z|_2wSYR67kNTW)M@Y6RJo z)ntp|nv|P@G55p^v9r67rX@aU)fdb^y^B;3_HvBiXW~k+X0yd|rXuT9O+l&1oohu8 zPg#`3F5Cm2dW`ve4TOe=*rXl_Aq#X=U2=U_8m^*52w!%tw)tk!j0HV#Mze}8~s|! z^SaK7khsBN{QDOT-f@uckLuy)?Klk5pRek;PjZ!w-8ANwKru+?b{h+tvg(V*C(u|s z>xpPvIp1c`J3k@gvB>!bPIQ|eO7m0jI$Iut>#y%h3i6c{?fekpY;hU(n$2HTRz59$ zf(g`QF?5B1x!DX7nJ?vNVsF%JNJooOkf9}#tvuzsBPseRi`=ZKljDI=dfYa}zgU^| z_aox-vETn4a1royq1kj_ zU}M){s#5=cZk`MM%#I;#DEMMxXFw`K)|5eJvB;a!t*7VB5WOz82k9KdtJZtd>4rDF zRhIO!^m=cy)hf6ihs?G$-*u;kdk%iJI8nd@!lIlL0Jt_Mx{vS0Mu@A#vfFndKn9?Z zY;B>N!SR4rnPyBLEl0|`e6ehIJ2C+KBDh-j(T9qaV!W6+*~*B4XuC0um*pgC*y(TG zcEG1~8M#ICdQZfeI`3NL_3NTxvtTpt+aNn)Ha#ZUMUZdaaGE7KqOV5e*N0?%{Kf}^ z@C+%S>@hC9%U*=6{m!XlRkPmX=o51WC3>C8`P${KDmLW=QJtOU{kZB$94H0&`ci{! zD3!Z`L*LtGs-kJ}J2C9oZdISvzpkx1QnPe=dO4q^-YKbns#x`hJw@WYyf{Y69-y&6 zKx4!xO7DsWXQIZ-!0v49u^8af)_9|8=y&T+T^BYBl8c!|Jm_$nrMmG%dOn`7QsmdF z8}Pp8CyOndAu{5^^|CStK<{CyG5jbQTC>#^IULh^73*k=>i|}|+O`Yp09N_0k^ObV z^riH2dY?_Ecay(qH0d?gj^mc2Er7PM%4r__ZooU5=mZ1itBr#@sF6nEsSetUiLK+b z!x4Z#qR`*_Re&#-XMsxT1$Tez+KQID>=$z0lxCO}#F|!@?dXnv*pH$zEh?1HR?x`K z69Ayeu@mE9O4cS|6K`;^VrG-Mwuq;IvCC|CpGuvbp8?v~nkX&-0XxBaMS!A9`m0#mVZe*P0?OIlW z*Z>~wIi?_0P_HEss8jfXXQ;iuLE<|xhvM;0g6rAX8&&F|{A8|R5T%AAlU$bcTK{At`D+i)3$nLWO^asp1*WDM z$C-l`)9ujm0_71kLGwaX%Mk+(D;Vc~zm-mVeZ6^TPGQf&H^&Dv^a>qC7oXw)&~a5B zwIGvWbBE)Z%L=<7OV&U#r9gJ zRRt!90iWl5lYM7sbOMs_;3bK=FC1jc86_AVks4wrozpXg%Sofiq|$EYD~Z*1N`5BJ z>wTU6od0*;&360{&rrsFD?Pgv9Ns7im$SBVsaz@@kJrRRlh(vbNuRD*eA`t$#G|Lz zJe!_>Z(~=;nuOvj>>cnd7L!%N=wqwnNXC4sEVE({lNob(B*HiWkj>y(Pe!kv;LwoD zn?aKcN(T}vNZ(dTn)M8#{xW)qBGKe&SOR}k#1huy9E7;{lW?0%ljFUK8 zuK60qFvMc#KDsK+p4{X2I;=31*em(>JPt5N+`#TVk=fO2|Ign9Oa)1@CuxkLmYo$s zLNE5?>7^XE$Ch+W#{rQVcwVY4(h;jV)Y|QO$|Kdrx9BY2CRWSl-gKO9Ixz zREu8g4don9{Oej>AogHB6Q%_*U8rrc`GA&ml%%S5xjA*AvgQb@RRIShc{iV$*t%q> zmqG!*71K8WP~l~4`I#Lnt7G}La)G}5c%go31)nFhDA(5O=|hX>2TU_b$42ZY4SUTp z!8sPqc8){6`VG6IPU&Z3xJWu##kAyBQZBOH(n7^S!~h{ng9O<$>iozs?Vi zH3T3j^ujUrX-{?3--HHjXUBvtW#1**K~jrm+;q}_HQc<1Clf4Ik;N+^QnJ(1kKXZw z36Tt4b@72U)CCg@B)Bv4H&Qk}+mTzcLk+kQR8?DU;^6B>6X59nMf8V^FRBWRMn1$W z)N+7@mHhLlH;!hT#?P)Yl}J1}KF0yr>E$Nmkj+Q+l&q~6jA7qK1UdQA$u0CMG&PjG-ug6maavbf=n(~l zq*(%1AN95`_J4BK%N8`(+UXB#h-i37@!vgg^cQ83&K&q4P*Srg%y!^IWBAPZBySnl z(P5Cn`k86kn>Gh;EBijnyUqlG!cJk9*=HDBw((}T%bjMwOl}K|&`+5r=hP|-pY_?F zhA4g*kk{_DJt|L?CsaGggwlgD?B-hK2@QHp3sQ)ifwl?;Z7DHh8Zkm1biTU;>gT?B z<@5=&*{9_%&>v`n_rSe)<&#QX2mkh6;1)?oj$f{2gCe;aqB-^aptrVLwe@R(t{USJ zFSuD>ZC;3ZZ>%<^ked@GWAl=RY!U9%V5_llVt|!r{9~?=eY#zs&g9}}lf9I4^YcqN zo^JMUDi?!n({FlQXFe8WQEA$Y`2rY{uPejGi=+uldBC~mgI(SBaWj?;?)732{J18T zMZE>@O8v15m70a4hfGk#6Sd|g-xpbRba%-jVYa*?SN-^*w1j1VF_oKUu+#QW2J-Jq zG}gY~#4T0yvNY`be@dlJeJT@JaC&_HDHzN-8JmQkH8MU)Hy3C1(z;hJszPxOSAT7X z?dK>k*uo#$UjPf>rq9V}<)J(m_TD9R1Fn6`7>GtMag>w?pp6tk%e&Ev(bx=Y-Xb!S z2cU|GeY%o@?0i5++F&Pt>&p%>^b;F>L*?F-mao44h=rm&fgclWj*DE%l3d4wQ)5V@;c(M@tz<{IDQt0LVz)60`ZaE8H#;=e>_ga$In`C8 znJrBjlJc9*t+l4rr?aJG74%5KPNbYP)IqITczV%1^+44Yv%K8Z#%W|SfkBBOiO?d9 z@qwWz4AHC|Ib5&y4Yd?c9H!g7PRHL|GxOuCc9=5zHG;05;5DjGuL z7FstiG9v(`MdpL4*R8kqQ+^ufcyCNa8-^pm<>G>zr@XTtMuLu62K(V1-#5#z{z!jq--!2mw z_h~N?_+7p6XVzv10*NS3O-SALH{!(vQ>gmD;jCThn$CJ93gq}zEEm;-reMW=x-aEd zFPIqC$sjGbmKn-@=exDvrcS}#8&3+ko>-b1YZ9kj zoGa+?&qyp6R*Qn*|6tRe=mj#5-{{J5sdt$`@fC8$>5Cb@ttWl?dXPQ#jx=Br95OH4 z{D=f|d_vXKD8dL}+pLA2U6O5dsJ1^=7r@BB&YfMe8)*liEyUHa04^#ZdQZWm61y(| z0xuJ2FHL9*H%32H@U6B8fwgu-w@s0ITgZ@eev3VD3O53 zEP_3EurL=9FjZd_%i#wIcXewahDNUO-j{ORx{1T>L{`|2unwV`Z^@mtY@TrA;;?v{ zg>;l+-N=Acs-alTDc`U88lG}knxN+-%lWS6T!S_!GJ;*ivh$L*?!{iDv`JB0XC2=U z!;z^vbyFsu3={iz;jxi;bxEhzCX$`1*5ZT|hVDBD?(XHGBIJslr?q3)3z}K>3&r~C zp0Vs_ktDKex0A+3nH>x!VWrXtC3Zb)VIEL=BCDf)#M2D)Izlwg)8J7A*eZfZ@YdRO z%N`XjL_EbrPFUvsW&5(uSSr%+gOAu6NZDH34p_Awr+SiGWIXpQH_|qrbclXU7632lQ;+8RTb?^38xP?#^}P{Ca6xRPSO9>k?8GkGHV(bu22>Uf45>st_gTbz+G~ zj!}~rlPmIj>ugvkH~E9WkB0|}b?co=9L9z_k2JJ_N}2T&2F9@CNsNQvF(;=lDwG`^ zjxq}SwgwG2?&dk08#^LM)`q20IcCj&ClJ@Q@P1Uv%2agYP4=Kl@>chaEUL?sppc5v z2cO`U52E1uMm~kj4;o76-ubL2ooo%-6gL~E0hnT5R{H~nbKHoasF}oIWT+bu{uMQ# zK1Ysk*r-u%Krha1@`%YsWj#-M>+H~=B+)_>R5qEo=d>K(H(r4XeXIIW?aZz~KOE2Z zLbi!xF4sKi=g;Khn3m8D^$7QP$;_JvmZ&^IwFd8ctJEc^dq7}MoEN(bIG*~pmjuiB zDj3rK*0akt8jodS(W=O3|1iLlC^w%K0bsFH(8HfJx90!4sWqV~4{pjjv?_>``w&WQ z#|gcpCVL(=K)!yt-kUV-cMx|U!TMSo-()jDV(<_fT|p{_9^wP z-fW)NI24G~)|l|;6fMtn+#KWHQ&i&psyf_?baknQ!}?;2Kq5 zWdiTm_MiI3D;Y$AF|bSvD?uLRtWdYyV6x4=xo*DJ3ifRSlYI{!c=Y%o9(wb5!utJO z?HjpwOf=DqsIEOpQxZw`zL6<5X^HjPTXJc-l; zaoey=x8aK6$CnWNP-iX`_ga8cqS@cYl(gwVB7fo|yMxvrznvu}L@p;P*DSTjbYNsF z#L6i{oC)`FRS+%4XkX3D<9KS;lJ>vs?LwU)*6&JC9{X2gos>k>Tn+O3F#Z)$yAVZG z$@iDfDF59XAnqq6Q$POuphr>x@%aD$`k!+3|Kp^yKCCv4gOlIe&fFA*SgE-Ft&$_5 za*Aj7Y>II6-hs;f6+5LI%oqsO9(47gYM#A~NzzxHuo9hwDm@m5{BINqC57$-x3pc; zAPq(!ZQLhW?7!?p3P8a8gLvq-`oaZ)6WOv4IWfYw(nJd(M0u~8-u%BMdGKfG_*M|# zN&S1GMlSm!j;_b=aEI?vytK0*?w5M}FwVQsC$R{g4yG-ng2>AASVk zXexdFyGbOJugcj{5oBKaKi?8jgnVnU;~+u*GoP3I_kE!g#gFS5D~`q+b`d5d|Bf|+ znS2NEHY||^e^M^Py^DRdaipWVOi6L zScJv=A%F@As`JeLrtO!!F!KtN(@r37Jj$QP!{S6WH>DLY^b(#i_rB!~q%~-Yw!i4F zrXl{f_+u2z=58?Hi<%6}$I0q-QAfJ2_$oS3umTCC@?X}99^qAGScJ*trgBTWVdI9= z7NX@7Ffa&I{$psj!gu#PBIYRA1jQr-IPp?u3inxd=bOIO)raKpfd`-DX%Yc#a_8EErRxfLdNy+%PC^cgw_Ktobt+nL_eK zLmyOOOk_8ZHia@#DGWLGtMX>nYu%fFMl^unH#l$~x!iw(QBRGqM=BKkXRNY2S}>~@ zWU3k8paFVBHLjTQ`>%8ch+@uARlRGIe$p;3V{HBTy~ZKMQ8s0a9%oUd)~D733rao3I&K5Hc@Ltn*| z|C}?YsI&2|LU1!7aAzd?g*aQw@6JNSG;h*B4i_O~ujo)AF|NVAe)Y)IZ{VmUYaKRu_#RU>Z2QQjte%Nt@(`2C6`*mpvI?O>s)RuK!)?(<+9va2u~ zTQm0w3EgAP%F$M@8V|l8mswg+raY&>lqYa-1%z#xQg2ipTmZbV|1ntxrH~rjnsW{e zvt8ChQKi0SPRS!sjisl*AH@cw<4OXp$Y(A^whMAf)-SuP)_QIn!L!SPl z&?ii~-ItnX^CEf(o^Uw*NY+-RW|z~Xs%7Id`R0P1I9R^zO?1M;;A<%MU^5UZ8Tx4- zr(C>%%YK*8ZRQR7R~(fgGiN5g)o?QU2MS-fdj3aC5|sMuxF3*KDE-NKpyr7wLfYj! z1T`$1lrr;n8LoH+(QAEx`egGq;I5MxI=f%A))^YZU zI+8tlK-&>iM-(0u9Do8{X7?o%^}XQ8^t_+!9mb9lJB`8>f?F5=0p-!+C>*{fgQe*t z={_C!%3VG-R6--^pJ>(pX$&`^qhJS6d%H~$r~{De{GfY07_lOwV-XckWk9_~j5f_B zuOjnr$>=Q91*K7l-E%A3`Y0Yz@M|80Q_aMW&a`|`R)r@uu5mBl{3(Qy`>JT zp=hqP#jYjZB{K{HL}E!&)z{ zF;+J3;#pAdAaoD&AFN(^Lqk9;xT)Fs`%l{Rz`RUR<_uGXW5;@qbmGLQvt~VO|C~-S0D1nAUa%rF%+zS(Gc8?5 z%+{-u9D!=&zp|Aq3a0*cwQhGLPC&ud^$D-pV(p)rX=I3g&G_&Yxx`)^!n6)r`6;fp z6HEUe(Mu83Ou!VXwU!DC-2$ytP5G>}NRvPL&kT?}E~ZwPA!0ZkWTCla<3qKfoyYN# z#4-IZ_K^t}MT9Bk$9N=vxq}q&mJZSJ@I$VH?w_pW;6GM&T)zis=G5W$|8oe%oB_X4 zr4zyx{=GEiF^cJLhgSGhnQm== ze?M%he7?o&q~kNjVav&I%Al#K-u?CReb7^C``CSiD;P%WZFE}GIQ!CFhVTgEg^Kg` zH*s%19o<~*R^H!iiHu|jdaQg8(0=bEiHNvNQHqXXDVCYK^|mRPUaO&uFZt90q(~kP zHA{=2>67^=k-Lktc?W8K=k-)>o0ez#4fejLW779~mLjFzjIe@qkti}Jud`XpwS6lD zE>S;k?*o-(+(-P5MQa;+Z9F&n_~O2@?W#oVGkW{&zC)hz?>{kkfFmX%&wAwM@dJl9 z-MOEM%sHe4r=X(p%;%tKt8p#z`k?ucGg`Mw7PzuCscl45jLqKSczL{G$X}?OW$(+N zoN2qr_t$N_LBy~ndQn#Z|KA-Lh~5Mn!V=9=Eh{S!ZzhMuAPJ81YXisxI*U^9@P;p9 z@?rihipmSYgT}n0v1fxzK8O3Q8-MNhJI3$vatYSIcZ#z7_Nser2@D{v{JUkfxFR=> zc{~8=-{D={vMutcKfFiQFAU=^f@eMH>GIqWt)~V~YB(ygx%nwC8N>I(3H;!MOJ|1s9fl_AKpa@MD&$hREQcpJb(okVgfx7Ug4IUP z2zOZ3@$A;U_UjOB;>SN-2k0f#Si_&QC)ULL+?}hlfiUG$8KQzi+{SVx6;lB*3VVyq z9$`*g;cVRsm=AG0O%_73nT-V5+iz+jS`fiP@kwnIV*P`;q!$^+Z$&QG3D3)&Y^e|KW57b;X& zgIDq_M>4~Fj{6w(N3baMmUb(Oc9z@QSLE9o@s~ZnB>B$DQsBJi<_m}6!19MlbWcf#qn&k{xKjA zealxh;HqI-ZQ`b`ks~TnI;USJSN?r0tYi6)Z; zNlZGvYl_da-tWiW$FcW1)?WMlzUK!&rrvYjam6{#agKA`^2E7^IF>I(Ol_)G6385S z*nlR(;VrGBmv-q$n#g4*1`*8Fzb#W zmVGFzquSFXm8+g#SGlYtqdc9?K8c)q5@{ycJFKaImH0eD1}bjMe5P4toBXCXhD~fx z+E9rr#7-48KAPb7+Q0}#tn2bM`PA_(Li6+`>z&P^OoiquvA{dUm(C7B@L=AONE43e zoMW?}!lpK>)?BcGFVei)?3QoWtnfA}u+vk?>JHhG#a8OIuRvsc@^#d1ZH9r>><3Ifk{9&a7^P%DUq# z>#h}OgH65Huj@SVqH<*F2BUV!+xuM7PbHp8cQ(@>jKwO#%u>tKt+8T1ptGFGffOdM zi1+ov9tJ={pr=UKR<)#^Grmv+yH;aqzh5W^B;{NAp3}V7#Ky6+KN)@@s?10h?I?LQGacd^ZPItKI%{-Z<*NV zg%@_cGfrc=Fo8-v$^9SpVg8!G5Hi;f9{@a~`Vz(OL{kByNQMWRCVDxSnDP2F>qS{a zKdjLocdiYIe&hHaZa!6!??mrlMBQuTrWVntlcK6#Oj9N;V^B5=@8zC7A1U-UzU5aI zzf$OPk?W%St(H=(RD(Xj^>y>`?=#)-lfFAQS12t!MX>Zi47)heNkF3HQ&L&<_jSC0 zN*x_I79@3J&LLMaFO#$e+9H^-ClDXTk&pDuuF6#RowB1>K{z7?huMd|ox#M^2tnTD zNbS^|7c>&2cK)@FivULLb6t+-C_MySqB;wB85uWQ@lF@fe}hmqFnnybjIQaQXg0IQ z*U^0T<7UV4sjXyBaw|)7aXHOw_}aXVU}Fh$*@Cj%uqn;TIbKw+*(28j^IPAOhkhNX`aRLscM0?~%whK3%ttdG zg<8DS>b!k2^xh9-(ij=*HuWUJq{PP=L3dZ2bxkMpyKvmnh@9_+5d!M;5%-l+J}IZO zr#(%7=7^k)%~($LTfF2e9Dt(PqC}Nab%XbtPPE^eFQoLTFv%mQ`!Sa^?^92(ojzJ^XW+Wp4kNDKp5&X|serp>zH#3Y+H z{%r~s))+Y!|LQl6G5Ta3`Ydvv^WB;|qjg?CBPEdbOZ--Hqo&)RG+F#BTY)`a=z=|#3M(7K;Sh#TMW=SiIDcymkux)Q)EoInuhLD zLRK;fWICN3BV&z_n=cp#=IF57Mw}T#_Wd_%76y~&zS*tG#1zXG$20AN^C!9=ONQk6 z%u)1O$kA;K$K*A7>t1?nmGjC>J>g{KTKmT26>5nC=?O4G&+iwHMQ6|9Qpo>|K>nPw z^ZA2!+3afP14%f37|}~JmPvaSR4+g9P>fraPJ3qcIGwtUZld_&aLU7cU1`eFsq5YL zUiti=(P2cfSQX4sZBD<}F5oJy^ie?Dr{91aUbyj2FgA+w>_dv$$bH!ZWsN7#!4PMrO~=+1RI$v_UW&4p}BX^iX7Kkfqz)Hm>n?K&Av zas>f9B(vbrqd&>1DHy$HVhaD9{QvI9F1%$MdU}$%ufo<~-2EjRB~B=DxMBgNGT+v! z6pOj_rYPpF?|>*jW!YUENfVuS(XMwR-rJ%m$=$o&;P0Y=!Y1|RX^ZuSagzap?JHx~%y{pkZi0c|3<&p8cf{>&jO z1i`U^v+){|9H+KZEx_UiAO0ynnXM|GItspOyE|%KIng z{Q>p=hY=OdCB_>TaUyy@z-?QdgcviP`Ch&y;k0;7CHsxXWIn~sos`RQ3>1X4u8hJ1 zFjpEcw!2GB%DajwP9=KsxWD`I5ffACwo$nA z7O$EsKlBZ%gTB{AbufOrYBMAEEU29{T(zXh3v!J%nXXj#U%P<6c*A8EbjR=tm#7;) z1}DJLcY_O&a9Ob?JfK?}%|H4;<_t4l@!}8}Dl#x6aovlu@%FwfUTpU=_bU1MP8$p% zZN7G`bMJj2ftL;s+lL=;S{&?D!oCafn_K}$yTR(9a(&VDk1`4>uQuKSOEl1R*`&fa zedi}<14ibIoNJYF+|;o7Y|P_Z*!MQoyV9aN9$X1}-J;7480zOe4^^U;E#h^O4j0;f zKcpbgC=t;xY6AZrA+$TEzg=hD_wDQ6a8t`pf#A*#PQ7xY_f3*^o>3kLw#LT2!;2%K zyceNFdNHep^)>L63O98!yW40iOwD&BgG||HT~4)f&G4h?v}Gi}xZ5 zMS2U{o9uT-#~z!l+3}eB!on31o|W6MTXPn{zxVuXlxNsD!E>;>cC+pXoqo%Pql0_) zz1Qlz(ABxAhAS1U15`=5tOl|o*?AWl!dxWsCk-QR)-j;x*X(bTczf-_t$&ozh61ae z+4m6`uHC&j9=ZAoeDL$-UL9Rm=p)Oqe6=EpOS>a2Q@!CjEg5dyen`l&TZYb{fABcR zkX)~LE6`?Dp~NWLna>3Z-$L``Gp|#I8h!8M+ghSC4fs*NW3f}(!v^y+kh zB=w@kYpT?=k;&U3)a(4nhg_;EWaw5_St_Htz~T7CWYB`iMGt$#V_j_%&v2g2j)Y0p z%ODEpW+jPut7(k$<3*gRM{}UA-wbR8&?>i!_$kn369wJ2r?pD*bf?0>g0+?Vb^t>W zut+iLAUm?X2s`V{BlO8$0`Ii=ey6HjqT+W@h`|o_6n-W|u?FvMgG`wxd z%MTsK1ZpNUEJv+)g9J+XBB7Dg_?~RaDEzb9JIv4`sa7k}zMSb1Q(trUHdW&jXX^8rxjX*4t>RWj)tIee(;(rFYfBluOQ(lg1+8Y}_SHxi} zO!*QJ0Ja<0-3|&#?OdGG@n4?)ASatYDFn{=k{Dx+&RcRqzA713lTx_^H7;B6ufInP z9NeetliSrAe6obgimF$|vSUDtdZMuLkxJiW)oNQbQZiNcc;F8+n~?;Lvb) zbtL!dU4)6YWtr>#?b~quO6&M=<}1fzA|KRy6%MzzUXL7h<5I|3PLzaAVQp*;8pj=4 z|H$`B=K4O(`_x)(D5LlNTnw9`v?nx=K&6N_j=Q2&VxAdr{40PBanlotA;$BIO!Q$W zrwXlgnX-s#w$@!6NDdtqFO%FR_GuB<>B9>P%=^|KTW;w%=^plA!!X5CS=`jH3JLuB zk+oNk<45_IBlfECPu5LVYMdBzy@qcYZiMs7Liv3P)1WDC^Z0bHTVjS8Wm^L~z~Z9; zViU=Cs0wJRflcGRneQ!swuISK795PbZ-ii#n)E){DERbq*nuPoFMOk*QPO9TdVL^2 z*T<)pglfE{) zBlxctntBdXH(pCxV5Nx%7~I(c0}4|a{~hV4xt}E@*d{Ly)&&i zGi#|$*j_SftUkyf3)(8Kvg#gG0YM24%ycP5Z7B4LJ89=|r)y*ohaS3S_mC+6_I*{yV? z=kD$J)sY&tT7Tg(ua;95IY;*(FP&#WyfRodY2(i(9+w!X0Z4FpI=7#hXqP2W`m&V1 zrns%M>;!e?N-rph5y=%J zPIHSTndYX?zw%PlNU$vJ&+Rg4drpa0bdwwLNb%`B^BrbMI2pHKmcpIw_>wQorF`GA2#u81j@ngRzf8krAP4^gWA&PY(H*zy}VkdCp*mUMJ$1O0l5rFLvLRoN_B>tvig~ zw8X&jEm~ z!fffKfX6}k zw(PSUYqhbk*AI0)^jraae8GA&W7!>6wU!~~3Ir{MXhqCig*i73MQK?VJ{|Q66hD}; z?N+QXirgmuq!3D!pFe4PQ}f6mh};Gi!EYb!)WHLk0Gwxsx6dd{VD}wWp*i)3{0zE= zdOnLMID($tt-QZ{smnic!3fa69sQ&SdARo|raG$ltKlr%_SZHtZ9gJ;H$C(9oVEtp z8zhCEEv@v%ma`g&dtdGfk=N4;)^SD2e?84dA4->rc#IyNqe<)cxnS}J*_Ba>J zvxuOvXB+fa$ELe?5gJgG=U~THG&Zof#4B>~IaseANnSQ=4}U7|qF|p@&8)oGF6VO+ z%CxnJ#eI1?GL}#tkzn|9g#zXB8BJ@A25a)4As{?#37to9I2sGV5^_ z#y#t<^ysmE@#b{m#Vl12smpL=<{i?aw{rVaQi};*+li;Oo+rwS)!k3d&W~G5A-?bV zQq+MOK|!8>K9h{k>MOsr*$7nPf~Nf*S*enGg(SVLY{Gf(YN5FI-rAYE1;glkP`vAD zcHC%7J54ha7(q%94Sg9gRraHse(un9RRv-_FxL;XOc&Vntj)iGu@;<#H}W42l}5N< zz2*LyEysjM)Gu%qlc62U1!?ex@#@az7`9IT(zbBlQgf*loUrv!7ufx&pXj-s%%~0j zq=GXFO;NHe7g&k<E%rXHa- zDZ}sjtIuWjgk@MRq%hZQjS` zEd55maKfE|28Tkun@1C8K~vZdmT9{|*a8g(7T?^KzutfRULbuu?dvA=)B}4z%STt@ zKq8+8{v_sIxfJmWiH`}>oq)sc$N6e7Z?b^cLm}gFxZ>o9k%Tm)$ zekj>^a^~9cM$LhFbpRLEP+>K(;F^2qt5L;T74FgML61E(XQ38dE-K5tX?{w#A6wDH zWVGqlS3l;mrd%gAwo|8p^1^WOY>y+1dOr1xk(ryC)O`LSD@x91U;nm-v&$^)Qduf? zt@4g-A<1F~=`RVnTpt6zQ~XxL=gl*uO{P8mll}7}e6@x`zCZp`jiCbC1_EV>GSQ#U z2|%~;)4c7~pRSOk51?p=kVfigD{I3ENq7tLb&)oVi;ZFq5_2jeZ$Iq5)gS4G`)t5k4Xh-p>TB?`&6V9|_ zoPnI`LlENHG#|x8?V$7t9<6$ECxN6s5j!!y{HN4C;2+`3Ns6jd zPH^YX?FfOdoTw0M{<(YxO=Q_@0;>__qD|bGQ&^x;aOt~#>XwIsIA{@wcJTMM1dtIG z+dt0|j?j%zSla(}ugu_Hq3Qyte`;B(6yP(wn2!F>;ZX4C|Che*=i5I&*L1V+D?z{C z?Wo~gcWs87(z*AEC_b$aT`A)f1DRrJvCCdvS%8P&1;RqBkcQMFYsj2^Ots{bQ z{hyUEDd)PUs>**@8niiB;?lx%5)x7WG!`2sHg*?b$F=%*0tdZ{{%aGdD^=&$m zA@1A>7){)!P%jOMVX)R?5ss8wl1c=aNemb%DQFKVC2`ZFiRZ6I*cOfYs#l(^@H+tE z_?c&dhMtj0U(fWjo&DqK+4!#xPms|leSx8ob_a`(0QD5KGyV1cS55fPT zQ7T#?A&0-#7ZQ&^eDW2hLP6ufu={!sM6UmxFJqi9K|C!Zk4Q#s8_M6Y!=DITF}qTp z2VVcF{UTY2SE4HEu_ah|$_9d`Fz8PWVHR#u+T7?^#YKF&%iwPr^y# z$S9<34c_ko9Ssim6GglG-}YsK>U7G5M%Kg6O6^# zDVzKCKw?mVfqd89O8I9XE5JY&7gD53To2@3Fp&RUUq-#$t6)4nBx?ZiG{WC<-49H} zzyCPC&EDN<#f&r#{I6RV|MNwa1YL!u-o$q7PY|%SNiV6GmWj!`bi#+`>4^p`c0{=7 zhjLucpAlwO&?q6^7a>2oY&A*qx|ES)DIHJG&1#fj`8fK1IH?(j$nU2OJRrd1o~X+T z`#leDAU^}^+CB*i^hLiHT?zVKTciCHuIryg`w8ad4?l7I>;Js_gHE_9vNv?{dX`dt z5cBn=zWqS%_c!kfQ^tXTJhM&(Xl}b{ysbW7 zWY7Zi`h_2fn6;y7oHu~^Y`sV2de)nq>Ru^oUtwu5_ECzeVok)ZtI0tPm+-=~bdRlc zm(~{0&cdE}(vv9&&t8QVgX-FSc9Y$OHqZ*kCPBh&ofos%t$(=(e%|UrIi6{Gb+++} zHu|MK=*XGuQcH~CbJ+&c+uR}5s$VQudo0lXdeFQ>%&eWZhv*_(9Z0Td-kc~+bX^Dr zm9mMCpx=qiaX`fMo1OU1OugKEYcT#u<6scE`zlyj5V<%_kaQM$!fs}Mo zj0Vi)`WrHgYx!Bh!i;_(a}wO|Vb{M{*GQfJ(ReY{sOxh9cegBq2D%S-Y-p95=(;U^ z_BrX+xA63H+8C9K=Y=O;t|fY(FH($YR{Lov4rH*lg>j)gJfW5O!m#WCq`G1KN)lwo zcs30u%V2a;&2r2OG&1Gm-*Ke~Mp1rH_Pzi6*(Iel0eZy#WGOnX1=K_no;fUodraEA zIGQcY4()zY+e3QVYvXMwm|>|a{D}hS;4797iJ!bYt_6KF>Ct+FIxwH}4xc;Z{H|9Q zM=tuETjyJqv)-WhrJN}BNC=)0v3A%y2ocpr4q4}@q+*aWCj~tpHFwW8OC!EC5ny(` z++YEHZb=!uj_5`_=7TiMU1sy*#cg&SWGhG*(@~^$t++E(C1{i%^uRt)PsoY;j(8w$ zlu+a4Jo(Tae?h(6pEy3pZ_#-wtYPlm%#|^``X^l)9PBoO?$pDKO~2+_R(j)(`uKLH zfy{qQ&m({8^H_Cwg3slNd-rs?ssuv`H#g-D&V{KlgYU|W@jKDDTO;w4_0x_6XwvOt7p^!yKLsRWe!`Y|AbEC;JbKaaOHLx5Ab;3l^B}>eQ zGNc&<&)QhLcR`201-s3g_tuY}O6YsR)pX=SUoxrZDXQxhC%o2@r2L=&CZwlznJA^+ ztF^&&ZGn?58y`#TDL%tqLmE{xA-9goh^X~&xqbCaGW5xDvqM_PotcZl)JX5WkOI-!O^MDwKs)p zMYc?^w{|(?dicIdZ4hY*Ff?yTE8Hmk9`b1Hg1}@yNGIQ6rLRJ)vTl6{j|*o_+93nu zF*fMpM06JJuk>q7QxP@Y8TTn?I!Jqfb91&WcP-_?b zkmbH>uJ)qVuGdRAClwtBhM#-767P~Q_1vYNaZWK%#b!Icl zQT8YLy+=(xAJ60XWChu-zOA~1m>~t->*w8gtkIGNe_S~3+d?`5qpgY76pCGU1znU* zD#a$!Wxj)zHu`6EN+ZKLT~UuzIB-)ix-10RdNNkg)1b8XhS;wj`U<;)KyaWw{G3ux zn48CQLudAB$ANqXkMPyH0ZwdXC6*(87icKU&$Es#3eZ1pCYIGsY?MJIttgRO#m21n zFL6IB3!r(4B*$aU9wyCEoTf(TA<5mkE`jqLIv7$AnGrheD^?u;MyOwFEc1LikeFiHRXSCeYI}lcHfPbhac@HUH z$Gl$3;48TSIcG7|J7mnAELd*x8WywbS{9MrCe~v;W5hNm1-3bS;?KBXy(!EUk-Px= zw+RWpS#R6)-CVLH&~X|+7Mj2Oxx-|qdWBqNJAblO-8v>f+l?(k6goNj{ysauKWGMz z{kZDVVo@0AMi9ak5EGhWOkDU(3rs5drjOEs+}c!%%5yon1%uOpGb0C|i%!2m5}9(0 zi3Rpv+8EZ@EDR-HmTenAQ5u|sEe>b;0>ITu88(f80PnyYki$h-7z$8Od7|2YbY}!172zjH?faCG@y-u*4MK7FEGH z-rs-4@mml-!Fd;Ne`Q~cFWFVKEk8R^?^O-$cpwppHR>$Fi2SSRqH!k zjM%LR#^*yB1LXFl(obT$HZgyEl*&e0^JPQic9O?eidgY>peG{sYrp!MZ0$15fdHri{iS z+=M$5MSh)b2{++W&ixYpah=xt3cG>@`77h#-Jf4dxPcUOTNG@pzrWiIGBa%;GMeu*Cm85_qRI4%7C zu0Jv59GZ=E#GhZ916hVErO}@Yq^tvZ!#}rr1Nom({ok3u!uTu-zvnNd$g7LiV4VaX z@3Zrh)5M%|o=w(^!maGg3W1ZK{_3QnH^7|qz75U+LP8w5kLOZ^&-qLUp)~~G%_@ec z7?@n#_Pp4DC_HNukbZ!Kk_VPX`j4-O{0g9SSbG@IEdbjC&~7{}ItUmtGo*kAmL1`8 zJgBG-WeV$^8@r#Vj7KVli6x^r1NS4_`DVE|E>7#|DwRz6+hmT4qWv;o9)o-#%))tR zM)xx;md|-}yw0su2Tv~7;OuZKbt%dS59Hgegeq=(KRek?dft&M_9W|Xq=xgZ1D}WY z)duhN050T!HYjT3Wy#m6@fxQM0MZFG zvuu}pzAm#AEd(+ZR4p{!#8I7BQ4ruXXhxw0sW%*WNWizIj^5$;s4iUefDF7RhK*76 z{Zp%P)*XfkQsf@npTaUDKk*ZfTfse<=d4G28y_}mW$Oh>gPAAq$J{RvU3exJA@HS; zDjyH!3yc0Ga8-%Lkf87?3+9Sa>v^R!fzkbinLPkQPPQyL&*XX8_r560(}{`@I)uv# z29ChNKwmtc1e4-NH30APUf*A@v>baPwslM2X&WlR?RxV@j>M~tZ_jj0`toM?&Am2@ z;e5Vxg$17@K@vLPIF+eDF?Ce|nX+^S05tO7GtXgq$R98O zSv>UngwvNV%sP|8t=7wClV#acttJrEqbw;)Ka-YzkPK0_AO%RA4*kvE( z2o&Rlb%Lt_%D?(0;-3S2No@FnHA>hJ3myrj1e0NMK=9enHb^(hYnL2_Wb94B>*_0- z`F83I`A9j;6s^cG8~};@Q=|u>@YOSiI=m9J;o7EVrPK-* z%@2n6n6U-QPSrW=d7^5Aw>6=3iVjR6R2olBnU@Q(EHR&-)KF(qB zsO#gvbUWZ3aCqi?OAh2S!AP1Qc_~OYX#9Y&&USP5s85RVI&W&0Qi*;4o~4x9qg(ih zbF&3=`qX`WHI${nO#0xbxQA(;PLQJ@h~l2syZL34nOg(auEk&}mU>W=hbp6lP!72N zn)7TK9;;rml+2An2Gl_V!XQK7k#=dr&yO;79#U3$ua<>UVC~}cHP71e-dpB&0MnDZ zkQY+c;Af{D*{~Xa1+biNG+u6$kLg(&Vhea`;QWfnmc|9tv`A75Dltc|pjb8?zkh08 zw8q)b?W#p=0bSL?lpn$lB=zp_Jw50Qhvlfmrc$j2M@_kWE$`-~$`;|s;vj?xuN**u zta<}k9Qt_2kB>%d4nb@D1C_TA0mJ{U32F9Nd^B>|>?54^fxTD0`)cIN<j9K*6wh&Ddd@LBk?<(P5# z&6WoBJk8{eh*(|)!ILz%^Q;o6R3so+MpadG1UC6AbTAw+ZKI{FYaTqX__zpGo;oco zHeD*bAGq~!a?G)U?J~#rE)l<#-r zzj^L;V&po>?v^*SeDI}C2v$bHc$oA`^lGTGWX(glqCe3lp+9*AvWl$<`y`sB{l;4Taqa)5QEB=c=2dv7r~+g!#d>L6SjuW=0taqE0I?FI7g% z?s|~C=yT)tT9h%83VC~G84TedfTJ)Wrdd$-7a0P`>O5+|<(FJsYH>5M+zTjeXog&} zz)zFU6%*sFK^;P?LxA$$PL?${0RyiD8mvKm$Q7AP=={-4Rjy_0bh@(c*r(EK20ZB@ zz|M?&C9DkBAU8(_)LLo^=uO}LM#RD|Fz(u_{xmjFyvC}k(O`RV(pBgKUQP()5JCW^ z?~m^0q-&^>^#rV#^_qllSl39G@DZqWL`DaQP+eDUbiuHVI0-x>xjq@AGC0{o7R>j8y@ zZn~*!L&g2c@$Nn)WAs838~&#hq}0MmW?&AzsD1sO7zw3|g%uuVF66Ti&BUE=uP<#7 zbeYNU)3-vm!E-NKaAM>65d$E@BtaQj^03p>5jeQnG+rErlksT-Qax270+>RuI1qDy zMdMDWm}R$vc|?0h#P0_;z4uuPQfh+0FyM(g)nu)4&7uEjBO1 z{1U**B|vgLvN=;<%Sb<57UaA&S?+aqh`@??c;$$7NITcjo9GP)i3E4)#-R!jGQ|O{8XH>xiaUqYz-oUSsA{GgJLyz#wD-qdGwP zSp`e+U!Cs**D$SG=lss~{t`iq1i+&ScpM&BOl|__C4lNmUwuc0J0l7b_J3W5L@$E! zxj6Lj+L|aeUF!M_3{H01!${!zZ(O246092g2RtL??)j2;6jdw~1OE$PR5c6ezfdCP zJw4-#Q#is@4xk2?gdM{0kG=3nqCnc1Gq+~z`qNK{ShcK zo2l}fBLmX5GCJkSfEdn%St?+5y-p9F0g4;|eBpq>b=}6RBf|MmcGLjQL*ch|fsTXo(8KTgUGcn6(}hGc>88E{Q0+zN$)@_iRw5-chA(mC2JHhRz-yEl}zGqRmgl1xrC z#`_@pFxIlbd^GQCiMGL4E=VjMK-?qBfTBw`?fYgv`VtIdN@LII-7HaNPlXs(5k%R? z{AsGqY=g9=-t$tZ^r{2}f!zDoCFdlH0OwA=UU!+iH4K7XO&HhkPLjx5clf%op0Lgr zi!R)dwdA-+#g=_afCZoGA`UhGIEWD%M%$>Rh*QcdcDOkpw z)PpH6FjX2{cVACQvs2_atY>F>ugO?-6*Kzb_t*{-4HtX{rL>p0fn)I%)-f?HJ;!bm zoi)fEv%hw`a&_b%_+b#c+O>7}v+P&esx`;lhG$i5t!v+}21#02K2ag_-rqReTuvzN zImi{alu(IcLqeUD>_(#rKw4X#MmOxva>EXE4ITLamt8LP0VQjoF14 z*g@{*DSYZ>=)+d~!#BD5csKIg@84npdE)(W4rwW;9y#?K18SUfmz|mXyrY)B6&i_f zD#cmk)0`+zvES$!+J#|;vo>CA*c*6ftLGl4MbyPxs|^~Oo==!~jJ6CQnU{bFY)OaI zTCUB3JoUUK5$sf>hp1*i;NtXl#1_;# zhY4=LqT;x4D9f7≦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 z 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 literal 50253 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 Q5%5Px!$7_KhJDok0CMi+0{{R3 literal 0 HcmV?d00001 From ddfb4ca8b06d2206e511b7a63378f7eade174d67 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:35:20 -0500 Subject: [PATCH 30/31] rename file --- .github/images/{dialog.png => picker.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/images/{dialog.png => picker.png} (100%) diff --git a/.github/images/dialog.png b/.github/images/picker.png similarity index 100% rename from .github/images/dialog.png rename to .github/images/picker.png From 2a46512e299e7558e7df992dccc3903036f9ae68 Mon Sep 17 00:00:00 2001 From: James Fenn <18jafenn90@gmail.com> Date: Wed, 7 Nov 2018 23:35:54 -0500 Subject: [PATCH 31/31] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aa46201..49c974f 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ ColorPickerDialog is a simple dialog making it quick and easy to add a color pic For testing and experimentation purposes, a sample apk can be downloaded [here](https://jfenn.me/projects/colorpickerdialog). -|Color Picker|Image Color Picker| -|--------|--------| -|![img](./.github/images/dialog.png?raw=true)|![img](./.github/images/image.png?raw=true)| +|Color Picker|No Alpha|Dark Theme| +|--------|--------|--------| +|![img](./.github/images/picker.png?raw=true)|![img](./.github/images/noalpha.png?raw=true)|![img](./.github/images/darktheme.png?raw=true)| ## Usage