Cherish: Monet settings
Signed-off-by: Hưng Phan <phandinhhungvp2001@gmail.com>
This commit is contained in:
5
res/drawable/color_picker_preview_background.xml
Normal file
5
res/drawable/color_picker_preview_background.xml
Normal 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>
|
||||
5
res/drawable/color_picker_seekbar_background.xml
Normal file
5
res/drawable/color_picker_seekbar_background.xml
Normal 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>
|
||||
11
res/drawable/color_picker_seekbar_thumb.xml
Normal file
11
res/drawable/color_picker_seekbar_thumb.xml
Normal 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>
|
||||
135
res/layout/color_picker_layout.xml
Normal file
135
res/layout/color_picker_layout.xml
Normal 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>
|
||||
22
res/values-night/styles.xml
Normal file
22
res/values-night/styles.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
55
res/xml/monet_engine_settings.xml
Normal file
55
res/xml/monet_engine_settings.xml
Normal 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>
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
418
src/com/cherish/settings/fragments/ColorPickerFragment.kt
Normal file
418
src/com/cherish/settings/fragments/ColorPickerFragment.kt
Normal 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))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/com/cherish/settings/fragments/MonetEngineSettings.kt
Normal file
37
src/com/cherish/settings/fragments/MonetEngineSettings.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user