Reduce duplicated cleanup code
This commit is contained in:
@@ -394,44 +394,40 @@ internal class AospLauncherTaskbarHooks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun performAction(controller: Any?, action: NavButtonAction) {
|
private fun performAction(controller: Any?, action: NavButtonAction) {
|
||||||
when (action) {
|
val handled = when (action) {
|
||||||
NavButtonAction.STOCK,
|
NavButtonAction.STOCK,
|
||||||
NavButtonAction.NONE,
|
NavButtonAction.NONE,
|
||||||
-> Unit
|
-> true
|
||||||
|
|
||||||
NavButtonAction.BACK -> {
|
NavButtonAction.BACK ->
|
||||||
if (!callTaskbarMethod(controller, "executeBack", arrayOf(KeyEvent::class.java), null)) {
|
callTaskbarMethod(controller, "executeBack", arrayOf(KeyEvent::class.java), null)
|
||||||
actions.perform(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavButtonAction.HOME -> {
|
NavButtonAction.HOME ->
|
||||||
if (!callTaskbarMethod(controller, "navigateHome", emptyArray())) {
|
callTaskbarMethod(controller, "navigateHome", emptyArray())
|
||||||
actions.perform(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavButtonAction.ASSISTANT -> {
|
NavButtonAction.ASSISTANT ->
|
||||||
if (!callTaskbarMethod(controller, "onLongPressHome", emptyArray())) {
|
callTaskbarMethod(controller, "onLongPressHome", emptyArray())
|
||||||
actions.perform(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavButtonAction.RECENTS -> {
|
NavButtonAction.RECENTS ->
|
||||||
if (!callTaskbarMethod(controller, "navigateToOverview", emptyArray())) {
|
callTaskbarMethod(controller, "navigateToOverview", emptyArray())
|
||||||
actions.perform(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavButtonAction.KILL_FOREGROUND_APP -> {
|
NavButtonAction.KILL_FOREGROUND_APP -> {
|
||||||
requestPrivilegedAction(PRIVILEGED_ACTION_KILL_FOREGROUND_APP, null)
|
requestPrivilegedAction(PRIVILEGED_ACTION_KILL_FOREGROUND_APP, null)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
NavButtonAction.TOGGLE_FLASHLIGHT -> {
|
NavButtonAction.TOGGLE_FLASHLIGHT -> {
|
||||||
requestPrivilegedAction(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT, null)
|
requestPrivilegedAction(PRIVILEGED_ACTION_TOGGLE_FLASHLIGHT, null)
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
NavButtonAction.TOGGLE_AUTO_ROTATE -> actions.perform(action)
|
NavButtonAction.TOGGLE_AUTO_ROTATE -> {
|
||||||
|
actions.perform(action)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!handled) {
|
||||||
|
actions.perform(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,58 +126,29 @@ internal fun callIntIntMethodIfExists(
|
|||||||
second: Int,
|
second: Int,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
methodNames.forEach { methodName ->
|
methodNames.forEach { methodName ->
|
||||||
findMethodsNamed(target.javaClass, methodName)
|
optionalMethod(target, methodName) { types ->
|
||||||
.firstOrNull { method ->
|
types.size >= 2 && types[0] == Int::class.javaPrimitiveType && types[1] == Int::class.javaPrimitiveType
|
||||||
val types = method.parameterTypes
|
}?.let { method -> return invokeOptional(method, target, first, second) }
|
||||||
types.size >= 2 &&
|
|
||||||
types[0] == Int::class.javaPrimitiveType &&
|
|
||||||
types[1] == Int::class.javaPrimitiveType
|
|
||||||
}
|
|
||||||
?.let { method ->
|
|
||||||
return try {
|
|
||||||
method.invoke(target, first, second)
|
|
||||||
true
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callIntMethodIfExists(target: Any, methodName: String, value: Int): Boolean {
|
internal fun callIntMethodIfExists(target: Any, methodName: String, value: Int): Boolean {
|
||||||
return findMethodsNamed(target.javaClass, methodName)
|
return invokeOptional(target, methodName, value) { types ->
|
||||||
.firstOrNull { method ->
|
|
||||||
val types = method.parameterTypes
|
|
||||||
types.size == 1 && types[0] == Int::class.javaPrimitiveType
|
types.size == 1 && types[0] == Int::class.javaPrimitiveType
|
||||||
}
|
}
|
||||||
?.let { method ->
|
|
||||||
runCatching { method.invoke(target, value) }.isSuccess
|
|
||||||
} == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callIntIntMethodIfExists(target: Any, methodName: String, first: Int, second: Int): Boolean {
|
internal fun callIntIntMethodIfExists(target: Any, methodName: String, first: Int, second: Int): Boolean {
|
||||||
return findMethodsNamed(target.javaClass, methodName)
|
return invokeOptional(target, methodName, first, second) { types ->
|
||||||
.firstOrNull { method ->
|
types.size == 2 && types[0] == Int::class.javaPrimitiveType && types[1] == Int::class.javaPrimitiveType
|
||||||
val types = method.parameterTypes
|
|
||||||
types.size == 2 &&
|
|
||||||
types[0] == Int::class.javaPrimitiveType &&
|
|
||||||
types[1] == Int::class.javaPrimitiveType
|
|
||||||
}
|
}
|
||||||
?.let { method ->
|
|
||||||
runCatching { method.invoke(target, first, second) }.isSuccess
|
|
||||||
} == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callFloatMethodIfExists(target: Any, methodName: String, value: Float): Boolean {
|
internal fun callFloatMethodIfExists(target: Any, methodName: String, value: Float): Boolean {
|
||||||
return findMethodsNamed(target.javaClass, methodName)
|
return invokeOptional(target, methodName, value) { types ->
|
||||||
.firstOrNull { method ->
|
|
||||||
val types = method.parameterTypes
|
|
||||||
types.size == 1 && types[0] == Float::class.javaPrimitiveType
|
types.size == 1 && types[0] == Float::class.javaPrimitiveType
|
||||||
}
|
}
|
||||||
?.let { method ->
|
|
||||||
runCatching { method.invoke(target, value) }.isSuccess
|
|
||||||
} == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callSetButtonImageIfExists(
|
internal fun callSetButtonImageIfExists(
|
||||||
@@ -186,36 +157,47 @@ internal fun callSetButtonImageIfExists(
|
|||||||
lightDrawable: Drawable,
|
lightDrawable: Drawable,
|
||||||
darkDrawable: Drawable,
|
darkDrawable: Drawable,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return findMethodsNamed(target.javaClass, "setButtonImage")
|
return invokeOptional(target, "setButtonImage", id, lightDrawable, darkDrawable) { types ->
|
||||||
.firstOrNull { method ->
|
|
||||||
val types = method.parameterTypes
|
|
||||||
types.size == 3 &&
|
types.size == 3 &&
|
||||||
types[0] == Int::class.javaPrimitiveType &&
|
types[0] == Int::class.javaPrimitiveType &&
|
||||||
Drawable::class.java.isAssignableFrom(types[1]) &&
|
Drawable::class.java.isAssignableFrom(types[1]) &&
|
||||||
Drawable::class.java.isAssignableFrom(types[2])
|
Drawable::class.java.isAssignableFrom(types[2])
|
||||||
}
|
}
|
||||||
?.let { method ->
|
|
||||||
runCatching { method.invoke(target, id, lightDrawable, darkDrawable) }.isSuccess
|
|
||||||
} == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callMethodIfExists(target: Any, methodName: String): Any? {
|
internal fun callMethodIfExists(target: Any, methodName: String): Any? {
|
||||||
return findMethodsNamed(target.javaClass, methodName)
|
return optionalMethod(target, methodName) { it.isEmpty() }
|
||||||
.firstOrNull { method -> method.parameterTypes.isEmpty() }
|
|
||||||
?.let { method ->
|
?.let { method ->
|
||||||
runCatching { method.invoke(target) }.getOrNull()
|
runCatching { method.invoke(target) }.getOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun callBooleanMethodIfExists(target: Any, methodName: String, value: Boolean): Boolean {
|
internal fun callBooleanMethodIfExists(target: Any, methodName: String, value: Boolean): Boolean {
|
||||||
return findMethodsNamed(target.javaClass, methodName)
|
return invokeOptional(target, methodName, value) { types ->
|
||||||
.firstOrNull { method ->
|
|
||||||
val types = method.parameterTypes
|
|
||||||
types.size == 1 && types[0] == Boolean::class.javaPrimitiveType
|
types.size == 1 && types[0] == Boolean::class.javaPrimitiveType
|
||||||
}
|
}
|
||||||
?.let { method ->
|
}
|
||||||
runCatching { method.invoke(target, value) }.isSuccess
|
|
||||||
} ?: false
|
private fun optionalMethod(
|
||||||
|
target: Any,
|
||||||
|
methodName: String,
|
||||||
|
accepts: (Array<Class<*>>) -> Boolean,
|
||||||
|
): Method? {
|
||||||
|
return findMethodsNamed(target.javaClass, methodName).firstOrNull { accepts(it.parameterTypes) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invokeOptional(
|
||||||
|
target: Any,
|
||||||
|
methodName: String,
|
||||||
|
vararg args: Any?,
|
||||||
|
accepts: (Array<Class<*>>) -> Boolean,
|
||||||
|
): Boolean {
|
||||||
|
val method = optionalMethod(target, methodName, accepts) ?: return false
|
||||||
|
return invokeOptional(method, target, *args)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invokeOptional(method: Method, target: Any, vararg args: Any?): Boolean {
|
||||||
|
return runCatching { method.invoke(target, *args) }.isSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getFieldValue(target: Any?, fieldName: String): Any? {
|
internal fun getFieldValue(target: Any?, fieldName: String): Any? {
|
||||||
|
|||||||
@@ -224,6 +224,77 @@ class SettingsActivity : Activity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun EditText.afterTextChanged(onChanged: (String) -> Unit) {
|
||||||
|
addTextChangedListener(object : TextWatcher {
|
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||||
|
override fun afterTextChanged(editable: Editable?) = onChanged(editable?.toString().orEmpty())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class NumericField(
|
||||||
|
private val input: EditText,
|
||||||
|
private val minusButton: Button,
|
||||||
|
private val plusButton: Button,
|
||||||
|
private val step: Float,
|
||||||
|
private val parse: (String) -> Float?,
|
||||||
|
private val sanitize: (Float) -> Float,
|
||||||
|
private val format: (Float) -> String,
|
||||||
|
private val persist: (Float) -> Unit,
|
||||||
|
) {
|
||||||
|
private var lastValid = 0f
|
||||||
|
private var updatingText = false
|
||||||
|
|
||||||
|
fun bind(initialValue: Float) {
|
||||||
|
apply(initialValue, persist = false)
|
||||||
|
input.setOnFocusChangeListener { _, hasFocus ->
|
||||||
|
if (!hasFocus) {
|
||||||
|
normalize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input.afterTextChanged { text ->
|
||||||
|
if (updatingText) {
|
||||||
|
return@afterTextChanged
|
||||||
|
}
|
||||||
|
val parsed = parse(text) ?: return@afterTextChanged
|
||||||
|
if (parsed == sanitize(parsed)) {
|
||||||
|
lastValid = parsed
|
||||||
|
persist(parsed)
|
||||||
|
sendSettingsChangedBroadcast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachRepeatButton(minusButton) { adjust(-step) }
|
||||||
|
attachRepeatButton(plusButton) { adjust(step) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun normalize(): Float {
|
||||||
|
val normalized = sanitize(parse(input.text.toString()) ?: lastValid)
|
||||||
|
apply(normalized, persist = true)
|
||||||
|
return normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adjust(delta: Float) {
|
||||||
|
apply(normalize() + delta, persist = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun apply(value: Float, persist: Boolean) {
|
||||||
|
val sanitized = sanitize(value)
|
||||||
|
val text = format(sanitized)
|
||||||
|
updatingText = true
|
||||||
|
if (input.text.toString() != text) {
|
||||||
|
input.setText(text)
|
||||||
|
input.setSelection(input.text.length)
|
||||||
|
}
|
||||||
|
updatingText = false
|
||||||
|
|
||||||
|
lastValid = sanitized
|
||||||
|
if (persist) {
|
||||||
|
persist(sanitized)
|
||||||
|
sendSettingsChangedBroadcast()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inner class NavButtonSectionController(
|
private inner class NavButtonSectionController(
|
||||||
sectionView: View,
|
sectionView: View,
|
||||||
private val buttonId: NavButtonId,
|
private val buttonId: NavButtonId,
|
||||||
@@ -237,8 +308,7 @@ class SettingsActivity : Activity() {
|
|||||||
private val plusButton: Button = sectionView.findViewById(R.id.plus_button)
|
private val plusButton: Button = sectionView.findViewById(R.id.plus_button)
|
||||||
private val testButton: Button = sectionView.findViewById(R.id.test_button)
|
private val testButton: Button = sectionView.findViewById(R.id.test_button)
|
||||||
|
|
||||||
private var lastValidDurationMs = settingsStore.defaultLongPressDurationMs()
|
private lateinit var durationField: NumericField
|
||||||
private var updatingDurationText = false
|
|
||||||
|
|
||||||
fun bind() {
|
fun bind() {
|
||||||
val config = settingsStore.getConfig(buttonId)
|
val config = settingsStore.getConfig(buttonId)
|
||||||
@@ -255,10 +325,14 @@ class SettingsActivity : Activity() {
|
|||||||
settingsStore::setLongPressAction,
|
settingsStore::setLongPressAction,
|
||||||
)
|
)
|
||||||
|
|
||||||
applyDuration(config.longPressDurationMs, persist = false)
|
durationField = durationField(
|
||||||
bindDurationInput()
|
durationInput,
|
||||||
bindStepButtons()
|
minusButton,
|
||||||
attachTestButton(testButton, ::resolveDurationForUse)
|
plusButton,
|
||||||
|
persist = { settingsStore.setLongPressDurationMs(buttonId, it) },
|
||||||
|
)
|
||||||
|
durationField.bind(config.longPressDurationMs.toFloat())
|
||||||
|
attachTestButton(testButton) { durationField.normalize().toInt() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindActionSpinner(
|
private fun bindActionSpinner(
|
||||||
@@ -276,89 +350,6 @@ class SettingsActivity : Activity() {
|
|||||||
sendSettingsChangedBroadcast()
|
sendSettingsChangedBroadcast()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindDurationInput() {
|
|
||||||
durationInput.setOnFocusChangeListener { _, hasFocus ->
|
|
||||||
if (!hasFocus) {
|
|
||||||
normalizeTypedDuration()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
durationInput.addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
count: Int,
|
|
||||||
after: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun onTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
before: Int,
|
|
||||||
count: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun afterTextChanged(editable: Editable?) {
|
|
||||||
if (updatingDurationText) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val parsed = editable?.toString()?.toIntOrNull() ?: return
|
|
||||||
if (parsed in NavButtonSettingsStore.MIN_DURATION_MS..NavButtonSettingsStore.MAX_DURATION_MS) {
|
|
||||||
lastValidDurationMs = parsed
|
|
||||||
settingsStore.setLongPressDurationMs(buttonId, parsed)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindStepButtons() {
|
|
||||||
attachRepeatButton(minusButton) {
|
|
||||||
adjustDuration(-NavButtonSettingsStore.DURATION_STEP_MS)
|
|
||||||
}
|
|
||||||
attachRepeatButton(plusButton) {
|
|
||||||
adjustDuration(NavButtonSettingsStore.DURATION_STEP_MS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun adjustDuration(deltaMs: Int) {
|
|
||||||
val current = resolveDurationForUse()
|
|
||||||
val updated = (current + deltaMs).coerceIn(
|
|
||||||
NavButtonSettingsStore.MIN_DURATION_MS,
|
|
||||||
NavButtonSettingsStore.MAX_DURATION_MS,
|
|
||||||
)
|
|
||||||
applyDuration(updated, persist = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun normalizeTypedDuration(): Int {
|
|
||||||
val parsed = durationInput.text.toString().toIntOrNull() ?: lastValidDurationMs
|
|
||||||
val normalized = settingsStore.sanitizeDuration(parsed)
|
|
||||||
applyDuration(normalized, persist = true)
|
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveDurationForUse(): Int {
|
|
||||||
return normalizeTypedDuration()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyDuration(durationMs: Int, persist: Boolean) {
|
|
||||||
val sanitized = settingsStore.sanitizeDuration(durationMs)
|
|
||||||
val text = sanitized.toString()
|
|
||||||
updatingDurationText = true
|
|
||||||
if (durationInput.text.toString() != text) {
|
|
||||||
durationInput.setText(text)
|
|
||||||
durationInput.setSelection(durationInput.text.length)
|
|
||||||
}
|
|
||||||
updatingDurationText = false
|
|
||||||
|
|
||||||
lastValidDurationMs = sanitized
|
|
||||||
if (persist) {
|
|
||||||
settingsStore.setLongPressDurationMs(buttonId, sanitized)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class SideArrowsSectionController(sectionView: View) {
|
private inner class SideArrowsSectionController(sectionView: View) {
|
||||||
@@ -384,21 +375,31 @@ class SettingsActivity : Activity() {
|
|||||||
private val testButton: Button = sectionView.findViewById(R.id.side_arrow_test_button)
|
private val testButton: Button = sectionView.findViewById(R.id.side_arrow_test_button)
|
||||||
|
|
||||||
private val decimalSeparator = DecimalFormatSymbols.getInstance().decimalSeparator
|
private val decimalSeparator = DecimalFormatSymbols.getInstance().decimalSeparator
|
||||||
private var lastValidDurationMs = settingsStore.defaultLongPressDurationMs()
|
private lateinit var durationField: NumericField
|
||||||
private var lastValidRepeatSpeed = NavButtonSettingsStore.DEFAULT_SIDE_ARROW_REPEAT_STEPS_PER_SECOND
|
private lateinit var repeatSpeedField: NumericField
|
||||||
private var updatingDurationText = false
|
|
||||||
private var updatingRepeatSpeedText = false
|
|
||||||
|
|
||||||
fun bind() {
|
fun bind() {
|
||||||
sideArrowsCheckbox.isChecked = settingsStore.isSideArrowsEnabled()
|
sideArrowsCheckbox.isChecked = settingsStore.isSideArrowsEnabled()
|
||||||
bindLongPressActionSpinner()
|
bindLongPressActionSpinner()
|
||||||
applyRepeatSpeed(settingsStore.getSideArrowRepeatStepsPerSecond(), persist = false)
|
repeatSpeedField = NumericField(
|
||||||
bindRepeatSpeedInput()
|
repeatSpeedInput,
|
||||||
bindRepeatSpeedButtons()
|
speedMinusButton,
|
||||||
applyDuration(settingsStore.getSideArrowLongPressDurationMs(), persist = false)
|
speedPlusButton,
|
||||||
bindDurationInput()
|
NavButtonSettingsStore.SIDE_ARROW_REPEAT_SPEED_STEP,
|
||||||
bindDurationButtons()
|
parse = ::parseRepeatSpeed,
|
||||||
attachTestButton(testButton, ::resolveDurationForUse)
|
sanitize = settingsStore::sanitizeSideArrowRepeatSpeed,
|
||||||
|
format = ::formatRepeatSpeed,
|
||||||
|
persist = settingsStore::setSideArrowRepeatStepsPerSecond,
|
||||||
|
)
|
||||||
|
repeatSpeedField.bind(settingsStore.getSideArrowRepeatStepsPerSecond())
|
||||||
|
durationField = durationField(
|
||||||
|
durationInput,
|
||||||
|
durationMinusButton,
|
||||||
|
durationPlusButton,
|
||||||
|
persist = settingsStore::setSideArrowLongPressDurationMs,
|
||||||
|
)
|
||||||
|
durationField.bind(settingsStore.getSideArrowLongPressDurationMs().toFloat())
|
||||||
|
attachTestButton(testButton) { durationField.normalize().toInt() }
|
||||||
updateOptionsEnabled()
|
updateOptionsEnabled()
|
||||||
|
|
||||||
sideArrowsCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
sideArrowsCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||||
@@ -422,100 +423,6 @@ class SettingsActivity : Activity() {
|
|||||||
updateRepeatSpeedVisibility(settingsStore.getSideArrowLongPressAction())
|
updateRepeatSpeedVisibility(settingsStore.getSideArrowLongPressAction())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindRepeatSpeedInput() {
|
|
||||||
repeatSpeedInput.setOnFocusChangeListener { _, hasFocus ->
|
|
||||||
if (!hasFocus) {
|
|
||||||
normalizeTypedRepeatSpeed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repeatSpeedInput.addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
count: Int,
|
|
||||||
after: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun onTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
before: Int,
|
|
||||||
count: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun afterTextChanged(editable: Editable?) {
|
|
||||||
if (updatingRepeatSpeedText) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val parsed = parseRepeatSpeed(editable?.toString()) ?: return
|
|
||||||
if (parsed in NavButtonSettingsStore.MIN_SIDE_ARROW_REPEAT_STEPS_PER_SECOND..
|
|
||||||
NavButtonSettingsStore.MAX_SIDE_ARROW_REPEAT_STEPS_PER_SECOND
|
|
||||||
) {
|
|
||||||
lastValidRepeatSpeed = parsed
|
|
||||||
settingsStore.setSideArrowRepeatStepsPerSecond(parsed)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindRepeatSpeedButtons() {
|
|
||||||
attachRepeatButton(speedMinusButton) {
|
|
||||||
adjustRepeatSpeed(-NavButtonSettingsStore.SIDE_ARROW_REPEAT_SPEED_STEP)
|
|
||||||
}
|
|
||||||
attachRepeatButton(speedPlusButton) {
|
|
||||||
adjustRepeatSpeed(NavButtonSettingsStore.SIDE_ARROW_REPEAT_SPEED_STEP)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindDurationInput() {
|
|
||||||
durationInput.setOnFocusChangeListener { _, hasFocus ->
|
|
||||||
if (!hasFocus) {
|
|
||||||
normalizeTypedDuration()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
durationInput.addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
count: Int,
|
|
||||||
after: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun onTextChanged(
|
|
||||||
s: CharSequence?,
|
|
||||||
start: Int,
|
|
||||||
before: Int,
|
|
||||||
count: Int,
|
|
||||||
) = Unit
|
|
||||||
|
|
||||||
override fun afterTextChanged(editable: Editable?) {
|
|
||||||
if (updatingDurationText) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val parsed = editable?.toString()?.toIntOrNull() ?: return
|
|
||||||
if (parsed in NavButtonSettingsStore.MIN_DURATION_MS..NavButtonSettingsStore.MAX_DURATION_MS) {
|
|
||||||
lastValidDurationMs = parsed
|
|
||||||
settingsStore.setSideArrowLongPressDurationMs(parsed)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindDurationButtons() {
|
|
||||||
attachRepeatButton(durationMinusButton) {
|
|
||||||
adjustDuration(-NavButtonSettingsStore.DURATION_STEP_MS)
|
|
||||||
}
|
|
||||||
attachRepeatButton(durationPlusButton) {
|
|
||||||
adjustDuration(NavButtonSettingsStore.DURATION_STEP_MS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateOptionsEnabled() {
|
private fun updateOptionsEnabled() {
|
||||||
val enabled = sideArrowsCheckbox.isChecked
|
val enabled = sideArrowsCheckbox.isChecked
|
||||||
optionsContainer.alpha = if (enabled) 1f else 0.45f
|
optionsContainer.alpha = if (enabled) 1f else 0.45f
|
||||||
@@ -536,38 +443,6 @@ class SettingsActivity : Activity() {
|
|||||||
if (action == SideArrowLongPressAction.MULTIPLE_STEPS) View.VISIBLE else View.GONE
|
if (action == SideArrowLongPressAction.MULTIPLE_STEPS) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun adjustRepeatSpeed(delta: Float) {
|
|
||||||
applyRepeatSpeed(resolveRepeatSpeedForUse() + delta, persist = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun normalizeTypedRepeatSpeed(): Float {
|
|
||||||
val parsed = parseRepeatSpeed(repeatSpeedInput.text.toString()) ?: lastValidRepeatSpeed
|
|
||||||
val normalized = settingsStore.sanitizeSideArrowRepeatSpeed(parsed)
|
|
||||||
applyRepeatSpeed(normalized, persist = true)
|
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveRepeatSpeedForUse(): Float {
|
|
||||||
return normalizeTypedRepeatSpeed()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyRepeatSpeed(stepsPerSecond: Float, persist: Boolean) {
|
|
||||||
val sanitized = settingsStore.sanitizeSideArrowRepeatSpeed(stepsPerSecond)
|
|
||||||
val text = formatRepeatSpeed(sanitized)
|
|
||||||
updatingRepeatSpeedText = true
|
|
||||||
if (repeatSpeedInput.text.toString() != text) {
|
|
||||||
repeatSpeedInput.setText(text)
|
|
||||||
repeatSpeedInput.setSelection(repeatSpeedInput.text.length)
|
|
||||||
}
|
|
||||||
updatingRepeatSpeedText = false
|
|
||||||
|
|
||||||
lastValidRepeatSpeed = sanitized
|
|
||||||
if (persist) {
|
|
||||||
settingsStore.setSideArrowRepeatStepsPerSecond(sanitized)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseRepeatSpeed(text: String?): Float? {
|
private fun parseRepeatSpeed(text: String?): Float? {
|
||||||
return text
|
return text
|
||||||
?.trim()
|
?.trim()
|
||||||
@@ -586,42 +461,23 @@ class SettingsActivity : Activity() {
|
|||||||
return raw.replace('.', decimalSeparator)
|
return raw.replace('.', decimalSeparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun adjustDuration(deltaMs: Int) {
|
}
|
||||||
val current = resolveDurationForUse()
|
|
||||||
val updated = (current + deltaMs).coerceIn(
|
private fun durationField(
|
||||||
NavButtonSettingsStore.MIN_DURATION_MS,
|
input: EditText,
|
||||||
NavButtonSettingsStore.MAX_DURATION_MS,
|
minusButton: Button,
|
||||||
|
plusButton: Button,
|
||||||
|
persist: (Int) -> Unit,
|
||||||
|
): NumericField {
|
||||||
|
return NumericField(
|
||||||
|
input,
|
||||||
|
minusButton,
|
||||||
|
plusButton,
|
||||||
|
NavButtonSettingsStore.DURATION_STEP_MS.toFloat(),
|
||||||
|
parse = { it.toIntOrNull()?.toFloat() },
|
||||||
|
sanitize = { settingsStore.sanitizeDuration(it.toInt()).toFloat() },
|
||||||
|
format = { it.toInt().toString() },
|
||||||
|
persist = { persist(it.toInt()) },
|
||||||
)
|
)
|
||||||
applyDuration(updated, persist = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun normalizeTypedDuration(): Int {
|
|
||||||
val parsed = durationInput.text.toString().toIntOrNull() ?: lastValidDurationMs
|
|
||||||
val normalized = settingsStore.sanitizeDuration(parsed)
|
|
||||||
applyDuration(normalized, persist = true)
|
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveDurationForUse(): Int {
|
|
||||||
return normalizeTypedDuration()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyDuration(durationMs: Int, persist: Boolean) {
|
|
||||||
val sanitized = settingsStore.sanitizeDuration(durationMs)
|
|
||||||
val text = sanitized.toString()
|
|
||||||
updatingDurationText = true
|
|
||||||
if (durationInput.text.toString() != text) {
|
|
||||||
durationInput.setText(text)
|
|
||||||
durationInput.setSelection(durationInput.text.length)
|
|
||||||
}
|
|
||||||
updatingDurationText = false
|
|
||||||
|
|
||||||
lastValidDurationMs = sanitized
|
|
||||||
if (persist) {
|
|
||||||
settingsStore.setSideArrowLongPressDurationMs(sanitized)
|
|
||||||
sendSettingsChangedBroadcast()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user