修复已知BUG调色器MD3化

This commit is contained in:
muqing 2024-01-28 17:02:54 +08:00
parent c6089ae67c
commit c5fa00b988
55 changed files with 2141 additions and 441 deletions

View File

@ -24,15 +24,15 @@ android {
keyAlias 'coldmint' keyAlias 'coldmint'
} }
} }
compileSdkVersion 33 compileSdk 33
buildToolsVersion "30.0.3" // buildToolsVersion "30.0.3"
defaultConfig { defaultConfig {
applicationId "com.coldmint.rust.pro" applicationId "com.coldmint.rust.pro"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 33 targetSdkVersion 33
versionCode 28 versionCode 28
versionName "2.1 Bata6(2023-7-20)" versionName "2.1.1 Bata6(2023-7-20)"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -91,12 +91,15 @@ dependencies {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib' 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 platform('com.google.firebase:firebase-bom:31.1.1')
implementation 'com.google.firebase:firebase-analytics-ktx' implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-crashlytics-ktx' implementation 'com.google.firebase:firebase-crashlytics-ktx'
implementation 'com.google.firebase:firebase-perf-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" def nav_version = "2.5.1"
// implementation 'com.luolc:emoji-rain:0.1.1' // implementation 'com.luolc:emoji-rain:0.1.1'
@ -133,16 +136,10 @@ dependencies {
implementation 'com.github.florent37:glidepalette:2.1.2' implementation 'com.github.florent37:glidepalette:2.1.2'
implementation 'cat.ereza:customactivityoncrash:2.3.0' implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.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 '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.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation 'androidx.preference:preference-ktx:1.2.0' 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'
} }

Binary file not shown.

View File

@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// 被测试应用程序的上下文
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.coldmint.rust.pro", appContext.getPackageName());
}
}

View File

@ -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)
}
}

View File

@ -24,27 +24,28 @@
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.rust.Concept" android:theme="@style/Theme.rust.Concept"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true"
android:screenOrientation="portrait"
tools:targetApi="tiramisu">
<activity <activity
android:name=".FeedbackActivity" android:name=".FeedbackActivity"
android:exported="false" android:exported="false"
android:screenOrientation="portrait" /> android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity" />
<activity <activity
android:name=".ChangePasswordActivity" android:name=".ChangePasswordActivity"
android:exported="false" android:exported="false"
android:screenOrientation="portrait" /> android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity" />
<activity <activity
android:name=".NetworkTemplatePackageDetailsActivity" android:name=".NetworkTemplatePackageDetailsActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".CustomizeEditTextActivity" android:name=".CustomizeEditTextActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".SearchActivity" android:name=".SearchActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
@ -68,93 +69,71 @@
android:value="portrait|landscape" /> <!-- Activity注册 --> android:value="portrait|landscape" /> <!-- Activity注册 -->
<activity <activity
android:name=".CreationWizardActivity" android:name=".CreationWizardActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".TurretDesignActivity" android:name=".TurretDesignActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".BrowserActivity" android:name=".BrowserActivity"
android:exported="false" android:exported="false"
android:label="@string/built_in_browser" android:label="@string/built_in_browser"/> <!-- 适配全面屏 -->
android:screenOrientation="portrait" /> <!-- 适配全面屏 -->
<activity <activity
android:name=".OrderListActivity" android:name=".OrderListActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".SearchResultActivity" android:name=".SearchResultActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".PayActivity" android:name=".PayActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ReviewModActivity" android:name=".ReviewModActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ReportListActivity" android:name=".ReportListActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ErrorInfoActivity" android:name=".ErrorInfoActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".UserListActivity" android:name=".UserListActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ActivateActivity" android:name=".ActivateActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ThanksActivity" android:name=".ThanksActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".WorkManagementActivity" android:name=".WorkManagementActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".FullScreenCoverActivity" android:name=".FullScreenCoverActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".TagActivity" android:name=".TagActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ReportActivity" android:name=".ReportActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".EditUserInfoActivity" android:name=".EditUserInfoActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".UserHomePageActivity" android:name=".UserHomePageActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".WebModInfoActivity" android:name=".WebModInfoActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ErrorActivity" android:name=".ErrorActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name="com.yalantis.ucrop.UCropActivity" android:name="com.yalantis.ucrop.UCropActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask">
android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -167,8 +146,7 @@
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:exported="true" android:exported="true"
android:label="@string/file_importer" android:label="@string/file_importer"
android:maxRecents="3" android:maxRecents="3">
android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -268,93 +246,69 @@
</activity> </activity>
<activity <activity
android:name=".AboutActivity" android:name=".AboutActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ValueTypeActivity" android:name=".ValueTypeActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".GlobalOperationsActivity" android:name=".GlobalOperationsActivity"
android:label="@string/global_operations" android:label="@string/global_operations"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".EditActivity" android:name=".EditActivity"
android:exported="true" android:exported="true"
android:label="@string/mod_action1" android:label="@string/mod_action1"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".CreateModActivity" android:name=".CreateModActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".UnitsActivity" android:name=".UnitsActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".OptimizeActivity" android:name=".OptimizeActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".FileManagerActivity" android:name=".FileManagerActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".CreateUnitActivity" android:name=".CreateUnitActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".TemplateParserActivity" android:name=".TemplateParserActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".LibraryActivity" android:name=".LibraryActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".SettingsActivity" android:name=".SettingsActivity"
android:exported="true" android:exported="true"
android:label="@string/setting" android:label="@string/setting"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".TemplateMakerActivity" android:name=".TemplateMakerActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".CreateTemplateActivity" android:name=".CreateTemplateActivity"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".CodeTableActivity" android:name=".CodeTableActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".LoginActivity" android:name=".LoginActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".RegisterActivity" android:name=".RegisterActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".EditModInfoActivity" android:name=".EditModInfoActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ApplicationListActivity" android:name=".ApplicationListActivity"
android:exported="false" android:exported="false" />
android:screenOrientation="portrait" />
<activity <activity
android:name=".GameCheckActivity" android:name=".GameCheckActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".RecyclingStationActivity" android:name=".RecyclingStationActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".BookmarkManagerActivity" android:name=".BookmarkManagerActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".ReleaseModActivity" android:name=".ReleaseModActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
<activity <activity
android:name=".PackActivity" android:name=".PackActivity"
android:exported="false" android:exported="false"/>
android:screenOrientation="portrait" />
</application> </application>
</manifest> </manifest>

View File

@ -8,7 +8,12 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.MediaStore 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.PopupMenu
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
@ -17,7 +22,6 @@ import androidx.core.view.GravityCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions 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.AppOperator
import com.coldmint.rust.core.tool.DebugHelper import com.coldmint.rust.core.tool.DebugHelper
import com.coldmint.rust.core.tool.FileOperator 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.adapters.FileAdapter
import com.coldmint.rust.pro.base.BaseActivity import com.coldmint.rust.pro.base.BaseActivity
import com.coldmint.rust.pro.databean.ErrorInfo 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.coldmint.rust.pro.viewmodel.EditViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar 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.EditorSearcher
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
import jp.wasabeef.glide.transformations.BlurTransformation import jp.wasabeef.glide.transformations.BlurTransformation
import java.io.File import java.io.File
import java.util.*
import kotlin.collections.ArrayList
class EditActivity : BaseActivity<ActivityEditBinding>() { class EditActivity : BaseActivity<ActivityEditBinding>() {
private val viewModel by lazy { private val viewModel by lazy {
ViewModelProvider(this).get(EditViewModel::class.java) ViewModelProvider(this)[EditViewModel::class.java]
} }
private lateinit var turretCoordinateResults: ActivityResultLauncher<Intent> private lateinit var turretCoordinateResults: ActivityResultLauncher<Intent>

View File

@ -1,27 +1,21 @@
package com.coldmint.rust.pro 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 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.net.Uri
import android.os.* import android.os.Bundle
import android.view.* import android.os.Handler
import android.widget.* import android.os.Looper
import android.widget.Toast.makeText 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.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide import androidx.recyclerview.widget.LinearLayoutManager
import com.coldmint.dialog.CoreDialog import com.coldmint.dialog.CoreDialog
import com.coldmint.dialog.InputDialog import com.coldmint.dialog.InputDialog
import com.coldmint.rust.core.tool.DebugHelper 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.core.tool.LineParser
import com.coldmint.rust.pro.adapters.FileAdapter import com.coldmint.rust.pro.adapters.FileAdapter
import com.coldmint.rust.pro.adapters.FileTabAdapter 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.databean.FileTab
import com.coldmint.rust.pro.databinding.ActivityFileBinding import com.coldmint.rust.pro.databinding.ActivityFileBinding
import com.coldmint.rust.pro.interfaces.BookmarkListener import com.coldmint.rust.pro.interfaces.BookmarkListener
import com.coldmint.rust.pro.tool.AppSettings 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.ui.StableLinearLayoutManager
import com.coldmint.rust.pro.viewmodel.FileManagerViewModel import com.coldmint.rust.pro.viewmodel.FileManagerViewModel
import com.google.android.material.chip.Chip import com.google.android.material.snackbar.Snackbar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.SnackbarContentLayout
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zhanghai.android.fastscroll.FastScrollerBuilder import me.zhanghai.android.fastscroll.FastScrollerBuilder
import java.io.BufferedReader
import java.io.File 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<ActivityFileBinding>() { class FileManagerActivity : BaseActivity<ActivityFileBinding>() {

View File

@ -1,20 +1,17 @@
package com.coldmint.rust.pro 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.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources import android.os.Bundle
import com.google.android.material.snackbar.Snackbar import android.os.Handler
import android.os.* import android.os.Looper
import android.util.Log import android.view.KeyEvent
import android.view.* import android.view.LayoutInflater
import android.widget.Toast import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.core.view.isVisible 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.debug.LogCat
import com.coldmint.rust.core.interfaces.ApiCallBack import com.coldmint.rust.core.interfaces.ApiCallBack
import com.coldmint.rust.core.interfaces.UnzipListener 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.AppUpdate
import com.coldmint.rust.core.web.ServerConfiguration 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.ActivityMainBinding
import com.coldmint.rust.pro.databinding.HeadLayoutBinding 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.EventRecord
import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.viewmodel.StartViewModel import com.coldmint.rust.pro.viewmodel.StartViewModel
import com.google.android.material.color.DynamicColors import com.google.android.material.color.DynamicColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson import com.google.gson.Gson
import com.gyf.immersionbar.ImmersionBar import com.gyf.immersionbar.ImmersionBar
@ -331,7 +333,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
intent.putExtra("type", "template") intent.putExtra("type", "template")
startActivity(intent) startActivity(intent)
} }
else -> { else -> {
} }
} }
@ -380,7 +381,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
menu.findItem(R.id.rust_api).setOnMenuItemClickListener { menu.findItem(R.id.rust_api).setOnMenuItemClickListener {
val thisIntent = Intent(this, BrowserActivity::class.java) val thisIntent = Intent(this, BrowserActivity::class.java)
thisIntent.putExtra("link", "https://rustedwarfareapicode.top/") thisIntent.putExtra("link", "https://git.coldmint.top/")
thisIntent.putExtra("javaScriptEnabled", true) thisIntent.putExtra("javaScriptEnabled", true)
startActivity(thisIntent) startActivity(thisIntent)
false false

View File

@ -1,23 +1,22 @@
package com.coldmint.rust.pro package com.coldmint.rust.pro
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.os.Environment import android.content.pm.ActivityInfo
import android.util.Log import android.os.Bundle
import cat.ereza.customactivityoncrash.config.CaocConfig import cat.ereza.customactivityoncrash.config.CaocConfig
import com.coldmint.rust.core.debug.LogCat import com.coldmint.rust.core.debug.LogCat
import com.coldmint.rust.core.debug.LogCatObserver 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.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.DynamicColors
import com.google.android.material.color.DynamicColorsOptions import com.google.android.material.color.DynamicColorsOptions
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import com.hjq.language.MultiLanguages import com.hjq.language.MultiLanguages
import com.youth.banner.BuildConfig import com.youth.banner.BuildConfig
import java.util.*
class RustApplication : Application() { class RustApplication : Application() {
@ -38,7 +37,7 @@ class RustApplication : Application() {
AppSettings.initAppSettings(this) AppSettings.initAppSettings(this)
//动态颜色 //动态颜色
val options = DynamicColorsOptions.Builder() val options = DynamicColorsOptions.Builder()
.setPrecondition { activity, theme -> .setPrecondition { _, _ ->
AppSettings AppSettings
.getValue( .getValue(
AppSettings.Setting.DynamicColor, AppSettings.Setting.DynamicColor,
@ -66,8 +65,24 @@ class RustApplication : Application() {
.errorActivity(ErrorActivity::class.java) //default: null (default error activity) .errorActivity(ErrorActivity::class.java) //default: null (default error activity)
.apply() .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) {}
})
} }

View File

@ -1,9 +1,6 @@
package com.coldmint.rust.pro.base package com.coldmint.rust.pro.base
import android.content.Context 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.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
@ -11,24 +8,15 @@ import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.coldmint.dialog.CoreDialog import com.coldmint.dialog.CoreDialog
import com.coldmint.rust.pro.R import com.coldmint.rust.pro.R
import com.google.android.material.appbar.MaterialToolbar 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.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout 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 com.hjq.language.MultiLanguages
import java.util.*
/*主活动,所有活动都应该继承于此*/ /*主活动,所有活动都应该继承于此*/
abstract class BaseActivity<ViewBingType : ViewBinding> : abstract class BaseActivity<ViewBingType : ViewBinding> :

View File

@ -1,6 +1,5 @@
package com.coldmint.rust.pro.edit.autoComplete package com.coldmint.rust.pro.edit.autoComplete
import android.os.Bundle
import com.coldmint.rust.core.SourceFile import com.coldmint.rust.core.SourceFile
import com.coldmint.rust.core.database.code.CodeDao import com.coldmint.rust.core.database.code.CodeDao
import com.coldmint.rust.core.database.code.CodeDataBase 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.DebugHelper
import com.coldmint.rust.core.tool.LineParser import com.coldmint.rust.core.tool.LineParser
import com.coldmint.rust.pro.edit.RustAnalyzer 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.AppSettings
import com.coldmint.rust.pro.tool.CompletionItemConverter import com.coldmint.rust.pro.tool.CompletionItemConverter
import io.github.rosemoe.sora.lang.completion.CompletionPublisher import io.github.rosemoe.sora.lang.completion.CompletionPublisher
import io.github.rosemoe.sora.text.CharPosition import io.github.rosemoe.sora.text.CharPosition
import io.github.rosemoe.sora.text.ContentReference import io.github.rosemoe.sora.text.ContentReference
import io.github.rosemoe.sora.widget.CodeEditor
/** /**
* 代码自动完成项目来自数据库 * 代码自动完成项目来自数据库

View File

@ -2,11 +2,10 @@ package com.coldmint.rust.pro.fragments
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.coldmint.dialog.CoreDialog import com.coldmint.dialog.CoreDialog
import com.coldmint.rust.core.dataBean.BannerItemDataBean 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.AppSettings
import com.coldmint.rust.pro.tool.GlobalMethod import com.coldmint.rust.pro.tool.GlobalMethod
import com.coldmint.rust.pro.tool.TextStyleMaker import com.coldmint.rust.pro.tool.TextStyleMaker
import com.coldmint.rust.pro.ui.StableLinearLayoutManager import com.coldmint.rust.pro.ui.ScrollLinearLayoutManager
import com.google.android.material.color.DynamicColors
import com.youth.banner.adapter.BannerImageAdapter import com.youth.banner.adapter.BannerImageAdapter
import com.youth.banner.holder.BannerImageHolder import com.youth.banner.holder.BannerImageHolder
import com.youth.banner.indicator.CircleIndicator import com.youth.banner.indicator.CircleIndicator
import com.youth.banner.transformer.AlphaPageTransformer
import com.youth.banner.transformer.DepthPageTransformer
class RecommendedFragment : BaseFragment<FragmentRecommendedBinding>() { class RecommendedFragment : BaseFragment<FragmentRecommendedBinding>() {
@ -233,10 +229,10 @@ class RecommendedFragment : BaseFragment<FragmentRecommendedBinding>() {
} }
override fun whenViewCreated(inflater: LayoutInflater, savedInstanceState: Bundle?) { override fun whenViewCreated(inflater: LayoutInflater, savedInstanceState: Bundle?) {
viewBinding.latestReleaseView.layoutManager = StableLinearLayoutManager(requireContext()) viewBinding.latestReleaseView.layoutManager = ScrollLinearLayoutManager(requireContext())
viewBinding.soleRecommendedRecyclerView.layoutManager = viewBinding.soleRecommendedRecyclerView.layoutManager =
StableLinearLayoutManager(requireContext()) ScrollLinearLayoutManager(requireContext())
viewBinding.randomRecommendedView.layoutManager = StableLinearLayoutManager(requireContext()) viewBinding.randomRecommendedView.layoutManager = ScrollLinearLayoutManager(requireContext())
loadRandomRecommended() loadRandomRecommended()
viewBinding.changeRandomRecommended.setOnClickListener { viewBinding.changeRandomRecommended.setOnClickListener {
loadRandomRecommended() loadRandomRecommended()

View File

@ -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
}
}

View File

@ -3,13 +3,10 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center"> android:gravity="center">
<Button <Button
style="@style/Widget.MaterialComponents.Button.TextButton.Dialog" style="@style/Widget.MaterialComponents.Button.TextButton.Dialog"
android:id="@+id/codeTextItemView" android:id="@+id/codeTextItemView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="项目"/> android:text="项目"/>
</LinearLayout> </LinearLayout>

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merge> <merge>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -13,8 +12,7 @@
android:id="@+id/titleView" android:id="@+id/titleView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:layout_alignParentTop="true" android:layout_alignParentTop="true">
app:cardBackgroundColor="?android:windowBackground">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:gravity="center"
android:orientation="vertical">
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> 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" />
<TextView <TextView
android:id="@+id/textview" android:id="@+id/textview"
style="@style/TextAppearance.Material3.HeadlineMedium" style="@style/TextAppearance.Material3.HeadlineMedium"
@ -18,27 +18,23 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:text="@string/no_content" android:text="@string/no_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone" /> android:visibility="gone" />
<LinearLayout
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/linearLayout3"
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<HorizontalScrollView <HorizontalScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.chip.ChipGroup <com.google.android.material.chip.ChipGroup
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:singleLine="true" app:singleLine="true"
app:singleSelection="true"> app:singleSelection="true">
@ -77,15 +73,16 @@
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>
</HorizontalScrollView> </HorizontalScrollView>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

View File

@ -7,8 +7,6 @@
android:animateLayoutChanges="true" android:animateLayoutChanges="true"
android:gravity="center" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -30,7 +28,6 @@
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:visibility="visible"> android:visibility="visible">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -75,7 +72,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:text="@string/change_random_recommended" /> android:text="@string/change_random_recommended"
card_view:ignore="RelativeOverlap" />
</RelativeLayout> </RelativeLayout>

View File

@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@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());
}
}

View File

@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -18,3 +18,4 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
android.injected.testOnly=false android.injected.testOnly=false
android.suppressUnsupportedCompileSdk=32,33

1
library/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

20
library/build.gradle Normal file
View File

@ -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'
}

17
library/proguard-rules.pro vendored Normal file
View File

@ -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 *;
#}

View File

@ -0,0 +1,5 @@
<manifest package="com.flask.colorpicker">
<application/>
</manifest>

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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<OnColorChangedListener> colorChangedListeners = new ArrayList<>();
private ArrayList<OnColorSelectedListener> 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;
}
}
}

View File

@ -0,0 +1,5 @@
package com.flask.colorpicker;
public interface OnColorChangedListener {
void onColorChanged(int selectedColor);
}

View File

@ -0,0 +1,5 @@
package com.flask.colorpicker;
public interface OnColorSelectedListener {
void onColorSelected(int selectedColor);
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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<ColorCircle> 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<ColorCircle> 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));
}
}

View File

@ -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;
}

View File

@ -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<ColorCircle> getColorCircleList();
}

View File

@ -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++;
}
}
}
}

View File

@ -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++;
}
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,5 @@
package com.flask.colorpicker.slider;
public interface OnValueChangedListener {
void onValueChanged(float value);
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/PickerEditText"
android:hint="Color Value"
android:inputType="textNoSuggestions" />

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="@dimen/default_preview_height"
android:background="@android:color/transparent"
android:gravity="center"
android:orientation="horizontal" />

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/default_preview_height"
android:layout_height="@dimen/default_preview_height"
android:background="@android:color/transparent"
android:padding="2dp">
<ImageView
android:layout_width="@dimen/default_preview_image_height"
android:layout_height="@dimen/default_preview_image_height"
android:src="@android:color/transparent"
android:id="@+id/image_preview"/>
</LinearLayout>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/color_indicator"
android:layout_width="32dp"
android:layout_height="32dp"
tools:ignore="ContentDescription" />

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ColorPickerPreference">
<attr name="alphaSlider" format="boolean"/>
<attr name="lightnessSlider" format="boolean"/>
<attr name="border" format="boolean"/>
<attr name="density" format="integer"/>
<attr name="initialColor" format="integer"/>
<attr name="wheelType" format="enum">
<enum name="FLOWER" value="0"/>
<enum name="CIRCLE" value="1"/>
</attr>
<attr name="lightnessSliderView" format="reference"/>
<attr name="alphaSliderView" format="reference"/>
<attr name="pickerColorEdit" format="boolean"/>
<attr name="pickerColorEditTextColor" format="integer"/>
<attr name="pickerTitle" format="reference|string"/>
<attr name="pickerButtonOk" format="reference|string"/>
<attr name="pickerButtonCancel" format="reference|string"/>
</declare-styleable>
<declare-styleable name="AbsCustomSlider">
<attr name="inVerticalOrientation" format="boolean"/>
</declare-styleable>
</resources>

View File

@ -0,0 +1,10 @@
<resources>
<dimen name="default_slider_height">36dp</dimen>
<dimen name="default_slider_margin">24dp</dimen>
<dimen name="default_slider_bar_height">4dp</dimen>
<dimen name="default_slider_handler_radius">10dp</dimen>
<dimen name="default_padding_side">24dp</dimen>
<dimen name="default_preview_height">40dp</dimen>
<dimen name="default_preview_image_height">36dp</dimen>
<dimen name="default_margin_top">20dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="PickerEditText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_margin">4dp</item>
<item name="android:imeOptions">actionNext</item>
<item name="android:singleLine">true</item>
<item name="android:textSize">22sp</item>
</style>
</resources>

View File

@ -2,3 +2,4 @@ include ':app'
rootProject.name = "RustedAssistant" rootProject.name = "RustedAssistant"
include ':assistantCoreLibrary' include ':assistantCoreLibrary'
include ':dialog' include ':dialog'
include(':library')