From 53a97a86308534d830e41b9b28585a2c1b09803a Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 19:59:43 +0300 Subject: [PATCH 1/6] Refactor: Settings UI --- .../ui/SettingsActivity.kt | 324 +----------------- .../ui/component/LongPressSettings.kt | 74 ++++ .../ui/component/ModuleIsNotEnabled.kt | 68 ++++ .../ui/component/NumberAlertDialog.kt | 69 ++++ .../ui/component/VibrationEffectSetting.kt | 203 +++++++++++ 5 files changed, 429 insertions(+), 309 deletions(-) create mode 100644 app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt create mode 100644 app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/ModuleIsNotEnabled.kt create mode 100644 app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/NumberAlertDialog.kt create mode 100644 app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt index a30a59e..967a5a1 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt @@ -28,35 +28,22 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Edit import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ColorScheme -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.MenuAnchorType -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold -import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField import androidx.compose.material3.TopAppBar import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -64,31 +51,21 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.LinkAnnotation -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLinkStyles -import androidx.compose.ui.text.buildAnnotatedString -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.style.TextDecoration -import androidx.compose.ui.text.withLink import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.core.animation.doOnEnd import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import ru.hepolise.volumekeytrackcontrol.ui.component.LongPressSetting +import ru.hepolise.volumekeytrackcontrol.ui.component.ModuleIsNotEnabled +import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationEffectSetting +import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationSettingData import ru.hepolise.volumekeytrackcontrol.util.Constants -import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.LONG_PRESS_DURATION import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.LONG_PRESS_DURATION_DEFAULT_VALUE -import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SELECTED_EFFECT import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SELECTED_EFFECT_DEFAULT_VALUE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SETTINGS_PREFS_NAME -import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_AMPLITUDE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_AMPLITUDE_DEFAULT_VALUE -import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_LENGTH import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_LENGTH_DEFAULT_VALUE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getLongPressDuration import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibrationAmplitude @@ -96,7 +73,6 @@ import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibration import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibrationType import ru.hepolise.volumekeytrackcontrol.util.VibrationType import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.getVibrator -import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.triggerVibration import ru.hepolise.volumekeytrackcontrolmodule.R @@ -141,26 +117,6 @@ class SettingsActivity : ComponentActivity() { } } -private val VibrationEffectTitles = VibrationType.values.associateWith { - when (it) { - VibrationType.Disabled -> R.string.vibration_disabled - VibrationType.Manual -> R.string.vibration_manual - else -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - when (it) { - VibrationType.Click -> R.string.vibration_effect_click - VibrationType.DoubleClick -> R.string.vibration_effect_double_click - VibrationType.HeavyClick -> R.string.vibration_effect_heavy_click - VibrationType.Tick -> R.string.vibration_effect_tick - else -> throw IllegalStateException("Unknown VibrationType: $it") - } - } else { - throw IllegalStateException("VibrationType is not supported on this API level") - } - } - } -} - @OptIn(ExperimentalMaterial3Api::class) @Composable fun VibrationSettingsScreen(vibrator: Vibrator?) { @@ -199,183 +155,24 @@ fun VibrationSettingsScreen(vibrator: Vibrator?) { horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = stringResource(R.string.long_press_settings), fontSize = 20.sp) - - Slider( - value = longPressDuration.toFloat(), - onValueChange = { - longPressDuration = it.toInt() - }, - valueRange = 100f..1000f, - onValueChangeFinished = { - sharedPreferences.edit().putInt(LONG_PRESS_DURATION, longPressDuration) - .apply() - }, - modifier = Modifier.widthIn(max = 300.dp) - ) - - var showLongPressTimeoutDialog by remember { mutableStateOf(false) } - Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.long_press_duration, longPressDuration)) - IconButton( - onClick = { - showLongPressTimeoutDialog = true - } - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = stringResource(R.string.edit) - ) - } - } - - if (showLongPressTimeoutDialog) { - NumberAlertDialog( - title = stringResource(R.string.long_press_duration_dialog_title), - defaultValue = longPressDuration, - minValue = 100, - maxValue = 1000, - onDismissRequest = { showLongPressTimeoutDialog = false }, - onConfirm = { - longPressDuration = it - sharedPreferences.edit().putInt(LONG_PRESS_DURATION, it).apply() - showLongPressTimeoutDialog = false - } - ) + LongPressSetting(longPressDuration, sharedPreferences) { + longPressDuration = it } HorizontalDivider(modifier = Modifier.widthIn(max = 300.dp)) - Text(text = stringResource(R.string.vibration_settings), fontSize = 20.sp) - - var effectExpanded by remember { mutableStateOf(false) } - ExposedDropdownMenuBox( - expanded = effectExpanded, - onExpandedChange = { effectExpanded = !effectExpanded } + VibrationEffectSetting( + value = VibrationSettingData( + vibrationType, vibrationLength, vibrationAmplitude + ), + vibrator = vibrator, + sharedPreferences = sharedPreferences ) { - TextField( - value = stringResource(VibrationEffectTitles[vibrationType]!!), - onValueChange = {}, - readOnly = true, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon(expanded = effectExpanded) - }, - modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable) - ) - ExposedDropdownMenu( - expanded = effectExpanded, - onDismissRequest = { effectExpanded = false }) { - VibrationType.values.forEach { effect -> - DropdownMenuItem( - text = { Text(stringResource(VibrationEffectTitles[effect]!!)) }, - onClick = { - vibrationType = effect - sharedPreferences.edit().putString(SELECTED_EFFECT, effect.key) - .apply() - effectExpanded = false - } - ) - } - } + vibrationType = it.vibrationType + vibrationLength = it.vibrationLength + vibrationAmplitude = it.vibrationAmplitude } - if (vibrationType == VibrationType.Manual) { - Slider( - value = vibrationLength.toFloat(), - onValueChange = { - vibrationLength = it.toInt() - }, - valueRange = 10f..500f, - onValueChangeFinished = { - sharedPreferences.edit().putInt(VIBRATION_LENGTH, vibrationLength) - .apply() - }, - modifier = Modifier.widthIn(max = 300.dp) - ) - - var showManualVibrationLengthDialog by remember { mutableStateOf(false) } - Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.vibration_length, vibrationLength)) - IconButton( - onClick = { - showManualVibrationLengthDialog = true - } - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = stringResource(R.string.edit) - ) - } - } - - if (showManualVibrationLengthDialog) { - NumberAlertDialog( - title = stringResource(R.string.vibration_length_dialog_title), - defaultValue = vibrationLength, - minValue = 10, - maxValue = 500, - onDismissRequest = { showManualVibrationLengthDialog = false }, - onConfirm = { - vibrationLength = it - sharedPreferences.edit().putInt(VIBRATION_LENGTH, it).apply() - showManualVibrationLengthDialog = false - } - ) - } - - Slider( - value = vibrationAmplitude.toFloat(), - onValueChange = { - vibrationAmplitude = it.toInt() - }, - valueRange = 1f..255f, - onValueChangeFinished = { - sharedPreferences.edit().putInt(VIBRATION_AMPLITUDE, vibrationAmplitude) - .apply() - }, - modifier = Modifier.widthIn(max = 300.dp) - ) - - var showVibrationAmplitudeDialog by remember { mutableStateOf(false) } - Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.vibration_amplitude, vibrationAmplitude)) - IconButton( - onClick = { - showVibrationAmplitudeDialog = true - } - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = stringResource(R.string.edit) - ) - } - } - - if (showVibrationAmplitudeDialog) { - NumberAlertDialog( - title = stringResource(R.string.vibration_amplitude_dialog_title), - defaultValue = vibrationAmplitude, - minValue = 1, - maxValue = 255, - onDismissRequest = { showVibrationAmplitudeDialog = false }, - onConfirm = { - vibrationAmplitude = it - sharedPreferences.edit().putInt(VIBRATION_AMPLITUDE, it) - .apply() - showVibrationAmplitudeDialog = false - } - ) - } - - } - - if (vibrationType != VibrationType.Disabled) { - Button(onClick = { - vibrator?.triggerVibration(sharedPreferences) - }) { - Text(stringResource(R.string.test_vibration)) - } - } } Row( modifier = Modifier @@ -449,97 +246,6 @@ fun dynamicColorScheme(context: Context): ColorScheme { } } -@Composable -fun NumberAlertDialog( - title: String, - defaultValue: Int, - onDismissRequest: () -> Unit, - onConfirm: (Int) -> Unit, - minValue: Int, - maxValue: Int -) { - fun validate(value: Int) = value in minValue..maxValue - var value by remember { mutableStateOf(defaultValue.toString()) } - val focusRequester = remember { FocusRequester() } - AlertDialog( - onDismissRequest = onDismissRequest, - title = { Text(text = title) }, - text = { - Column { - OutlinedTextField( - value = value, - onValueChange = { value = it }, - label = { Text(stringResource(R.string.value_in_range, minValue, maxValue)) }, - keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), - isError = value.toIntOrNull() == null || !validate(value.toInt()), - modifier = Modifier.focusRequester(focusRequester) - ) - } - }, - confirmButton = { - Button( - onClick = { - onConfirm(value.toInt()) - }, - enabled = value.toIntOrNull() != null && validate(value.toInt()) - ) { - Text(text = stringResource(R.string.ok)) - } - }, - dismissButton = { - TextButton(onClick = onDismissRequest) { - Text(text = stringResource(R.string.cancel)) - } - }, - ) - LaunchedEffect(true) { - focusRequester.requestFocus() - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun ModuleIsNotEnabled() { - Scaffold( - topBar = { - TopAppBar(title = { Text(stringResource(R.string.app_name)) }) - } - ) { padding -> - Box( - modifier = Modifier - .fillMaxSize() - ) { - Column( - modifier = Modifier - .fillMaxSize() - .padding(padding), - verticalArrangement = Arrangement.spacedBy(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Text( - text = buildAnnotatedString { - append(stringResource(id = R.string.module_is_not_enabled)) - append(" ") - withLink( - LinkAnnotation.Url( - url = Constants.GITHUB_NEW_ISSUE, - styles = TextLinkStyles( - style = SpanStyle( - color = MaterialTheme.colorScheme.primary, - textDecoration = TextDecoration.Underline - ) - ) - ) - ) { - append(stringResource(id = R.string.open_issue)) - } - } - ) - } - } - } -} - @Preview(showBackground = true) @Composable fun PreviewVibrationSettingsScreen() { diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt new file mode 100644 index 0000000..572ee21 --- /dev/null +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt @@ -0,0 +1,74 @@ +package ru.hepolise.volumekeytrackcontrol.ui.component + +import android.content.SharedPreferences +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Slider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.LONG_PRESS_DURATION +import ru.hepolise.volumekeytrackcontrolmodule.R + +@Composable +fun LongPressSetting( + longPressDuration: Int, + sharedPreferences: SharedPreferences, + onValueChange: (Int) -> Unit +) { + + Text(text = stringResource(R.string.long_press_settings), fontSize = 20.sp) + + Slider( + value = longPressDuration.toFloat(), + onValueChange = { onValueChange(it.toInt()) }, + valueRange = 100f..1000f, + onValueChangeFinished = { + sharedPreferences.edit().putInt(LONG_PRESS_DURATION, longPressDuration) + .apply() + }, + modifier = Modifier.widthIn(max = 300.dp) + ) + + var showLongPressTimeoutDialog by remember { mutableStateOf(false) } + Row(verticalAlignment = Alignment.CenterVertically) { + Text(stringResource(R.string.long_press_duration, longPressDuration)) + IconButton( + onClick = { + showLongPressTimeoutDialog = true + } + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit) + ) + } + } + + if (showLongPressTimeoutDialog) { + NumberAlertDialog( + title = stringResource(R.string.long_press_duration_dialog_title), + defaultValue = longPressDuration, + minValue = 100, + maxValue = 1000, + onDismissRequest = { showLongPressTimeoutDialog = false }, + onConfirm = { + onValueChange(it) + sharedPreferences.edit().putInt(LONG_PRESS_DURATION, it).apply() + showLongPressTimeoutDialog = false + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/ModuleIsNotEnabled.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/ModuleIsNotEnabled.kt new file mode 100644 index 0000000..14ca231 --- /dev/null +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/ModuleIsNotEnabled.kt @@ -0,0 +1,68 @@ +package ru.hepolise.volumekeytrackcontrol.ui.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.LinkAnnotation +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextLinkStyles +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.withLink +import androidx.compose.ui.unit.dp +import ru.hepolise.volumekeytrackcontrol.util.Constants +import ru.hepolise.volumekeytrackcontrolmodule.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ModuleIsNotEnabled() { + Scaffold( + topBar = { + TopAppBar(title = { Text(stringResource(R.string.app_name)) }) + } + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = buildAnnotatedString { + append(stringResource(id = R.string.module_is_not_enabled)) + append(" ") + withLink( + LinkAnnotation.Url( + url = Constants.GITHUB_NEW_ISSUE, + styles = TextLinkStyles( + style = SpanStyle( + color = MaterialTheme.colorScheme.primary, + textDecoration = TextDecoration.Underline + ) + ) + ) + ) { + append(stringResource(id = R.string.open_issue)) + } + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/NumberAlertDialog.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/NumberAlertDialog.kt new file mode 100644 index 0000000..4588ac5 --- /dev/null +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/NumberAlertDialog.kt @@ -0,0 +1,69 @@ +package ru.hepolise.volumekeytrackcontrol.ui.component + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import ru.hepolise.volumekeytrackcontrolmodule.R + +@Composable +fun NumberAlertDialog( + title: String, + defaultValue: Int, + onDismissRequest: () -> Unit, + onConfirm: (Int) -> Unit, + minValue: Int, + maxValue: Int +) { + fun validate(value: Int) = value in minValue..maxValue + var value by remember { mutableStateOf(defaultValue.toString()) } + val focusRequester = remember { FocusRequester() } + AlertDialog( + onDismissRequest = onDismissRequest, + title = { Text(text = title) }, + text = { + Column { + OutlinedTextField( + value = value, + onValueChange = { value = it }, + label = { Text(stringResource(R.string.value_in_range, minValue, maxValue)) }, + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number), + isError = value.toIntOrNull() == null || !validate(value.toInt()), + modifier = Modifier.focusRequester(focusRequester) + ) + } + }, + confirmButton = { + Button( + onClick = { + onConfirm(value.toInt()) + }, + enabled = value.toIntOrNull() != null && validate(value.toInt()) + ) { + Text(text = stringResource(R.string.ok)) + } + }, + dismissButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(R.string.cancel)) + } + }, + ) + LaunchedEffect(true) { + focusRequester.requestFocus() + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt new file mode 100644 index 0000000..fe16fc2 --- /dev/null +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt @@ -0,0 +1,203 @@ +package ru.hepolise.volumekeytrackcontrol.ui.component + +import android.content.SharedPreferences +import android.os.Build +import android.os.Vibrator +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Edit +import androidx.compose.material3.Button +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MenuAnchorType +import androidx.compose.material3.Slider +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SELECTED_EFFECT +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_AMPLITUDE +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.VIBRATION_LENGTH +import ru.hepolise.volumekeytrackcontrol.util.VibrationType +import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.triggerVibration +import ru.hepolise.volumekeytrackcontrolmodule.R + +data class VibrationSettingData( + val vibrationType: VibrationType, + val vibrationLength: Int, + val vibrationAmplitude: Int +) + +private val VibrationEffectTitles = VibrationType.values.associateWith { + when (it) { + VibrationType.Disabled -> R.string.vibration_disabled + VibrationType.Manual -> R.string.vibration_manual + else -> { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + when (it) { + VibrationType.Click -> R.string.vibration_effect_click + VibrationType.DoubleClick -> R.string.vibration_effect_double_click + VibrationType.HeavyClick -> R.string.vibration_effect_heavy_click + VibrationType.Tick -> R.string.vibration_effect_tick + else -> throw IllegalStateException("Unknown VibrationType: $it") + } + } else { + throw IllegalStateException("VibrationType is not supported on this API level") + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun VibrationEffectSetting( + value: VibrationSettingData, + vibrator: Vibrator?, + sharedPreferences: SharedPreferences, + onValueChange: (VibrationSettingData) -> Unit +) { + val (vibrationType, vibrationLength, vibrationAmplitude) = value + Text(text = stringResource(R.string.vibration_settings), fontSize = 20.sp) + + var effectExpanded by remember { mutableStateOf(false) } + ExposedDropdownMenuBox( + expanded = effectExpanded, + onExpandedChange = { effectExpanded = !effectExpanded } + ) { + TextField( + value = stringResource(VibrationEffectTitles[vibrationType]!!), + onValueChange = {}, + readOnly = true, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon(expanded = effectExpanded) + }, + modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable) + ) + ExposedDropdownMenu( + expanded = effectExpanded, + onDismissRequest = { effectExpanded = false }) { + VibrationType.values.forEach { effect -> + DropdownMenuItem( + text = { Text(stringResource(VibrationEffectTitles[effect]!!)) }, + onClick = { + onValueChange(value.copy(vibrationType = effect)) + sharedPreferences.edit().putString(SELECTED_EFFECT, effect.key) + .apply() + effectExpanded = false + } + ) + } + } + } + + if (vibrationType == VibrationType.Manual) { + Slider( + value = vibrationLength.toFloat(), + onValueChange = { + onValueChange(value.copy(vibrationLength = it.toInt())) + }, + valueRange = 10f..500f, + onValueChangeFinished = { + sharedPreferences.edit().putInt(VIBRATION_LENGTH, vibrationLength) + .apply() + }, + modifier = Modifier.widthIn(max = 300.dp) + ) + + var showManualVibrationLengthDialog by remember { mutableStateOf(false) } + Row(verticalAlignment = Alignment.CenterVertically) { + Text(stringResource(R.string.vibration_length, vibrationLength)) + IconButton( + onClick = { + showManualVibrationLengthDialog = true + } + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit) + ) + } + } + + if (showManualVibrationLengthDialog) { + NumberAlertDialog( + title = stringResource(R.string.vibration_length_dialog_title), + defaultValue = vibrationLength, + minValue = 10, + maxValue = 500, + onDismissRequest = { showManualVibrationLengthDialog = false }, + onConfirm = { + onValueChange(value.copy(vibrationLength = it)) + sharedPreferences.edit().putInt(VIBRATION_LENGTH, it).apply() + showManualVibrationLengthDialog = false + } + ) + } + + Slider( + value = vibrationAmplitude.toFloat(), + onValueChange = { + onValueChange(value.copy(vibrationAmplitude = it.toInt())) + }, + valueRange = 1f..255f, + onValueChangeFinished = { + sharedPreferences.edit().putInt(VIBRATION_AMPLITUDE, vibrationAmplitude) + .apply() + }, + modifier = Modifier.widthIn(max = 300.dp) + ) + + var showVibrationAmplitudeDialog by remember { mutableStateOf(false) } + Row(verticalAlignment = Alignment.CenterVertically) { + Text(stringResource(R.string.vibration_amplitude, vibrationAmplitude)) + IconButton( + onClick = { + showVibrationAmplitudeDialog = true + } + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = stringResource(R.string.edit) + ) + } + } + + if (showVibrationAmplitudeDialog) { + NumberAlertDialog( + title = stringResource(R.string.vibration_amplitude_dialog_title), + defaultValue = vibrationAmplitude, + minValue = 1, + maxValue = 255, + onDismissRequest = { showVibrationAmplitudeDialog = false }, + onConfirm = { + onValueChange(value.copy(vibrationAmplitude = it)) + sharedPreferences.edit().putInt(VIBRATION_AMPLITUDE, it) + .apply() + showVibrationAmplitudeDialog = false + } + ) + } + + } + + if (vibrationType != VibrationType.Disabled) { + Button(onClick = { + vibrator?.triggerVibration(sharedPreferences) + }) { + Text(stringResource(R.string.test_vibration)) + } + } +} \ No newline at end of file From c9844b235d7eab9aaf9e38034ad2e8aead551926 Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 20:00:50 +0300 Subject: [PATCH 2/6] Refactor: Settings UI --- .../ui/component/{LongPressSettings.kt => LongPressSetting.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/{LongPressSettings.kt => LongPressSetting.kt} (100%) diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt similarity index 100% rename from app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSettings.kt rename to app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt From 5f0a17da26abb043af619a68a8d036588eead70e Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 20:45:15 +0300 Subject: [PATCH 3/6] Add possibility to swap Up/Down buttons --- .../module/VolumeKeyControlModuleHandlers.kt | 40 ++++++++++-------- .../ui/SettingsActivity.kt | 18 ++++++++ .../ui/component/SwapButtonsSetting.kt | 41 +++++++++++++++++++ .../util/SharedPreferencesUtil.kt | 7 ++++ app/src/main/res/values/strings.xml | 3 ++ 5 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/module/VolumeKeyControlModuleHandlers.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/module/VolumeKeyControlModuleHandlers.kt index 67c5e52..460161c 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/module/VolumeKeyControlModuleHandlers.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/module/VolumeKeyControlModuleHandlers.kt @@ -16,6 +16,7 @@ import de.robv.android.xposed.XposedHelpers import ru.hepolise.volumekeytrackcontrol.module.util.LogHelper import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getLongPressDuration +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.isSwapButtons import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.getVibrator import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.triggerVibration @@ -150,17 +151,25 @@ object VolumeKeyControlModuleHandlers { } private fun doHook(keyCode: Int, event: KeyEvent, param: MethodHookParam) { + val isSwap = SharedPreferencesUtil.prefs().isSwapButtons() + log("isSwap: $isSwap") + val isDown = when (keyCode) { + KeyEvent.KEYCODE_VOLUME_DOWN -> !isSwap + KeyEvent.KEYCODE_VOLUME_UP -> isSwap + else -> throw IllegalStateException("Unknown key code: $keyCode") + } when (event.action) { - KeyEvent.ACTION_DOWN -> handleDownAction(keyCode, param) - KeyEvent.ACTION_UP -> handleUpAction(keyCode, param) + KeyEvent.ACTION_DOWN -> handleDownAction(isDown, param) + KeyEvent.ACTION_UP -> handleUpAction(isDown, keyCode, param) } param.setResult(0) } - private fun handleDownAction(keyCode: Int, param: MethodHookParam) { - when (keyCode) { - KeyEvent.KEYCODE_VOLUME_DOWN -> isDownPressed = true - KeyEvent.KEYCODE_VOLUME_UP -> isUpPressed = true + private fun handleDownAction(isDown: Boolean, param: MethodHookParam) { + if (isDown) { + isDownPressed = true + } else { + isUpPressed = true } log("down action received, down: $isDownPressed, up: $isUpPressed") isLongPress = false @@ -171,17 +180,18 @@ object VolumeKeyControlModuleHandlers { // only one button pressed if (isMusicActive()) { log("music is active, creating delayed skip") - handleVolumeSkipPress(param.thisObject, keyCode) + handleVolumeSkipPress(param.thisObject, isDown) } log("creating delayed play pause") handleVolumePlayPausePress(param.thisObject) } } - private fun handleUpAction(keyCode: Int, param: MethodHookParam) { - when (keyCode) { - KeyEvent.KEYCODE_VOLUME_DOWN -> isDownPressed = false - KeyEvent.KEYCODE_VOLUME_UP -> isUpPressed = false + private fun handleUpAction(isDown: Boolean, keyCode: Int, param: MethodHookParam) { + if (isDown) { + isDownPressed = false + } else { + isUpPressed = false } log("up action received, down: $isDownPressed, up: $isUpPressed") handleVolumeAllPressAbort(param.thisObject) @@ -235,14 +245,10 @@ object VolumeKeyControlModuleHandlers { ) } - private fun handleVolumeSkipPress(instance: Any, keyCode: Int) { + private fun handleVolumeSkipPress(instance: Any, isDown: Boolean) { val handler = instance.getHandler() handler.postDelayed( - when (keyCode) { - KeyEvent.KEYCODE_VOLUME_UP -> getRunnable(instance, VOLUME_UP_LONG_PRESS) - KeyEvent.KEYCODE_VOLUME_DOWN -> getRunnable(instance, VOLUME_DOWN_LONG_PRESS) - else -> return - }, + getRunnable(instance, if (isDown) VOLUME_DOWN_LONG_PRESS else VOLUME_UP_LONG_PRESS), SharedPreferencesUtil.prefs().getLongPressDuration().toLong() ) } diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt index 967a5a1..060a505 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt @@ -55,10 +55,12 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.core.animation.doOnEnd import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import ru.hepolise.volumekeytrackcontrol.ui.component.LongPressSetting import ru.hepolise.volumekeytrackcontrol.ui.component.ModuleIsNotEnabled +import ru.hepolise.volumekeytrackcontrol.ui.component.SwapButtonsSetting import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationEffectSetting import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationSettingData import ru.hepolise.volumekeytrackcontrol.util.Constants @@ -71,6 +73,7 @@ import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getLongPress import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibrationAmplitude import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibrationLength import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.getVibrationType +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.isSwapButtons import ru.hepolise.volumekeytrackcontrol.util.VibrationType import ru.hepolise.volumekeytrackcontrol.util.VibratorUtil.getVibrator import ru.hepolise.volumekeytrackcontrolmodule.R @@ -134,6 +137,7 @@ fun VibrationSettingsScreen(vibrator: Vibrator?) { var vibrationType by remember { mutableStateOf(sharedPreferences.getVibrationType()) } var vibrationLength by remember { mutableIntStateOf(sharedPreferences.getVibrationLength()) } var vibrationAmplitude by remember { mutableIntStateOf(sharedPreferences.getVibrationAmplitude()) } + var isSwapButtons by remember { mutableStateOf(sharedPreferences.isSwapButtons()) } Scaffold( topBar = { @@ -173,7 +177,21 @@ fun VibrationSettingsScreen(vibrator: Vibrator?) { vibrationAmplitude = it.vibrationAmplitude } + + + HorizontalDivider(modifier = Modifier.widthIn(max = 300.dp)) + + Text(text = stringResource(R.string.other_settings), fontSize = 20.sp) + + SwapButtonsSetting( + isSwapButtons = isSwapButtons, + sharedPreferences = sharedPreferences + ) { + isSwapButtons = it + } + } + Row( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt new file mode 100644 index 0000000..5d7ccd1 --- /dev/null +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt @@ -0,0 +1,41 @@ +package ru.hepolise.volumekeytrackcontrol.ui.component + +import android.content.SharedPreferences +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Checkbox +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.IS_SWAP_BUTTONS +import ru.hepolise.volumekeytrackcontrolmodule.R + +@Composable +fun SwapButtonsSetting( + isSwapButtons: Boolean, + sharedPreferences: SharedPreferences, + onValueChange: (Boolean) -> Unit +) { + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = isSwapButtons, + onCheckedChange = { + onValueChange(it) + sharedPreferences.edit().putBoolean(IS_SWAP_BUTTONS, it).apply() + } + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = stringResource(R.string.swap_buttons), + modifier = Modifier.clickable { + onValueChange(!isSwapButtons) + sharedPreferences.edit().putBoolean(IS_SWAP_BUTTONS, isSwapButtons).apply() + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/util/SharedPreferencesUtil.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/util/SharedPreferencesUtil.kt index af477a4..33026e6 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/util/SharedPreferencesUtil.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/util/SharedPreferencesUtil.kt @@ -13,12 +13,14 @@ object SharedPreferencesUtil { const val VIBRATION_LENGTH = "vibrationLength" const val VIBRATION_AMPLITUDE = "vibrationAmplitude" const val LONG_PRESS_DURATION = "longPressDuration" + const val IS_SWAP_BUTTONS = "isSwapButtons" val SELECTED_EFFECT_DEFAULT_VALUE = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) VibrationType.Click.key else VibrationType.Manual.key const val VIBRATION_LENGTH_DEFAULT_VALUE = 50 const val VIBRATION_AMPLITUDE_DEFAULT_VALUE = 128 val LONG_PRESS_DURATION_DEFAULT_VALUE = ViewConfiguration.getLongPressTimeout() + const val IS_SWAP_BUTTONS_DEFAULT_VALUE = false fun SharedPreferences?.getVibrationType(): VibrationType { val defaultValue = SELECTED_EFFECT_DEFAULT_VALUE @@ -40,6 +42,11 @@ object SharedPreferencesUtil { return this?.getInt(LONG_PRESS_DURATION, defaultValue) ?: defaultValue } + fun SharedPreferences?.isSwapButtons(): Boolean { + val defaultValue = IS_SWAP_BUTTONS_DEFAULT_VALUE + return this?.getBoolean(IS_SWAP_BUTTONS, defaultValue) ?: defaultValue + } + fun prefs(): SharedPreferences? { val pref = XSharedPreferences(BuildConfig.APPLICATION_ID, SETTINGS_PREFS_NAME) return if (pref.file.canRead()) pref else null diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8f4d87c..f0b1579 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,6 +3,7 @@ Vibration Settings Long Press Settings + Other Settings Click Double Click @@ -21,6 +22,8 @@ Long Press Duration: %dms Long Press Duration + Swap Up/Down buttons for skipping + Reset settings Are you sure you want to reset settings? Settings are reset to default From 7a1ec466291a0d4c06bbefed16864477ec63a76e Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 20:56:29 +0300 Subject: [PATCH 4/6] Fix reset settings --- .../ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt index 060a505..0055edf 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/SettingsActivity.kt @@ -64,6 +64,7 @@ import ru.hepolise.volumekeytrackcontrol.ui.component.SwapButtonsSetting import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationEffectSetting import ru.hepolise.volumekeytrackcontrol.ui.component.VibrationSettingData import ru.hepolise.volumekeytrackcontrol.util.Constants +import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.IS_SWAP_BUTTONS_DEFAULT_VALUE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.LONG_PRESS_DURATION_DEFAULT_VALUE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SELECTED_EFFECT_DEFAULT_VALUE import ru.hepolise.volumekeytrackcontrol.util.SharedPreferencesUtil.SETTINGS_PREFS_NAME @@ -220,6 +221,7 @@ fun VibrationSettingsScreen(vibrator: Vibrator?) { vibrationLength = VIBRATION_LENGTH_DEFAULT_VALUE vibrationAmplitude = VIBRATION_AMPLITUDE_DEFAULT_VALUE longPressDuration = LONG_PRESS_DURATION_DEFAULT_VALUE + isSwapButtons = IS_SWAP_BUTTONS_DEFAULT_VALUE Toast.makeText( context, context.getString(R.string.settings_reset_toast), From 3d74c6584c59e0eec241c021b9cbc380b2931e87 Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 20:57:09 +0300 Subject: [PATCH 5/6] Long press setting, Vibration effect setting: make text clickable --- .../ui/component/LongPressSetting.kt | 6 +++++- .../ui/component/VibrationEffectSetting.kt | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt index 572ee21..871626e 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/LongPressSetting.kt @@ -1,6 +1,7 @@ package ru.hepolise.volumekeytrackcontrol.ui.component import android.content.SharedPreferences +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.widthIn import androidx.compose.material.icons.Icons @@ -44,7 +45,10 @@ fun LongPressSetting( var showLongPressTimeoutDialog by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.long_press_duration, longPressDuration)) + Text( + text = stringResource(R.string.long_press_duration, longPressDuration), + modifier = Modifier.clickable { showLongPressTimeoutDialog = true } + ) IconButton( onClick = { showLongPressTimeoutDialog = true diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt index fe16fc2..275c908 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/VibrationEffectSetting.kt @@ -3,6 +3,7 @@ package ru.hepolise.volumekeytrackcontrol.ui.component import android.content.SharedPreferences import android.os.Build import android.os.Vibrator +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.widthIn import androidx.compose.material.icons.Icons @@ -84,7 +85,8 @@ fun VibrationEffectSetting( trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = effectExpanded) }, - modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable) + modifier = Modifier + .menuAnchor(MenuAnchorType.PrimaryNotEditable) ) ExposedDropdownMenu( expanded = effectExpanded, @@ -119,7 +121,10 @@ fun VibrationEffectSetting( var showManualVibrationLengthDialog by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.vibration_length, vibrationLength)) + Text( + text = stringResource(R.string.vibration_length, vibrationLength), + modifier = Modifier.clickable { showManualVibrationLengthDialog = true } + ) IconButton( onClick = { showManualVibrationLengthDialog = true @@ -162,7 +167,10 @@ fun VibrationEffectSetting( var showVibrationAmplitudeDialog by remember { mutableStateOf(false) } Row(verticalAlignment = Alignment.CenterVertically) { - Text(stringResource(R.string.vibration_amplitude, vibrationAmplitude)) + Text( + text = stringResource(R.string.vibration_amplitude, vibrationAmplitude), + modifier = Modifier.clickable { showVibrationAmplitudeDialog = true } + ) IconButton( onClick = { showVibrationAmplitudeDialog = true From 10cbd00a9d1ea492e2e59a89582626e27a65cfb8 Mon Sep 17 00:00:00 2001 From: Hepolise Date: Sat, 15 Feb 2025 20:59:27 +0300 Subject: [PATCH 6/6] Fix SwapButtonsSetting --- .../volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt index 5d7ccd1..3763408 100644 --- a/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt +++ b/app/src/main/java/ru/hepolise/volumekeytrackcontrol/ui/component/SwapButtonsSetting.kt @@ -34,7 +34,7 @@ fun SwapButtonsSetting( text = stringResource(R.string.swap_buttons), modifier = Modifier.clickable { onValueChange(!isSwapButtons) - sharedPreferences.edit().putBoolean(IS_SWAP_BUTTONS, isSwapButtons).apply() + sharedPreferences.edit().putBoolean(IS_SWAP_BUTTONS, !isSwapButtons).apply() } ) }