Cherish: Monet settings

Signed-off-by: Hưng Phan <phandinhhungvp2001@gmail.com>
This commit is contained in:
jhonboy121
2022-09-27 23:49:29 +07:00
committed by Hưng Phan
parent d3bdfeccb1
commit 7d6755e20e
18 changed files with 990 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
</shape>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp" />
<gradient android:type="linear" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#FFFFFF">
<item>
<shape android:shape="oval">
<solid android:color="?android:attr/colorPrimaryDark" />
<size android:width="20dp"
android:height="20dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 FlamingoOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/default_padding"
android:paddingBottom="@dimen/default_padding">
<View
android:id="@+id/color_preview"
android:layout_width="0dp"
android:layout_height="@dimen/color_picker_preview_height"
android:layout_marginStart="@dimen/default_margin"
android:layout_marginEnd="@dimen/default_margin"
android:background="@drawable/color_picker_preview_background"
settings:layout_constraintEnd_toEndOf="parent"
settings:layout_constraintStart_toStartOf="parent"
settings:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/color_input"
style="@style/ColorPickerEditTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
settings:layout_constraintStart_toStartOf="@id/color_preview"
settings:layout_constraintTop_toTopOf="@id/color_preview"
settings:layout_constraintEnd_toEndOf="@id/color_preview"
settings:layout_constraintBottom_toBottomOf="@id/color_preview" />
<SeekBar
android:id="@+id/seekBar1"
style="@style/ColorPickerSeekBarStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
settings:layout_constraintBottom_toTopOf="@id/seekBar2"
settings:layout_constraintEnd_toEndOf="parent"
settings:layout_constraintStart_toStartOf="parent"
settings:layout_constraintTop_toBottomOf="@id/color_preview" />
<SeekBar
android:id="@+id/seekBar2"
style="@style/ColorPickerSeekBarStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
settings:layout_constraintBottom_toTopOf="@id/seekBar3"
settings:layout_constraintEnd_toEndOf="parent"
settings:layout_constraintStart_toStartOf="parent"
settings:layout_constraintTop_toBottomOf="@id/seekBar1" />
<SeekBar
android:id="@+id/seekBar3"
style="@style/ColorPickerSeekBarStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/default_margin"
settings:layout_constraintBottom_toTopOf="@id/barrier"
settings:layout_constraintEnd_toEndOf="parent"
settings:layout_constraintStart_toStartOf="parent"
settings:layout_constraintTop_toBottomOf="@id/seekBar2" />
<RadioGroup
android:id="@+id/color_model_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_margin"
android:orientation="horizontal"
settings:layout_constraintBottom_toBottomOf="@id/confirm_button"
settings:layout_constraintStart_toStartOf="parent"
settings:layout_constraintTop_toTopOf="@id/confirm_button">
<RadioButton
android:id="@+id/rgb_button"
style="@style/ColorPickerRadioButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/rgb" />
<RadioButton
android:id="@+id/hsl_button"
style="@style/ColorPickerRadioButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hsl" />
<RadioButton
android:id="@+id/hsv_button"
style="@style/ColorPickerRadioButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hsv" />
</RadioGroup>
<Button
android:id="@+id/cancel_button"
style="@style/ColorPickerButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp"
android:text="@string/cancel"
settings:layout_constraintBottom_toBottomOf="@id/confirm_button"
settings:layout_constraintEnd_toStartOf="@id/confirm_button"
settings:layout_constraintTop_toTopOf="@id/confirm_button" />
<Button
android:id="@+id/confirm_button"
style="@style/ColorPickerButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/default_margin"
android:text="@string/confirm"
settings:layout_constraintBottom_toBottomOf="parent"
settings:layout_constraintEnd_toEndOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
settings:barrierDirection="top"
settings:constraint_referenced_ids="color_model_group, confirm_button" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<style name="ColorPickerStyle" parent="Theme.MaterialComponents.BottomSheetDialog">
<item name="colorPrimary">@*android:color/primary_device_default_settings</item>
<item name="colorPrimaryDark">@*android:color/primary_device_default_settings_light</item>
<item name="colorAccent">@*android:color/accent_device_default_dark</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColorPrimary">#FFFFFF</item>
</style>
</resources>

View File

@@ -22,6 +22,8 @@
<dimen name="alert_dialog_padding_material">20dp</dimen>
<dimen name="color_preference_width">18dip</dimen>
<dimen name="color_preference_height">18dip</dimen>
<dimen name="color_picker_preview_height">80dp</dimen>
<!-- Shortcut picker -->
<dimen name="shortcut_picker_left_padding">70dip</dimen>

View File

@@ -97,6 +97,12 @@
<!-- Power menu Animations -->
<string name="power_menu_animation">Power menu</string>
<!-- Color picker -->
<string name="rgb">RGB</string>
<string name="hsl">HSL</string>
<string name="hsv">HSV</string>
<string name="invalid_color">Invalid color!</string>
<!-- QS header image -->
<!-- Lockscreen -->
@@ -715,5 +721,20 @@
<string name="app_lock_biometrics_allowed_title">Enable biometrics for unlocking</string>
<string name="app_lock_footer_text">Bubbles will be automatically dismissed after timeout</string>
<string name="enable_protection">Enable protection</string>
<!-- Monet engine -->
<string name="monet_engine_settings_title">Monet engine</string>
<string name="monet_engine_settings_summary">Custom color, colorfulness, brightness</string>
<string name="accurate_shades_title">Use accurate shades</string>
<string name="color_override_title">Custom color picker</string>
<string name="color_override_default_summary">Using wallpaper color</string>
<string name="custom_color_override_summary_placeholder">
Choosen color: <xliff:g example="#FF0000" id="Color">%1$s</xliff:g>. Set an empty value to use wallpaper color.
</string>
<string name="invalid_color_input">Invalid color input!</string>
<string name="chroma_factor_title">Colorfulness</string>
<string name="linear_lightness_title">Use custom lightness scale</string>
<string name="white_luminance_title">Brightness</string>
<string name="confirm">Confirm</string>
</resources>

View File

@@ -23,4 +23,46 @@
<dimen name="fod_picker_item_padding">20dp</dimen>
<color name="option_border_default">#5f6368</color>
<style name="ColorPickerStyle" parent="Theme.MaterialComponents.BottomSheetDialog">
<item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
<item name="colorPrimaryDark">@*android:color/primary_device_default_settings</item>
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColorPrimary">#000000</item>
</style>
<style name="ColorPickerSeekBarStyle" parent="Widget.AppCompat.SeekBar">
<item name="android:layout_marginTop">30dp</item>
<item name="android:paddingStart">16dp</item>
<item name="android:paddingEnd">18dp</item>
<item name="android:maxHeight">8dp</item>
<item name="android:progressDrawable">@drawable/color_picker_seekbar_background</item>
<item name="android:thumb">@drawable/color_picker_seekbar_thumb</item>
<item name="android:splitTrack">false</item>
</style>
<style name="ColorPickerRadioButtonStyle">
<item name="android:paddingTop">12dp</item>
<item name="android:paddingBottom">12dp</item>
<item name="android:buttonTint">?android:attr/colorAccent</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="ColorPickerButtonStyle">
<item name="android:background">@android:color/transparent</item>
<item name="android:minWidth">0dp</item>
<item name="android:minHeight">0dp</item>
<item name="android:padding">8dp</item>
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
<style name="ColorPickerEditTextStyle">
<item name="android:gravity">center</item>
<item name="android:inputType">textCapCharacters|textNoSuggestions</item>
<item name="android:importantForAutofill">no</item>
<item name="android:textCursorDrawable">@null</item>
<item name="android:imeOptions">actionDone</item>
<item name="android:singleLine">true</item>
</style>
</resources>

View File

@@ -65,6 +65,13 @@
android:summary="@string/dark_ui_mode_summary"
android:fragment="com.android.settings.display.darkmode.DarkModeSettingsFragment"
settings:controller="com.android.settings.display.DarkUIPreferenceController" />
<!-- Monet -->
<Preference
android:key="monet_engine_settings"
android:title="@string/monet_engine_settings_title"
android:summary="@string/monet_engine_settings_summary"
android:fragment="com.cherish.settings.fragments.MonetEngineSettings" />
<!-- Font style -->
<Preference

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 FlamingoOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/monet_engine_settings_title">
<!-- Accurate shades -->
<com.cherish.settings.preferences.SecureSettingSwitchPreference
android:key="monet_engine_accurate_shades"
android:title="@string/accurate_shades_title"
android:defaultValue="true" />
<!-- Color override -->
<com.cherish.settings.preferences.SecureSettingColorPickerPreference
android:key="monet_engine_color_override"
android:title="@string/color_override_title"
settings:controller="com.cherish.settings.fragments.MonetCustomColorPreferenceController" />
<!-- Chroma factor -->
<com.cherish.settings.preferences.CustomSeekBarPreference
android:key="chroma_factor"
android:title="@string/chroma_factor_title"
android:defaultValue="100"
android:max="100"
android:persistent="false"
android:min="0"
settings:interval="10"
settings:controller="com.cherish.settings.fragments.MonetChromaFactorPreferenceController" />
<!-- Custom lightness scale -->
<com.cherish.settings.preferences.SecureSettingSwitchPreference
android:key="monet_engine_linear_lightness"
android:title="@string/linear_lightness_title"
android:defaultValue="0" />
<!-- Brightness -->
<com.cherish.settings.preferences.SecureSettingSeekBarPreference
android:key="monet_engine_white_luminance"
android:title="@string/white_luminance_title"
android:defaultValue="425"
android:max="1000"
settings:min="1"
settings:interval="100" />
</PreferenceScreen>

View File

@@ -14,21 +14,32 @@
* limitations under the License.
*/
package com.cherish.settings.fragment
package com.cherish.settings.fragments
import androidx.preference.Preference
import com.android.internal.logging.nano.MetricsProto
import com.android.settings.dashboard.DashboardFragment
import com.cherish.settings.fragments.ColorPickerFragment
import com.cherish.settings.preferences.ColorPickerPreference
abstract class CherishDashboardFragment: DashboardFragment() {
override fun getMetricsCategory(): Int = MetricsProto.MetricsEvent.CHERISH_SETTINGS
override fun onDisplayPreferenceDialog(preference: Preference) {
super.onDisplayPreferenceDialog(preference)
if (preference is ColorPickerPreference) {
ColorPickerFragment(preference.color).apply {
setOnConfirmListener {
preference.setColor(it)
}
}.show(childFragmentManager, COLOR_PICKER_DIALOG_KEY)
} else {
super.onDisplayPreferenceDialog(preference)
}
}
companion object {
const val REQUEST_KEY = "CherishDashboardFragment#RequestKey"
const val COLOR_PICKER_DIALOG_KEY = "color_picker_dialog"
}
}

View File

@@ -0,0 +1,418 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.fragments
import android.annotation.ColorInt
import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.text.Editable
import android.text.Spanned
import android.text.InputFilter
import android.view.HapticFeedbackConstants.KEYBOARD_PRESS
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.RadioGroup
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import androidx.core.graphics.ColorUtils
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.DialogFragment.STYLE_NORMAL
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.android.settings.R
class ColorPickerFragment(
defaultColor: String? = "#FFFFFF",
) : BottomSheetDialogFragment(),
RadioGroup.OnCheckedChangeListener,
SeekBar.OnSeekBarChangeListener {
private lateinit var colorPreview: View
private lateinit var colorInput: EditText
private lateinit var seekBarOne: SeekBar
private lateinit var seekBarTwo: SeekBar
private lateinit var seekBarThree: SeekBar
private var colorModel = ColorModel.RGB
private var textInputChangedInternal = false // Internal variable to prevent loops with TextWatcher
private var confirmListener: (String) -> Unit = {}
@ColorInt
private var color: Int
init {
color = if (defaultColor == null || defaultColor.isEmpty()) {
Color.WHITE
} else {
try {
Color.parseColor(defaultColor)
} catch (e: IllegalArgumentException) {
Color.WHITE
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activity?.requestedOrientation = SCREEN_ORIENTATION_PORTRAIT
setStyle(STYLE_NORMAL, R.style.ColorPickerStyle)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.color_picker_layout, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
colorPreview = view.findViewById(R.id.color_preview)
colorInput = view.findViewById(R.id.color_input)
colorInput.doAfterTextChanged {
if (textInputChangedInternal) {
// Reset it here
textInputChangedInternal = false
return@doAfterTextChanged
}
if (it?.length != 7) return@doAfterTextChanged
color = try {
Color.parseColor(it.toString())
} catch (e: IllegalArgumentException) {
Toast.makeText(
context,
R.string.invalid_color,
Toast.LENGTH_SHORT
)
Color.WHITE
}
updateSliders()
updateSliderGradients(false)
previewColor(true)
}
colorInput.filters = arrayOf(
InputFilter.LengthFilter(7),
InputFilter filter@ { source, start, end, _, dstart, dend ->
// Deletion
if (start == 0 && end == 0) {
return@filter null
}
if (dstart == 0) {
// First character has to be # and rest of them
// (if present) be a valid hex char
if (!source.startsWith("#")) {
return@filter ""
}
// Just a single char
if (dstart == dend) return@filter null
if (!HEX_PATTERN.matches(source.subSequence(1, end))) {
return@filter ""
}
} else {
// Does not start from 0, so every char has to be valid hex
if (!HEX_PATTERN.matches(source)) {
return@filter ""
}
}
if ((end - start) == 7) { // Full hex input
if (!COLOR_HEX_PATTERN.matches(source)) {
return@filter ""
}
}
null
}
)
view.findViewById<Button>(R.id.cancel_button).setOnClickListener {
it.performHapticFeedback(KEYBOARD_PRESS)
dialog?.dismiss()
}
view.findViewById<Button>(R.id.confirm_button).setOnClickListener {
it.performHapticFeedback(KEYBOARD_PRESS)
dialog?.dismiss()
val colorHex = colorInput.text.toString()
if (colorHex.isEmpty() || colorHex.length == 7) {
confirmListener(colorHex)
}
}
/*
* Set the drawables as mutable so that they
* do not share a constant state or else all
* three slider gradients will look alike
*/
seekBarOne = view.findViewById<SeekBar>(R.id.seekBar1).also {
it.progressDrawable.mutate()
it.setOnSeekBarChangeListener(this)
}
seekBarTwo = view.findViewById<SeekBar>(R.id.seekBar2).also {
it.progressDrawable.mutate()
it.setOnSeekBarChangeListener(this)
}
seekBarThree = view.findViewById<SeekBar>(R.id.seekBar3).also {
it.progressDrawable.mutate()
it.setOnSeekBarChangeListener(this)
}
// Register listener for color model change
view.findViewById<RadioGroup>(R.id.color_model_group).also {
it.setOnCheckedChangeListener(this)
}
// Update sliders and preview
updateSliderMax()
updateSliders()
updateSliderGradients(true)
previewColor(false)
}
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (!fromUser) return
color = when (colorModel) {
ColorModel.RGB -> {
Color.rgb(
seekBarOne.progress,
seekBarTwo.progress,
seekBarThree.progress
)
}
ColorModel.HSV -> {
HSVToColor(
seekBarOne.progress.toFloat(),
seekBarTwo.progress / 100f,
seekBarThree.progress / 100f
)
}
ColorModel.HSL -> {
HSLToColor(
seekBarOne.progress.toFloat(),
seekBarTwo.progress / 100f,
seekBarThree.progress / 100f
)
}
}
if (colorModel != ColorModel.RGB) {
updateSliderGradients(false)
}
previewColor(false)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
// Not implemented
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
// Not implemented
}
override fun onCheckedChanged(group: RadioGroup, checkedId: Int) {
colorModel = when (checkedId) {
R.id.rgb_button -> ColorModel.RGB
R.id.hsv_button -> ColorModel.HSV
R.id.hsl_button -> ColorModel.HSL
else -> ColorModel.RGB
}
updateSliderMax()
updateSliders()
updateSliderGradients(true)
}
/*
* Set a confirmation listener that will be invoked when confirm
* button of the dialog is pressed.
*
* @param listener the listener to be invoked. Hex value of the
* color (including # prefix and RGB) will be the type parameter
* of the listener. Do note that the parameter can also be empty.
*/
fun setOnConfirmListener(listener: (String) -> Unit) {
confirmListener = listener
}
/**
* Used to update sliders if color model changes or
* user inputs a color hex. For the latter it must be called
* only after the accent colors are updated.
*/
private fun updateSliders() {
when (colorModel) {
ColorModel.RGB -> updateSliderProgressFromColor()
ColorModel.HSV -> {
val array = FloatArray(3)
Color.colorToHSV(color, array)
updateSliderProgressFromHSVorHSL(array)
}
ColorModel.HSL -> {
val array = FloatArray(3)
ColorUtils.colorToHSL(color, array)
updateSliderProgressFromHSVorHSL(array)
}
}
}
// For updating RGB slider progress
private fun updateSliderProgressFromColor() {
seekBarOne.progress = Color.red(color)
seekBarTwo.progress = Color.green(color)
seekBarThree.progress = Color.blue(color)
}
// For updating HSV / HSL slider progress
private fun updateSliderProgressFromHSVorHSL(hsvOrHSL: FloatArray) {
seekBarOne.progress = hsvOrHSL[0].toInt()
seekBarTwo.progress = (hsvOrHSL[1] * 100).toInt()
seekBarThree.progress = (hsvOrHSL[2] * 100).toInt()
}
// For updating the slider GradientDrawable's based on ColorModel
private fun updateSliderGradients(colorModelChanged: Boolean) {
if (colorModel == ColorModel.RGB) {
if (colorModelChanged) {
updateRGBGradient(seekBarOne.progressDrawable, Color.RED)
updateRGBGradient(seekBarTwo.progressDrawable, Color.GREEN)
updateRGBGradient(seekBarThree.progressDrawable, Color.BLUE)
}
} else {
if (colorModelChanged) {
updateHueGradient()
}
updateSaturationGradient()
if (colorModel == ColorModel.HSV) {
updateValueGradient()
} else {
updateLuminanceGradient()
}
}
}
private fun updateLuminanceGradient() {
val drawable = seekBarThree.progressDrawable as GradientDrawable
drawable.colors = intArrayOf(
Color.BLACK,
HSLToColor(
seekBarOne.progress.toFloat(),
seekBarTwo.progress / 100f,
0.5f
),
Color.WHITE,
)
}
private fun updateValueGradient() {
val drawable = seekBarThree.progressDrawable as GradientDrawable
drawable.colors = intArrayOf(
Color.BLACK,
HSVToColor(
seekBarOne.progress.toFloat(),
seekBarTwo.progress / 100f,
1f
),
)
}
private fun updateSaturationGradient() {
val drawable = seekBarTwo.progressDrawable as GradientDrawable
drawable.colors = intArrayOf(
Color.WHITE,
if (colorModel == ColorModel.HSV) {
HSVToColor(
seekBarOne.progress.toFloat(),
1f,
seekBarThree.progress / 100f
)
} else {
HSLToColor(
seekBarOne.progress.toFloat(),
1f,
seekBarThree.progress / 100f
)
}
)
}
private fun updateHueGradient() {
val drawable = seekBarOne.progressDrawable as GradientDrawable
drawable.colors = hueGradientColors
}
private fun updateRGBGradient(progressDrawable: Drawable, color: Int) {
val drawable = progressDrawable as GradientDrawable
drawable.colors = intArrayOf(Color.BLACK, color)
}
// inputFromUser should be set to true when user has entered a hex color
private fun previewColor(inputFromUser: Boolean) {
colorPreview.backgroundTintList = ColorStateList.valueOf(color)
colorInput.setTextColor(
if (ColorUtils.calculateLuminance(color) > 0.5) {
Color.BLACK
} else {
Color.WHITE
}
)
textInputChangedInternal = true
if (!inputFromUser) {
colorInput.setText(colorToHex(color))
}
}
private fun updateSliderMax() {
val isRGB = colorModel == ColorModel.RGB
seekBarOne.max = if (isRGB) 255 else 360
seekBarTwo.max = if (isRGB) 255 else 100
seekBarThree.max = if (isRGB) 255 else 100
}
private enum class ColorModel {
RGB,
HSL,
HSV
}
companion object {
private val HEX_PATTERN = Regex("[0-9a-fA-F]+")
private val COLOR_HEX_PATTERN = Regex("^[#][0-9a-fA-F]{6}")
private val hueGradientColors = IntArray(7) {
HSVToColor(it * 60f, 1f, 1f)
}
private fun HSVToColor(
hue: Float,
sat: Float,
value: Float,
): Int = Color.HSVToColor(floatArrayOf(hue, sat, value))
private fun HSLToColor(
hue: Float,
sat: Float,
lum: Float,
): Int = ColorUtils.HSLToColor(floatArrayOf(hue, sat, lum))
private fun colorToHex(color: Int) = String.format("#%06X", (0xFFFFFF and color))
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.fragments
import android.content.Context
import android.os.UserHandle
import android.provider.Settings
import androidx.preference.Preference
import com.android.settings.core.BasePreferenceController
import com.cherish.settings.preferences.CustomSeekBarPreference
class MonetChromaFactorPreferenceController(
context: Context,
key: String,
) : BasePreferenceController(context, key),
Preference.OnPreferenceChangeListener {
override fun getAvailabilityStatus(): Int = AVAILABLE
override fun updateState(preference: Preference) {
super.updateState(preference)
val chromaFactor = Settings.Secure.getFloatForUser(
mContext.contentResolver,
Settings.Secure.MONET_ENGINE_CHROMA_FACTOR,
CHROMA_DEFAULT,
UserHandle.USER_CURRENT
) * 100
(preference as CustomSeekBarPreference).apply {
setValue(chromaFactor.toInt())
}
}
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
return Settings.Secure.putFloatForUser(
mContext.contentResolver,
Settings.Secure.MONET_ENGINE_CHROMA_FACTOR,
(newValue as Int) / 100f,
UserHandle.USER_CURRENT
)
}
companion object {
private const val CHROMA_DEFAULT = 1f
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.fragments
import android.content.Context
import android.os.UserHandle
import android.provider.Settings
import com.android.settings.R
import com.android.settings.core.BasePreferenceController
class MonetCustomColorPreferenceController(
context: Context,
key: String,
) : BasePreferenceController(context, key) {
override fun getAvailabilityStatus(): Int = AVAILABLE
override fun getSummary(): CharSequence? {
val customColor = Settings.Secure.getStringForUser(
mContext.contentResolver,
Settings.Secure.MONET_ENGINE_COLOR_OVERRIDE,
UserHandle.USER_CURRENT,
)
return if (customColor == null || customColor.isBlank()) {
mContext.getString(R.string.color_override_default_summary)
} else {
mContext.getString(
R.string.custom_color_override_summary_placeholder,
customColor
)
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.fragments
import com.android.settings.R
import com.android.settings.search.BaseSearchIndexProvider
import com.android.settingslib.search.SearchIndexable
import com.cherish.settings.fragments.CherishDashboardFragment
@SearchIndexable
class MonetEngineSettings : CherishDashboardFragment() {
override protected fun getPreferenceScreenResId() = R.xml.monet_engine_settings
override protected fun getLogTag() = TAG
companion object {
private const val TAG = "MonetEngineSettings"
@JvmField
val SEARCH_INDEX_DATA_PROVIDER = BaseSearchIndexProvider(R.xml.monet_engine_settings)
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.preferences
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import androidx.preference.DialogPreference
open class ColorPickerPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
) : DialogPreference(context, attrs) {
var color: String? = null
private set
override protected fun onGetDefaultValue(a: TypedArray, index: Int): Any? {
return a.getString(index)
}
override protected fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) {
val def = defaultValue as? String
color = if (restoreValue) getPersistedString(def) else def
setSummary(color)
}
fun setColor(color: String) {
if (!callChangeListener(color)) return
this.color = color
setSummary(color)
persistString(color)
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.preferences
import android.content.Context
import android.util.AttributeSet
public class SecureSettingColorPickerPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
): ColorPickerPreference(context, attrs) {
init {
setPreferenceDataStore(SecureSettingsStore(context.contentResolver))
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2022 FlamingoOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cherish.settings.preferences
import android.content.Context
import android.util.AttributeSet
public class SystemSettingColorPickerPreference @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
): ColorPickerPreference(context, attrs) {
init {
setPreferenceDataStore(SystemSettingsStore(context.contentResolver))
}
}