feat(Zinnia): add configurable thresholds and previews for each size
Currently thresholds are unused, one day they should be hooked up to some formula based on real device pixels
This commit is contained in:
parent
e0b86e0fb4
commit
4fb5486a39
3 changed files with 89 additions and 83 deletions
|
|
@ -8,19 +8,25 @@ import com.aliucord.utils.DimenUtils.dp
|
|||
import com.discord.stores.StoreStream
|
||||
import kotlin.math.abs
|
||||
|
||||
enum class Threshold {
|
||||
Large,
|
||||
Medium,
|
||||
Small
|
||||
}
|
||||
|
||||
internal object APCAUtil {
|
||||
private val settings = ZinniaSettings
|
||||
|
||||
internal fun configureOn(view: TextView, colour: Int?) {
|
||||
internal fun configureOn(view: TextView, colour: Int?, threshold: Threshold) {
|
||||
when (settings.mode) {
|
||||
Mode.Block -> configureBlock(view, colour ?: Color.BLACK)
|
||||
Mode.Block -> configureBlock(view, colour ?: Color.BLACK, threshold)
|
||||
Mode.RoleDot -> configureRoleDot(view, colour ?: Color.BLACK)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureRoleDot(view: TextView, colour: Int) { }
|
||||
|
||||
private fun configureBlock(view: TextView, colourP: Int) {
|
||||
private fun configureBlock(view: TextView, colourP: Int, threshold: Threshold) {
|
||||
val isLight = StoreStream.getUserSettingsSystem().theme == "light"
|
||||
var colour = colourP
|
||||
val bcol = GradientDrawable()
|
||||
|
|
@ -68,10 +74,10 @@ internal object APCAUtil {
|
|||
}
|
||||
|
||||
val usePreferred = when (settings.blockMode) {
|
||||
BlockMode.ApcaOnly -> isApca(colours)
|
||||
BlockMode.ApcaOnly -> isApca(colours, threshold)
|
||||
BlockMode.WcagOnly -> isWcag(colours)
|
||||
BlockMode.ApcaLightWcagDark -> if (isLight) isApca(colours) else isWcag(colours)
|
||||
BlockMode.WcagLightApcaDark -> if (isLight) isWcag(colours) else isApca(colours)
|
||||
BlockMode.ApcaLightWcagDark -> if (isLight) isApca(colours, threshold) else isWcag(colours)
|
||||
BlockMode.WcagLightApcaDark -> if (isLight) isWcag(colours) else isApca(colours, threshold)
|
||||
BlockMode.ThemeOnly,
|
||||
BlockMode.InvertedThemeOnly,
|
||||
BlockMode.WhiteOnly,
|
||||
|
|
@ -90,10 +96,15 @@ internal object APCAUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private fun isApca(c: Colours): Boolean {
|
||||
private fun isApca(c: Colours, threshold: Threshold): Boolean {
|
||||
val cPref = abs(APCA.contrast(c.fgP, c.bgP))
|
||||
val cOth = abs(APCA.contrast(c.fgO, c.bgO))
|
||||
return cPref > settings.blockApcaThreshold || cPref > cOth
|
||||
val thresholdValue = when (threshold) {
|
||||
Threshold.Large -> settings.blockApcaThresholdLarge
|
||||
Threshold.Medium -> settings.blockApcaThresholdMedium
|
||||
Threshold.Small -> settings.blockApcaThresholdSmall
|
||||
}
|
||||
return cPref > thresholdValue || cPref > cOth
|
||||
}
|
||||
|
||||
private fun isWcag(c: Colours): Boolean {
|
||||
|
|
@ -101,5 +112,4 @@ internal object APCAUtil {
|
|||
val cOth = ColorUtils.calculateContrast(c.fgO, c.bgO)
|
||||
return cPref > settings.blockWcagThreshold || cPref > cOth
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class Zinnia : Plugin() {
|
|||
}
|
||||
}
|
||||
|
||||
APCAUtil.configureOn(usernameTextView, member.color)
|
||||
APCAUtil.configureOn(usernameTextView, member.color, Threshold.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ class Zinnia : Plugin() {
|
|||
) { (_, _: Int, entry: MessageEntry) ->
|
||||
val username = itemView.findViewById<TextView?>("chat_list_adapter_item_text_name")
|
||||
?: return@after
|
||||
APCAUtil.configureOn(username, entry.author?.color)
|
||||
APCAUtil.configureOn(username, entry.author?.color, Threshold.Large)
|
||||
}
|
||||
|
||||
// Configures for reply preview username
|
||||
|
|
@ -86,7 +86,7 @@ class Zinnia : Plugin() {
|
|||
val referencedAuthor = entry.replyData?.messageEntry?.author
|
||||
val replyUsername = itemView.findViewById<TextView?>("chat_list_adapter_item_text_decorator_reply_name")
|
||||
?: return@after
|
||||
APCAUtil.configureOn(replyUsername, referencedAuthor?.color)
|
||||
APCAUtil.configureOn(replyUsername, referencedAuthor?.color, Threshold.Small)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package moe.lava.awoocord.zinnia
|
||||
|
||||
import android.graphics.Color
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
|
|
@ -18,7 +19,6 @@ import com.aliucord.wrappers.users.globalName
|
|||
import com.discord.stores.StoreStream
|
||||
import com.discord.utilities.color.ColorCompat
|
||||
import com.discord.views.CheckedSetting
|
||||
import com.discord.views.RadioManager
|
||||
import com.lytefast.flexinput.R
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
|
|
@ -94,22 +94,18 @@ object ZinniaSettings {
|
|||
|
||||
var mode by reactive { api.delegateEnum(Mode.Block) }
|
||||
|
||||
var dotKeepNameColour by reactive { api.delegate(false) }
|
||||
|
||||
var blockAlsoDefault by reactive { api.delegate(true) }
|
||||
var blockInverted by reactive { api.delegate(false) }
|
||||
var blockMode by reactive { api.delegateEnum(BlockMode.ApcaLightWcagDark) }
|
||||
var blockApcaThreshold by reactive { api.delegate(45.0f) }
|
||||
var blockApcaThresholdLarge by reactive { api.delegate(45.0f) }
|
||||
var blockApcaThresholdMedium by reactive { api.delegate(45.0f) }
|
||||
var blockApcaThresholdSmall by reactive { api.delegate(45.0f) }
|
||||
var blockWcagThreshold by reactive { api.delegate(4.5f) }
|
||||
|
||||
private val _alpha = reactive { api.delegate("alpha", 255) }
|
||||
var alpha by _alpha
|
||||
|
||||
class Page : SettingsPage() {
|
||||
private lateinit var manager: RadioManager
|
||||
private lateinit var mRoleDot: CheckedSetting
|
||||
private lateinit var mBlock: CheckedSetting
|
||||
|
||||
private val checks = mutableListOf<CheckedSetting>()
|
||||
|
||||
private val _previewH = reactive { basicDelegate(0) }
|
||||
|
|
@ -119,7 +115,7 @@ object ZinniaSettings {
|
|||
private val _previewV = reactive { basicDelegate(100) }
|
||||
private var previewV by _previewV
|
||||
|
||||
private fun createRadio(newMode: BlockMode, text: String, subtext: String? = null): CheckedSetting {
|
||||
private fun addRadio(newMode: BlockMode, text: String, subtext: String? = null): CheckedSetting {
|
||||
return Utils.createCheckedSetting(requireContext(), CheckedSetting.ViewType.RADIO, text, subtext).addTo(linearLayout) {
|
||||
isChecked = blockMode == newMode
|
||||
setOnCheckedListener {
|
||||
|
|
@ -131,7 +127,18 @@ object ZinniaSettings {
|
|||
}
|
||||
}
|
||||
|
||||
private fun createSlider(
|
||||
private fun createLabel(text: String? = null): TextView {
|
||||
return TextView(context, null, 0, R.i.UiKit_TextView).apply {
|
||||
textSize = 16.0f
|
||||
typeface = ResourcesCompat.getFont(context, Constants.Fonts.whitney_medium)
|
||||
this.text = text
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
bottomMargin = 4.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSlider(
|
||||
min: Int,
|
||||
max: Int,
|
||||
initial: Int = min,
|
||||
|
|
@ -140,14 +147,7 @@ object ZinniaSettings {
|
|||
var pendingValue = initial
|
||||
return LinearLayout(requireContext(), null, 0, R.i.UiKit_Settings_Item).addTo(linearLayout) {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
val display = TextView(context, null, 0, R.i.UiKit_TextView).addTo(this) {
|
||||
textSize = 16.0f
|
||||
typeface = ResourcesCompat.getFont(context, Constants.Fonts.whitney_medium)
|
||||
text = onChange(initial, false)
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
bottomMargin = 4.dp
|
||||
}
|
||||
}
|
||||
val display = createLabel(onChange(initial, false)).addTo(this)
|
||||
SeekBar(context, null, 0, R.i.UiKit_SeekBar).addTo(this) {
|
||||
this.max = max - min
|
||||
progress = initial
|
||||
|
|
@ -171,15 +171,39 @@ object ZinniaSettings {
|
|||
}
|
||||
}
|
||||
|
||||
private fun createSlider(binding: Delegate<Int>, min: Int, max: Int, immediate: Boolean = false, label: (Int) -> String): LinearLayout {
|
||||
private fun addSlider(binding: Delegate<Int>, min: Int, max: Int, immediate: Boolean = false, label: (Int) -> String): LinearLayout {
|
||||
var value by binding
|
||||
return createSlider(min, max, value) { newValue, commit ->
|
||||
return addSlider(min, max, value) { newValue, commit ->
|
||||
@Suppress("AssignedValueIsNeverRead") // kt so dumb
|
||||
if (immediate || commit) value = newValue
|
||||
label(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPreview(
|
||||
label: String,
|
||||
styleRes: Int,
|
||||
): TextView {
|
||||
val ctx = requireContext()
|
||||
val view = TextView(ctx, null, 0, styleRes).apply {
|
||||
val me = StoreStream.getUsers().me
|
||||
text = me.globalName ?: me.username
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
marginStart = 16.dp
|
||||
marginEnd = 16.dp
|
||||
}
|
||||
}
|
||||
LinearLayout(ctx, null, 0, R.i.UiKit_Settings_Item).addTo(linearLayout) {
|
||||
view.addTo(this)
|
||||
createLabel(label).addTo(this) {
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
bottomMargin = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
onStateUpdate = {}
|
||||
super.onDestroyView()
|
||||
|
|
@ -196,42 +220,12 @@ object ZinniaSettings {
|
|||
val roleDotSettings = mutableListOf<CheckedSetting>()
|
||||
|
||||
addHeader(ctx, "Text colour")
|
||||
createRadio(BlockMode.ApcaLightWcagDark, "Automatic", "Adjusts text colour based on optimal contrast with role colour")
|
||||
createRadio(BlockMode.ThemeOnly, "By theme", "Adjusts text colour based on system theme (dark/light)")
|
||||
createRadio(BlockMode.InvertedThemeOnly, "By theme (inverted)", "Same as above, but inverted")
|
||||
createRadio(BlockMode.WhiteOnly, "White", "Force text colour to be white")
|
||||
createRadio(BlockMode.BlackOnly, "Black", "Force text colour to be black")
|
||||
createRadio(BlockMode.Unchanged, "Unchanged", "Keep text colour; ideal for using with a translucent block")
|
||||
|
||||
/*
|
||||
addHeader(ctx, "Mode")
|
||||
|
||||
mBlock = Utils.createCheckedSetting(
|
||||
ctx,
|
||||
CheckedSetting.ViewType.RADIO,
|
||||
"Block mode",
|
||||
"Wraps the username in a coloured block",
|
||||
).addTo(this) {
|
||||
isChecked = mode == Mode.Block
|
||||
setOnCheckedListener {
|
||||
mode = Mode.Block
|
||||
mRoleDot.isChecked = false
|
||||
}
|
||||
}
|
||||
|
||||
mRoleDot = Utils.createCheckedSetting(
|
||||
ctx,
|
||||
CheckedSetting.ViewType.RADIO,
|
||||
"Role dot mode",
|
||||
"Adds a coloured role dot next to the username, similar to how Discord does it in their new accessibility settings",
|
||||
).addTo(this) {
|
||||
isChecked = mode == Mode.RoleDot
|
||||
setOnCheckedListener {
|
||||
mode = Mode.RoleDot
|
||||
mBlock.isChecked = false
|
||||
}
|
||||
}
|
||||
*/
|
||||
addRadio(BlockMode.ApcaLightWcagDark, "Automatic", "Adjusts text colour based on optimal contrast with role colour")
|
||||
addRadio(BlockMode.ThemeOnly, "By theme", "Adjusts text colour based on system theme (dark/light)")
|
||||
addRadio(BlockMode.InvertedThemeOnly, "By theme (inverted)", "Same as above, but inverted")
|
||||
addRadio(BlockMode.WhiteOnly, "White", "Force text colour to be white")
|
||||
addRadio(BlockMode.BlackOnly, "Black", "Force text colour to be black")
|
||||
addRadio(BlockMode.Unchanged, "Unchanged", "Keep text colour; ideal for using with a translucent block")
|
||||
|
||||
addHeader(ctx, "Block Settings")
|
||||
|
||||
|
|
@ -248,7 +242,7 @@ object ZinniaSettings {
|
|||
blockSettings.add(this)
|
||||
}
|
||||
|
||||
createSlider(_alpha, 0, 255, true) { "Alpha: ${(it / 2.55f).roundToInt()}%" }
|
||||
addSlider(_alpha, 0, 255, true) { "Alpha: ${(it / 2.55f).roundToInt()}%" }
|
||||
|
||||
// createSlider(0, 255, blockApcaThreshold.roundToInt()) { value, commit ->
|
||||
// blockApcaThreshold = value.toFloat()
|
||||
|
|
@ -256,26 +250,27 @@ object ZinniaSettings {
|
|||
// }
|
||||
|
||||
addHeader(ctx, "Preview")
|
||||
val preview = TextView(ctx, null, 0, R.i.UiKit_TextView_Large_SingleLine).addTo(this) {
|
||||
val me = StoreStream.getUsers().me
|
||||
text = me.globalName ?: me.username
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
|
||||
marginStart = 16.dp
|
||||
marginEnd = 16.dp
|
||||
}
|
||||
}
|
||||
val previews = mutableListOf(
|
||||
Threshold.Large to createPreview("Message header username", R.i.UiKit_TextView_Large_SingleLine),
|
||||
Threshold.Medium to createPreview("Channels list", R.i.UiKit_TextView).apply {
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.d.uikit_textsize_medium))
|
||||
},
|
||||
Threshold.Small to createPreview("Message reply username", R.i.UiKit_TextView).apply {
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.d.uikit_textsize_small))
|
||||
},
|
||||
)
|
||||
|
||||
val hsv = floatArrayOf(0f, 0f, 0f)
|
||||
Color.colorToHSV(ColorCompat.getThemedColor(this, R.b.color_brand), hsv)
|
||||
previewH = hsv[0].roundToInt()
|
||||
previewS = (hsv[1] * 100).roundToInt()
|
||||
previewV = (hsv[2] * 100).roundToInt()
|
||||
createSlider(_previewH, 0, 360, true) { "Hue: $it" }
|
||||
createSlider(_previewS, 0, 100, true) { "Saturation: $it%" }
|
||||
createSlider(_previewV, 0, 100, true) { "Value: $it%" }
|
||||
addSlider(_previewH, 0, 360, true) { "Hue: $it" }
|
||||
addSlider(_previewS, 0, 100, true) { "Saturation: $it%" }
|
||||
addSlider(_previewV, 0, 100, true) { "Value: $it%" }
|
||||
|
||||
onStateUpdate = {
|
||||
updatePreview(preview)
|
||||
previews.forEach { updatePreview(it) }
|
||||
if (blockMode != BlockMode.Unchanged) {
|
||||
invertSwitch.l.b().isClickable = true
|
||||
invertSwitch.alpha = 1f
|
||||
|
|
@ -288,9 +283,10 @@ object ZinniaSettings {
|
|||
}
|
||||
}
|
||||
|
||||
fun updatePreview(preview: TextView) {
|
||||
fun updatePreview(pair: Pair<Threshold, TextView>) {
|
||||
val (threshold, preview) = pair
|
||||
val colour = Color.HSVToColor(floatArrayOf(previewH.toFloat(), previewS / 100f, previewV / 100f))
|
||||
APCAUtil.configureOn(preview, colour)
|
||||
APCAUtil.configureOn(preview, colour, threshold)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue