diff --git a/app/build.gradle b/app/build.gradle
index e74c17e..3eb630e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -24,15 +24,15 @@ android {
keyAlias 'coldmint'
}
}
- compileSdkVersion 33
- buildToolsVersion "30.0.3"
+ compileSdk 33
+// buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.coldmint.rust.pro"
minSdkVersion 23
targetSdkVersion 33
versionCode 28
- versionName "2.1 Bata6(2023-7-20)"
+ versionName "2.1.1 Bata6(2023-7-20)"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -91,12 +91,15 @@ dependencies {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
}
+ api 'androidx.appcompat:appcompat:1.6.1'
+ api 'com.google.android.material:material:1.9.0'
+
implementation platform('com.google.firebase:firebase-bom:31.1.1')
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-crashlytics-ktx'
implementation 'com.google.firebase:firebase-perf-ktx'
- implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
-
+// implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
+ api project(path: ':library')
def nav_version = "2.5.1"
// implementation 'com.luolc:emoji-rain:0.1.1'
@@ -133,16 +136,10 @@ dependencies {
implementation 'com.github.florent37:glidepalette:2.1.2'
implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
- implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'dev.rikka.rikkax.appcompat:appcompat:1.6.1'
- implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation 'androidx.preference:preference-ktx:1.2.0'
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
-
}
\ No newline at end of file
diff --git a/app/libs/colorpicker-0.0.15.aar b/app/libs/colorpicker-0.0.15.aar
deleted file mode 100644
index c70d803..0000000
Binary files a/app/libs/colorpicker-0.0.15.aar and /dev/null differ
diff --git a/app/src/androidTest/java/com/coldmint/rust/pro/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/coldmint/rust/pro/ExampleInstrumentedTest.java
deleted file mode 100644
index 08169d6..0000000
--- a/app/src/androidTest/java/com/coldmint/rust/pro/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.coldmint.rust.pro;
-
-import android.content.Context;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * 仪器测试,将在Android设备上执行。
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() {
- // 被测试应用程序的上下文。
- Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- assertEquals("com.coldmint.rust.pro", appContext.getPackageName());
- }
-
-
-}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/coldmint/rust/pro/SourceFileUnitTest.kt b/app/src/androidTest/java/com/coldmint/rust/pro/SourceFileUnitTest.kt
deleted file mode 100644
index 3d05313..0000000
--- a/app/src/androidTest/java/com/coldmint/rust/pro/SourceFileUnitTest.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.coldmint.rust.pro
-
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.coldmint.rust.core.SourceFile
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.Assert.*
-
-
-@RunWith(AndroidJUnit4::class)
-class SourceFileUnitTest {
-
- @Test
- fun testWriteValue() {
- val sourceFile = SourceFile("[core]\nname:124")
- //测试修改值
- sourceFile.writeValue("name", "love")
- assertEquals("[core]\nname:love", sourceFile.text)
- //测试修改值2
- sourceFile.text = "[core]\nname:124\nmsg:ni"
- sourceFile.writeValue("msg", "happy")
- sourceFile.writeValue("name", "loveMe")
- assertEquals("[core]\nname:loveMe\nmsg:happy", sourceFile.text)
- }
-
- @Test
- fun testReadValue() {
- val sourceFile = SourceFile("[core]\n\nname:124\nkey:value2")
- //测试修改值
- val value = sourceFile.readValue("name")
- assertEquals("124", value)
- //测试修改值2
- sourceFile.text = "[core]\nname:124\nmsg:ni"
- val value2 = sourceFile.readValue("msg")
- assertEquals("ni", value2)
- }
-}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0104239..c295d67 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,27 +24,28 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.rust.Concept"
- android:usesCleartextTraffic="true">
+ android:usesCleartextTraffic="true"
+ android:screenOrientation="portrait"
+ tools:targetApi="tiramisu">
+ android:screenOrientation="portrait"
+ tools:ignore="LockedOrientationActivity" />
+ android:screenOrientation="portrait"
+ tools:ignore="LockedOrientationActivity" />
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:label="@string/built_in_browser"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:name="com.yalantis.ucrop.UCropActivity"/>
+ android:launchMode="singleTask">
@@ -167,8 +146,7 @@
android:excludeFromRecents="true"
android:exported="true"
android:label="@string/file_importer"
- android:maxRecents="3"
- android:screenOrientation="portrait">
+ android:maxRecents="3">
@@ -268,93 +246,69 @@
+ android:exported="false"/>
+ android:name=".ValueTypeActivity"/>
+ android:label="@string/global_operations"/>
+ android:name=".CreateModActivity"/>
+ android:name=".UnitsActivity"/>
+ android:name=".OptimizeActivity"/>
+ android:name=".FileManagerActivity"/>
+ android:name=".CreateUnitActivity"/>
+ android:name=".TemplateParserActivity"/>
+ android:name=".LibraryActivity"/>
+ android:label="@string/setting"/>
+ android:name=".TemplateMakerActivity"/>
+ android:name=".CreateTemplateActivity"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false" />
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
+ android:exported="false"/>
\ No newline at end of file
diff --git a/app/src/main/java/com/coldmint/rust/pro/EditActivity.kt b/app/src/main/java/com/coldmint/rust/pro/EditActivity.kt
index 40acc3c..30eb9b4 100644
--- a/app/src/main/java/com/coldmint/rust/pro/EditActivity.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/EditActivity.kt
@@ -8,7 +8,12 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
-import android.view.*
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuItem
+import android.view.SubMenu
+import android.view.View
import android.widget.PopupMenu
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
@@ -17,7 +22,6 @@ import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.ViewModelProvider
-import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
@@ -31,7 +35,6 @@ import com.coldmint.rust.core.database.file.FileDataBase
import com.coldmint.rust.core.tool.AppOperator
import com.coldmint.rust.core.tool.DebugHelper
import com.coldmint.rust.core.tool.FileOperator
-import com.coldmint.rust.core.web.ServerConfiguration
import com.coldmint.rust.pro.adapters.FileAdapter
import com.coldmint.rust.pro.base.BaseActivity
import com.coldmint.rust.pro.databean.ErrorInfo
@@ -49,23 +52,16 @@ import com.coldmint.rust.pro.viewmodel.EditStartViewModel
import com.coldmint.rust.pro.viewmodel.EditViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
-import com.google.firebase.crashlytics.ktx.crashlytics
-import com.google.firebase.ktx.Firebase
-import io.github.rosemoe.sora.lang.completion.CompletionPublisher
-import io.github.rosemoe.sora.text.CharPosition
-import io.github.rosemoe.sora.text.ContentReference
import io.github.rosemoe.sora.widget.EditorSearcher
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
import jp.wasabeef.glide.transformations.BlurTransformation
import java.io.File
-import java.util.*
-import kotlin.collections.ArrayList
class EditActivity : BaseActivity() {
private val viewModel by lazy {
- ViewModelProvider(this).get(EditViewModel::class.java)
+ ViewModelProvider(this)[EditViewModel::class.java]
}
private lateinit var turretCoordinateResults: ActivityResultLauncher
diff --git a/app/src/main/java/com/coldmint/rust/pro/FileManagerActivity.kt b/app/src/main/java/com/coldmint/rust/pro/FileManagerActivity.kt
index 97e18d8..5aff312 100644
--- a/app/src/main/java/com/coldmint/rust/pro/FileManagerActivity.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/FileManagerActivity.kt
@@ -1,27 +1,21 @@
package com.coldmint.rust.pro
-import com.coldmint.rust.pro.base.BaseActivity
-import com.coldmint.rust.pro.tool.BookmarkManager
-import androidx.recyclerview.widget.LinearLayoutManager
import android.content.Intent
-import com.coldmint.rust.pro.tool.GlobalMethod
-import com.google.android.material.snackbar.Snackbar
-import android.provider.MediaStore
-import android.provider.DocumentsContract
-import android.content.ContentUris
-import android.content.Context
-import android.database.Cursor
import android.net.Uri
-import android.os.*
-import android.view.*
-import android.widget.*
-import android.widget.Toast.makeText
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.provider.MediaStore
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.annotation.RequiresApi
import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider
-import com.bumptech.glide.Glide
+import androidx.recyclerview.widget.LinearLayoutManager
import com.coldmint.dialog.CoreDialog
import com.coldmint.dialog.InputDialog
import com.coldmint.rust.core.tool.DebugHelper
@@ -29,27 +23,20 @@ import com.coldmint.rust.core.tool.FileOperator
import com.coldmint.rust.core.tool.LineParser
import com.coldmint.rust.pro.adapters.FileAdapter
import com.coldmint.rust.pro.adapters.FileTabAdapter
+import com.coldmint.rust.pro.base.BaseActivity
import com.coldmint.rust.pro.databean.FileTab
import com.coldmint.rust.pro.databinding.ActivityFileBinding
import com.coldmint.rust.pro.interfaces.BookmarkListener
import com.coldmint.rust.pro.tool.AppSettings
+import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.ui.StableLinearLayoutManager
import com.coldmint.rust.pro.viewmodel.FileManagerViewModel
-import com.google.android.material.chip.Chip
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.android.material.snackbar.SnackbarContentLayout
+import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import me.zhanghai.android.fastscroll.FastScrollerBuilder
-import java.io.BufferedReader
import java.io.File
-import java.io.InputStreamReader
-import java.lang.Exception
-import java.util.*
-import java.util.concurrent.Executors
-import javax.sql.CommonDataSource
-import kotlin.collections.ArrayList
class FileManagerActivity : BaseActivity() {
diff --git a/app/src/main/java/com/coldmint/rust/pro/MainActivity.kt b/app/src/main/java/com/coldmint/rust/pro/MainActivity.kt
index 655a090..7776691 100644
--- a/app/src/main/java/com/coldmint/rust/pro/MainActivity.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/MainActivity.kt
@@ -1,20 +1,17 @@
package com.coldmint.rust.pro
-import com.coldmint.rust.pro.base.BaseActivity
-import com.coldmint.rust.pro.tool.GlobalMethod
-import android.content.pm.PackageInfo
-import com.coldmint.rust.pro.tool.AppSettings
import android.content.Intent
+import android.content.pm.PackageInfo
import android.content.pm.PackageManager
-import android.content.res.Resources
-import com.google.android.material.snackbar.Snackbar
-import android.os.*
-import android.util.Log
-import android.view.*
-import android.widget.Toast
+import android.os.Bundle
+import android.os.Handler
+import android.os.Looper
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
-import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
@@ -33,16 +30,21 @@ import com.coldmint.rust.core.dataBean.template.TemplateInfo
import com.coldmint.rust.core.debug.LogCat
import com.coldmint.rust.core.interfaces.ApiCallBack
import com.coldmint.rust.core.interfaces.UnzipListener
-import com.coldmint.rust.core.tool.*
+import com.coldmint.rust.core.tool.AppOperator
+import com.coldmint.rust.core.tool.DebugHelper
+import com.coldmint.rust.core.tool.FileOperator
import com.coldmint.rust.core.web.AppUpdate
import com.coldmint.rust.core.web.ServerConfiguration
+import com.coldmint.rust.pro.base.BaseActivity
import com.coldmint.rust.pro.databinding.ActivityMainBinding
import com.coldmint.rust.pro.databinding.HeadLayoutBinding
-import com.coldmint.rust.pro.fragments.UserGroupFragment
+import com.coldmint.rust.pro.tool.AppSettings
import com.coldmint.rust.pro.tool.EventRecord
+import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.viewmodel.StartViewModel
import com.google.android.material.color.DynamicColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson
import com.gyf.immersionbar.ImmersionBar
@@ -331,7 +333,6 @@ class MainActivity : BaseActivity() {
intent.putExtra("type", "template")
startActivity(intent)
}
-
else -> {
}
}
@@ -380,7 +381,7 @@ class MainActivity : BaseActivity() {
menu.findItem(R.id.rust_api).setOnMenuItemClickListener {
val thisIntent = Intent(this, BrowserActivity::class.java)
- thisIntent.putExtra("link", "https://rustedwarfareapicode.top/")
+ thisIntent.putExtra("link", "https://git.coldmint.top/")
thisIntent.putExtra("javaScriptEnabled", true)
startActivity(thisIntent)
false
diff --git a/app/src/main/java/com/coldmint/rust/pro/RustApplication.kt b/app/src/main/java/com/coldmint/rust/pro/RustApplication.kt
index 273c0fc..86bb51f 100644
--- a/app/src/main/java/com/coldmint/rust/pro/RustApplication.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/RustApplication.kt
@@ -1,23 +1,22 @@
package com.coldmint.rust.pro
+import android.annotation.SuppressLint
+import android.app.Activity
import android.app.Application
import android.content.Context
-import android.os.Environment
-import android.util.Log
+import android.content.pm.ActivityInfo
+import android.os.Bundle
import cat.ereza.customactivityoncrash.config.CaocConfig
import com.coldmint.rust.core.debug.LogCat
import com.coldmint.rust.core.debug.LogCatObserver
-import com.coldmint.rust.core.web.ServerConfiguration
import com.coldmint.rust.pro.tool.AppSettings
-import com.coldmint.rust.pro.tool.CompletionItemConverter
-import com.coldmint.rust.pro.tool.GlobalMethod
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import com.hjq.language.MultiLanguages
import com.youth.banner.BuildConfig
-import java.util.*
+
class RustApplication : Application() {
@@ -38,7 +37,7 @@ class RustApplication : Application() {
AppSettings.initAppSettings(this)
//动态颜色
val options = DynamicColorsOptions.Builder()
- .setPrecondition { activity, theme ->
+ .setPrecondition { _, _ ->
AppSettings
.getValue(
AppSettings.Setting.DynamicColor,
@@ -66,8 +65,24 @@ class RustApplication : Application() {
.errorActivity(ErrorActivity::class.java) //default: null (default error activity)
.apply()
- MultiLanguages.init(this);
-
+ MultiLanguages.init(this)
+ registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
+ @SuppressLint("SourceLockedOrientationActivity")
+ override fun onActivityCreated(
+ activity: Activity,
+ savedInstanceState: Bundle?
+ ) {
+// android:screenOrientation="portrait"
+ //全局强制横屏
+ activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ }
+ override fun onActivityStarted(activity: Activity) {}
+ override fun onActivityResumed(activity: Activity) {}
+ override fun onActivityPaused(activity: Activity) {}
+ override fun onActivityStopped(activity: Activity) {}
+ override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
+ override fun onActivityDestroyed(activity: Activity) {}
+ })
}
diff --git a/app/src/main/java/com/coldmint/rust/pro/base/BaseActivity.kt b/app/src/main/java/com/coldmint/rust/pro/base/BaseActivity.kt
index 9bec71a..2a778c6 100644
--- a/app/src/main/java/com/coldmint/rust/pro/base/BaseActivity.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/base/BaseActivity.kt
@@ -1,9 +1,6 @@
package com.coldmint.rust.pro.base
import android.content.Context
-import android.content.res.Configuration
-import androidx.appcompat.app.AppCompatActivity
-import com.coldmint.rust.pro.tool.AppSettings
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
@@ -11,24 +8,15 @@ import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
-import androidx.appcompat.app.AppCompatDelegate
-import androidx.appcompat.widget.Toolbar
+import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import com.coldmint.dialog.CoreDialog
import com.coldmint.rust.pro.R
import com.google.android.material.appbar.MaterialToolbar
-import com.google.android.material.color.DynamicColors
-import com.google.android.material.color.DynamicColorsOptions
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
-import com.google.firebase.analytics.FirebaseAnalytics
-import com.google.firebase.analytics.ktx.analytics
-import com.google.firebase.ktx.Firebase
import com.hjq.language.MultiLanguages
-import java.util.*
/*主活动,所有活动都应该继承于此*/
abstract class BaseActivity :
diff --git a/app/src/main/java/com/coldmint/rust/pro/edit/autoComplete/CodeAutoCompleteJob.kt b/app/src/main/java/com/coldmint/rust/pro/edit/autoComplete/CodeAutoCompleteJob.kt
index 56ec152..c699280 100644
--- a/app/src/main/java/com/coldmint/rust/pro/edit/autoComplete/CodeAutoCompleteJob.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/edit/autoComplete/CodeAutoCompleteJob.kt
@@ -1,6 +1,5 @@
package com.coldmint.rust.pro.edit.autoComplete
-import android.os.Bundle
import com.coldmint.rust.core.SourceFile
import com.coldmint.rust.core.database.code.CodeDao
import com.coldmint.rust.core.database.code.CodeDataBase
@@ -8,14 +7,11 @@ import com.coldmint.rust.core.database.file.FileDataBase
import com.coldmint.rust.core.tool.DebugHelper
import com.coldmint.rust.core.tool.LineParser
import com.coldmint.rust.pro.edit.RustAnalyzer
-import com.coldmint.rust.pro.edit.RustAutoComplete
-import com.coldmint.rust.pro.edit.RustCompletionItem
import com.coldmint.rust.pro.tool.AppSettings
import com.coldmint.rust.pro.tool.CompletionItemConverter
import io.github.rosemoe.sora.lang.completion.CompletionPublisher
import io.github.rosemoe.sora.text.CharPosition
import io.github.rosemoe.sora.text.ContentReference
-import io.github.rosemoe.sora.widget.CodeEditor
/**
* 代码自动完成项目(来自数据库)
diff --git a/app/src/main/java/com/coldmint/rust/pro/fragments/RecommendedFragment.kt b/app/src/main/java/com/coldmint/rust/pro/fragments/RecommendedFragment.kt
index e6b17b8..aade47b 100644
--- a/app/src/main/java/com/coldmint/rust/pro/fragments/RecommendedFragment.kt
+++ b/app/src/main/java/com/coldmint/rust/pro/fragments/RecommendedFragment.kt
@@ -2,11 +2,10 @@ package com.coldmint.rust.pro.fragments
import android.content.Intent
import android.os.Bundle
-import android.util.Log
import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup
import androidx.core.view.isVisible
-import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.coldmint.dialog.CoreDialog
import com.coldmint.rust.core.dataBean.BannerItemDataBean
@@ -24,13 +23,10 @@ import com.coldmint.rust.pro.databinding.FragmentRecommendedBinding
import com.coldmint.rust.pro.tool.AppSettings
import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.tool.TextStyleMaker
-import com.coldmint.rust.pro.ui.StableLinearLayoutManager
-import com.google.android.material.color.DynamicColors
+import com.coldmint.rust.pro.ui.ScrollLinearLayoutManager
import com.youth.banner.adapter.BannerImageAdapter
import com.youth.banner.holder.BannerImageHolder
import com.youth.banner.indicator.CircleIndicator
-import com.youth.banner.transformer.AlphaPageTransformer
-import com.youth.banner.transformer.DepthPageTransformer
class RecommendedFragment : BaseFragment() {
@@ -233,10 +229,10 @@ class RecommendedFragment : BaseFragment() {
}
override fun whenViewCreated(inflater: LayoutInflater, savedInstanceState: Bundle?) {
- viewBinding.latestReleaseView.layoutManager = StableLinearLayoutManager(requireContext())
+ viewBinding.latestReleaseView.layoutManager = ScrollLinearLayoutManager(requireContext())
viewBinding.soleRecommendedRecyclerView.layoutManager =
- StableLinearLayoutManager(requireContext())
- viewBinding.randomRecommendedView.layoutManager = StableLinearLayoutManager(requireContext())
+ ScrollLinearLayoutManager(requireContext())
+ viewBinding.randomRecommendedView.layoutManager = ScrollLinearLayoutManager(requireContext())
loadRandomRecommended()
viewBinding.changeRandomRecommended.setOnClickListener {
loadRandomRecommended()
diff --git a/app/src/main/java/com/coldmint/rust/pro/ui/ScrollLinearLayoutManager.kt b/app/src/main/java/com/coldmint/rust/pro/ui/ScrollLinearLayoutManager.kt
new file mode 100644
index 0000000..ec9ecf7
--- /dev/null
+++ b/app/src/main/java/com/coldmint/rust/pro/ui/ScrollLinearLayoutManager.kt
@@ -0,0 +1,25 @@
+package com.coldmint.rust.pro.ui
+
+import android.content.Context
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+
+/**
+ * 稳定的线性布局管理器
+ */
+class ScrollLinearLayoutManager(val context: Context) : LinearLayoutManager(context) {
+
+ /**
+ * 这里加了try catch防止奔溃
+ */
+ override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
+ try {
+ super.onLayoutChildren(recycler, state)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ override fun canScrollVertically(): Boolean {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/code_tool_item.xml b/app/src/main/res/layout/code_tool_item.xml
index 44091c0..ef272b9 100644
--- a/app/src/main/res/layout/code_tool_item.xml
+++ b/app/src/main/res/layout/code_tool_item.xml
@@ -3,13 +3,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/edit_start.xml b/app/src/main/res/layout/edit_start.xml
index 54aab50..9391ac4 100644
--- a/app/src/main/res/layout/edit_start.xml
+++ b/app/src/main/res/layout/edit_start.xml
@@ -1,6 +1,5 @@
-
+ android:layout_alignParentTop="true">
-
-
+ android:layout_height="match_parent">
-
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
-
-
+ android:orientation="vertical">
+
+
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:visibility="gone">
-
+
+
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_recommended.xml b/app/src/main/res/layout/fragment_recommended.xml
index abaf905..11cce58 100644
--- a/app/src/main/res/layout/fragment_recommended.xml
+++ b/app/src/main/res/layout/fragment_recommended.xml
@@ -7,8 +7,6 @@
android:animateLayoutChanges="true"
android:gravity="center"
android:orientation="vertical">
-
-
-
+ android:text="@string/change_random_recommended"
+ card_view:ignore="RelativeOverlap" />
diff --git a/app/src/test/java/com/coldmint/rust/pro/ExampleUnitTest.java b/app/src/test/java/com/coldmint/rust/pro/ExampleUnitTest.java
deleted file mode 100644
index 73758e1..0000000
--- a/app/src/test/java/com/coldmint/rust/pro/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.coldmint.rust.pro;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/assistantCoreLibrary/src/androidTest/java/com/coldmint/rust/core/ExampleInstrumentedTest.java b/assistantCoreLibrary/src/androidTest/java/com/coldmint/rust/core/ExampleInstrumentedTest.java
deleted file mode 100644
index 0b60ccb..0000000
--- a/assistantCoreLibrary/src/androidTest/java/com/coldmint/rust/core/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.coldmint.rust.core;
-
-import android.content.Context;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.*;
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
- assertEquals("com.coldmint.rust.core.test", appContext.getPackageName());
- }
-}
\ No newline at end of file
diff --git a/assistantCoreLibrary/src/test/java/com/coldmint/rust/core/ExampleUnitTest.java b/assistantCoreLibrary/src/test/java/com/coldmint/rust/core/ExampleUnitTest.java
deleted file mode 100644
index 84835b3..0000000
--- a/assistantCoreLibrary/src/test/java/com/coldmint/rust/core/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.coldmint.rust.core;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see Testing documentation
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() {
- assertEquals(4, 2 + 2);
- }
-}
\ No newline at end of file
diff --git a/dialog/src/androidTest/java/com/coldmint/dialog/ExampleInstrumentedTest.kt b/dialog/src/androidTest/java/com/coldmint/dialog/ExampleInstrumentedTest.kt
deleted file mode 100644
index d7382ea..0000000
--- a/dialog/src/androidTest/java/com/coldmint/dialog/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.coldmint.dialog
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.coldmint.dialog.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/dialog/src/test/java/com/coldmint/dialog/ExampleUnitTest.kt b/dialog/src/test/java/com/coldmint/dialog/ExampleUnitTest.kt
deleted file mode 100644
index bfd9118..0000000
--- a/dialog/src/test/java/com/coldmint/dialog/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.coldmint.dialog
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 39bcbf4..768267d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -18,3 +18,4 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
android.injected.testOnly=false
+android.suppressUnsupportedCompileSdk=32,33
diff --git a/library/.gitignore b/library/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/library/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/library/build.gradle b/library/build.gradle
new file mode 100644
index 0000000..8bf278b
--- /dev/null
+++ b/library/build.gradle
@@ -0,0 +1,20 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdk 32
+ defaultConfig {
+ minSdk 21
+ targetSdk 32
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.9.0'
+}
diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro
new file mode 100644
index 0000000..73f7137
--- /dev/null
+++ b/library/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/flask/Documents/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/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..804b8ac
--- /dev/null
+++ b/library/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/library/src/main/java/com/flask/colorpicker/ColorCircle.java b/library/src/main/java/com/flask/colorpicker/ColorCircle.java
new file mode 100644
index 0000000..ba28baa
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/ColorCircle.java
@@ -0,0 +1,54 @@
+package com.flask.colorpicker;
+
+import android.graphics.Color;
+
+public class ColorCircle {
+ private float x, y;
+ private float[] hsv = new float[3];
+ private float[] hsvClone;
+ private int color;
+
+ public ColorCircle(float x, float y, float[] hsv) {
+ set(x, y, hsv);
+ }
+
+ public double sqDist(float x, float y) {
+ double dx = this.x - x;
+ double dy = this.y - y;
+ return dx * dx + dy * dy;
+ }
+
+ public float getX() {
+ return x;
+ }
+
+ public float getY() {
+ return y;
+ }
+
+ public float[] getHsv() {
+ return hsv;
+ }
+
+ public float[] getHsvWithLightness(float lightness) {
+ if (hsvClone == null)
+ hsvClone = hsv.clone();
+ hsvClone[0] = hsv[0];
+ hsvClone[1] = hsv[1];
+ hsvClone[2] = lightness;
+ return hsvClone;
+ }
+
+ public void set(float x, float y, float[] hsv) {
+ this.x = x;
+ this.y = y;
+ this.hsv[0] = hsv[0];
+ this.hsv[1] = hsv[1];
+ this.hsv[2] = hsv[2];
+ this.color = Color.HSVToColor(this.hsv);
+ }
+
+ public int getColor() {
+ return color;
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/ColorCircleDrawable.java b/library/src/main/java/com/flask/colorpicker/ColorCircleDrawable.java
new file mode 100644
index 0000000..9284f06
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/ColorCircleDrawable.java
@@ -0,0 +1,39 @@
+package com.flask.colorpicker;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.ColorDrawable;
+
+import com.flask.colorpicker.builder.PaintBuilder;
+
+public class ColorCircleDrawable extends ColorDrawable {
+ private float strokeWidth;
+ private Paint strokePaint = PaintBuilder.newPaint().style(Paint.Style.STROKE).stroke(strokeWidth).color(0xff9e9e9e).build();
+ private Paint fillPaint = PaintBuilder.newPaint().style(Paint.Style.FILL).color(0).build();
+ private Paint fillBackPaint = PaintBuilder.newPaint().shader(PaintBuilder.createAlphaPatternShader(26)).build();
+
+ public ColorCircleDrawable(int color) {
+ super(color);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawColor(0);
+
+ int width = canvas.getWidth();
+ float radius = width / 2f;
+ strokeWidth = radius / 8f;
+
+ this.strokePaint.setStrokeWidth(strokeWidth);
+ this.fillPaint.setColor(getColor());
+ canvas.drawCircle(radius, radius, radius - strokeWidth, fillBackPaint);
+ canvas.drawCircle(radius, radius, radius - strokeWidth, fillPaint);
+ canvas.drawCircle(radius, radius, radius - strokeWidth, strokePaint);
+ }
+
+ @Override
+ public void setColor(int color) {
+ super.setColor(color);
+ invalidateSelf();
+ }
+}
diff --git a/library/src/main/java/com/flask/colorpicker/ColorPickerPreference.java b/library/src/main/java/com/flask/colorpicker/ColorPickerPreference.java
new file mode 100644
index 0000000..6ef7b59
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/ColorPickerPreference.java
@@ -0,0 +1,155 @@
+package com.flask.colorpicker;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.preference.Preference;
+import androidx.annotation.NonNull;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.flask.colorpicker.builder.ColorPickerClickListener;
+import com.flask.colorpicker.builder.ColorPickerDialogBuilder;
+
+public class ColorPickerPreference extends Preference {
+
+ protected boolean alphaSlider;
+ protected boolean lightSlider;
+ protected boolean border;
+
+ protected int selectedColor = 0;
+
+ protected ColorPickerView.WHEEL_TYPE wheelType;
+ protected int density;
+
+ private boolean pickerColorEdit;
+ private String pickerTitle;
+ private String pickerButtonCancel;
+ private String pickerButtonOk;
+
+ protected ImageView colorIndicator;
+
+ public ColorPickerPreference(Context context) {
+ super(context);
+ }
+
+ public ColorPickerPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initWith(context, attrs);
+ }
+
+ public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initWith(context, attrs);
+ }
+
+ private void initWith(Context context, AttributeSet attrs) {
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerPreference);
+
+ try {
+ alphaSlider = typedArray.getBoolean(R.styleable.ColorPickerPreference_alphaSlider, false);
+ lightSlider = typedArray.getBoolean(R.styleable.ColorPickerPreference_lightnessSlider, false);
+ border = typedArray.getBoolean(R.styleable.ColorPickerPreference_border, true);
+
+ density = typedArray.getInt(R.styleable.ColorPickerPreference_density, 8);
+ wheelType = ColorPickerView.WHEEL_TYPE.indexOf(typedArray.getInt(R.styleable.ColorPickerPreference_wheelType, 0));
+
+ selectedColor = typedArray.getInt(R.styleable.ColorPickerPreference_initialColor, 0xffffffff);
+
+ pickerColorEdit = typedArray.getBoolean(R.styleable.ColorPickerPreference_pickerColorEdit, true);
+ pickerTitle = typedArray.getString(R.styleable.ColorPickerPreference_pickerTitle);
+ if (pickerTitle==null)
+ pickerTitle = "Choose color";
+
+ pickerButtonCancel = typedArray.getString(R.styleable.ColorPickerPreference_pickerButtonCancel);
+ if (pickerButtonCancel==null)
+ pickerButtonCancel = "cancel";
+
+ pickerButtonOk = typedArray.getString(R.styleable.ColorPickerPreference_pickerButtonOk);
+ if (pickerButtonOk==null)
+ pickerButtonOk = "ok";
+
+ } finally {
+ typedArray.recycle();
+ }
+
+ setWidgetLayoutResource(R.layout.color_widget);
+ }
+
+
+ @Override
+ protected void onBindView(@NonNull View view) {
+ super.onBindView(view);
+
+ int tmpColor = isEnabled()
+ ? selectedColor
+ : darken(selectedColor, .5f);
+
+ colorIndicator = (ImageView) view.findViewById(R.id.color_indicator);
+
+ ColorCircleDrawable colorChoiceDrawable = null;
+ Drawable currentDrawable = colorIndicator.getDrawable();
+ if (currentDrawable != null && currentDrawable instanceof ColorCircleDrawable)
+ colorChoiceDrawable = (ColorCircleDrawable) currentDrawable;
+
+ if (colorChoiceDrawable == null)
+ colorChoiceDrawable = new ColorCircleDrawable(tmpColor);
+
+ colorIndicator.setImageDrawable(colorChoiceDrawable);
+ }
+
+ public void setValue(int value) {
+ if (callChangeListener(value)) {
+ selectedColor = value;
+ persistInt(value);
+ notifyChanged();
+ }
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setValue(restoreValue ? getPersistedInt(0) : (Integer) defaultValue);
+ }
+
+ @Override
+ protected void onClick() {
+ ColorPickerDialogBuilder builder = ColorPickerDialogBuilder
+ .with(getContext())
+ .setTitle(pickerTitle)
+ .initialColor(selectedColor)
+ .showBorder(border)
+ .wheelType(wheelType)
+ .density(density)
+ .showColorEdit(pickerColorEdit)
+ .setPositiveButton(pickerButtonOk, new ColorPickerClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int selectedColorFromPicker, Integer[] allColors) {
+ setValue(selectedColorFromPicker);
+ }
+ })
+ .setNegativeButton(pickerButtonCancel, null);
+
+ if (!alphaSlider && !lightSlider) builder.noSliders();
+ else if (!alphaSlider) builder.lightnessSliderOnly();
+ else if (!lightSlider) builder.alphaSliderOnly();
+
+ builder
+ .build()
+ .show();
+ }
+
+ public static int darken(int color, float factor) {
+ int a = Color.alpha(color);
+ int r = Color.red(color);
+ int g = Color.green(color);
+ int b = Color.blue(color);
+
+ return Color.argb(a,
+ Math.max((int)(r * factor), 0),
+ Math.max((int)(g * factor), 0),
+ Math.max((int)(b * factor), 0));
+ }
+}
diff --git a/library/src/main/java/com/flask/colorpicker/ColorPickerView.java b/library/src/main/java/com/flask/colorpicker/ColorPickerView.java
new file mode 100644
index 0000000..bad746c
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/ColorPickerView.java
@@ -0,0 +1,572 @@
+package com.flask.colorpicker;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+import com.flask.colorpicker.builder.ColorWheelRendererBuilder;
+import com.flask.colorpicker.builder.PaintBuilder;
+import com.flask.colorpicker.renderer.ColorWheelRenderOption;
+import com.flask.colorpicker.renderer.ColorWheelRenderer;
+import com.flask.colorpicker.slider.AlphaSlider;
+import com.flask.colorpicker.slider.LightnessSlider;
+
+import java.util.ArrayList;
+
+public class ColorPickerView extends View {
+ private static final float STROKE_RATIO = 1.5f;
+
+ private Bitmap colorWheel;
+ private Canvas colorWheelCanvas;
+ private Bitmap currentColor;
+ private Canvas currentColorCanvas;
+ private boolean showBorder;
+ private int density = 8;
+
+ private float lightness = 1;
+ private float alpha = 1;
+ private int backgroundColor = 0x00000000;
+
+ private Integer initialColors[] = new Integer[]{null, null, null, null, null};
+ private int colorSelection = 0;
+ private Integer initialColor;
+ private Integer pickerColorEditTextColor;
+ private Paint colorWheelFill = PaintBuilder.newPaint().color(0).build();
+ private Paint selectorStroke = PaintBuilder.newPaint().color(0).build();
+ private Paint alphaPatternPaint = PaintBuilder.newPaint().build();
+ private ColorCircle currentColorCircle;
+
+ private ArrayList colorChangedListeners = new ArrayList<>();
+ private ArrayList listeners = new ArrayList<>();
+
+ private LightnessSlider lightnessSlider;
+ private AlphaSlider alphaSlider;
+ private EditText colorEdit;
+ private TextWatcher colorTextChange = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ try {
+ int color = Color.parseColor(s.toString());
+
+ // set the color without changing the edit text preventing stack overflow
+ setColor(color, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ }
+ };
+ private LinearLayout colorPreview;
+
+ private ColorWheelRenderer renderer;
+
+ private int alphaSliderViewId, lightnessSliderViewId;
+
+ public ColorPickerView(Context context) {
+ super(context);
+ initWith(context, null);
+ }
+
+ public ColorPickerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initWith(context, attrs);
+ }
+
+ public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initWith(context, attrs);
+ }
+
+ @TargetApi(21)
+ public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ initWith(context, attrs);
+ }
+
+ private void initWith(Context context, AttributeSet attrs) {
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ColorPickerPreference);
+
+ density = typedArray.getInt(R.styleable.ColorPickerPreference_density, 10);
+ initialColor = typedArray.getInt(R.styleable.ColorPickerPreference_initialColor, 0xffffffff);
+
+ pickerColorEditTextColor = typedArray.getInt(R.styleable.ColorPickerPreference_pickerColorEditTextColor, 0xffffffff);
+
+ WHEEL_TYPE wheelType = WHEEL_TYPE.indexOf(typedArray.getInt(R.styleable.ColorPickerPreference_wheelType, 0));
+ ColorWheelRenderer renderer = ColorWheelRendererBuilder.getRenderer(wheelType);
+
+ alphaSliderViewId = typedArray.getResourceId(R.styleable.ColorPickerPreference_alphaSliderView, 0);
+ lightnessSliderViewId = typedArray.getResourceId(R.styleable.ColorPickerPreference_lightnessSliderView, 0);
+
+ setRenderer(renderer);
+ setDensity(density);
+ setInitialColor(initialColor, true);
+
+ typedArray.recycle();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ updateColorWheel();
+ currentColorCircle = findNearestByColor(initialColor);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ if (alphaSliderViewId != 0)
+ setAlphaSlider((AlphaSlider) getRootView().findViewById(alphaSliderViewId));
+ if (lightnessSliderViewId != 0)
+ setLightnessSlider((LightnessSlider) getRootView().findViewById(lightnessSliderViewId));
+
+ updateColorWheel();
+ currentColorCircle = findNearestByColor(initialColor);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ updateColorWheel();
+ }
+
+ private void updateColorWheel() {
+ int width = getMeasuredWidth();
+ int height = getMeasuredHeight();
+
+ if (height < width)
+ width = height;
+ if (width <= 0)
+ return;
+ if (colorWheel == null || colorWheel.getWidth() != width) {
+ colorWheel = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
+ colorWheelCanvas = new Canvas(colorWheel);
+ alphaPatternPaint.setShader(PaintBuilder.createAlphaPatternShader(26));
+ }
+ if (currentColor == null || currentColor.getWidth() != width) {
+ currentColor = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
+ currentColorCanvas = new Canvas(currentColor);
+ }
+ drawColorWheel();
+ invalidate();
+ }
+
+ private void drawColorWheel() {
+ colorWheelCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ currentColorCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+ if (renderer == null) return;
+
+ float half = colorWheelCanvas.getWidth() / 2f;
+ float strokeWidth = STROKE_RATIO * (1f + ColorWheelRenderer.GAP_PERCENTAGE);
+ float maxRadius = half - strokeWidth - half / density;
+ float cSize = maxRadius / (density - 1) / 2;
+
+ ColorWheelRenderOption colorWheelRenderOption = renderer.getRenderOption();
+ colorWheelRenderOption.density = this.density;
+ colorWheelRenderOption.maxRadius = maxRadius;
+ colorWheelRenderOption.cSize = cSize;
+ colorWheelRenderOption.strokeWidth = strokeWidth;
+ colorWheelRenderOption.alpha = alpha;
+ colorWheelRenderOption.lightness = lightness;
+ colorWheelRenderOption.targetCanvas = colorWheelCanvas;
+
+ renderer.initWith(colorWheelRenderOption);
+ renderer.draw();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int width = 0;
+ if (widthMode == MeasureSpec.UNSPECIFIED)
+ width = widthMeasureSpec;
+ else if (widthMode == MeasureSpec.AT_MOST)
+ width = MeasureSpec.getSize(widthMeasureSpec);
+ else if (widthMode == MeasureSpec.EXACTLY)
+ width = MeasureSpec.getSize(widthMeasureSpec);
+
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int height = 0;
+ if (heightMode == MeasureSpec.UNSPECIFIED)
+ height = heightMeasureSpec;
+ else if (heightMode == MeasureSpec.AT_MOST)
+ height = MeasureSpec.getSize(heightMeasureSpec);
+ else if (heightMode == MeasureSpec.EXACTLY)
+ height = MeasureSpec.getSize(heightMeasureSpec);
+ int squareDimen = width;
+ if (height < width)
+ squareDimen = height;
+ setMeasuredDimension(squareDimen, squareDimen);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE: {
+ int lastSelectedColor = getSelectedColor();
+ currentColorCircle = findNearestByPosition(event.getX(), event.getY());
+ int selectedColor = getSelectedColor();
+
+ callOnColorChangedListeners(lastSelectedColor, selectedColor);
+
+ initialColor = selectedColor;
+ setColorToSliders(selectedColor);
+ updateColorWheel();
+ invalidate();
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ int selectedColor = getSelectedColor();
+ if (listeners != null) {
+ for (OnColorSelectedListener listener : listeners) {
+ try {
+ listener.onColorSelected(selectedColor);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ setColorToSliders(selectedColor);
+ setColorText(selectedColor);
+ setColorPreviewColor(selectedColor);
+ invalidate();
+ break;
+ }
+ }
+ return true;
+ }
+
+ protected void callOnColorChangedListeners(int oldColor, int newColor) {
+ if (colorChangedListeners != null && oldColor != newColor) {
+ for (OnColorChangedListener listener : colorChangedListeners) {
+ try {
+ listener.onColorChanged(newColor);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawColor(backgroundColor);
+
+ float maxRadius = canvas.getWidth() / (1f + ColorWheelRenderer.GAP_PERCENTAGE);
+ float size = maxRadius / density / 2;
+ if (colorWheel != null && currentColorCircle != null) {
+ colorWheelFill.setColor(Color.HSVToColor(currentColorCircle.getHsvWithLightness(this.lightness)));
+ colorWheelFill.setAlpha((int) (alpha * 0xff));
+
+ // a separate canvas is used to erase an issue with the alpha pattern around the edges
+ // draw circle slightly larger than it needs to be, then erase edges to proper dimensions
+ currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, alphaPatternPaint);
+ currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + 4, colorWheelFill);
+
+ selectorStroke = PaintBuilder.newPaint().color(0xffffffff).style(Paint.Style.STROKE).stroke(size * (STROKE_RATIO - 1)).xPerMode(PorterDuff.Mode.CLEAR).build();
+
+ if (showBorder) colorWheelCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
+ canvas.drawBitmap(colorWheel, 0, 0, null);
+
+ currentColorCanvas.drawCircle(currentColorCircle.getX(), currentColorCircle.getY(), size + (selectorStroke.getStrokeWidth() / 2f), selectorStroke);
+ canvas.drawBitmap(currentColor, 0, 0, null);
+ }
+ }
+
+ private ColorCircle findNearestByPosition(float x, float y) {
+ ColorCircle near = null;
+ double minDist = Double.MAX_VALUE;
+
+ for (ColorCircle colorCircle : renderer.getColorCircleList()) {
+ double dist = colorCircle.sqDist(x, y);
+ if (minDist > dist) {
+ minDist = dist;
+ near = colorCircle;
+ }
+ }
+
+ return near;
+ }
+
+ private ColorCircle findNearestByColor(int color) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ ColorCircle near = null;
+ double minDiff = Double.MAX_VALUE;
+ double x = hsv[1] * Math.cos(hsv[0] * Math.PI / 180);
+ double y = hsv[1] * Math.sin(hsv[0] * Math.PI / 180);
+
+ for (ColorCircle colorCircle : renderer.getColorCircleList()) {
+ float[] hsv1 = colorCircle.getHsv();
+ double x1 = hsv1[1] * Math.cos(hsv1[0] * Math.PI / 180);
+ double y1 = hsv1[1] * Math.sin(hsv1[0] * Math.PI / 180);
+ double dx = x - x1;
+ double dy = y - y1;
+ double dist = dx * dx + dy * dy;
+ if (dist < minDiff) {
+ minDiff = dist;
+ near = colorCircle;
+ }
+ }
+
+ return near;
+ }
+
+ public int getSelectedColor() {
+ int color = 0;
+ if (currentColorCircle != null)
+ color = Utils.colorAtLightness(currentColorCircle.getColor(), this.lightness);
+ return Utils.adjustAlpha(this.alpha, color);
+ }
+
+ public Integer[] getAllColors() {
+ return initialColors;
+ }
+
+ public void setInitialColors(Integer[] colors, int selectedColor) {
+ this.initialColors = colors;
+ this.colorSelection = selectedColor;
+ Integer initialColor = this.initialColors[this.colorSelection];
+ if (initialColor == null) initialColor = 0xffffffff;
+ setInitialColor(initialColor, true);
+ }
+
+ public void setInitialColor(int color, boolean updateText) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+
+ this.alpha = Utils.getAlphaPercent(color);
+ this.lightness = hsv[2];
+ this.initialColors[this.colorSelection] = color;
+ this.initialColor = color;
+ setColorPreviewColor(color);
+ setColorToSliders(color);
+ if (this.colorEdit != null && updateText)
+ setColorText(color);
+ currentColorCircle = findNearestByColor(color);
+ }
+
+ public void setLightness(float lightness) {
+ int lastSelectedColor = getSelectedColor();
+
+ this.lightness = lightness;
+ if (currentColorCircle != null) {
+ this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(lightness));
+ if (this.colorEdit != null)
+ this.colorEdit.setText(Utils.getHexString(this.initialColor, this.alphaSlider != null));
+ if (this.alphaSlider != null && this.initialColor != null)
+ this.alphaSlider.setColor(this.initialColor);
+
+ callOnColorChangedListeners(lastSelectedColor, this.initialColor);
+
+ updateColorWheel();
+ invalidate();
+ }
+ }
+
+ public void setColor(int color, boolean updateText) {
+ setInitialColor(color, updateText);
+ updateColorWheel();
+ invalidate();
+ }
+
+ public void setAlphaValue(float alpha) {
+ int lastSelectedColor = getSelectedColor();
+
+ this.alpha = alpha;
+ this.initialColor = Color.HSVToColor(Utils.alphaValueAsInt(this.alpha), currentColorCircle.getHsvWithLightness(this.lightness));
+ if (this.colorEdit != null)
+ this.colorEdit.setText(Utils.getHexString(this.initialColor, this.alphaSlider != null));
+ if (this.lightnessSlider != null && this.initialColor != null)
+ this.lightnessSlider.setColor(this.initialColor);
+
+ callOnColorChangedListeners(lastSelectedColor, this.initialColor);
+
+ updateColorWheel();
+ invalidate();
+ }
+
+ public void addOnColorChangedListener(OnColorChangedListener listener) {
+ this.colorChangedListeners.add(listener);
+ }
+
+ public void addOnColorSelectedListener(OnColorSelectedListener listener) {
+ this.listeners.add(listener);
+ }
+
+ public void setLightnessSlider(LightnessSlider lightnessSlider) {
+ this.lightnessSlider = lightnessSlider;
+ if (lightnessSlider != null) {
+ this.lightnessSlider.setColorPicker(this);
+ this.lightnessSlider.setColor(getSelectedColor());
+ }
+ }
+
+ public void setAlphaSlider(AlphaSlider alphaSlider) {
+ this.alphaSlider = alphaSlider;
+ if (alphaSlider != null) {
+ this.alphaSlider.setColorPicker(this);
+ this.alphaSlider.setColor(getSelectedColor());
+ }
+ }
+
+ public void setColorEdit(EditText colorEdit) {
+ this.colorEdit = colorEdit;
+ if (this.colorEdit != null) {
+ this.colorEdit.setVisibility(View.VISIBLE);
+ this.colorEdit.addTextChangedListener(colorTextChange);
+ setColorEditTextColor(pickerColorEditTextColor);
+ }
+ }
+
+ public void setColorEditTextColor(int argb) {
+ this.pickerColorEditTextColor = argb;
+ if (colorEdit != null)
+ colorEdit.setTextColor(argb);
+ }
+
+ public void setDensity(int density) {
+ this.density = Math.max(2, density);
+ invalidate();
+ }
+
+ public void setRenderer(ColorWheelRenderer renderer) {
+ this.renderer = renderer;
+ invalidate();
+ }
+
+ public void setColorPreview(LinearLayout colorPreview, Integer selectedColor) {
+ if (colorPreview == null)
+ return;
+ this.colorPreview = colorPreview;
+ if (selectedColor == null)
+ selectedColor = 0;
+ int children = colorPreview.getChildCount();
+ if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
+ return;
+
+ for (int i = 0; i < children; i++) {
+ View childView = colorPreview.getChildAt(i);
+ if (!(childView instanceof LinearLayout))
+ continue;
+ LinearLayout childLayout = (LinearLayout) childView;
+ if (i == selectedColor) {
+ childLayout.setBackgroundColor(Color.WHITE);
+ }
+ ImageView childImage = (ImageView) childLayout.findViewById(R.id.image_preview);
+ childImage.setClickable(true);
+ childImage.setTag(i);
+ childImage.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (v == null)
+ return;
+ Object tag = v.getTag();
+ if (tag == null || !(tag instanceof Integer))
+ return;
+ setSelectedColor((int) tag);
+ }
+ });
+ }
+ }
+
+ public void setSelectedColor(int previewNumber) {
+ if (initialColors == null || initialColors.length < previewNumber)
+ return;
+ this.colorSelection = previewNumber;
+ setHighlightedColor(previewNumber);
+ Integer color = initialColors[previewNumber];
+ if (color == null)
+ return;
+ setColor(color, true);
+ }
+
+ public void setShowBorder(boolean showBorder) {
+ this.showBorder = showBorder;
+ }
+
+ private void setHighlightedColor(int previewNumber) {
+ int children = colorPreview.getChildCount();
+ if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
+ return;
+
+ for (int i = 0; i < children; i++) {
+ View childView = colorPreview.getChildAt(i);
+ if (!(childView instanceof LinearLayout))
+ continue;
+ LinearLayout childLayout = (LinearLayout) childView;
+ if (i == previewNumber) {
+ childLayout.setBackgroundColor(Color.WHITE);
+ } else {
+ childLayout.setBackgroundColor(Color.TRANSPARENT);
+ }
+ }
+ }
+
+ private void setColorPreviewColor(int newColor) {
+ if (colorPreview == null || initialColors == null || colorSelection > initialColors.length || initialColors[colorSelection] == null)
+ return;
+
+ int children = colorPreview.getChildCount();
+ if (children == 0 || colorPreview.getVisibility() != View.VISIBLE)
+ return;
+
+ View childView = colorPreview.getChildAt(colorSelection);
+ if (!(childView instanceof LinearLayout))
+ return;
+ LinearLayout childLayout = (LinearLayout) childView;
+ ImageView childImage = (ImageView) childLayout.findViewById(R.id.image_preview);
+ childImage.setImageDrawable(new ColorCircleDrawable(newColor));
+ }
+
+ private void setColorText(int argb) {
+ if (colorEdit == null)
+ return;
+ colorEdit.setText(Utils.getHexString(argb, this.alphaSlider != null));
+ }
+
+ private void setColorToSliders(int selectedColor) {
+ if (lightnessSlider != null)
+ lightnessSlider.setColor(selectedColor);
+ if (alphaSlider != null)
+ alphaSlider.setColor(selectedColor);
+ }
+
+ public enum WHEEL_TYPE {
+ FLOWER, CIRCLE;
+
+ public static WHEEL_TYPE indexOf(int index) {
+ switch (index) {
+ case 0:
+ return FLOWER;
+ case 1:
+ return CIRCLE;
+ }
+ return FLOWER;
+ }
+ }
+}
diff --git a/library/src/main/java/com/flask/colorpicker/OnColorChangedListener.java b/library/src/main/java/com/flask/colorpicker/OnColorChangedListener.java
new file mode 100644
index 0000000..eda2a53
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/OnColorChangedListener.java
@@ -0,0 +1,5 @@
+package com.flask.colorpicker;
+
+public interface OnColorChangedListener {
+ void onColorChanged(int selectedColor);
+}
diff --git a/library/src/main/java/com/flask/colorpicker/OnColorSelectedListener.java b/library/src/main/java/com/flask/colorpicker/OnColorSelectedListener.java
new file mode 100644
index 0000000..dbf8f72
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/OnColorSelectedListener.java
@@ -0,0 +1,5 @@
+package com.flask.colorpicker;
+
+public interface OnColorSelectedListener {
+ void onColorSelected(int selectedColor);
+}
diff --git a/library/src/main/java/com/flask/colorpicker/Utils.java b/library/src/main/java/com/flask/colorpicker/Utils.java
new file mode 100644
index 0000000..8e92c5e
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/Utils.java
@@ -0,0 +1,40 @@
+package com.flask.colorpicker;
+
+import android.graphics.Color;
+
+/**
+ * Created by Charles Andersons on 4/17/15.
+ */
+public class Utils {
+ public static float getAlphaPercent(int argb) {
+ return Color.alpha(argb) / 255f;
+ }
+
+ public static int alphaValueAsInt(float alpha) {
+ return Math.round(alpha * 255);
+ }
+
+ public static int adjustAlpha(float alpha, int color) {
+ return alphaValueAsInt(alpha) << 24 | (0x00ffffff & color);
+ }
+
+ public static int colorAtLightness(int color, float lightness) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ hsv[2] = lightness;
+ return Color.HSVToColor(hsv);
+ }
+
+ public static float lightnessOfColor(int color) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ return hsv[2];
+ }
+
+ public static String getHexString(int color, boolean showAlpha) {
+ int base = showAlpha ? 0xFFFFFFFF : 0xFFFFFF;
+ String format = showAlpha ? "#%08X" : "#%06X";
+ return String.format(format, (base & color)).toUpperCase();
+ }
+
+}
diff --git a/library/src/main/java/com/flask/colorpicker/builder/ColorPickerClickListener.java b/library/src/main/java/com/flask/colorpicker/builder/ColorPickerClickListener.java
new file mode 100644
index 0000000..35e70e9
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/builder/ColorPickerClickListener.java
@@ -0,0 +1,10 @@
+package com.flask.colorpicker.builder;
+
+import android.content.DialogInterface;
+
+/**
+ * Created by Charles Anderson on 4/17/15.
+ */
+public interface ColorPickerClickListener {
+ void onClick(DialogInterface d, int lastSelectedColor, Integer[] allColors);
+}
diff --git a/library/src/main/java/com/flask/colorpicker/builder/ColorPickerDialogBuilder.java b/library/src/main/java/com/flask/colorpicker/builder/ColorPickerDialogBuilder.java
new file mode 100644
index 0000000..f200550
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/builder/ColorPickerDialogBuilder.java
@@ -0,0 +1,294 @@
+package com.flask.colorpicker.builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.text.InputFilter;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import androidx.appcompat.app.AlertDialog;
+import com.flask.colorpicker.ColorPickerView;
+import com.flask.colorpicker.OnColorChangedListener;
+import com.flask.colorpicker.OnColorSelectedListener;
+import com.flask.colorpicker.R;
+import com.flask.colorpicker.Utils;
+import com.flask.colorpicker.renderer.ColorWheelRenderer;
+import com.flask.colorpicker.slider.AlphaSlider;
+import com.flask.colorpicker.slider.LightnessSlider;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+public class ColorPickerDialogBuilder {
+ private MaterialAlertDialogBuilder builder;
+ private LinearLayout pickerContainer;
+ private ColorPickerView colorPickerView;
+ private LightnessSlider lightnessSlider;
+ private AlphaSlider alphaSlider;
+ private EditText colorEdit;
+ private LinearLayout colorPreview;
+
+ private boolean isLightnessSliderEnabled = true;
+ private boolean isAlphaSliderEnabled = true;
+ private boolean isBorderEnabled = true;
+ private boolean isColorEditEnabled = false;
+ private boolean isPreviewEnabled = false;
+ private int pickerCount = 1;
+ private int defaultMargin = 0;
+ private int defaultMarginTop = 0;
+ private Integer[] initialColor = new Integer[]{null, null, null, null, null};
+
+ private ColorPickerDialogBuilder(Context context) {
+ this(context, 0);
+ }
+
+ private ColorPickerDialogBuilder(Context context, int theme) {
+ defaultMargin = getDimensionAsPx(context, R.dimen.default_slider_margin);
+ defaultMarginTop = getDimensionAsPx(context, R.dimen.default_margin_top);
+
+ builder = new MaterialAlertDialogBuilder(context, theme);
+ pickerContainer = new LinearLayout(context);
+ pickerContainer.setOrientation(LinearLayout.VERTICAL);
+ pickerContainer.setGravity(Gravity.CENTER_HORIZONTAL);
+ pickerContainer.setPadding(defaultMargin, defaultMarginTop, defaultMargin, 0);
+
+ LinearLayout.LayoutParams layoutParamsForColorPickerView = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
+ layoutParamsForColorPickerView.weight = 1;
+ colorPickerView = new ColorPickerView(context);
+
+ pickerContainer.addView(colorPickerView, layoutParamsForColorPickerView);
+
+ builder.setView(pickerContainer);
+ }
+
+ public static ColorPickerDialogBuilder with(Context context) {
+ return new ColorPickerDialogBuilder(context);
+ }
+
+ public static ColorPickerDialogBuilder with(Context context, int theme) {
+ return new ColorPickerDialogBuilder(context, theme);
+ }
+
+ public ColorPickerDialogBuilder setTitle(String title) {
+ builder.setTitle(title);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setTitle(int titleId) {
+ builder.setTitle(titleId);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder initialColor(int initialColor) {
+ this.initialColor[0] = initialColor;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder initialColors(int[] initialColor) {
+ for (int i = 0; i < initialColor.length && i < this.initialColor.length; i++) {
+ this.initialColor[i] = initialColor[i];
+ }
+ return this;
+ }
+
+ public ColorPickerDialogBuilder wheelType(ColorPickerView.WHEEL_TYPE wheelType) {
+ ColorWheelRenderer renderer = ColorWheelRendererBuilder.getRenderer(wheelType);
+ colorPickerView.setRenderer(renderer);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder density(int density) {
+ colorPickerView.setDensity(density);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setOnColorChangedListener(OnColorChangedListener onColorChangedListener) {
+ colorPickerView.addOnColorChangedListener(onColorChangedListener);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setOnColorSelectedListener(OnColorSelectedListener onColorSelectedListener) {
+ colorPickerView.addOnColorSelectedListener(onColorSelectedListener);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setPositiveButton(CharSequence text, final ColorPickerClickListener onClickListener) {
+ builder.setPositiveButton(text, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ positiveButtonOnClick(dialog, onClickListener);
+ }
+ });
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setPositiveButton(int textId, final ColorPickerClickListener onClickListener) {
+ builder.setPositiveButton(textId, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ positiveButtonOnClick(dialog, onClickListener);
+ }
+ });
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setNegativeButton(CharSequence text, DialogInterface.OnClickListener onClickListener) {
+ builder.setNegativeButton(text, onClickListener);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setNegativeButton(int textId, DialogInterface.OnClickListener onClickListener) {
+ builder.setNegativeButton(textId, onClickListener);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder noSliders() {
+ isLightnessSliderEnabled = false;
+ isAlphaSliderEnabled = false;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder alphaSliderOnly() {
+ isLightnessSliderEnabled = false;
+ isAlphaSliderEnabled = true;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder lightnessSliderOnly() {
+ isLightnessSliderEnabled = true;
+ isAlphaSliderEnabled = false;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder showAlphaSlider(boolean showAlpha) {
+ isAlphaSliderEnabled = showAlpha;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder showLightnessSlider(boolean showLightness) {
+ isLightnessSliderEnabled = showLightness;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder showBorder(boolean showBorder) {
+ isBorderEnabled = showBorder;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder showColorEdit(boolean showEdit) {
+ isColorEditEnabled = showEdit;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setColorEditTextColor(int argb) {
+ colorPickerView.setColorEditTextColor(argb);
+ return this;
+ }
+
+ public ColorPickerDialogBuilder showColorPreview(boolean showPreview) {
+ isPreviewEnabled = showPreview;
+ if (!showPreview)
+ pickerCount = 1;
+ return this;
+ }
+
+ public ColorPickerDialogBuilder setPickerCount(int pickerCount) throws IndexOutOfBoundsException {
+ if (pickerCount < 1 || pickerCount > 5)
+ throw new IndexOutOfBoundsException("Picker Can Only Support 1-5 Colors");
+ this.pickerCount = pickerCount;
+ if (this.pickerCount > 1)
+ this.isPreviewEnabled = true;
+ return this;
+ }
+
+ public AlertDialog build() {
+ Context context = builder.getContext();
+ colorPickerView.setInitialColors(initialColor, getStartOffset(initialColor));
+ colorPickerView.setShowBorder(isBorderEnabled);
+
+ if (isLightnessSliderEnabled) {
+ LinearLayout.LayoutParams layoutParamsForLightnessBar = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getDimensionAsPx(context, R.dimen.default_slider_height));
+ lightnessSlider = new LightnessSlider(context);
+ lightnessSlider.setLayoutParams(layoutParamsForLightnessBar);
+ pickerContainer.addView(lightnessSlider);
+ colorPickerView.setLightnessSlider(lightnessSlider);
+ lightnessSlider.setColor(getStartColor(initialColor));
+ lightnessSlider.setShowBorder(isBorderEnabled);
+ }
+ if (isAlphaSliderEnabled) {
+ LinearLayout.LayoutParams layoutParamsForAlphaBar = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getDimensionAsPx(context, R.dimen.default_slider_height));
+ alphaSlider = new AlphaSlider(context);
+ alphaSlider.setLayoutParams(layoutParamsForAlphaBar);
+ pickerContainer.addView(alphaSlider);
+ colorPickerView.setAlphaSlider(alphaSlider);
+ alphaSlider.setColor(getStartColor(initialColor));
+ alphaSlider.setShowBorder(isBorderEnabled);
+ }
+ if (isColorEditEnabled) {
+ LinearLayout.LayoutParams layoutParamsForColorEdit = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ colorEdit = (EditText) View.inflate(context, R.layout.color_edit, null);
+ colorEdit.setFilters(new InputFilter[]{new InputFilter.AllCaps()});
+ colorEdit.setSingleLine();
+ colorEdit.setVisibility(View.GONE);
+
+ // limit number of characters to hexColors
+ int maxLength = isAlphaSliderEnabled ? 9 : 7;
+ colorEdit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
+
+ pickerContainer.addView(colorEdit, layoutParamsForColorEdit);
+
+ colorEdit.setText(Utils.getHexString(getStartColor(initialColor), isAlphaSliderEnabled));
+ colorPickerView.setColorEdit(colorEdit);
+ }
+ if (isPreviewEnabled) {
+ colorPreview = (LinearLayout) View.inflate(context, R.layout.color_preview, null);
+ colorPreview.setVisibility(View.GONE);
+ pickerContainer.addView(colorPreview);
+
+ if (initialColor.length == 0) {
+ ImageView colorImage = (ImageView) View.inflate(context, R.layout.color_selector, null);
+ colorImage.setImageDrawable(new ColorDrawable(Color.WHITE));
+ } else {
+ for (int i = 0; i < initialColor.length && i < this.pickerCount; i++) {
+ if (initialColor[i] == null)
+ break;
+ LinearLayout colorLayout = (LinearLayout) View.inflate(context, R.layout.color_selector, null);
+ ImageView colorImage = colorLayout.findViewById(R.id.image_preview);
+ colorImage.setImageDrawable(new ColorDrawable(initialColor[i]));
+ colorPreview.addView(colorLayout);
+ }
+ }
+ colorPreview.setVisibility(View.VISIBLE);
+ colorPickerView.setColorPreview(colorPreview, getStartOffset(initialColor));
+ }
+
+ return builder.create();
+ }
+
+ private Integer getStartOffset(Integer[] colors) {
+ int start = 0;
+ for (int i = 0; i < colors.length; i++) {
+ if (colors[i] == null) {
+ return start;
+ }
+ start = (i + 1) / 2;
+ }
+ return start;
+ }
+
+ private int getStartColor(Integer[] colors) {
+ Integer startColor = getStartOffset(colors);
+ return startColor == null ? Color.WHITE : colors[startColor];
+ }
+
+ private static int getDimensionAsPx(Context context, int rid) {
+ return (int) (context.getResources().getDimension(rid) + .5f);
+ }
+
+ private void positiveButtonOnClick(DialogInterface dialog, ColorPickerClickListener onClickListener) {
+ int selectedColor = colorPickerView.getSelectedColor();
+ Integer[] allColors = colorPickerView.getAllColors();
+ onClickListener.onClick(dialog, selectedColor, allColors);
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/builder/ColorWheelRendererBuilder.java b/library/src/main/java/com/flask/colorpicker/builder/ColorWheelRendererBuilder.java
new file mode 100644
index 0000000..cc816ee
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/builder/ColorWheelRendererBuilder.java
@@ -0,0 +1,18 @@
+package com.flask.colorpicker.builder;
+
+import com.flask.colorpicker.ColorPickerView;
+import com.flask.colorpicker.renderer.ColorWheelRenderer;
+import com.flask.colorpicker.renderer.FlowerColorWheelRenderer;
+import com.flask.colorpicker.renderer.SimpleColorWheelRenderer;
+
+public class ColorWheelRendererBuilder {
+ public static ColorWheelRenderer getRenderer(ColorPickerView.WHEEL_TYPE wheelType) {
+ switch (wheelType) {
+ case CIRCLE:
+ return new SimpleColorWheelRenderer();
+ case FLOWER:
+ return new FlowerColorWheelRenderer();
+ }
+ throw new IllegalArgumentException("wrong WHEEL_TYPE");
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/builder/PaintBuilder.java b/library/src/main/java/com/flask/colorpicker/builder/PaintBuilder.java
new file mode 100644
index 0000000..a8bb6a5
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/builder/PaintBuilder.java
@@ -0,0 +1,82 @@
+package com.flask.colorpicker.builder;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Shader;
+
+public class PaintBuilder {
+ public static PaintHolder newPaint() {
+ return new PaintHolder();
+ }
+
+ public static class PaintHolder {
+ private Paint paint;
+
+ private PaintHolder() {
+ this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ }
+
+ public PaintHolder color(int color) {
+ this.paint.setColor(color);
+ return this;
+ }
+
+ public PaintHolder antiAlias(boolean flag) {
+ this.paint.setAntiAlias(flag);
+ return this;
+ }
+
+ public PaintHolder style(Paint.Style style) {
+ this.paint.setStyle(style);
+ return this;
+ }
+
+ public PaintHolder mode(PorterDuff.Mode mode) {
+ this.paint.setXfermode(new PorterDuffXfermode(mode));
+ return this;
+ }
+
+ public PaintHolder stroke(float width) {
+ this.paint.setStrokeWidth(width);
+ return this;
+ }
+
+ public PaintHolder xPerMode(PorterDuff.Mode mode) {
+ this.paint.setXfermode(new PorterDuffXfermode(mode));
+ return this;
+ }
+
+ public PaintHolder shader(Shader shader) {
+ this.paint.setShader(shader);
+ return this;
+ }
+
+ public Paint build() {
+ return this.paint;
+ }
+ }
+
+ public static Shader createAlphaPatternShader(int size) {
+ size /= 2;
+ size = Math.max(8, size * 2);
+ return new BitmapShader(createAlphaBackgroundPattern(size), Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
+ }
+
+ private static Bitmap createAlphaBackgroundPattern(int size) {
+ Paint alphaPatternPaint = PaintBuilder.newPaint().build();
+ Bitmap bm = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(bm);
+ int s = Math.round(size / 2f);
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 2; j++) {
+ if ((i + j) % 2 == 0) alphaPatternPaint.setColor(0xffffffff);
+ else alphaPatternPaint.setColor(0xffd0d0d0);
+ c.drawRect(i * s, j * s, (i + 1) * s, (j + 1) * s, alphaPatternPaint);
+ }
+ return bm;
+ }
+}
diff --git a/library/src/main/java/com/flask/colorpicker/renderer/AbsColorWheelRenderer.java b/library/src/main/java/com/flask/colorpicker/renderer/AbsColorWheelRenderer.java
new file mode 100644
index 0000000..9ce0f98
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/renderer/AbsColorWheelRenderer.java
@@ -0,0 +1,34 @@
+package com.flask.colorpicker.renderer;
+
+import com.flask.colorpicker.ColorCircle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbsColorWheelRenderer implements ColorWheelRenderer {
+ protected ColorWheelRenderOption colorWheelRenderOption;
+ protected List colorCircleList = new ArrayList<>();
+
+ public void initWith(ColorWheelRenderOption colorWheelRenderOption) {
+ this.colorWheelRenderOption = colorWheelRenderOption;
+ this.colorCircleList.clear();
+ }
+
+ @Override
+ public ColorWheelRenderOption getRenderOption() {
+ if (colorWheelRenderOption == null) colorWheelRenderOption = new ColorWheelRenderOption();
+ return colorWheelRenderOption;
+ }
+
+ public List getColorCircleList() {
+ return colorCircleList;
+ }
+
+ protected int getAlphaValueAsInt() {
+ return Math.round(colorWheelRenderOption.alpha * 255);
+ }
+
+ protected int calcTotalCount(float radius, float size) {
+ return Math.max(1, (int) ((1f - GAP_PERCENTAGE) * Math.PI / (Math.asin(size / radius)) + 0.5f));
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderOption.java b/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderOption.java
new file mode 100644
index 0000000..6a8c7eb
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderOption.java
@@ -0,0 +1,10 @@
+package com.flask.colorpicker.renderer;
+
+import android.graphics.Canvas;
+
+public class ColorWheelRenderOption {
+ public int density;
+ public float maxRadius;
+ public float cSize, strokeWidth, alpha, lightness;
+ public Canvas targetCanvas;
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderer.java b/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderer.java
new file mode 100644
index 0000000..180fcda
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/renderer/ColorWheelRenderer.java
@@ -0,0 +1,17 @@
+package com.flask.colorpicker.renderer;
+
+import com.flask.colorpicker.ColorCircle;
+
+import java.util.List;
+
+public interface ColorWheelRenderer {
+ float GAP_PERCENTAGE = 0.025f;
+
+ void draw();
+
+ ColorWheelRenderOption getRenderOption();
+
+ void initWith(ColorWheelRenderOption colorWheelRenderOption);
+
+ List getColorCircleList();
+}
diff --git a/library/src/main/java/com/flask/colorpicker/renderer/FlowerColorWheelRenderer.java b/library/src/main/java/com/flask/colorpicker/renderer/FlowerColorWheelRenderer.java
new file mode 100644
index 0000000..02927af
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/renderer/FlowerColorWheelRenderer.java
@@ -0,0 +1,50 @@
+package com.flask.colorpicker.renderer;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+
+import com.flask.colorpicker.ColorCircle;
+import com.flask.colorpicker.builder.PaintBuilder;
+
+public class FlowerColorWheelRenderer extends AbsColorWheelRenderer {
+ private Paint selectorFill = PaintBuilder.newPaint().build();
+ private float[] hsv = new float[3];
+ private float sizeJitter = 1.2f;
+
+ @Override
+ public void draw() {
+ final int setSize = colorCircleList.size();
+ int currentCount = 0;
+ float half = colorWheelRenderOption.targetCanvas.getWidth() / 2f;
+ int density = colorWheelRenderOption.density;
+ float strokeWidth = colorWheelRenderOption.strokeWidth;
+ float maxRadius = colorWheelRenderOption.maxRadius;
+ float cSize = colorWheelRenderOption.cSize;
+
+ for (int i = 0; i < density; i++) {
+ float p = (float) i / (density - 1); // 0~1
+ float jitter = (i - density / 2f) / density; // -0.5 ~ 0.5
+ float radius = maxRadius * p;
+ float size = Math.max(1.5f + strokeWidth, cSize + (i == 0 ? 0 : cSize * sizeJitter * jitter));
+ int total = Math.min(calcTotalCount(radius, size), density * 2);
+
+ for (int j = 0; j < total; j++) {
+ double angle = Math.PI * 2 * j / total + (Math.PI / total) * ((i + 1) % 2);
+ float x = half + (float) (radius * Math.cos(angle));
+ float y = half + (float) (radius * Math.sin(angle));
+ hsv[0] = (float) (angle * 180 / Math.PI);
+ hsv[1] = radius / maxRadius;
+ hsv[2] = colorWheelRenderOption.lightness;
+ selectorFill.setColor(Color.HSVToColor(hsv));
+ selectorFill.setAlpha(getAlphaValueAsInt());
+
+ colorWheelRenderOption.targetCanvas.drawCircle(x, y, size - strokeWidth, selectorFill);
+
+ if (currentCount >= setSize) {
+ colorCircleList.add(new ColorCircle(x, y, hsv));
+ } else colorCircleList.get(currentCount).set(x, y, hsv);
+ currentCount++;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/renderer/SimpleColorWheelRenderer.java b/library/src/main/java/com/flask/colorpicker/renderer/SimpleColorWheelRenderer.java
new file mode 100644
index 0000000..46a3769
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/renderer/SimpleColorWheelRenderer.java
@@ -0,0 +1,46 @@
+package com.flask.colorpicker.renderer;
+
+import android.graphics.Color;
+import android.graphics.Paint;
+
+import com.flask.colorpicker.ColorCircle;
+import com.flask.colorpicker.builder.PaintBuilder;
+
+public class SimpleColorWheelRenderer extends AbsColorWheelRenderer {
+ private Paint selectorFill = PaintBuilder.newPaint().build();
+ private float[] hsv = new float[3];
+
+ @Override
+ public void draw() {
+ final int setSize = colorCircleList.size();
+ int currentCount = 0;
+ float half = colorWheelRenderOption.targetCanvas.getWidth() / 2f;
+ int density = colorWheelRenderOption.density;
+ float maxRadius = colorWheelRenderOption.maxRadius;
+
+ for (int i = 0; i < density; i++) {
+ float p = (float) i / (density - 1); // 0~1
+ float radius = maxRadius * p;
+ float size = colorWheelRenderOption.cSize;
+ int total = calcTotalCount(radius, size);
+
+ for (int j = 0; j < total; j++) {
+ double angle = Math.PI * 2 * j / total + (Math.PI / total) * ((i + 1) % 2);
+ float x = half + (float) (radius * Math.cos(angle));
+ float y = half + (float) (radius * Math.sin(angle));
+ hsv[0] = (float) (angle * 180 / Math.PI);
+ hsv[1] = radius / maxRadius;
+ hsv[2] = colorWheelRenderOption.lightness;
+ selectorFill.setColor(Color.HSVToColor(hsv));
+ selectorFill.setAlpha(getAlphaValueAsInt());
+
+ colorWheelRenderOption.targetCanvas.drawCircle(x, y, size - colorWheelRenderOption.strokeWidth, selectorFill);
+
+ if (currentCount >= setSize)
+ colorCircleList.add(new ColorCircle(x, y, hsv));
+ else colorCircleList.get(currentCount).set(x, y, hsv);
+ currentCount++;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/slider/AbsCustomSlider.java b/library/src/main/java/com/flask/colorpicker/slider/AbsCustomSlider.java
new file mode 100644
index 0000000..76edec4
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/slider/AbsCustomSlider.java
@@ -0,0 +1,189 @@
+package com.flask.colorpicker.slider;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.PorterDuff;
+import androidx.annotation.DimenRes;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.flask.colorpicker.R;
+
+public abstract class AbsCustomSlider extends View {
+ protected Bitmap bitmap;
+ protected Canvas bitmapCanvas;
+ protected Bitmap bar;
+ protected Canvas barCanvas;
+ protected OnValueChangedListener onValueChangedListener;
+ protected int barOffsetX;
+ protected int handleRadius = 20;
+ protected int barHeight = 5;
+ protected float value = 1;
+ protected boolean showBorder = false;
+
+ private boolean inVerticalOrientation = false;
+
+ public AbsCustomSlider(Context context) {
+ super(context);
+ init(context, null);
+ }
+
+ public AbsCustomSlider(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public AbsCustomSlider(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ private void init(Context context, AttributeSet attrs) {
+ TypedArray styledAttrs = context.getTheme().obtainStyledAttributes(
+ attrs, R.styleable.AbsCustomSlider, 0, 0);
+ try {
+ inVerticalOrientation = styledAttrs.getBoolean(
+ R.styleable.AbsCustomSlider_inVerticalOrientation, inVerticalOrientation);
+ } finally {
+ styledAttrs.recycle();
+ }
+ }
+
+ protected void updateBar() {
+ handleRadius = getDimension(R.dimen.default_slider_handler_radius);
+ barHeight = getDimension(R.dimen.default_slider_bar_height);
+ barOffsetX = handleRadius;
+
+ if (bar == null)
+ createBitmaps();
+ drawBar(barCanvas);
+ invalidate();
+ }
+
+ protected void createBitmaps() {
+ int width;
+ int height;
+ if (inVerticalOrientation) {
+ width = getHeight();
+ height = getWidth();
+ } else {
+ width = getWidth();
+ height = getHeight();
+ }
+
+ bar = Bitmap.createBitmap(Math.max(width - barOffsetX * 2, 1), barHeight, Bitmap.Config.ARGB_8888);
+ barCanvas = new Canvas(bar);
+
+ if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
+ if (bitmap != null) bitmap.recycle();
+ bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ bitmapCanvas = new Canvas(bitmap);
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int width;
+ int height;
+ if (inVerticalOrientation) {
+ width = getHeight();
+ height = getWidth();
+
+ canvas.rotate(-90);
+ canvas.translate(-width, 0);
+ } else {
+ width = getWidth();
+ height = getHeight();
+ }
+
+ if (bar != null && bitmapCanvas != null) {
+ bitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ bitmapCanvas.drawBitmap(bar, barOffsetX, (height - bar.getHeight()) / 2, null);
+
+ float x = handleRadius + value * (width - handleRadius * 2);
+ float y = height / 2f;
+ drawHandle(bitmapCanvas, x, y);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ }
+ }
+
+ protected abstract void drawBar(Canvas barCanvas);
+
+ protected abstract void onValueChanged(float value);
+
+ protected abstract void drawHandle(Canvas canvas, float x, float y);
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ updateBar();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int width = 0;
+ if (widthMode == MeasureSpec.UNSPECIFIED)
+ width = widthMeasureSpec;
+ else if (widthMode == MeasureSpec.AT_MOST)
+ width = MeasureSpec.getSize(widthMeasureSpec);
+ else if (widthMode == MeasureSpec.EXACTLY)
+ width = MeasureSpec.getSize(widthMeasureSpec);
+
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int height = 0;
+ if (heightMode == MeasureSpec.UNSPECIFIED)
+ height = heightMeasureSpec;
+ else if (heightMode == MeasureSpec.AT_MOST)
+ height = MeasureSpec.getSize(heightMeasureSpec);
+ else if (heightMode == MeasureSpec.EXACTLY)
+ height = MeasureSpec.getSize(heightMeasureSpec);
+
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_MOVE: {
+ if (bar != null) {
+ if (inVerticalOrientation) {
+ value = 1 - (event.getY() - barOffsetX) / bar.getWidth();
+ } else {
+ value = (event.getX() - barOffsetX) / bar.getWidth();
+ }
+ value = Math.max(0, Math.min(value, 1));
+ onValueChanged(value);
+ invalidate();
+ }
+ break;
+ }
+ case MotionEvent.ACTION_UP: {
+ onValueChanged(value);
+ if (onValueChangedListener != null)
+ onValueChangedListener.onValueChanged(value);
+ invalidate();
+ }
+ }
+ return true;
+ }
+
+ protected int getDimension(@DimenRes int id) {
+ return getResources().getDimensionPixelSize(id);
+ }
+
+ public void setShowBorder(boolean showBorder) {
+ this.showBorder = showBorder;
+ }
+
+ public void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
+ this.onValueChangedListener = onValueChangedListener;
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/slider/AlphaSlider.java b/library/src/main/java/com/flask/colorpicker/slider/AlphaSlider.java
new file mode 100644
index 0000000..cf3db82
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/slider/AlphaSlider.java
@@ -0,0 +1,100 @@
+package com.flask.colorpicker.slider;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+
+import com.flask.colorpicker.ColorPickerView;
+import com.flask.colorpicker.Utils;
+import com.flask.colorpicker.builder.PaintBuilder;
+
+public class AlphaSlider extends AbsCustomSlider {
+ public int color;
+ private Paint alphaPatternPaint = PaintBuilder.newPaint().build();
+ private Paint barPaint = PaintBuilder.newPaint().build();
+ private Paint solid = PaintBuilder.newPaint().build();
+ private Paint clearingStroke = PaintBuilder.newPaint().color(0xffffffff).xPerMode(PorterDuff.Mode.CLEAR).build();
+
+ private Paint clearStroke = PaintBuilder.newPaint().build();
+ private Bitmap clearBitmap;
+ private Canvas clearBitmapCanvas;
+
+ private ColorPickerView colorPicker;
+
+ public AlphaSlider(Context context) {
+ super(context);
+ }
+
+ public AlphaSlider(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public AlphaSlider(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void createBitmaps() {
+ super.createBitmaps();
+ alphaPatternPaint.setShader(PaintBuilder.createAlphaPatternShader(barHeight * 2));
+ clearBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
+ clearBitmapCanvas = new Canvas(clearBitmap);
+ }
+
+ @Override
+ protected void drawBar(Canvas barCanvas) {
+ int width = barCanvas.getWidth();
+ int height = barCanvas.getHeight();
+
+ barCanvas.drawRect(0, 0, width, height, alphaPatternPaint);
+ int l = Math.max(2, width / 256);
+ for (int x = 0; x <= width; x += l) {
+ float alpha = (float) x / (width - 1);
+ barPaint.setColor(color);
+ barPaint.setAlpha(Math.round(alpha * 255));
+ barCanvas.drawRect(x, 0, x + l, height, barPaint);
+ }
+ }
+
+ @Override
+ protected void onValueChanged(float value) {
+ if (colorPicker != null)
+ colorPicker.setAlphaValue(value);
+ }
+
+ @Override
+ protected void drawHandle(Canvas canvas, float x, float y) {
+ solid.setColor(color);
+ solid.setAlpha(Math.round(value * 255));
+ if (showBorder) canvas.drawCircle(x, y, handleRadius, clearingStroke);
+ if (value < 1) {
+ // this fixes the same artifact issue from ColorPickerView
+ // happens when alpha pattern is drawn underneath a circle with the same size
+ clearBitmapCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + 4, alphaPatternPaint);
+ clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + 4, solid);
+
+ clearStroke = PaintBuilder.newPaint().color(0xffffffff).style(Paint.Style.STROKE).stroke(6).xPerMode(PorterDuff.Mode.CLEAR).build();
+ clearBitmapCanvas.drawCircle(x, y, handleRadius * 0.75f + (clearStroke.getStrokeWidth() / 2), clearStroke);
+ canvas.drawBitmap(clearBitmap, 0, 0, null);
+ } else {
+ canvas.drawCircle(x, y, handleRadius * 0.75f, solid);
+ }
+ }
+
+ public void setColorPicker(ColorPickerView colorPicker) {
+ this.colorPicker = colorPicker;
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ this.value = Utils.getAlphaPercent(color);
+ if (bar != null) {
+ updateBar();
+ invalidate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/slider/LightnessSlider.java b/library/src/main/java/com/flask/colorpicker/slider/LightnessSlider.java
new file mode 100644
index 0000000..58de0b2
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/slider/LightnessSlider.java
@@ -0,0 +1,74 @@
+package com.flask.colorpicker.slider;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+
+import com.flask.colorpicker.ColorPickerView;
+import com.flask.colorpicker.Utils;
+import com.flask.colorpicker.builder.PaintBuilder;
+
+public class LightnessSlider extends AbsCustomSlider {
+ private int color;
+ private Paint barPaint = PaintBuilder.newPaint().build();
+ private Paint solid = PaintBuilder.newPaint().build();
+ private Paint clearingStroke = PaintBuilder.newPaint().color(0xffffffff).xPerMode(PorterDuff.Mode.CLEAR).build();
+
+ private ColorPickerView colorPicker;
+
+ public LightnessSlider(Context context) {
+ super(context);
+ }
+
+ public LightnessSlider(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LightnessSlider(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void drawBar(Canvas barCanvas) {
+ int width = barCanvas.getWidth();
+ int height = barCanvas.getHeight();
+
+ float[] hsv = new float[3];
+ Color.colorToHSV(color, hsv);
+ int l = Math.max(2, width / 256);
+ for (int x = 0; x <= width; x += l) {
+ hsv[2] = (float) x / (width - 1);
+ barPaint.setColor(Color.HSVToColor(hsv));
+ barCanvas.drawRect(x, 0, x + l, height, barPaint);
+ }
+ }
+
+ @Override
+ protected void onValueChanged(float value) {
+ if (colorPicker != null)
+ colorPicker.setLightness(value);
+ }
+
+ @Override
+ protected void drawHandle(Canvas canvas, float x, float y) {
+ solid.setColor(Utils.colorAtLightness(color, value));
+ if (showBorder) canvas.drawCircle(x, y, handleRadius, clearingStroke);
+ canvas.drawCircle(x, y, handleRadius * 0.75f, solid);
+ }
+
+ public void setColorPicker(ColorPickerView colorPicker) {
+ this.colorPicker = colorPicker;
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ this.value = Utils.lightnessOfColor(color);
+ if (bar != null) {
+ updateBar();
+ invalidate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/flask/colorpicker/slider/OnValueChangedListener.java b/library/src/main/java/com/flask/colorpicker/slider/OnValueChangedListener.java
new file mode 100644
index 0000000..68b263a
--- /dev/null
+++ b/library/src/main/java/com/flask/colorpicker/slider/OnValueChangedListener.java
@@ -0,0 +1,5 @@
+package com.flask.colorpicker.slider;
+
+public interface OnValueChangedListener {
+ void onValueChanged(float value);
+}
\ No newline at end of file
diff --git a/library/src/main/res/layout/color_edit.xml b/library/src/main/res/layout/color_edit.xml
new file mode 100644
index 0000000..53707c8
--- /dev/null
+++ b/library/src/main/res/layout/color_edit.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/color_preview.xml b/library/src/main/res/layout/color_preview.xml
new file mode 100644
index 0000000..22c0551
--- /dev/null
+++ b/library/src/main/res/layout/color_preview.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/color_selector.xml b/library/src/main/res/layout/color_selector.xml
new file mode 100644
index 0000000..b9ef85a
--- /dev/null
+++ b/library/src/main/res/layout/color_selector.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/src/main/res/layout/color_widget.xml b/library/src/main/res/layout/color_widget.xml
new file mode 100644
index 0000000..9d0f6f7
--- /dev/null
+++ b/library/src/main/res/layout/color_widget.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..45887f9
--- /dev/null
+++ b/library/src/main/res/values/attrs.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/src/main/res/values/dimens.xml b/library/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..d373754
--- /dev/null
+++ b/library/src/main/res/values/dimens.xml
@@ -0,0 +1,10 @@
+
+ 36dp
+ 24dp
+ 4dp
+ 10dp
+ 24dp
+ 40dp
+ 36dp
+ 20dp
+
diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml
new file mode 100644
index 0000000..afdeddf
--- /dev/null
+++ b/library/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index d7d6933..28c6272 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,3 +2,4 @@ include ':app'
rootProject.name = "RustedAssistant"
include ':assistantCoreLibrary'
include ':dialog'
+include(':library')