diff --git a/.gitignore b/.gitignore index bc4b9b5..aa724b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,49 +1,15 @@ -########### Specifies intentionally untracked files to ignore ########### - -### Gradle -.gradle/ -build/ - -### IntelliJ IDEA -/.idea *.iml -*.iws -captures/ -.navigation/ -local.properties -bin/ -gen/ -out/ -*.apk -*.ap_ - -### Android -*.jks -*.dex - -### Java -*.class -hs_err_pid* - -### Windows -Desktop.ini -Thumbs.db -ehthumbs.db - -### OSX +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml .DS_Store - -### Linux -*~ -.fuse_hidden* -.directory -.Trash-* - -### Logs -*.log - -### Crashlytics -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/codeStyles b/.idea/codeStyles new file mode 100644 index 0000000..ad98bfd --- /dev/null +++ b/.idea/codeStyles @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..d7c08c9 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..8918d93 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..148fdd2 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..cd203e4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..931b96c --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ce2fc3c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,29 +0,0 @@ -language: android - -android: - components: - - tools # Tools - - platform-tools # Platform tools - - build-tools-28.0.3 # Build tools version - - android-28 # Target SDK version - - extra-android-m2repository # Support repo - - sys-img-armeabi-v7a-android-18 # Emulator - -jdk: - - oraclejdk8 - -script: - - ./gradlew build - -branches: - except: - - gh-pages - -notifications: - email: false - -sudo: false - -cache: - directories: - - $HOME/.gradle \ No newline at end of file diff --git a/README.md b/README.md index 56e4c08..9b69a2e 100644 --- a/README.md +++ b/README.md @@ -44,17 +44,21 @@ Note: Using AndroidX's `PreferenceFragmentCompat`? Then use `com.jaredrummler.an You can add attributes to customize the `ColorPreference`: -| name | type | documentation | -|---------------------|-----------|---------------------------------------------------------------------------------------| -| cpv_dialogType | enum | "custom" to show the color picker, "preset" to show pre-defined colors | -| cpv_showAlphaSlider | boolean | Show a slider for changing the alpha of a color (adding transparency) | -| cpv_colorShape | enum | "square" or "circle" for the shape of the color preview | -| cpv_colorPresets | reference | An int-array of pre-defined colors to show in the dialog | -| cpv_dialogTitle | reference | The string resource id for the dialog title. By default the title is "Select a Color" | -| cpv_showColorShades | boolean | true to show different shades of the selected color | -| cpv_allowPresets | boolean | true to add a button to toggle to the custom color picker | -| cpv_allowCustom | boolean | true to add a button to toggle to the presets color picker | -| cpv_showDialog | boolean | true to let the ColorPreference handle showing the dialog | +| name | type | documentation | +|------------------------------|-----------|-------------------------------------------------------------------------------------------| +| cpv_dialogType | enum | "custom" to show the color picker, "preset" to show pre-defined colors | +| cpv_showAlphaSlider | boolean | Show a slider for changing the alpha of a color (adding transparency) | +| cpv_colorShape | enum | "square" or "circle" for the shape of the color preview | +| cpv_colorPresets | reference | An int-array of pre-defined colors to show in the dialog | +| cpv_dialogTitle | reference | The string resource id for the dialog title. By default the title is "Select a Color" | +| cpv_dialogPresetsActionText | reference | The string resource id for the dialog button that has "Presets" by default | +| cpv_dialogSelectActionText | reference | The string resource id for the dialog button that has "Select" by default | +| cpv_dialogCustomActionText | reference | The string resource id for the dialog button that has "Custom" by default | +| cpv_dialogTransparencyActionText | reference | The string resource id for the dialog button that has "Transparency" by default | +| cpv_showColorShades | boolean | true to show different shades of the selected color | +| cpv_allowPresets | boolean | true to add a button to toggle to the custom color picker | +| cpv_allowCustom | boolean | true to add a button to toggle to the presets color picker | +| cpv_showDialog | boolean | true to let the ColorPreference handle showing the dialog | You can also show a `ColorPickerDialog` without using the `ColorPreference`: diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..048ee15 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,42 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace 'com.jaredrummler.android.colorpicker.demo' + compileSdk 34 + + defaultConfig { + applicationId "com.jaredrummler.android.colorpicker.demo" + minSdk 21 + targetSdk 34 + versionCode 1 + versionName "1.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation libs.androidx.core.ktx + implementation libs.androidx.appcompat + implementation libs.material + implementation project(':library') + + api("androidx.preference:preference-ktx:1.2.1") + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/demo/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml similarity index 94% rename from demo/src/main/AndroidManifest.xml rename to app/src/main/AndroidManifest.xml index 19688b7..ef64299 100644 --- a/demo/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,7 +25,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - + @@ -38,4 +38,4 @@ android:screenOrientation="portrait"/> - \ No newline at end of file + diff --git a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java similarity index 96% rename from demo/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java rename to app/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java index 5506bc0..dd75944 100644 --- a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java +++ b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/BasePreferenceFragment.java @@ -31,7 +31,7 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat { if (preference instanceof PreferenceCategory) { setZeroPaddingToLayoutChildren(holder.itemView); } else { - View iconFrame = holder.itemView.findViewById(R.id.icon_frame); + View iconFrame = holder.itemView.findViewById(android.R.id.icon_frame); if (iconFrame != null) { iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE); } @@ -54,4 +54,4 @@ private void setZeroPaddingToLayoutChildren(View view) { } } } -} \ No newline at end of file +} diff --git a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java similarity index 74% rename from demo/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java rename to app/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java index 525e859..6248431 100644 --- a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java +++ b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/ColorPickerActivity.java @@ -19,11 +19,13 @@ import android.content.SharedPreferences; import android.graphics.PixelFormat; import android.os.Bundle; -import android.preference.PreferenceManager; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; + import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.PreferenceManager; + import com.jaredrummler.android.colorpicker.ColorPanelView; import com.jaredrummler.android.colorpicker.ColorPickerView; import com.jaredrummler.android.colorpicker.ColorPickerView.OnColorChangedListener; @@ -39,12 +41,12 @@ public class ColorPickerActivity extends AppCompatActivity implements OnColorCha setContentView(R.layout.activity_color_picker); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(this); int initialColor = prefs.getInt("color_3", 0xFF000000); - colorPickerView = (ColorPickerView) findViewById(R.id.cpv_color_picker_view); - ColorPanelView colorPanelView = (ColorPanelView) findViewById(R.id.cpv_color_panel_old); - newColorPanelView = (ColorPanelView) findViewById(R.id.cpv_color_panel_new); + colorPickerView = (ColorPickerView) findViewById(com.jaredrummler.android.colorpicker.R.id.cpv_color_picker_view); + ColorPanelView colorPanelView = (ColorPanelView) findViewById(com.jaredrummler.android.colorpicker.R.id.cpv_color_panel_old); + newColorPanelView = (ColorPanelView) findViewById(com.jaredrummler.android.colorpicker.R.id.cpv_color_panel_new); Button btnOK = (Button) findViewById(R.id.okButton); Button btnCancel = (Button) findViewById(R.id.cancelButton); @@ -65,16 +67,14 @@ public class ColorPickerActivity extends AppCompatActivity implements OnColorCha } @Override public void onClick(View v) { - switch (v.getId()) { - case R.id.okButton: - SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit(); - edit.putInt("color_3", colorPickerView.getColor()); - edit.apply(); - finish(); - break; - case R.id.cancelButton: - finish(); - break; - } + int id = v.getId(); + if (id == R.id.okButton) { + SharedPreferences.Editor edit = PreferenceManager.getDefaultSharedPreferences(this).edit(); + edit.putInt("color_3", colorPickerView.getColor()); + edit.apply(); + finish(); + } else if (id == R.id.cancelButton) { + finish(); + } } } diff --git a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java similarity index 75% rename from demo/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java rename to app/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java index 1374a84..ec3030c 100644 --- a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java +++ b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/DemoFragment.java @@ -1,7 +1,10 @@ package com.jaredrummler.android.colorpicker.demo; +import android.content.Intent; import android.os.Bundle; import android.util.Log; + +import androidx.annotation.NonNull; import androidx.preference.Preference; import com.jaredrummler.android.colorpicker.ColorPreferenceCompat; @@ -25,5 +28,13 @@ public class DemoFragment extends BasePreferenceFragment { return true; } }); + + findPreference("show_activity").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(@NonNull Preference preference) { + startActivity(new Intent(getActivity(),ColorPickerActivity.class)); + return true; + } + }); } } diff --git a/app/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java new file mode 100644 index 0000000..0e2fe5c --- /dev/null +++ b/app/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2017 Jared Rummler + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jaredrummler.android.colorpicker.demo; + +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.graphics.Color; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.jaredrummler.android.colorpicker.ColorPickerDialog; +import com.jaredrummler.android.colorpicker.ColorPickerDialogListener; + +public class MainActivity extends AppCompatActivity implements ColorPickerDialogListener { + + private static final String TAG = "MainActivity"; + + // Give your color picker dialog unique IDs if you have multiple dialogs. + private static final int DIALOG_ID = 0; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction().add(android.R.id.content, new DemoFragment()).commit(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int itemId = item.getItemId(); + if (itemId == R.id.menu_color_picker_dialog) { + ColorPickerDialog.newBuilder() + .setDialogType(ColorPickerDialog.TYPE_PRESETS) + .setDialogId(DIALOG_ID) + .setColor(Color.BLACK) + .setAllowPresets(true) + .setShowColorShades(false) + .setAllowCustom(true) + .setShowAlphaSlider(true) + .setCustomButtonText(R.string.test) + .setSelectedButtonText(R.string.test2) + .setPresetsButtonText(R.string.test3) + .show(this); + return true; + } else if (itemId == R.id.menu_github) { + try { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/jaredrummler/ColorPicker"))); + } catch (ActivityNotFoundException ignored) { + } + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onColorSelected(int dialogId, int color) { + Log.d(TAG, "onColorSelected() called with: dialogId = [" + dialogId + "], color = [" + color + "]"); + switch (dialogId) { + case DIALOG_ID: + // We got result from the dialog that is shown when clicking on the icon in the action bar. + Toast.makeText(MainActivity.this, "Selected Color: #" + Integer.toHexString(color), Toast.LENGTH_SHORT).show(); + break; + } + } + + @Override + public void onDialogDismissed(int dialogId) { + Log.d(TAG, "onDialogDismissed() called with: dialogId = [" + dialogId + "]"); + } + +} diff --git a/demo/src/main/res/drawable/ic_github_white_24dp.xml b/app/src/main/res/drawable/ic_github_white_24dp.xml similarity index 100% rename from demo/src/main/res/drawable/ic_github_white_24dp.xml rename to app/src/main/res/drawable/ic_github_white_24dp.xml diff --git a/demo/src/main/res/drawable/ic_palette_white_24dp.xml b/app/src/main/res/drawable/ic_palette_white_24dp.xml similarity index 100% rename from demo/src/main/res/drawable/ic_palette_white_24dp.xml rename to app/src/main/res/drawable/ic_palette_white_24dp.xml diff --git a/demo/src/main/res/layout-v21/activity_color_picker.xml b/app/src/main/res/layout-v21/activity_color_picker.xml similarity index 100% rename from demo/src/main/res/layout-v21/activity_color_picker.xml rename to app/src/main/res/layout-v21/activity_color_picker.xml diff --git a/demo/src/main/res/layout/activity_color_picker.xml b/app/src/main/res/layout/activity_color_picker.xml similarity index 100% rename from demo/src/main/res/layout/activity_color_picker.xml rename to app/src/main/res/layout/activity_color_picker.xml diff --git a/demo/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml similarity index 100% rename from demo/src/main/res/menu/main.xml rename to app/src/main/res/menu/main.xml diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from demo/src/main/res/mipmap-hdpi/ic_launcher.png rename to app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from demo/src/main/res/mipmap-mdpi/ic_launcher.png rename to app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from demo/src/main/res/mipmap-xhdpi/ic_launcher.png rename to app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from demo/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/demo/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml similarity index 100% rename from demo/src/main/res/values-v21/styles.xml rename to app/src/main/res/values-v21/styles.xml diff --git a/demo/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from demo/src/main/res/values-w820dp/dimens.xml rename to app/src/main/res/values-w820dp/dimens.xml diff --git a/demo/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml similarity index 100% rename from demo/src/main/res/values/colors.xml rename to app/src/main/res/values/colors.xml diff --git a/demo/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml similarity index 100% rename from demo/src/main/res/values/dimens.xml rename to app/src/main/res/values/dimens.xml diff --git a/demo/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml similarity index 88% rename from demo/src/main/res/values/strings.xml rename to app/src/main/res/values/strings.xml index 44144ac..f23ee85 100644 --- a/demo/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -20,4 +20,8 @@ Settings Color Picker Dialog GitHub + + test + test2 + test3 diff --git a/demo/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml similarity index 100% rename from demo/src/main/res/values/styles.xml rename to app/src/main/res/values/styles.xml diff --git a/app/src/main/res/xml/main.xml b/app/src/main/res/xml/main.xml new file mode 100644 index 0000000..d5ca39d --- /dev/null +++ b/app/src/main/res/xml/main.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build.gradle b/build.gradle index cffdbfb..6ab3255 100644 --- a/build.gradle +++ b/build.gradle @@ -1,42 +1,6 @@ -buildscript { - - // @formatter:off - ext.buildConfig = [ - compileSdk : 30, - targetSdk : 30, - minSdk : 14, - gradlePlugin : '4.0.0' - ] - ext.versions = [ - androidx : '1.1.0', - preferences : '1.1.1' - ] - ext.deps = [ - 'androidx' : [ - 'appCompat' : "androidx.appcompat:appcompat:${versions.androidx}", - 'preferences' : "androidx.preference:preference:${versions.preferences}" - ] - ] - // @formatter:on - - repositories { - google() - mavenCentral() - jcenter() - } - dependencies { - classpath "com.android.tools.build:gradle:${buildConfig.gradlePlugin}" - } -} - -allprojects { - repositories { - google() - mavenCentral() - jcenter() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { +alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.android.library) apply false } diff --git a/demo/.gitignore b/demo/.gitignore deleted file mode 100644 index 796b96d..0000000 --- a/demo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/demo/build.gradle b/demo/build.gradle deleted file mode 100644 index 7efb855..0000000 --- a/demo/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -apply plugin: 'com.android.application' - -android { - compileSdkVersion buildConfig.compileSdk - defaultConfig { - applicationId "com.jaredrummler.android.colorpicker.demo" - minSdkVersion buildConfig.minSdk - targetSdkVersion buildConfig.targetSdk - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - lintOptions { - checkReleaseBuilds false - abortOnError false - } -} - -dependencies { - implementation deps.androidx.appCompat - implementation deps.androidx.preferences - implementation project(':library') -} diff --git a/demo/proguard-rules.pro b/demo/proguard-rules.pro deleted file mode 100644 index 677edc8..0000000 --- a/demo/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\android-sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java b/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java deleted file mode 100644 index dcdb5aa..0000000 --- a/demo/src/main/java/com/jaredrummler/android/colorpicker/demo/MainActivity.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2017 Jared Rummler - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.jaredrummler.android.colorpicker.demo; - -import android.content.ActivityNotFoundException; -import android.content.Intent; -import android.graphics.Color; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.widget.Toast; -import androidx.appcompat.app.AppCompatActivity; -import com.jaredrummler.android.colorpicker.ColorPickerDialog; -import com.jaredrummler.android.colorpicker.ColorPickerDialogListener; - -public class MainActivity extends AppCompatActivity implements ColorPickerDialogListener { - - private static final String TAG = "MainActivity"; - - // Give your color picker dialog unique IDs if you have multiple dialogs. - private static final int DIALOG_ID = 0; - - - @Override protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState == null) { - getSupportFragmentManager().beginTransaction().add(android.R.id.content, new DemoFragment()).commit(); - } - } - - @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.main, menu); - return true; - } - - @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_color_picker_dialog: - ColorPickerDialog.newBuilder() - .setDialogType(ColorPickerDialog.TYPE_CUSTOM) - .setAllowPresets(false) - .setDialogId(DIALOG_ID) - .setColor(Color.BLACK) - .setShowAlphaSlider(true) - .show(this); - return true; - case R.id.menu_github: - try { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/jaredrummler/ColorPicker"))); - } catch (ActivityNotFoundException ignored) { - } - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override public void onColorSelected(int dialogId, int color) { - Log.d(TAG, "onColorSelected() called with: dialogId = [" + dialogId + "], color = [" + color + "]"); - switch (dialogId) { - case DIALOG_ID: - // We got result from the dialog that is shown when clicking on the icon in the action bar. - Toast.makeText(MainActivity.this, "Selected Color: #" + Integer.toHexString(color), Toast.LENGTH_SHORT).show(); - break; - } - } - - @Override public void onDialogDismissed(int dialogId) { - Log.d(TAG, "onDialogDismissed() called with: dialogId = [" + dialogId + "]"); - } - -} - \ No newline at end of file diff --git a/demo/src/main/res/xml/main.xml b/demo/src/main/res/xml/main.xml deleted file mode 100644 index f13a710..0000000 --- a/demo/src/main/res/xml/main.xml +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 5465fec..132244e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,23 @@ -android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..65367fe --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,23 @@ +[versions] +agp = "8.7.0-alpha03" +kotlin = "1.9.24" +coreKtx = "1.13.1" +junit = "4.13.2" +junitVersion = "1.2.1" +espressoCore = "3.6.1" +appcompat = "1.7.0" +material = "1.12.0" + +[libraries] +androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } +junit = { group = "junit", name = "junit", version.ref = "junit" } +androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } +androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +material = { group = "com.google.android.material", name = "material", version.ref = "material" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "agp" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +android-library = { id = "com.android.library", version.ref = "agp" } + diff --git a/gradle/maven-push.gradle b/gradle/maven-push.gradle deleted file mode 100644 index f43fd3e..0000000 --- a/gradle/maven-push.gradle +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2013 Chris Banes - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -apply plugin: 'maven' -apply plugin: 'signing' - -def isReleaseBuild() { - return VERSION_NAME.contains("SNAPSHOT") == false -} - -def getReleaseRepositoryUrl() { - return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - -def getSnapshotRepositoryUrl() { - return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL - : "https://oss.sonatype.org/content/repositories/snapshots/" -} - -def getRepositoryUsername() { - return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "" -} - -def getRepositoryPassword() { - return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "" -} - -afterEvaluate { project -> - uploadArchives { - repositories { - mavenDeployer { - beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - - pom.groupId = GROUP - pom.artifactId = POM_ARTIFACT_ID - pom.version = VERSION_NAME - - repository(url: getReleaseRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - snapshotRepository(url: getSnapshotRepositoryUrl()) { - authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) - } - - pom.project { - name POM_NAME - packaging POM_PACKAGING - description POM_DESCRIPTION - url POM_URL - - scm { - url POM_SCM_URL - connection POM_SCM_CONNECTION - developerConnection POM_SCM_DEV_CONNECTION - } - - licenses { - license { - name POM_LICENCE_NAME - url POM_LICENCE_URL - distribution POM_LICENCE_DIST - } - } - - developers { - developer { - id POM_DEVELOPER_ID - name POM_DEVELOPER_NAME - } - } - } - } - } - } - - signing { - required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } - sign configurations.archives - } - - task androidJavadocs(type: Javadoc) { - source = android.sourceSets.main.java.srcDirs - classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) - if (JavaVersion.current().isJava8Compatible()) { - options.addStringOption('Xdoclint:none', '-quiet') - } - failOnError false - } - - task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { - classifier = 'javadoc' - from androidJavadocs.destinationDir - } - - task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.sourceFiles - } - - artifacts { - archives androidSourcesJar - archives androidJavadocsJar - } -} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 13372ae..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c396b23..200ce0e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 29 08:20:06 IDT 2020 +#Mon Jul 29 18:56:34 IDT 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/gradlew b/gradlew index 9d82f78..4f906e0 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,20 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## ## @@ -6,20 +22,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# 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 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='"-Xmx64m" "-Xms64m"' + # 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 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,28 +75,14 @@ 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. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -85,7 +106,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 @@ -105,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -134,27 +156,30 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 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" -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 8a0b282..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -8,20 +24,23 @@ @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 Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@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="-Xmx64m" "-Xms64m" + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,34 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windowz 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. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -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 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/library/.gitignore b/library/.gitignore index 796b96d..42afabf 100644 --- a/library/.gitignore +++ b/library/.gitignore @@ -1 +1 @@ -/build +/build \ No newline at end of file diff --git a/library/build.gradle b/library/build.gradle index f80ec1d..85b5ba1 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,20 +1,55 @@ -apply plugin: 'com.android.library' +plugins { + id 'com.android.library' + id 'kotlin-android' + id 'maven-publish' +} android { - compileSdkVersion buildConfig.compileSdk - resourcePrefix "cpv_" - defaultConfig { - minSdkVersion buildConfig.minSdk - targetSdkVersion buildConfig.targetSdk - } - lintOptions { - abortOnError false - } + namespace 'com.jaredrummler.android.colorpicker' + compileSdk 34 + + defaultConfig { + minSdk 21 + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + publishing { + singleVariant("release") { + // if you don't want sources/javadoc, remove these lines + withSourcesJar() + withJavadocJar() + } + } + buildFeatures { + buildConfig = false + } + kotlinOptions { + jvmTarget = '1.8' + } +} +afterEvaluate { + publishing { + publications { + release(MavenPublication) { + from components.release + } + } + } } dependencies { - implementation deps.androidx.appCompat - implementation deps.androidx.preferences -} + api 'androidx.core:core-ktx:1.13.1' + api 'com.google.android.material:material:1.12.0' + api 'androidx.preference:preference-ktx:1.2.1' -apply from: rootProject.file('gradle/maven-push.gradle') +} diff --git a/library/consumer-rules.pro b/library/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/library/gradle.properties b/library/gradle.properties deleted file mode 100644 index f81fb84..0000000 --- a/library/gradle.properties +++ /dev/null @@ -1,19 +0,0 @@ -VERSION_NAME=1.1.0 -VERSION_CODE=110 -GROUP=com.jaredrummler -ARTIFACT_ID=colorpicker -POM_NAME=colorpicker -POM_ARTIFACT_ID=colorpicker -POM_PACKAGING=aar -POM_DESCRIPTION=A simply good looking color picker component for Android -POM_URL=https://github.com/jaredrummler/ColorPicker -POM_SCM_URL=https://github.com/jaredrummler/ColorPicker -POM_SCM_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git -POM_SCM_DEV_CONNECTION=scm:git@github.com:jaredrummler/ColorPicker.git -POM_LICENCE_NAME=The Apache Software License, Version 2.0 -POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt -POM_LICENCE_DIST=repo -POM_DEVELOPER_ID=jaredrummler -POM_DEVELOPER_NAME=Jared Rummler -SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots -RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2 \ No newline at end of file diff --git a/library/jitpack.yml b/library/jitpack.yml new file mode 100644 index 0000000..b499014 --- /dev/null +++ b/library/jitpack.yml @@ -0,0 +1,2 @@ +jdk: + -openjdk11 diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro index 677edc8..481bb43 100644 --- a/library/proguard-rules.pro +++ b/library/proguard-rules.pro @@ -1,17 +1,21 @@ # Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\android-sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html -# Add any project specific keep options here: - # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerDialog.java b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerDialog.java index fee2f82..40bd05c 100644 --- a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerDialog.java +++ b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPickerDialog.java @@ -43,6 +43,7 @@ import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; + import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -51,6 +52,7 @@ import androidx.core.graphics.ColorUtils; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentActivity; + import java.util.Arrays; import java.util.Locale; @@ -67,876 +69,924 @@ */ public class ColorPickerDialog extends DialogFragment implements ColorPickerView.OnColorChangedListener, TextWatcher { - private static final String TAG = "ColorPickerDialog"; - - public static final int TYPE_CUSTOM = 0; - public static final int TYPE_PRESETS = 1; - - /** - * Material design colors used as the default color presets - */ - public static final int[] MATERIAL_COLORS = { - 0xFFF44336, // RED 500 - 0xFFE91E63, // PINK 500 - 0xFFFF2C93, // LIGHT PINK 500 - 0xFF9C27B0, // PURPLE 500 - 0xFF673AB7, // DEEP PURPLE 500 - 0xFF3F51B5, // INDIGO 500 - 0xFF2196F3, // BLUE 500 - 0xFF03A9F4, // LIGHT BLUE 500 - 0xFF00BCD4, // CYAN 500 - 0xFF009688, // TEAL 500 - 0xFF4CAF50, // GREEN 500 - 0xFF8BC34A, // LIGHT GREEN 500 - 0xFFCDDC39, // LIME 500 - 0xFFFFEB3B, // YELLOW 500 - 0xFFFFC107, // AMBER 500 - 0xFFFF9800, // ORANGE 500 - 0xFF795548, // BROWN 500 - 0xFF607D8B, // BLUE GREY 500 - 0xFF9E9E9E, // GREY 500 - }; - - static final int ALPHA_THRESHOLD = 165; - - private static final String ARG_ID = "id"; - private static final String ARG_TYPE = "dialogType"; - private static final String ARG_COLOR = "color"; - private static final String ARG_ALPHA = "alpha"; - private static final String ARG_PRESETS = "presets"; - private static final String ARG_ALLOW_PRESETS = "allowPresets"; - private static final String ARG_ALLOW_CUSTOM = "allowCustom"; - private static final String ARG_DIALOG_TITLE = "dialogTitle"; - private static final String ARG_SHOW_COLOR_SHADES = "showColorShades"; - private static final String ARG_COLOR_SHAPE = "colorShape"; - private static final String ARG_PRESETS_BUTTON_TEXT = "presetsButtonText"; - private static final String ARG_CUSTOM_BUTTON_TEXT = "customButtonText"; - private static final String ARG_SELECTED_BUTTON_TEXT = "selectedButtonText"; - - ColorPickerDialogListener colorPickerDialogListener; - FrameLayout rootView; - int[] presets; - @ColorInt int color; - int dialogType; - int dialogId; - boolean showColorShades; - int colorShape; - - // -- PRESETS -------------------------- - ColorPaletteAdapter adapter; - LinearLayout shadesLayout; - SeekBar transparencySeekBar; - TextView transparencyPercText; - - // -- CUSTOM --------------------------- - ColorPickerView colorPicker; - ColorPanelView newColorPanel; - EditText hexEditText; - boolean showAlphaSlider; - private int presetsButtonStringRes; - private boolean fromEditText; - private int customButtonStringRes; - - private final OnTouchListener onPickerTouchListener = new OnTouchListener() { - @Override public boolean onTouch(View v, MotionEvent event) { - if (v != hexEditText && hexEditText.hasFocus()) { - hexEditText.clearFocus(); - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0); - hexEditText.clearFocus(); - return true; - } - return false; - } - }; - - /** - * Create a new Builder for creating a {@link ColorPickerDialog} instance - * - * @return The {@link Builder builder} to create the {@link ColorPickerDialog}. - */ - public static Builder newBuilder() { - return new Builder(); - } - - @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - dialogId = getArguments().getInt(ARG_ID); - showAlphaSlider = getArguments().getBoolean(ARG_ALPHA); - showColorShades = getArguments().getBoolean(ARG_SHOW_COLOR_SHADES); - colorShape = getArguments().getInt(ARG_COLOR_SHAPE); - if (savedInstanceState == null) { - color = getArguments().getInt(ARG_COLOR); - dialogType = getArguments().getInt(ARG_TYPE); - } else { - color = savedInstanceState.getInt(ARG_COLOR); - dialogType = savedInstanceState.getInt(ARG_TYPE); - } + private static final String TAG = "ColorPickerDialog"; - rootView = new FrameLayout(requireActivity()); - if (dialogType == TYPE_CUSTOM) { - rootView.addView(createPickerView()); - } else if (dialogType == TYPE_PRESETS) { - rootView.addView(createPresetsView()); - } + public static final int TYPE_CUSTOM = 0; + public static final int TYPE_PRESETS = 1; - int selectedButtonStringRes = getArguments().getInt(ARG_SELECTED_BUTTON_TEXT); - if (selectedButtonStringRes == 0) { - selectedButtonStringRes = R.string.cpv_select; - } + /** + * Material design colors used as the default color presets + */ + public static final int[] MATERIAL_COLORS = { + 0xFFF44336, // RED 500 + 0xFFE91E63, // PINK 500 + 0xFFFF2C93, // LIGHT PINK 500 + 0xFF9C27B0, // PURPLE 500 + 0xFF673AB7, // DEEP PURPLE 500 + 0xFF3F51B5, // INDIGO 500 + 0xFF2196F3, // BLUE 500 + 0xFF03A9F4, // LIGHT BLUE 500 + 0xFF00BCD4, // CYAN 500 + 0xFF009688, // TEAL 500 + 0xFF4CAF50, // GREEN 500 + 0xFF8BC34A, // LIGHT GREEN 500 + 0xFFCDDC39, // LIME 500 + 0xFFFFEB3B, // YELLOW 500 + 0xFFFFC107, // AMBER 500 + 0xFFFF9800, // ORANGE 500 + 0xFF795548, // BROWN 500 + 0xFF607D8B, // BLUE GREY 500 + 0xFF9E9E9E, // GREY 500 + }; - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()).setView(rootView) - .setPositiveButton(selectedButtonStringRes, new DialogInterface.OnClickListener() { - @Override public void onClick(DialogInterface dialog, int which) { - onColorSelected(color); - } - }); + static final int ALPHA_THRESHOLD = 165; + + private static final String ARG_ID = "id"; + private static final String ARG_TYPE = "dialogType"; + private static final String ARG_COLOR = "color"; + private static final String ARG_ALPHA = "alpha"; + private static final String ARG_PRESETS = "presets"; + private static final String ARG_ALLOW_PRESETS = "allowPresets"; + private static final String ARG_ALLOW_CUSTOM = "allowCustom"; + private static final String ARG_DIALOG_TITLE = "dialogTitle"; + private static final String ARG_SHOW_COLOR_SHADES = "showColorShades"; + private static final String ARG_COLOR_SHAPE = "colorShape"; + private static final String ARG_PRESETS_BUTTON_TEXT = "presetsButtonText"; + private static final String ARG_CUSTOM_BUTTON_TEXT = "customButtonText"; + private static final String ARG_SELECTED_BUTTON_TEXT = "selectedButtonText"; + private static final String ARG_TRANSPARENCY_BUTTON_TEXT = "transparencyButtonText"; - int dialogTitleStringRes = getArguments().getInt(ARG_DIALOG_TITLE); - if (dialogTitleStringRes != 0) { - builder.setTitle(dialogTitleStringRes); - } + ColorPickerDialogListener colorPickerDialogListener; + FrameLayout rootView; + int[] presets; + @ColorInt + int color; + int dialogType; + int dialogId; + boolean showColorShades; + int colorShape; + + // -- PRESETS -------------------------- + ColorPaletteAdapter adapter; + LinearLayout shadesLayout; + SeekBar transparencySeekBar; + TextView transparencyPercText; + + // -- CUSTOM --------------------------- + ColorPickerView colorPicker; + ColorPanelView newColorPanel; + EditText hexEditText; + boolean showAlphaSlider; + private int presetsButtonStringRes; + private boolean fromEditText; + private int customButtonStringRes; + private final OnTouchListener onPickerTouchListener = new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (v != hexEditText && hexEditText.hasFocus()) { + hexEditText.clearFocus(); + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0); + hexEditText.clearFocus(); + return true; + } + return false; + } + }; - presetsButtonStringRes = getArguments().getInt(ARG_PRESETS_BUTTON_TEXT); - customButtonStringRes = getArguments().getInt(ARG_CUSTOM_BUTTON_TEXT); + /** + * Create a new Builder for creating a {@link ColorPickerDialog} instance + * + * @return The {@link Builder builder} to create the {@link ColorPickerDialog}. + */ + public static Builder newBuilder() { + return new Builder(); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + dialogId = getArguments().getInt(ARG_ID); + showAlphaSlider = getArguments().getBoolean(ARG_ALPHA); + showColorShades = getArguments().getBoolean(ARG_SHOW_COLOR_SHADES); + colorShape = getArguments().getInt(ARG_COLOR_SHAPE); + if (savedInstanceState == null) { + color = getArguments().getInt(ARG_COLOR); + dialogType = getArguments().getInt(ARG_TYPE); + } else { + color = savedInstanceState.getInt(ARG_COLOR); + dialogType = savedInstanceState.getInt(ARG_TYPE); + } - int neutralButtonStringRes; - if (dialogType == TYPE_CUSTOM && getArguments().getBoolean(ARG_ALLOW_PRESETS)) { - neutralButtonStringRes = (presetsButtonStringRes != 0 ? presetsButtonStringRes : R.string.cpv_presets); - } else if (dialogType == TYPE_PRESETS && getArguments().getBoolean(ARG_ALLOW_CUSTOM)) { - neutralButtonStringRes = (customButtonStringRes != 0 ? customButtonStringRes : R.string.cpv_custom); - } else { - neutralButtonStringRes = 0; - } + rootView = new FrameLayout(requireActivity()); + if (dialogType == TYPE_CUSTOM) { + rootView.addView(createPickerView()); + } else if (dialogType == TYPE_PRESETS) { + rootView.addView(createPresetsView()); + } - if (neutralButtonStringRes != 0) { - builder.setNeutralButton(neutralButtonStringRes, null); - } + int selectedButtonStringRes = getArguments().getInt(ARG_SELECTED_BUTTON_TEXT); + if (selectedButtonStringRes == 0) { + selectedButtonStringRes = R.string.cpv_select; + } + AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()).setView(rootView) + .setPositiveButton(selectedButtonStringRes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onColorSelected(color); + } + }); + + int dialogTitleStringRes = getArguments().getInt(ARG_DIALOG_TITLE); + if (dialogTitleStringRes != 0) { + builder.setTitle(dialogTitleStringRes); + } - return builder.create(); - } - - @Override public void onStart() { - super.onStart(); - AlertDialog dialog = (AlertDialog) getDialog(); - - // http://stackoverflow.com/a/16972670/1048340 - //noinspection ConstantConditions - dialog.getWindow() - .clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - - // Do not dismiss the dialog when clicking the neutral button. - Button neutralButton = dialog.getButton(AlertDialog.BUTTON_NEUTRAL); - if (neutralButton != null) { - neutralButton.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - rootView.removeAllViews(); - switch (dialogType) { - case TYPE_CUSTOM: - dialogType = TYPE_PRESETS; - ((Button) v).setText(customButtonStringRes != 0 ? customButtonStringRes : R.string.cpv_custom); - rootView.addView(createPresetsView()); - break; - case TYPE_PRESETS: - dialogType = TYPE_CUSTOM; - ((Button) v).setText(presetsButtonStringRes != 0 ? presetsButtonStringRes : R.string.cpv_presets); - rootView.addView(createPickerView()); - } - } - }); - } - } - - @Override public void onDismiss(DialogInterface dialog) { - super.onDismiss(dialog); - onDialogDismissed(); - } - - @Override public void onSaveInstanceState(Bundle outState) { - outState.putInt(ARG_COLOR, color); - outState.putInt(ARG_TYPE, dialogType); - super.onSaveInstanceState(outState); - } - - /** - * Set the callback. - *

- * Note: The preferred way to handle the callback is to have the calling Activity implement - * {@link ColorPickerDialogListener} as this will not survive an orientation change. - * - * @param colorPickerDialogListener The callback invoked when a color is selected or the dialog is dismissed. - */ - public void setColorPickerDialogListener(ColorPickerDialogListener colorPickerDialogListener) { - this.colorPickerDialogListener = colorPickerDialogListener; - } - - // region Custom Picker - - View createPickerView() { - View contentView = View.inflate(getActivity(), R.layout.cpv_dialog_color_picker, null); - colorPicker = (ColorPickerView) contentView.findViewById(R.id.cpv_color_picker_view); - ColorPanelView oldColorPanel = (ColorPanelView) contentView.findViewById(R.id.cpv_color_panel_old); - newColorPanel = (ColorPanelView) contentView.findViewById(R.id.cpv_color_panel_new); - ImageView arrowRight = (ImageView) contentView.findViewById(R.id.cpv_arrow_right); - hexEditText = (EditText) contentView.findViewById(R.id.cpv_hex); - - try { - final TypedValue value = new TypedValue(); - TypedArray typedArray = - getActivity().obtainStyledAttributes(value.data, new int[] { android.R.attr.textColorPrimary }); - int arrowColor = typedArray.getColor(0, Color.BLACK); - typedArray.recycle(); - arrowRight.setColorFilter(arrowColor); - } catch (Exception ignored) { + presetsButtonStringRes = getArguments().getInt(ARG_PRESETS_BUTTON_TEXT); + customButtonStringRes = getArguments().getInt(ARG_CUSTOM_BUTTON_TEXT); + + int neutralButtonStringRes; + if (dialogType == TYPE_CUSTOM && getArguments().getBoolean(ARG_ALLOW_PRESETS)) { + neutralButtonStringRes = (presetsButtonStringRes != 0 ? presetsButtonStringRes : R.string.cpv_presets); + } else if (dialogType == TYPE_PRESETS && getArguments().getBoolean(ARG_ALLOW_CUSTOM)) { + neutralButtonStringRes = (customButtonStringRes != 0 ? customButtonStringRes : R.string.cpv_custom); + } else { + neutralButtonStringRes = 0; + } + + if (neutralButtonStringRes != 0) { + builder.setNeutralButton(neutralButtonStringRes, null); + } + + return builder.create(); + } + + @Override + public void onStart() { + super.onStart(); + AlertDialog dialog = (AlertDialog) getDialog(); + + // http://stackoverflow.com/a/16972670/1048340 + //noinspection ConstantConditions + dialog.getWindow() + .clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); + + // Do not dismiss the dialog when clicking the neutral button. + Button neutralButton = dialog.getButton(AlertDialog.BUTTON_NEUTRAL); + if (neutralButton != null) { + neutralButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + rootView.removeAllViews(); + switch (dialogType) { + case TYPE_CUSTOM: + dialogType = TYPE_PRESETS; + ((Button) v).setText(customButtonStringRes != 0 ? customButtonStringRes : R.string.cpv_custom); + rootView.addView(createPresetsView()); + break; + case TYPE_PRESETS: + dialogType = TYPE_CUSTOM; + ((Button) v).setText(presetsButtonStringRes != 0 ? presetsButtonStringRes : R.string.cpv_presets); + rootView.addView(createPickerView()); + } + } + }); + } } - colorPicker.setAlphaSliderVisible(showAlphaSlider); - oldColorPanel.setColor(getArguments().getInt(ARG_COLOR)); - colorPicker.setColor(color, true); - newColorPanel.setColor(color); - setHex(color); + @Override + public void onDismiss(DialogInterface dialog) { + super.onDismiss(dialog); + onDialogDismissed(); + } - if (!showAlphaSlider) { - hexEditText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(6) }); + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putInt(ARG_COLOR, color); + outState.putInt(ARG_TYPE, dialogType); + super.onSaveInstanceState(outState); } - newColorPanel.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if (newColorPanel.getColor() == color) { - onColorSelected(color); - dismiss(); + /** + * Set the callback. + *

+ * Note: The preferred way to handle the callback is to have the calling Activity implement + * {@link ColorPickerDialogListener} as this will not survive an orientation change. + * + * @param colorPickerDialogListener The callback invoked when a color is selected or the dialog is dismissed. + */ + public void setColorPickerDialogListener(ColorPickerDialogListener colorPickerDialogListener) { + this.colorPickerDialogListener = colorPickerDialogListener; + } + + // region Custom Picker + + View createPickerView() { + View contentView = View.inflate(getActivity(), R.layout.cpv_dialog_color_picker, null); + colorPicker = (ColorPickerView) contentView.findViewById(R.id.cpv_color_picker_view); + ColorPanelView oldColorPanel = (ColorPanelView) contentView.findViewById(R.id.cpv_color_panel_old); + newColorPanel = (ColorPanelView) contentView.findViewById(R.id.cpv_color_panel_new); + ImageView arrowRight = (ImageView) contentView.findViewById(R.id.cpv_arrow_right); + hexEditText = (EditText) contentView.findViewById(R.id.cpv_hex); + + try { + final TypedValue value = new TypedValue(); + TypedArray typedArray = + getActivity().obtainStyledAttributes(value.data, new int[]{android.R.attr.textColorPrimary}); + int arrowColor = typedArray.getColor(0, Color.BLACK); + typedArray.recycle(); + arrowRight.setColorFilter(arrowColor); + } catch (Exception ignored) { } - } - }); - contentView.setOnTouchListener(onPickerTouchListener); - colorPicker.setOnColorChangedListener(this); - hexEditText.addTextChangedListener(this); + colorPicker.setAlphaSliderVisible(showAlphaSlider); + oldColorPanel.setColor(getArguments().getInt(ARG_COLOR)); + colorPicker.setColor(color, true); + newColorPanel.setColor(color); + setHex(color); - hexEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(hexEditText, InputMethodManager.SHOW_IMPLICIT); + if (!showAlphaSlider) { + hexEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(6)}); } - } - }); - return contentView; - } + newColorPanel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (newColorPanel.getColor() == color) { + onColorSelected(color); + dismiss(); + } + } + }); - @Override public void onColorChanged(int newColor) { - color = newColor; - if (newColorPanel != null) { - newColorPanel.setColor(newColor); - } - if (!fromEditText && hexEditText != null) { - setHex(newColor); - if (hexEditText.hasFocus()) { - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0); - hexEditText.clearFocus(); - } + contentView.setOnTouchListener(onPickerTouchListener); + colorPicker.setOnColorChangedListener(this); + hexEditText.addTextChangedListener(this); + + hexEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(hexEditText, InputMethodManager.SHOW_IMPLICIT); + } + } + }); + + return contentView; } - fromEditText = false; - } - @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { + @Override + public void onColorChanged(int newColor) { + color = newColor; + if (newColorPanel != null) { + newColorPanel.setColor(newColor); + } + if (!fromEditText && hexEditText != null) { + setHex(newColor); + if (hexEditText.hasFocus()) { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(hexEditText.getWindowToken(), 0); + hexEditText.clearFocus(); + } + } + fromEditText = false; + } - } + @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 onTextChanged(CharSequence s, int start, int before, int count) { - @Override public void afterTextChanged(Editable s) { - if (hexEditText.isFocused()) { - int color = parseColorString(s.toString()); - if (color != colorPicker.getColor()) { - fromEditText = true; - colorPicker.setColor(color, true); - } } - } - private void setHex(int color) { - if (showAlphaSlider) { - hexEditText.setText(String.format("%08X", (color))); - } else { - hexEditText.setText(String.format("%06X", (0xFFFFFF & color))); + @Override + public void afterTextChanged(Editable s) { + if (hexEditText.isFocused()) { + int color = parseColorString(s.toString()); + if (color != colorPicker.getColor()) { + fromEditText = true; + colorPicker.setColor(color, true); + } + } } - } - private int parseColorString(String colorString) throws NumberFormatException { - int a, r, g, b = 0; - if (colorString.startsWith("#")) { - colorString = colorString.substring(1); + private void setHex(int color) { + if (showAlphaSlider) { + hexEditText.setText(String.format("%08X", (color))); + } else { + hexEditText.setText(String.format("%06X", (0xFFFFFF & color))); + } } - if (colorString.length() == 0) { - r = 0; - a = 255; - g = 0; - } else if (colorString.length() <= 2) { - a = 255; - r = 0; - b = Integer.parseInt(colorString, 16); - g = 0; - } else if (colorString.length() == 3) { - a = 255; - r = Integer.parseInt(colorString.substring(0, 1), 16); - g = Integer.parseInt(colorString.substring(1, 2), 16); - b = Integer.parseInt(colorString.substring(2, 3), 16); - } else if (colorString.length() == 4) { - a = 255; - r = Integer.parseInt(colorString.substring(0, 2), 16); - g = r; - r = 0; - b = Integer.parseInt(colorString.substring(2, 4), 16); - } else if (colorString.length() == 5) { - a = 255; - r = Integer.parseInt(colorString.substring(0, 1), 16); - g = Integer.parseInt(colorString.substring(1, 3), 16); - b = Integer.parseInt(colorString.substring(3, 5), 16); - } else if (colorString.length() == 6) { - a = 255; - r = Integer.parseInt(colorString.substring(0, 2), 16); - g = Integer.parseInt(colorString.substring(2, 4), 16); - b = Integer.parseInt(colorString.substring(4, 6), 16); - } else if (colorString.length() == 7) { - a = Integer.parseInt(colorString.substring(0, 1), 16); - r = Integer.parseInt(colorString.substring(1, 3), 16); - g = Integer.parseInt(colorString.substring(3, 5), 16); - b = Integer.parseInt(colorString.substring(5, 7), 16); - } else if (colorString.length() == 8) { - a = Integer.parseInt(colorString.substring(0, 2), 16); - r = Integer.parseInt(colorString.substring(2, 4), 16); - g = Integer.parseInt(colorString.substring(4, 6), 16); - b = Integer.parseInt(colorString.substring(6, 8), 16); - } else { - b = -1; - g = -1; - r = -1; - a = -1; + + private int parseColorString(String colorString) throws NumberFormatException { + int a, r, g, b = 0; + if (colorString.startsWith("#")) { + colorString = colorString.substring(1); + } + if (colorString.length() == 0) { + r = 0; + a = 255; + g = 0; + } else if (colorString.length() <= 2) { + a = 255; + r = 0; + b = Integer.parseInt(colorString, 16); + g = 0; + } else if (colorString.length() == 3) { + a = 255; + r = Integer.parseInt(colorString.substring(0, 1), 16); + g = Integer.parseInt(colorString.substring(1, 2), 16); + b = Integer.parseInt(colorString.substring(2, 3), 16); + } else if (colorString.length() == 4) { + a = 255; + r = Integer.parseInt(colorString.substring(0, 2), 16); + g = r; + r = 0; + b = Integer.parseInt(colorString.substring(2, 4), 16); + } else if (colorString.length() == 5) { + a = 255; + r = Integer.parseInt(colorString.substring(0, 1), 16); + g = Integer.parseInt(colorString.substring(1, 3), 16); + b = Integer.parseInt(colorString.substring(3, 5), 16); + } else if (colorString.length() == 6) { + a = 255; + r = Integer.parseInt(colorString.substring(0, 2), 16); + g = Integer.parseInt(colorString.substring(2, 4), 16); + b = Integer.parseInt(colorString.substring(4, 6), 16); + } else if (colorString.length() == 7) { + a = Integer.parseInt(colorString.substring(0, 1), 16); + r = Integer.parseInt(colorString.substring(1, 3), 16); + g = Integer.parseInt(colorString.substring(3, 5), 16); + b = Integer.parseInt(colorString.substring(5, 7), 16); + } else if (colorString.length() == 8) { + a = Integer.parseInt(colorString.substring(0, 2), 16); + r = Integer.parseInt(colorString.substring(2, 4), 16); + g = Integer.parseInt(colorString.substring(4, 6), 16); + b = Integer.parseInt(colorString.substring(6, 8), 16); + } else { + b = -1; + g = -1; + r = -1; + a = -1; + } + return Color.argb(a, r, g, b); } - return Color.argb(a, r, g, b); - } - // -- endregion -- + // -- endregion -- - // region Presets Picker + // region Presets Picker - View createPresetsView() { - View contentView = View.inflate(getActivity(), R.layout.cpv_dialog_presets, null); - shadesLayout = (LinearLayout) contentView.findViewById(R.id.shades_layout); - transparencySeekBar = (SeekBar) contentView.findViewById(R.id.transparency_seekbar); - transparencyPercText = (TextView) contentView.findViewById(R.id.transparency_text); - GridView gridView = (GridView) contentView.findViewById(R.id.gridView); + View createPresetsView() { + View contentView = View.inflate(getActivity(), R.layout.cpv_dialog_presets, null); + shadesLayout = (LinearLayout) contentView.findViewById(R.id.shades_layout); + transparencySeekBar = (SeekBar) contentView.findViewById(R.id.transparency_seekbar); + transparencyPercText = (TextView) contentView.findViewById(R.id.transparency_text); + final TextView transparencyTitle = (TextView) contentView.findViewById(R.id.transparency_title); + int transparencyButtonStringRes = getArguments().getInt(ARG_TRANSPARENCY_BUTTON_TEXT); + if (transparencyButtonStringRes == 0) + transparencyButtonStringRes = R.string.cpv_transparency; + transparencyTitle.setText(transparencyButtonStringRes); - loadPresets(); + GridView gridView = (GridView) contentView.findViewById(R.id.gridView); - if (showColorShades) { - createColorShades(color); - } else { - shadesLayout.setVisibility(View.GONE); - contentView.findViewById(R.id.shades_divider).setVisibility(View.GONE); - } + loadPresets(); - adapter = new ColorPaletteAdapter(new ColorPaletteAdapter.OnColorSelectedListener() { - @Override public void onColorSelected(int newColor) { - if (color == newColor) { - // Double tab selects the color - ColorPickerDialog.this.onColorSelected(color); - dismiss(); - return; - } - color = newColor; if (showColorShades) { - createColorShades(color); + createColorShades(color); + } else { + shadesLayout.setVisibility(View.GONE); + contentView.findViewById(R.id.shades_divider).setVisibility(View.GONE); } - } - }, presets, getSelectedItemPosition(), colorShape); - gridView.setAdapter(adapter); + adapter = new ColorPaletteAdapter(new ColorPaletteAdapter.OnColorSelectedListener() { + @Override + public void onColorSelected(int newColor) { + if (color == newColor) { + // Double tab selects the color + ColorPickerDialog.this.onColorSelected(color); + dismiss(); + return; + } + color = newColor; + if (showColorShades) { + createColorShades(color); + } + } + }, presets, getSelectedItemPosition(), colorShape); - if (showAlphaSlider) { - setupTransparency(); - } else { - contentView.findViewById(R.id.transparency_layout).setVisibility(View.GONE); - contentView.findViewById(R.id.transparency_title).setVisibility(View.GONE); - } + gridView.setAdapter(adapter); - return contentView; - } - - private void loadPresets() { - int alpha = Color.alpha(color); - presets = getArguments().getIntArray(ARG_PRESETS); - if (presets == null) presets = MATERIAL_COLORS; - boolean isMaterialColors = presets == MATERIAL_COLORS; - presets = Arrays.copyOf(presets, presets.length); // don't update the original array when modifying alpha - if (alpha != 255) { - // add alpha to the presets - for (int i = 0; i < presets.length; i++) { - int color = presets[i]; - int red = Color.red(color); - int green = Color.green(color); - int blue = Color.blue(color); - presets[i] = Color.argb(alpha, red, green, blue); - } - } - presets = unshiftIfNotExists(presets, color); - int initialColor = getArguments().getInt(ARG_COLOR); - if (initialColor != color) { - // The user clicked a color and a configuration change occurred. Make sure the initial color is in the presets - presets = unshiftIfNotExists(presets, initialColor); - } - if (isMaterialColors && presets.length == 19) { - // Add black to have a total of 20 colors if the current color is in the material color palette - presets = pushIfNotExists(presets, Color.argb(alpha, 0, 0, 0)); - } - } - - void createColorShades(@ColorInt final int color) { - final int[] colorShades = getColorShades(color); - - if (shadesLayout.getChildCount() != 0) { - for (int i = 0; i < shadesLayout.getChildCount(); i++) { - FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); - final ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); - ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); - cpv.setColor(colorShades[i]); - cpv.setTag(false); - iv.setImageDrawable(null); - } - return; - } + if (showAlphaSlider) { + setupTransparency(); + } else { + contentView.findViewById(R.id.transparency_layout).setVisibility(View.GONE); + transparencyTitle.setVisibility(View.GONE); + } - final int horizontalPadding = getResources().getDimensionPixelSize(R.dimen.cpv_item_horizontal_padding); - - for (final int colorShade : colorShades) { - int layoutResId; - if (colorShape == ColorShape.SQUARE) { - layoutResId = R.layout.cpv_color_item_square; - } else { - layoutResId = R.layout.cpv_color_item_circle; - } - - final View view = View.inflate(getActivity(), layoutResId, null); - final ColorPanelView colorPanelView = (ColorPanelView) view.findViewById(R.id.cpv_color_panel_view); - - ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) colorPanelView.getLayoutParams(); - params.leftMargin = params.rightMargin = horizontalPadding; - colorPanelView.setLayoutParams(params); - colorPanelView.setColor(colorShade); - shadesLayout.addView(view); - - colorPanelView.post(new Runnable() { - @Override public void run() { - // The color is black when rotating the dialog. This is a dirty fix. WTF!? - colorPanelView.setColor(colorShade); - } - }); - - colorPanelView.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if (v.getTag() instanceof Boolean && (Boolean) v.getTag()) { - onColorSelected(ColorPickerDialog.this.color); - dismiss(); - return; // already selected - } - ColorPickerDialog.this.color = colorPanelView.getColor(); - adapter.selectNone(); - for (int i = 0; i < shadesLayout.getChildCount(); i++) { - FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); - ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); - ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); - iv.setImageResource(cpv == v ? R.drawable.cpv_preset_checked : 0); - if (cpv == v && ColorUtils.calculateLuminance(cpv.getColor()) >= 0.65 - || Color.alpha(cpv.getColor()) <= ALPHA_THRESHOLD) { - iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); - } else { - iv.setColorFilter(null); + return contentView; + } + + private void loadPresets() { + int alpha = Color.alpha(color); + presets = getArguments().getIntArray(ARG_PRESETS); + if (presets == null) presets = MATERIAL_COLORS; + boolean isMaterialColors = presets == MATERIAL_COLORS; + presets = Arrays.copyOf(presets, presets.length); // don't update the original array when modifying alpha + if (alpha != 255) { + // add alpha to the presets + for (int i = 0; i < presets.length; i++) { + int color = presets[i]; + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + presets[i] = Color.argb(alpha, red, green, blue); } - cpv.setTag(cpv == v); - } } - }); - colorPanelView.setOnLongClickListener(new View.OnLongClickListener() { - @Override public boolean onLongClick(View v) { - colorPanelView.showHint(); - return true; + presets = unshiftIfNotExists(presets, color); + int initialColor = getArguments().getInt(ARG_COLOR); + if (initialColor != color) { + // The user clicked a color and a configuration change occurred. Make sure the initial color is in the presets + presets = unshiftIfNotExists(presets, initialColor); + } + if (isMaterialColors && presets.length == 19) { + // Add black to have a total of 20 colors if the current color is in the material color palette + presets = pushIfNotExists(presets, Color.argb(alpha, 0, 0, 0)); } - }); } - } - private void onColorSelected(int color) { - if (colorPickerDialogListener != null) { - Log.w(TAG, "Using deprecated listener which may be remove in future releases"); - colorPickerDialogListener.onColorSelected(dialogId, color); - return; - } - Activity activity = getActivity(); - if (activity instanceof ColorPickerDialogListener) { - ((ColorPickerDialogListener) activity).onColorSelected(dialogId, color); - } else { - throw new IllegalStateException("The activity must implement ColorPickerDialogListener"); + void createColorShades(@ColorInt final int color) { + final int[] colorShades = getColorShades(color); + + if (shadesLayout.getChildCount() != 0) { + for (int i = 0; i < shadesLayout.getChildCount(); i++) { + FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); + final ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); + ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); + cpv.setColor(colorShades[i]); + cpv.setTag(false); + iv.setImageDrawable(null); + } + return; + } + + final int horizontalPadding = getResources().getDimensionPixelSize(R.dimen.cpv_item_horizontal_padding); + + for (final int colorShade : colorShades) { + int layoutResId; + if (colorShape == ColorShape.SQUARE) { + layoutResId = R.layout.cpv_color_item_square; + } else { + layoutResId = R.layout.cpv_color_item_circle; + } + + final View view = View.inflate(getActivity(), layoutResId, null); + final ColorPanelView colorPanelView = (ColorPanelView) view.findViewById(R.id.cpv_color_panel_view); + + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) colorPanelView.getLayoutParams(); + params.leftMargin = params.rightMargin = horizontalPadding; + colorPanelView.setLayoutParams(params); + colorPanelView.setColor(colorShade); + shadesLayout.addView(view); + + colorPanelView.post(new Runnable() { + @Override + public void run() { + // The color is black when rotating the dialog. This is a dirty fix. WTF!? + colorPanelView.setColor(colorShade); + } + }); + + colorPanelView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getTag() instanceof Boolean && (Boolean) v.getTag()) { + onColorSelected(ColorPickerDialog.this.color); + dismiss(); + return; // already selected + } + ColorPickerDialog.this.color = colorPanelView.getColor(); + adapter.selectNone(); + for (int i = 0; i < shadesLayout.getChildCount(); i++) { + FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); + ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); + ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); + iv.setImageResource(cpv == v ? R.drawable.cpv_preset_checked : 0); + if (cpv == v && ColorUtils.calculateLuminance(cpv.getColor()) >= 0.65 + || Color.alpha(cpv.getColor()) <= ALPHA_THRESHOLD) { + iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + } else { + iv.setColorFilter(null); + } + cpv.setTag(cpv == v); + } + } + }); + colorPanelView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + colorPanelView.showHint(); + return true; + } + }); + } } - } - private void onDialogDismissed() { - if (colorPickerDialogListener != null) { - Log.w(TAG, "Using deprecated listener which may be remove in future releases"); - colorPickerDialogListener.onDialogDismissed(dialogId); - return; + private void onColorSelected(int color) { + if (colorPickerDialogListener != null) { + Log.w(TAG, "Using deprecated listener which may be remove in future releases"); + colorPickerDialogListener.onColorSelected(dialogId, color); + return; + } + Activity activity = getActivity(); + if (activity instanceof ColorPickerDialogListener) { + ((ColorPickerDialogListener) activity).onColorSelected(dialogId, color); + } else { + throw new IllegalStateException("The activity must implement ColorPickerDialogListener"); + } } - Activity activity = getActivity(); - if (activity instanceof ColorPickerDialogListener) { - ((ColorPickerDialogListener) activity).onDialogDismissed(dialogId); + + private void onDialogDismissed() { + if (colorPickerDialogListener != null) { + Log.w(TAG, "Using deprecated listener which may be remove in future releases"); + colorPickerDialogListener.onDialogDismissed(dialogId); + return; + } + Activity activity = getActivity(); + if (activity instanceof ColorPickerDialogListener) { + ((ColorPickerDialogListener) activity).onDialogDismissed(dialogId); + } } - } - - private int shadeColor(@ColorInt int color, double percent) { - String hex = String.format("#%06X", (0xFFFFFF & color)); - long f = Long.parseLong(hex.substring(1), 16); - double t = percent < 0 ? 0 : 255; - double p = percent < 0 ? percent * -1 : percent; - long R = f >> 16; - long G = f >> 8 & 0x00FF; - long B = f & 0x0000FF; - int alpha = Color.alpha(color); - int red = (int) (Math.round((t - R) * p) + R); - int green = (int) (Math.round((t - G) * p) + G); - int blue = (int) (Math.round((t - B) * p) + B); - return Color.argb(alpha, red, green, blue); - } - - private int[] getColorShades(@ColorInt int color) { - return new int[] { - shadeColor(color, 0.9), shadeColor(color, 0.7), shadeColor(color, 0.5), shadeColor(color, 0.333), - shadeColor(color, 0.166), shadeColor(color, -0.125), shadeColor(color, -0.25), shadeColor(color, -0.375), - shadeColor(color, -0.5), shadeColor(color, -0.675), shadeColor(color, -0.7), shadeColor(color, -0.775), - }; - } - - private void setupTransparency() { - int progress = 255 - Color.alpha(color); - transparencySeekBar.setMax(255); - transparencySeekBar.setProgress(progress); - int percentage = (int) ((double) progress * 100 / 255); - transparencyPercText.setText(String.format(Locale.ENGLISH, "%d%%", percentage)); - transparencySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + + private int shadeColor(@ColorInt int color, double percent) { + String hex = String.format("#%06X", (0xFFFFFF & color)); + long f = Long.parseLong(hex.substring(1), 16); + double t = percent < 0 ? 0 : 255; + double p = percent < 0 ? percent * -1 : percent; + long R = f >> 16; + long G = f >> 8 & 0x00FF; + long B = f & 0x0000FF; + int alpha = Color.alpha(color); + int red = (int) (Math.round((t - R) * p) + R); + int green = (int) (Math.round((t - G) * p) + G); + int blue = (int) (Math.round((t - B) * p) + B); + return Color.argb(alpha, red, green, blue); + } + + private int[] getColorShades(@ColorInt int color) { + return new int[]{ + shadeColor(color, 0.9), shadeColor(color, 0.7), shadeColor(color, 0.5), shadeColor(color, 0.333), + shadeColor(color, 0.166), shadeColor(color, -0.125), shadeColor(color, -0.25), shadeColor(color, -0.375), + shadeColor(color, -0.5), shadeColor(color, -0.675), shadeColor(color, -0.7), shadeColor(color, -0.775), + }; + } + + private void setupTransparency() { + int progress = 255 - Color.alpha(color); + transparencySeekBar.setMax(255); + transparencySeekBar.setProgress(progress); int percentage = (int) ((double) progress * 100 / 255); transparencyPercText.setText(String.format(Locale.ENGLISH, "%d%%", percentage)); - int alpha = 255 - progress; - // update items in GridView: - for (int i = 0; i < adapter.colors.length; i++) { - int color = adapter.colors[i]; - int red = Color.red(color); - int green = Color.green(color); - int blue = Color.blue(color); - adapter.colors[i] = Color.argb(alpha, red, green, blue); - } - adapter.notifyDataSetChanged(); - // update shades: - for (int i = 0; i < shadesLayout.getChildCount(); i++) { - FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); - ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); - ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); - if (layout.getTag() == null) { - // save the original border color - layout.setTag(cpv.getBorderColor()); - } - int color = cpv.getColor(); - color = Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); - if (alpha <= ALPHA_THRESHOLD) { - cpv.setBorderColor(color | 0xFF000000); - } else { - cpv.setBorderColor((int) layout.getTag()); - } - if (cpv.getTag() != null && (Boolean) cpv.getTag()) { - // The alpha changed on the selected shaded color. Update the checkmark color filter. - if (alpha <= ALPHA_THRESHOLD) { - iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); - } else { - if (ColorUtils.calculateLuminance(color) >= 0.65) { - iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); - } else { - iv.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); - } + transparencySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + int percentage = (int) ((double) progress * 100 / 255); + transparencyPercText.setText(String.format(Locale.ENGLISH, "%d%%", percentage)); + int alpha = 255 - progress; + // update items in GridView: + for (int i = 0; i < adapter.colors.length; i++) { + int color = adapter.colors[i]; + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + adapter.colors[i] = Color.argb(alpha, red, green, blue); + } + adapter.notifyDataSetChanged(); + // update shades: + for (int i = 0; i < shadesLayout.getChildCount(); i++) { + FrameLayout layout = (FrameLayout) shadesLayout.getChildAt(i); + ColorPanelView cpv = (ColorPanelView) layout.findViewById(R.id.cpv_color_panel_view); + ImageView iv = (ImageView) layout.findViewById(R.id.cpv_color_image_view); + if (layout.getTag() == null) { + // save the original border color + layout.setTag(cpv.getBorderColor()); + } + int color = cpv.getColor(); + color = Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); + if (alpha <= ALPHA_THRESHOLD) { + cpv.setBorderColor(color | 0xFF000000); + } else { + cpv.setBorderColor((int) layout.getTag()); + } + if (cpv.getTag() != null && (Boolean) cpv.getTag()) { + // The alpha changed on the selected shaded color. Update the checkmark color filter. + if (alpha <= ALPHA_THRESHOLD) { + iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + } else { + if (ColorUtils.calculateLuminance(color) >= 0.65) { + iv.setColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN); + } else { + iv.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN); + } + } + } + cpv.setColor(color); + } + // update color: + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + color = Color.argb(alpha, red, green, blue); } - } - cpv.setColor(color); - } - // update color: - int red = Color.red(color); - int green = Color.green(color); - int blue = Color.blue(color); - color = Color.argb(alpha, red, green, blue); - } - - @Override public void onStartTrackingTouch(SeekBar seekBar) { - } + @Override + public void onStartTrackingTouch(SeekBar seekBar) { - @Override public void onStopTrackingTouch(SeekBar seekBar) { + } - } - }); - } + @Override + public void onStopTrackingTouch(SeekBar seekBar) { - private int[] unshiftIfNotExists(int[] array, int value) { - boolean present = false; - for (int i : array) { - if (i == value) { - present = true; - break; - } - } - if (!present) { - int[] newArray = new int[array.length + 1]; - newArray[0] = value; - System.arraycopy(array, 0, newArray, 1, newArray.length - 1); - return newArray; + } + }); } - return array; - } - - private int[] pushIfNotExists(int[] array, int value) { - boolean present = false; - for (int i : array) { - if (i == value) { - present = true; - break; - } + + private int[] unshiftIfNotExists(int[] array, int value) { + boolean present = false; + for (int i : array) { + if (i == value) { + present = true; + break; + } + } + if (!present) { + int[] newArray = new int[array.length + 1]; + newArray[0] = value; + System.arraycopy(array, 0, newArray, 1, newArray.length - 1); + return newArray; + } + return array; } - if (!present) { - int[] newArray = new int[array.length + 1]; - newArray[newArray.length - 1] = value; - System.arraycopy(array, 0, newArray, 0, newArray.length - 1); - return newArray; + + private int[] pushIfNotExists(int[] array, int value) { + boolean present = false; + for (int i : array) { + if (i == value) { + present = true; + break; + } + } + if (!present) { + int[] newArray = new int[array.length + 1]; + newArray[newArray.length - 1] = value; + System.arraycopy(array, 0, newArray, 0, newArray.length - 1); + return newArray; + } + return array; } - return array; - } - - private int getSelectedItemPosition() { - for (int i = 0; i < presets.length; i++) { - if (presets[i] == color) { - return i; - } + + private int getSelectedItemPosition() { + for (int i = 0; i < presets.length; i++) { + if (presets[i] == color) { + return i; + } + } + return -1; } - return -1; - } - // endregion + // endregion - // region Builder + // region Builder - @IntDef({ TYPE_CUSTOM, TYPE_PRESETS }) public @interface DialogType { + @IntDef({TYPE_CUSTOM, TYPE_PRESETS}) + public @interface DialogType { - } + } - public static final class Builder { + public static final class Builder { - ColorPickerDialogListener colorPickerDialogListener; - @StringRes int dialogTitle = R.string.cpv_default_title; - @StringRes int presetsButtonText = R.string.cpv_presets; - @StringRes int customButtonText = R.string.cpv_custom; - @StringRes int selectedButtonText = R.string.cpv_select; - @DialogType int dialogType = TYPE_PRESETS; - int[] presets = MATERIAL_COLORS; - @ColorInt int color = Color.BLACK; - int dialogId = 0; - boolean showAlphaSlider = false; - boolean allowPresets = true; - boolean allowCustom = true; - boolean showColorShades = true; - @ColorShape int colorShape = ColorShape.CIRCLE; - - /*package*/ Builder() { + ColorPickerDialogListener colorPickerDialogListener; + @StringRes + int dialogTitle = R.string.cpv_default_title; + @StringRes + int presetsButtonText = R.string.cpv_presets; + @StringRes + int customButtonText = R.string.cpv_custom; + @StringRes + int selectedButtonText = R.string.cpv_select; + @StringRes + int transparencyButtonText = R.string.cpv_transparency; + @DialogType + int dialogType = TYPE_PRESETS; + int[] presets = MATERIAL_COLORS; + @ColorInt + int color = Color.BLACK; + int dialogId = 0; + boolean showAlphaSlider = false; + boolean allowPresets = true; + boolean allowCustom = true; + boolean showColorShades = true; + @ColorShape + int colorShape = ColorShape.CIRCLE; - } + /*package*/ Builder() { - /** - * Set the dialog title string resource id - * - * @param dialogTitle The string resource used for the dialog title - * @return This builder object for chaining method calls - */ - public Builder setDialogTitle(@StringRes int dialogTitle) { - this.dialogTitle = dialogTitle; - return this; - } + } - /** - * Set the selected button text string resource id - * - * @param selectedButtonText The string resource used for the selected button text - * @return This builder object for chaining method calls - */ - public Builder setSelectedButtonText(@StringRes int selectedButtonText) { - this.selectedButtonText = selectedButtonText; - return this; - } + /** + * Set the dialog title string resource id + * + * @param dialogTitle The string resource used for the dialog title + * @return This builder object for chaining method calls + */ + public Builder setDialogTitle(@StringRes int dialogTitle) { + this.dialogTitle = dialogTitle; + return this; + } - /** - * Set the presets button text string resource id - * - * @param presetsButtonText The string resource used for the presets button text - * @return This builder object for chaining method calls - */ - public Builder setPresetsButtonText(@StringRes int presetsButtonText) { - this.presetsButtonText = presetsButtonText; - return this; - } + /** + * Set the selected button text string resource id + * + * @param selectedButtonText The string resource used for the selected button text + * @return This builder object for chaining method calls + */ + public Builder setSelectedButtonText(@StringRes int selectedButtonText) { + this.selectedButtonText = selectedButtonText; + return this; + } - /** - * Set the custom button text string resource id - * - * @param customButtonText The string resource used for the custom button text - * @return This builder object for chaining method calls - */ - public Builder setCustomButtonText(@StringRes int customButtonText) { - this.customButtonText = customButtonText; - return this; - } + /** + * Set the transparency button text string resource id + * + * @param transparencyButtonText The string resource used for the transparency button text + * @return This builder object for chaining method calls + */ + public Builder setTransparencyButtonText(@StringRes int transparencyButtonText) { + this.transparencyButtonText = transparencyButtonText; + return this; + } - /** - * Set which dialog view to show. - * - * @param dialogType Either {@link ColorPickerDialog#TYPE_CUSTOM} or {@link ColorPickerDialog#TYPE_PRESETS}. - * @return This builder object for chaining method calls - */ - public Builder setDialogType(@DialogType int dialogType) { - this.dialogType = dialogType; - return this; - } + /** + * Set the presets button text string resource id + * + * @param presetsButtonText The string resource used for the presets button text + * @return This builder object for chaining method calls + */ + public Builder setPresetsButtonText(@StringRes int presetsButtonText) { + this.presetsButtonText = presetsButtonText; + return this; + } - /** - * Set the colors used for the presets - * - * @param presets An array of color ints. - * @return This builder object for chaining method calls - */ - public Builder setPresets(@NonNull int[] presets) { - this.presets = presets; - return this; - } + /** + * Set the custom button text string resource id + * + * @param customButtonText The string resource used for the custom button text + * @return This builder object for chaining method calls + */ + public Builder setCustomButtonText(@StringRes int customButtonText) { + this.customButtonText = customButtonText; + return this; + } - /** - * Set the original color - * - * @param color The default color for the color picker - * @return This builder object for chaining method calls - */ - public Builder setColor(int color) { - this.color = color; - return this; - } + /** + * Set which dialog view to show. + * + * @param dialogType Either {@link ColorPickerDialog#TYPE_CUSTOM} or {@link ColorPickerDialog#TYPE_PRESETS}. + * @return This builder object for chaining method calls + */ + public Builder setDialogType(@DialogType int dialogType) { + this.dialogType = dialogType; + return this; + } - /** - * Set the dialog id used for callbacks - * - * @param dialogId The id that is sent back to the {@link ColorPickerDialogListener}. - * @return This builder object for chaining method calls - */ - public Builder setDialogId(int dialogId) { - this.dialogId = dialogId; - return this; - } + /** + * Set the colors used for the presets + * + * @param presets An array of color ints. + * @return This builder object for chaining method calls + */ + public Builder setPresets(@NonNull int[] presets) { + this.presets = presets; + return this; + } - /** - * Show the alpha slider - * - * @param showAlphaSlider {@code true} to show the alpha slider. Currently only supported with the {@link - * ColorPickerView}. - * @return This builder object for chaining method calls - */ - public Builder setShowAlphaSlider(boolean showAlphaSlider) { - this.showAlphaSlider = showAlphaSlider; - return this; - } + /** + * Set the original color + * + * @param color The default color for the color picker + * @return This builder object for chaining method calls + */ + public Builder setColor(int color) { + this.color = color; + return this; + } - /** - * Show/Hide a neutral button to select preset colors. - * - * @param allowPresets {@code false} to disable showing the presets button. - * @return This builder object for chaining method calls - */ - public Builder setAllowPresets(boolean allowPresets) { - this.allowPresets = allowPresets; - return this; - } + /** + * Set the dialog id used for callbacks + * + * @param dialogId The id that is sent back to the {@link ColorPickerDialogListener}. + * @return This builder object for chaining method calls + */ + public Builder setDialogId(int dialogId) { + this.dialogId = dialogId; + return this; + } - /** - * Show/Hide the neutral button to select a custom color. - * - * @param allowCustom {@code false} to disable showing the custom button. - * @return This builder object for chaining method calls - */ - public Builder setAllowCustom(boolean allowCustom) { - this.allowCustom = allowCustom; - return this; - } + /** + * Show the alpha slider + * + * @param showAlphaSlider {@code true} to show the alpha slider. Currently only supported with the {@link + * ColorPickerView}. + * @return This builder object for chaining method calls + */ + public Builder setShowAlphaSlider(boolean showAlphaSlider) { + this.showAlphaSlider = showAlphaSlider; + return this; + } - /** - * Show/Hide the color shades in the presets picker - * - * @param showColorShades {@code false} to hide the color shades. - * @return This builder object for chaining method calls - */ - public Builder setShowColorShades(boolean showColorShades) { - this.showColorShades = showColorShades; - return this; - } + /** + * Show/Hide a neutral button to select preset colors. + * + * @param allowPresets {@code false} to disable showing the presets button. + * @return This builder object for chaining method calls + */ + public Builder setAllowPresets(boolean allowPresets) { + this.allowPresets = allowPresets; + return this; + } - /** - * Set the shape of the color panel view. - * - * @param colorShape Either {@link ColorShape#CIRCLE} or {@link ColorShape#SQUARE}. - * @return This builder object for chaining method calls - */ - public Builder setColorShape(int colorShape) { - this.colorShape = colorShape; - return this; - } + /** + * Show/Hide the neutral button to select a custom color. + * + * @param allowCustom {@code false} to disable showing the custom button. + * @return This builder object for chaining method calls + */ + public Builder setAllowCustom(boolean allowCustom) { + this.allowCustom = allowCustom; + return this; + } - /** - * Create the {@link ColorPickerDialog} instance. - * - * @return A new {@link ColorPickerDialog}. - * @see #show(FragmentActivity) - */ - public ColorPickerDialog create() { - ColorPickerDialog dialog = new ColorPickerDialog(); - Bundle args = new Bundle(); - args.putInt(ARG_ID, dialogId); - args.putInt(ARG_TYPE, dialogType); - args.putInt(ARG_COLOR, color); - args.putIntArray(ARG_PRESETS, presets); - args.putBoolean(ARG_ALPHA, showAlphaSlider); - args.putBoolean(ARG_ALLOW_CUSTOM, allowCustom); - args.putBoolean(ARG_ALLOW_PRESETS, allowPresets); - args.putInt(ARG_DIALOG_TITLE, dialogTitle); - args.putBoolean(ARG_SHOW_COLOR_SHADES, showColorShades); - args.putInt(ARG_COLOR_SHAPE, colorShape); - args.putInt(ARG_PRESETS_BUTTON_TEXT, presetsButtonText); - args.putInt(ARG_CUSTOM_BUTTON_TEXT, customButtonText); - args.putInt(ARG_SELECTED_BUTTON_TEXT, selectedButtonText); - dialog.setArguments(args); - return dialog; - } + /** + * Show/Hide the color shades in the presets picker + * + * @param showColorShades {@code false} to hide the color shades. + * @return This builder object for chaining method calls + */ + public Builder setShowColorShades(boolean showColorShades) { + this.showColorShades = showColorShades; + return this; + } - /** - * Create and show the {@link ColorPickerDialog} created with this builder. - * - * @param activity The current activity. - */ - public void show(FragmentActivity activity) { - create().show(activity.getSupportFragmentManager(), "color-picker-dialog"); + /** + * Set the shape of the color panel view. + * + * @param colorShape Either {@link ColorShape#CIRCLE} or {@link ColorShape#SQUARE}. + * @return This builder object for chaining method calls + */ + public Builder setColorShape(int colorShape) { + this.colorShape = colorShape; + return this; + } + + /** + * Create the {@link ColorPickerDialog} instance. + * + * @return A new {@link ColorPickerDialog}. + * @see #show(FragmentActivity) + */ + public ColorPickerDialog create() { + ColorPickerDialog dialog = new ColorPickerDialog(); + Bundle args = new Bundle(); + args.putInt(ARG_ID, dialogId); + args.putInt(ARG_TYPE, dialogType); + args.putInt(ARG_COLOR, color); + args.putIntArray(ARG_PRESETS, presets); + args.putBoolean(ARG_ALPHA, showAlphaSlider); + args.putBoolean(ARG_ALLOW_CUSTOM, allowCustom); + args.putBoolean(ARG_ALLOW_PRESETS, allowPresets); + args.putInt(ARG_DIALOG_TITLE, dialogTitle); + args.putBoolean(ARG_SHOW_COLOR_SHADES, showColorShades); + args.putInt(ARG_COLOR_SHAPE, colorShape); + args.putInt(ARG_PRESETS_BUTTON_TEXT, presetsButtonText); + args.putInt(ARG_CUSTOM_BUTTON_TEXT, customButtonText); + args.putInt(ARG_SELECTED_BUTTON_TEXT, selectedButtonText); + args.putInt(ARG_TRANSPARENCY_BUTTON_TEXT, transparencyButtonText); + dialog.setArguments(args); + return dialog; + } + + /** + * Create and show the {@link ColorPickerDialog} created with this builder. + * + * @param activity The current activity. + */ + public void show(FragmentActivity activity) { + create().show(activity.getSupportFragmentManager(), "color-picker-dialog"); + } } - } - // endregion + // endregion } diff --git a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreference.java b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreference.java index 0021dd5..23bc510 100644 --- a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreference.java +++ b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreference.java @@ -22,8 +22,10 @@ import android.preference.Preference; import android.util.AttributeSet; import android.view.View; + import androidx.annotation.ColorInt; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import androidx.fragment.app.FragmentActivity; /** @@ -31,181 +33,206 @@ */ public class ColorPreference extends Preference implements ColorPickerDialogListener { - private static final int SIZE_NORMAL = 0; - private static final int SIZE_LARGE = 1; - - private OnShowDialogListener onShowDialogListener; - private int color = Color.BLACK; - private boolean showDialog; - @ColorPickerDialog.DialogType private int dialogType; - private int colorShape; - private boolean allowPresets; - private boolean allowCustom; - private boolean showAlphaSlider; - private boolean showColorShades; - private int previewSize; - private int[] presets; - private int dialogTitle; - - public ColorPreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(attrs); - } - - public ColorPreference(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(attrs); - } - - private void init(AttributeSet attrs) { - setPersistent(true); - TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference); - showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true); - //noinspection WrongConstant - dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS); - colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE); - allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true); - allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true); - showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false); - showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true); - previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL); - final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0); - dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title); - if (presetsResId != 0) { - presets = getContext().getResources().getIntArray(presetsResId); - } else { - presets = ColorPickerDialog.MATERIAL_COLORS; - } - if (colorShape == ColorShape.CIRCLE) { - setWidgetLayoutResource( - previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle); - } else { - setWidgetLayoutResource( - previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square); - } - a.recycle(); - } - - @Override protected void onClick() { - super.onClick(); - if (onShowDialogListener != null) { - onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color); - } else if (showDialog) { - ColorPickerDialog dialog = ColorPickerDialog.newBuilder() - .setDialogType(dialogType) - .setDialogTitle(dialogTitle) - .setColorShape(colorShape) - .setPresets(presets) - .setAllowPresets(allowPresets) - .setAllowCustom(allowCustom) - .setShowAlphaSlider(showAlphaSlider) - .setShowColorShades(showColorShades) - .setColor(color) - .create(); - dialog.setColorPickerDialogListener(this); - FragmentActivity activity = (FragmentActivity) getContext(); - activity.getSupportFragmentManager() - .beginTransaction() - .add(dialog, getFragmentTag()) - .commitAllowingStateLoss(); - } - } - - @Override protected void onAttachedToActivity() { - super.onAttachedToActivity(); - - if (showDialog) { - FragmentActivity activity = (FragmentActivity) getContext(); - ColorPickerDialog fragment = - (ColorPickerDialog) activity.getSupportFragmentManager().findFragmentByTag(getFragmentTag()); - if (fragment != null) { - // re-bind preference to fragment - fragment.setColorPickerDialogListener(this); - } - } - } - - @Override protected void onBindView(View view) { - super.onBindView(view); - ColorPanelView preview = (ColorPanelView) view.findViewById(R.id.cpv_preference_preview_color_panel); - if (preview != null) { - preview.setColor(color); - } - } - - @Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { - if (restorePersistedValue) { - color = getPersistedInt(0xFF000000); - } else { - color = (Integer) defaultValue; - persistInt(color); - } - } - - @Override protected Object onGetDefaultValue(TypedArray a, int index) { - return a.getInteger(index, Color.BLACK); - } - - @Override public void onColorSelected(int dialogId, @ColorInt int color) { - saveValue(color); - } - - @Override public void onDialogDismissed(int dialogId) { - // no-op - } - - /** - * Set the new color - * - * @param color The newly selected color - */ - public void saveValue(@ColorInt int color) { - this.color = color; - persistInt(this.color); - notifyChanged(); - callChangeListener(color); - } - - /** - * Get the colors that will be shown in the {@link ColorPickerDialog}. - * - * @return An array of color ints - */ - public int[] getPresets() { - return presets; - } - - /** - * Set the colors shown in the {@link ColorPickerDialog}. - * - * @param presets An array of color ints - */ - public void setPresets(@NonNull int[] presets) { - this.presets = presets; - } - - /** - * The listener used for showing the {@link ColorPickerDialog}. - * Call {@link #saveValue(int)} after the user chooses a color. - * If this is set then it is up to you to show the dialog. - * - * @param listener The listener to show the dialog - */ - public void setOnShowDialogListener(OnShowDialogListener listener) { - onShowDialogListener = listener; - } - - /** - * The tag used for the {@link ColorPickerDialog}. - * - * @return The tag - */ - public String getFragmentTag() { - return "color_" + getKey(); - } - - public interface OnShowDialogListener { - - void onShowColorPickerDialog(String title, int currentColor); - } + private static final int SIZE_NORMAL = 0; + private static final int SIZE_LARGE = 1; + + private OnShowDialogListener onShowDialogListener; + private int color = Color.BLACK; + private boolean showDialog; + @ColorPickerDialog.DialogType + private int dialogType; + private int colorShape; + private boolean allowPresets; + private boolean allowCustom; + private boolean showAlphaSlider; + private boolean showColorShades; + private int previewSize; + private int[] presets; + private int dialogTitle; + @StringRes + private int dialogPresetsActionText; + @StringRes + private int dialogSelectActionText; + @StringRes + private int dialogCustomActionText; + @StringRes + private int dialogTransparencyActionText; + + public ColorPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public ColorPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs); + } + + private void init(AttributeSet attrs) { + setPersistent(true); + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference); + showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true); + //noinspection WrongConstant + dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS); + colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE); + allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true); + allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true); + showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false); + showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true); + previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL); + final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0); + dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title); + dialogPresetsActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogPresetsActionText, R.string.cpv_presets); + dialogSelectActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogSelectActionText, R.string.cpv_select); + dialogCustomActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogCustomActionText, R.string.cpv_custom); + dialogTransparencyActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTransparencyActionText, R.string.cpv_transparency); + + if (presetsResId != 0) { + presets = getContext().getResources().getIntArray(presetsResId); + } else { + presets = ColorPickerDialog.MATERIAL_COLORS; + } + if (colorShape == ColorShape.CIRCLE) { + setWidgetLayoutResource( + previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle); + } else { + setWidgetLayoutResource( + previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square); + } + a.recycle(); + } + + @Override + protected void onClick() { + super.onClick(); + if (onShowDialogListener != null) { + onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color); + } else if (showDialog) { + ColorPickerDialog dialog = ColorPickerDialog.newBuilder() + .setDialogType(dialogType) + .setDialogTitle(dialogTitle) + .setPresetsButtonText(dialogPresetsActionText) + .setSelectedButtonText(dialogSelectActionText) + .setCustomButtonText(dialogCustomActionText) + .setTransparencyButtonText(dialogTransparencyActionText) + .setColorShape(colorShape) + .setPresets(presets) + .setAllowPresets(allowPresets) + .setAllowCustom(allowCustom) + .setShowAlphaSlider(showAlphaSlider) + .setShowColorShades(showColorShades) + .setColor(color) + .create(); + dialog.setColorPickerDialogListener(this); + FragmentActivity activity = (FragmentActivity) getContext(); + activity.getSupportFragmentManager() + .beginTransaction() + .add(dialog, getFragmentTag()) + .commitAllowingStateLoss(); + } + } + + @Override + protected void onAttachedToActivity() { + super.onAttachedToActivity(); + + if (showDialog) { + FragmentActivity activity = (FragmentActivity) getContext(); + ColorPickerDialog fragment = + (ColorPickerDialog) activity.getSupportFragmentManager().findFragmentByTag(getFragmentTag()); + if (fragment != null) { + // re-bind preference to fragment + fragment.setColorPickerDialogListener(this); + } + } + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + ColorPanelView preview = (ColorPanelView) view.findViewById(R.id.cpv_preference_preview_color_panel); + if (preview != null) { + preview.setColor(color); + } + } + + @Override + protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { + if (restorePersistedValue) { + color = getPersistedInt(0xFF000000); + } else { + color = (Integer) defaultValue; + persistInt(color); + } + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, Color.BLACK); + } + + @Override + public void onColorSelected(int dialogId, @ColorInt int color) { + saveValue(color); + } + + @Override + public void onDialogDismissed(int dialogId) { + // no-op + } + + /** + * Set the new color + * + * @param color The newly selected color + */ + public void saveValue(@ColorInt int color) { + this.color = color; + persistInt(this.color); + notifyChanged(); + callChangeListener(color); + } + + /** + * Get the colors that will be shown in the {@link ColorPickerDialog}. + * + * @return An array of color ints + */ + public int[] getPresets() { + return presets; + } + + /** + * Set the colors shown in the {@link ColorPickerDialog}. + * + * @param presets An array of color ints + */ + public void setPresets(@NonNull int[] presets) { + this.presets = presets; + } + + /** + * The listener used for showing the {@link ColorPickerDialog}. + * Call {@link #saveValue(int)} after the user chooses a color. + * If this is set then it is up to you to show the dialog. + * + * @param listener The listener to show the dialog + */ + public void setOnShowDialogListener(OnShowDialogListener listener) { + onShowDialogListener = listener; + } + + /** + * The tag used for the {@link ColorPickerDialog}. + * + * @return The tag + */ + public String getFragmentTag() { + return "color_" + getKey(); + } + + public interface OnShowDialogListener { + + void onShowColorPickerDialog(String title, int currentColor); + } } diff --git a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreferenceCompat.java b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreferenceCompat.java index 42e579e..3a5117e 100644 --- a/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreferenceCompat.java +++ b/library/src/main/java/com/jaredrummler/android/colorpicker/ColorPreferenceCompat.java @@ -5,8 +5,10 @@ import android.content.res.TypedArray; import android.graphics.Color; import android.util.AttributeSet; + import androidx.annotation.ColorInt; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -16,192 +18,216 @@ */ public class ColorPreferenceCompat extends Preference implements ColorPickerDialogListener { - private static final int SIZE_NORMAL = 0; - private static final int SIZE_LARGE = 1; - - private OnShowDialogListener onShowDialogListener; - private int color = Color.BLACK; - private boolean showDialog; - @ColorPickerDialog.DialogType private int dialogType; - private int colorShape; - private boolean allowPresets; - private boolean allowCustom; - private boolean showAlphaSlider; - private boolean showColorShades; - private int previewSize; - private int[] presets; - private int dialogTitle; - - public ColorPreferenceCompat(Context context, AttributeSet attrs) { - super(context, attrs); - init(attrs); - } - - public ColorPreferenceCompat(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(attrs); - } - - private void init(AttributeSet attrs) { - setPersistent(true); - TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference); - showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true); - //noinspection WrongConstant - dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS); - colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE); - allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true); - allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true); - showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false); - showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true); - previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL); - final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0); - dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title); - if (presetsResId != 0) { - presets = getContext().getResources().getIntArray(presetsResId); - } else { - presets = ColorPickerDialog.MATERIAL_COLORS; - } - if (colorShape == ColorShape.CIRCLE) { - setWidgetLayoutResource( - previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle); - } else { - setWidgetLayoutResource( - previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square); - } - a.recycle(); - } - - @Override protected void onClick() { - super.onClick(); - if (onShowDialogListener != null) { - onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color); - } else if (showDialog) { - ColorPickerDialog dialog = ColorPickerDialog.newBuilder() - .setDialogType(dialogType) - .setDialogTitle(dialogTitle) - .setColorShape(colorShape) - .setPresets(presets) - .setAllowPresets(allowPresets) - .setAllowCustom(allowCustom) - .setShowAlphaSlider(showAlphaSlider) - .setShowColorShades(showColorShades) - .setColor(color) - .create(); - dialog.setColorPickerDialogListener(this); - getActivity().getSupportFragmentManager() - .beginTransaction() - .add(dialog, getFragmentTag()) - .commitAllowingStateLoss(); - } - } - - public FragmentActivity getActivity() { - Context context = getContext(); - if (context instanceof FragmentActivity) { - return (FragmentActivity) context; - } else if (context instanceof ContextWrapper) { - Context baseContext = ((ContextWrapper) context).getBaseContext(); - if (baseContext instanceof FragmentActivity) { - return (FragmentActivity) baseContext; - } - } - throw new IllegalStateException("Error getting activity from context"); - } - - @Override public void onAttached() { - super.onAttached(); - if (showDialog) { - ColorPickerDialog fragment = - (ColorPickerDialog) getActivity().getSupportFragmentManager().findFragmentByTag(getFragmentTag()); - if (fragment != null) { - // re-bind preference to fragment - fragment.setColorPickerDialogListener(this); - } - } - } - - @Override public void onBindViewHolder(PreferenceViewHolder holder) { - super.onBindViewHolder(holder); - ColorPanelView preview = (ColorPanelView) holder.itemView.findViewById(R.id.cpv_preference_preview_color_panel); - if (preview != null) { - preview.setColor(color); - } - } - - @Override protected void onSetInitialValue(Object defaultValue) { - super.onSetInitialValue(defaultValue); - if (defaultValue instanceof Integer) { - color = (Integer) defaultValue; - persistInt(color); - } else { - color = getPersistedInt(0xFF000000); - } - } - - @Override protected Object onGetDefaultValue(TypedArray a, int index) { - return a.getInteger(index, Color.BLACK); - } - - @Override public void onColorSelected(int dialogId, @ColorInt int color) { - saveValue(color); - } - - @Override public void onDialogDismissed(int dialogId) { - // no-op - } - - /** - * Set the new color - * - * @param color The newly selected color - */ - public void saveValue(@ColorInt int color) { - this.color = color; - persistInt(this.color); - notifyChanged(); - callChangeListener(color); - } - - /** - * Get the colors that will be shown in the {@link ColorPickerDialog}. - * - * @return An array of color ints - */ - public int[] getPresets() { - return presets; - } - - /** - * Set the colors shown in the {@link ColorPickerDialog}. - * - * @param presets An array of color ints - */ - public void setPresets(@NonNull int[] presets) { - this.presets = presets; - } - - /** - * The listener used for showing the {@link ColorPickerDialog}. - * Call {@link #saveValue(int)} after the user chooses a color. - * If this is set then it is up to you to show the dialog. - * - * @param listener The listener to show the dialog - */ - public void setOnShowDialogListener(OnShowDialogListener listener) { - onShowDialogListener = listener; - } - - /** - * The tag used for the {@link ColorPickerDialog}. - * - * @return The tag - */ - public String getFragmentTag() { - return "color_" + getKey(); - } - - public interface OnShowDialogListener { - - void onShowColorPickerDialog(String title, int currentColor); - } + private static final int SIZE_NORMAL = 0; + private static final int SIZE_LARGE = 1; + + private OnShowDialogListener onShowDialogListener; + private int color = Color.BLACK; + private boolean showDialog; + @ColorPickerDialog.DialogType + private int dialogType; + private int colorShape; + private boolean allowPresets; + private boolean allowCustom; + private boolean showAlphaSlider; + private boolean showColorShades; + private int previewSize; + private int[] presets; + private int dialogTitle; + @StringRes + private int dialogPresetsActionText; + @StringRes + private int dialogSelectActionText; + @StringRes + private int dialogCustomActionText; + @StringRes + private int dialogTransparencyActionText; + + public ColorPreferenceCompat(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public ColorPreferenceCompat(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(attrs); + } + + private void init(AttributeSet attrs) { + setPersistent(true); + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPreference); + showDialog = a.getBoolean(R.styleable.ColorPreference_cpv_showDialog, true); + //noinspection WrongConstant + dialogType = a.getInt(R.styleable.ColorPreference_cpv_dialogType, ColorPickerDialog.TYPE_PRESETS); + colorShape = a.getInt(R.styleable.ColorPreference_cpv_colorShape, ColorShape.CIRCLE); + allowPresets = a.getBoolean(R.styleable.ColorPreference_cpv_allowPresets, true); + allowCustom = a.getBoolean(R.styleable.ColorPreference_cpv_allowCustom, true); + showAlphaSlider = a.getBoolean(R.styleable.ColorPreference_cpv_showAlphaSlider, false); + showColorShades = a.getBoolean(R.styleable.ColorPreference_cpv_showColorShades, true); + previewSize = a.getInt(R.styleable.ColorPreference_cpv_previewSize, SIZE_NORMAL); + final int presetsResId = a.getResourceId(R.styleable.ColorPreference_cpv_colorPresets, 0); + dialogTitle = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTitle, R.string.cpv_default_title); + dialogPresetsActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogPresetsActionText, R.string.cpv_presets); + dialogSelectActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogSelectActionText, R.string.cpv_select); + dialogCustomActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogCustomActionText, R.string.cpv_custom); + dialogTransparencyActionText = a.getResourceId(R.styleable.ColorPreference_cpv_dialogTransparencyActionText, R.string.cpv_transparency); + if (presetsResId != 0) { + presets = getContext().getResources().getIntArray(presetsResId); + } else { + presets = ColorPickerDialog.MATERIAL_COLORS; + } + if (colorShape == ColorShape.CIRCLE) { + setWidgetLayoutResource( + previewSize == SIZE_LARGE ? R.layout.cpv_preference_circle_large : R.layout.cpv_preference_circle); + } else { + setWidgetLayoutResource( + previewSize == SIZE_LARGE ? R.layout.cpv_preference_square_large : R.layout.cpv_preference_square); + } + a.recycle(); + } + + @Override + protected void onClick() { + super.onClick(); + if (onShowDialogListener != null) { + onShowDialogListener.onShowColorPickerDialog((String) getTitle(), color); + } else if (showDialog) { + ColorPickerDialog dialog = ColorPickerDialog.newBuilder() + .setDialogType(dialogType) + .setDialogTitle(dialogTitle) + .setPresetsButtonText(dialogPresetsActionText) + .setSelectedButtonText(dialogSelectActionText) + .setTransparencyButtonText(dialogTransparencyActionText) + .setCustomButtonText(dialogCustomActionText) + .setColorShape(colorShape) + .setPresets(presets) + .setAllowPresets(allowPresets) + .setAllowCustom(allowCustom) + .setShowAlphaSlider(showAlphaSlider) + .setShowColorShades(showColorShades) + .setColor(color) + .create(); + dialog.setColorPickerDialogListener(this); + getActivity().getSupportFragmentManager() + .beginTransaction() + .add(dialog, getFragmentTag()) + .commitAllowingStateLoss(); + } + } + + public FragmentActivity getActivity() { + Context context = getContext(); + if (context instanceof FragmentActivity) { + return (FragmentActivity) context; + } else if (context instanceof ContextWrapper) { + Context baseContext = ((ContextWrapper) context).getBaseContext(); + if (baseContext instanceof FragmentActivity) { + return (FragmentActivity) baseContext; + } + } + throw new IllegalStateException("Error getting activity from context"); + } + + @Override + public void onAttached() { + super.onAttached(); + if (showDialog) { + ColorPickerDialog fragment = + (ColorPickerDialog) getActivity().getSupportFragmentManager().findFragmentByTag(getFragmentTag()); + if (fragment != null) { + // re-bind preference to fragment + fragment.setColorPickerDialogListener(this); + } + } + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + ColorPanelView preview = (ColorPanelView) holder.itemView.findViewById(R.id.cpv_preference_preview_color_panel); + if (preview != null) { + preview.setColor(color); + } + } + + @Override + protected void onSetInitialValue(Object defaultValue) { + super.onSetInitialValue(defaultValue); + if (defaultValue instanceof Integer) { + color = (Integer) defaultValue; + persistInt(color); + } else { + color = getPersistedInt(0xFF000000); + } + } + + @Override + protected Object onGetDefaultValue(TypedArray a, int index) { + return a.getInteger(index, Color.BLACK); + } + + @Override + public void onColorSelected(int dialogId, @ColorInt int color) { + saveValue(color); + } + + @Override + public void onDialogDismissed(int dialogId) { + // no-op + } + + /** + * Set the new color + * + * @param color The newly selected color + */ + public void saveValue(@ColorInt int color) { + this.color = color; + persistInt(this.color); + notifyChanged(); + callChangeListener(color); + } + + /** + * Get the colors that will be shown in the {@link ColorPickerDialog}. + * + * @return An array of color ints + */ + public int[] getPresets() { + return presets; + } + + /** + * Set the colors shown in the {@link ColorPickerDialog}. + * + * @param presets An array of color ints + */ + public void setPresets(@NonNull int[] presets) { + this.presets = presets; + } + + /** + * The listener used for showing the {@link ColorPickerDialog}. + * Call {@link #saveValue(int)} after the user chooses a color. + * If this is set then it is up to you to show the dialog. + * + * @param listener The listener to show the dialog + */ + public void setOnShowDialogListener(OnShowDialogListener listener) { + onShowDialogListener = listener; + } + + /** + * The tag used for the {@link ColorPickerDialog}. + * + * @return The tag + */ + public String getFragmentTag() { + return "color_" + getKey(); + } + + public interface OnShowDialogListener { + + void onShowColorPickerDialog(String title, int currentColor); + } } diff --git a/library/src/main/res/layout/cpv_dialog_presets.xml b/library/src/main/res/layout/cpv_dialog_presets.xml index 1811efa..c51c5eb 100644 --- a/library/src/main/res/layout/cpv_dialog_presets.xml +++ b/library/src/main/res/layout/cpv_dialog_presets.xml @@ -1,100 +1,55 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 1329450..1c756c5 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -24,6 +24,11 @@ + + + + + diff --git a/settings.gradle b/settings.gradle index 462ba77..5dc87cd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,24 @@ -include ':demo', ':library' +pluginManagement { + repositories { + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "ColorPicker" +include ':app' +include ':library'