From a944bd127c88066403a9a5e3c897bac989cb8eb7 Mon Sep 17 00:00:00 2001 From: Kyujin Cho Date: Sun, 18 Feb 2024 21:43:50 +0900 Subject: [PATCH] feature: make Wi-Fi calling carrier name configurable (#265) --- .github/workflows/build-apk.yml | 7 +- .../dev/bluehouse/enablevolte/Components.kt | 745 ------------------ .../dev/bluehouse/enablevolte/HomeActivity.kt | 1 + .../java/dev/bluehouse/enablevolte/Moder.kt | 5 +- .../components/BooleanPropertyView.kt | 67 ++ .../components/ClickablePropertyView.kt | 59 ++ .../enablevolte/components/Common.kt | 47 ++ .../components/KeyValueEditView.kt | 322 ++++++++ .../enablevolte/components/LoadingDialog.kt | 106 +++ .../components/RadioSelectPropertyView.kt | 139 ++++ .../components/StringPropertyView.kt | 99 +++ .../components/UserAgentPropertyView.kt | 192 +++++ .../dev/bluehouse/enablevolte/pages/Config.kt | 47 +- .../enablevolte/pages/DumpedConfig.kt | 2 +- .../dev/bluehouse/enablevolte/pages/Editor.kt | 8 +- .../dev/bluehouse/enablevolte/pages/Home.kt | 8 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 18 files changed, 1084 insertions(+), 774 deletions(-) delete mode 100644 app/src/main/java/dev/bluehouse/enablevolte/Components.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/BooleanPropertyView.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/ClickablePropertyView.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/Common.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/KeyValueEditView.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/LoadingDialog.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/RadioSelectPropertyView.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/StringPropertyView.kt create mode 100644 app/src/main/java/dev/bluehouse/enablevolte/components/UserAgentPropertyView.kt diff --git a/.github/workflows/build-apk.yml b/.github/workflows/build-apk.yml index 53c3d00..2852ca2 100644 --- a/.github/workflows/build-apk.yml +++ b/.github/workflows/build-apk.yml @@ -74,7 +74,12 @@ jobs: KEY_ALIAS: ${{ secrets.key-alias }} KEY_PASSWORD: ${{ secrets.key-password }} BUILD_TYPE: ${{ inputs.build-type }} - if: ${{ secrets.key-password != '' }} + if: ${{ env.KEY_PASSWORD != '' }} + - name: Rename APK + run: mv app-unsigned-aligned.apk dev.bluehouse.enablevolte.apk + env: + KEY_PASSWORD: ${{ secrets.key-password }} + if: ${{ env.KEY_PASSWORD == '' }} - name: Upload APK uses: actions/upload-artifact@v3 with: diff --git a/app/src/main/java/dev/bluehouse/enablevolte/Components.kt b/app/src/main/java/dev/bluehouse/enablevolte/Components.kt deleted file mode 100644 index ad769da..0000000 --- a/app/src/main/java/dev/bluehouse/enablevolte/Components.kt +++ /dev/null @@ -1,745 +0,0 @@ -package dev.bluehouse.enablevolte - -import android.os.Build.VERSION -import android.util.Log -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.selection.selectableGroup -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.AlertDialogDefaults -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Surface -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.platform.LocalLifecycleOwner -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.TextUnit -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver -import androidx.lifecycle.LifecycleOwner -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext - -@Composable -fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) { - val eventHandler = rememberUpdatedState(onEvent) - val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) - - DisposableEffect(lifecycleOwner.value) { - val lifecycle = lifecycleOwner.value.lifecycle - val observer = LifecycleEventObserver { owner, event -> - eventHandler.value(owner, event) - } - - lifecycle.addObserver(observer) - onDispose { - lifecycle.removeObserver(observer) - } - } -} - -@Composable -fun HeaderText(text: String) { - Row(modifier = Modifier.padding(top = 20.dp, bottom = 12.dp)) { - Text(text = text, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) - } -} - -@Composable -fun BooleanPropertyView( - label: String, - toggled: Boolean?, - enabled: Boolean = true, - trueLabel: String = stringResource(R.string.yes), - falseLabel: String = stringResource(R.string.no), - minSdk: Int = VERSION.SDK_INT, - onClick: ((Boolean) -> Unit)? = null, -) { - val localEnabled = enabled && VERSION.SDK_INT >= minSdk - - if (toggled == null) { - Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, fontSize = 18.sp, modifier = Modifier.padding(bottom = 4.dp)) - Text(text = stringResource(R.string.unknown), fontSize = 14.sp, color = MaterialTheme.colorScheme.outline) - } - return - } - if (onClick != null) { - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, modifier = Modifier.weight(1F), fontSize = 18.sp) - Switch(checked = toggled, enabled = localEnabled, onCheckedChange = onClick) - } - } else { - Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, fontSize = 18.sp, modifier = Modifier.padding(bottom = 4.dp)) - Text(text = if (toggled) { trueLabel } else { falseLabel }, fontSize = 14.sp, color = MaterialTheme.colorScheme.outline) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun UserAgentUpdateDialog( - labels: Array, - values: Array, - selectedIndex: Int, - typedText: String, - dropdownExpanded: Boolean, - onTextUpdate: (String) -> Unit, - onIndexUpdate: (Int) -> Unit, - onDismissRequest: () -> Unit, - onExpandedChange: (Boolean) -> Unit, -) { - AlertDialog(onDismissRequest = onDismissRequest) { - Surface( - modifier = Modifier - .wrapContentWidth() - .wrapContentHeight(), - shape = RoundedCornerShape(10), - ) { - Column(modifier = Modifier.padding(all = 16.dp)) { - Text(text = stringResource(R.string.update_value), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(bottom = 24.dp)) - ExposedDropdownMenuBox( - expanded = dropdownExpanded, - onExpandedChange = onExpandedChange, - modifier = Modifier.padding(bottom = 8.dp), - ) { - TextField( - // The `menuAnchor` modifier must be passed to the text field for correctness. - modifier = Modifier - .menuAnchor() - .wrapContentWidth(), - readOnly = true, - value = if (values[selectedIndex] == typedText) labels[selectedIndex] else "Custom", - onValueChange = {}, - label = { Text(stringResource(R.string.presets)) }, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = dropdownExpanded) }, - colors = ExposedDropdownMenuDefaults.textFieldColors(), - ) - ExposedDropdownMenu( - expanded = dropdownExpanded, - onDismissRequest = { onExpandedChange(false) }, - ) { - labels.forEachIndexed { i, label -> - DropdownMenuItem( - text = { Text(text = label) }, - onClick = { - onTextUpdate(values[i]) - onIndexUpdate(i) - onExpandedChange(false) - }, - contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, - ) - } - } - } - TextField(textStyle = TextStyle(fontSize = 14.sp), value = typedText, onValueChange = { onTextUpdate(it) }) - Row(modifier = Modifier.align(Alignment.End).padding(top = 16.dp)) { - TextButton( - border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), - modifier = Modifier.padding(end = 8.dp), - shape = ButtonDefaults.outlinedShape, - onClick = { onDismissRequest() }, - ) { - Text(stringResource(R.string.dismiss)) - } - TextButton( - border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), - shape = ButtonDefaults.outlinedShape, - colors = ButtonDefaults.filledTonalButtonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - onClick = { - onTextUpdate(typedText) - onDismissRequest() - }, - ) { - Text(stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) - } - } - } - } - } -} - -@Composable -fun UserAgentPropertyView(label: String, value: String?, onUpdate: ((String) -> Unit)? = null) { - val labels = arrayOf(stringResource(R.string.default_), stringResource(R.string.lgu)) - val values = arrayOf(stringResource(R.string.ua_default), stringResource(R.string.ua_lgu)) - - var typedText by rememberSaveable { mutableStateOf("") } - var openTextEditDialog by rememberSaveable { mutableStateOf(false) } - var dropdownExpanded by rememberSaveable { mutableStateOf(false) } - var selectedIndex by rememberSaveable { mutableIntStateOf(if (values.contains(value)) values.indexOf(value) else 0) } - - if (onUpdate != null) { - if (openTextEditDialog) { - UserAgentUpdateDialog( - labels, - values, - selectedIndex, - typedText, - dropdownExpanded, - onTextUpdate = { - typedText = it - onUpdate(typedText) - }, - onIndexUpdate = { - selectedIndex = it - }, - onDismissRequest = { openTextEditDialog = false }, - onExpandedChange = { dropdownExpanded = it }, - ) - } - } - ClickablePropertyView(label = label, value = value) { - if (value != null) { - typedText = value - openTextEditDialog = true - } - } -} - -@Composable -fun StringPropertyView(label: String, value: String?, onUpdate: ((String) -> Unit)? = null) { - var typedText by rememberSaveable { mutableStateOf("") } - var openTextEditDialog by rememberSaveable { mutableStateOf(false) } - - if (onUpdate != null) { - if (openTextEditDialog) { - AlertDialog( - onDismissRequest = { - // Dismiss the dialog when the user clicks outside the dialog or on the back - // button. If you want to disable that functionality, simply use an empty - // onDismissRequest. - openTextEditDialog = false - }, - confirmButton = { - TextButton( - onClick = { - onUpdate(typedText) - openTextEditDialog = false - }, - ) { - Text(stringResource(R.string.confirm)) - } - }, - dismissButton = { - TextButton( - onClick = { - openTextEditDialog = false - }, - ) { - Text(stringResource(R.string.dismiss)) - } - }, - title = { Text(text = stringResource(R.string.update_value), style = MaterialTheme.typography.titleLarge) }, - text = { - TextField(value = typedText, onValueChange = { typedText = it }) - }, - ) - } - } - ClickablePropertyView(label = label, value = value) { - if (value != null) { - typedText = value - openTextEditDialog = true - } - } -} - -enum class ValueType { - Int, - Long, - Bool, - String, - IntArray, - LongArray, - BoolArray, - StringArray, - Unknown, -} - -data class ArrayValueType(val v: T) - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun EditPropertyDialog( - availableKeys: Iterable?, - configKey: String, - selectedValueType: ValueType?, - value: String, - keyDropdownExpanded: Boolean, - valueTypeDropdownExpanded: Boolean, - filteringOptions: List, - onConfigKeyChange: (String) -> Unit, - onValueTypeChange: (ValueType) -> Unit, - onValueChange: (String) -> Unit, - onUpdate: (String, ValueType?, String) -> Boolean, - onKeyDropdownExpandedChange: (Boolean) -> Unit, - onValueDropdownExpandedChange: (Boolean) -> Unit, - dismissDialog: () -> Unit, -) { - val TAG = "Components:EditPropertyDialog" - Dialog( - onDismissRequest = { dismissDialog() }, - properties = DialogProperties(), - ) { - Card( - colors = CardDefaults.cardColors( - containerColor = AlertDialogDefaults.containerColor, - contentColor = AlertDialogDefaults.textContentColor, - ), - ) { - Column(modifier = Modifier.padding(20.dp)) { - Text(stringResource(R.string.update_value), modifier = Modifier.padding(bottom = 16.dp), style = MaterialTheme.typography.labelMedium) - if (availableKeys != null) { - ExposedDropdownMenuBox( - expanded = keyDropdownExpanded, - onExpandedChange = { - Log.d(TAG, "Expand state change requested: ${!keyDropdownExpanded}") - onKeyDropdownExpandedChange(it) - }, - ) { - TextField( - // The `menuAnchor` modifier must be passed to the text field for correctness. - modifier = Modifier - .menuAnchor() - .fillMaxWidth() - .onFocusChanged { - onKeyDropdownExpandedChange(it.isFocused) - }, - value = configKey, - onValueChange = { onConfigKeyChange(it) }, - label = { Text(stringResource(R.string.property_name)) }, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = keyDropdownExpanded) }, - colors = ExposedDropdownMenuDefaults.textFieldColors(), - ) - if (filteringOptions.isNotEmpty() && keyDropdownExpanded) { - ExposedDropdownMenu( - expanded = true, - onDismissRequest = {}, - ) { - filteringOptions.forEach { selectionOption -> - DropdownMenuItem( - text = { Text(selectionOption) }, - onClick = { - onConfigKeyChange(selectionOption) - onKeyDropdownExpandedChange(false) - }, - contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, - ) - } - } - } - } - } else { - TextField( - value = configKey, - label = { Text(stringResource(R.string.property_name)) }, - onValueChange = { onConfigKeyChange(it) }, - ) - } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 4.dp), - verticalAlignment = if (selectedValueType == ValueType.Bool) { Alignment.CenterVertically } else { Alignment.Top }, - ) { - ExposedDropdownMenuBox( - expanded = valueTypeDropdownExpanded, - onExpandedChange = { onValueDropdownExpandedChange(it) }, - modifier = Modifier - .padding(bottom = 8.dp) - .weight(1.0F), - ) { - TextField( - // The `menuAnchor` modifier must be passed to the text field for correctness. - modifier = Modifier - .menuAnchor() - .weight(1.0F), - readOnly = true, - value = selectedValueType?.name ?: "", - onValueChange = {}, - label = { Text(stringResource(R.string.property_type)) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon(expanded = valueTypeDropdownExpanded) - }, - colors = ExposedDropdownMenuDefaults.textFieldColors(), - ) - ExposedDropdownMenu( - expanded = valueTypeDropdownExpanded, - onDismissRequest = { onValueDropdownExpandedChange(false) }, - ) { - ValueType.values().forEach { valueType -> - DropdownMenuItem( - text = { Text(text = valueType.name) }, - onClick = { - if (selectedValueType != valueType) { - onValueTypeChange(valueType) - onValueChange("") - } - onValueDropdownExpandedChange(false) - }, - contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, - ) - } - } - } - Box(modifier = Modifier.weight(0.05F)) - Box(modifier = Modifier.weight(1.0F, fill = true)) { - when (selectedValueType) { - ValueType.Bool -> Row( - modifier = Modifier.selectableGroup(), - verticalAlignment = Alignment.CenterVertically, - ) { - RadioButton( - selected = value == "true", - onClick = { onValueChange("true") }, - ) - Text(stringResource(R.string.true_)) - RadioButton( - selected = value == "false", - onClick = { onValueChange("false") }, - ) - Text(stringResource(R.string.false_)) - } - ValueType.Int, ValueType.Long -> TextField( - value = value, - onValueChange = { onValueChange(it) }, - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), - ) - is ValueType -> TextField(value = value, onValueChange = { onValueChange(it) }) - else -> Box(modifier = Modifier.fillMaxWidth()) - } - } - } - Row(modifier = Modifier.align(Alignment.End).padding(top = 16.dp)) { - TextButton( - border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), - modifier = Modifier.padding(end = 8.dp), - shape = ButtonDefaults.outlinedShape, - onClick = { dismissDialog() }, - ) { Text(stringResource(R.string.dismiss)) } - TextButton( - border = if (selectedValueType != null) BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary) else null, - shape = ButtonDefaults.outlinedShape, - colors = ButtonDefaults.filledTonalButtonColors( - containerColor = MaterialTheme.colorScheme.primary, - ), - onClick = { - if (onUpdate(configKey, selectedValueType, value)) { - dismissDialog() - } - }, - enabled = selectedValueType != null, - ) { Text(stringResource(R.string.confirm)) } - } - } - } - } -} - -@Composable -fun KeyValueEditView(label: String, availableKeys: Iterable? = null, onUpdate: ((String, ValueType?, String) -> Boolean)) { - var configKey by rememberSaveable { mutableStateOf("") } - var selectedValueType: ValueType? by rememberSaveable { mutableStateOf(null) } - var value by rememberSaveable { mutableStateOf("") } - var openEditPropertyDialog by rememberSaveable { mutableStateOf(false) } - var keyDropdownExpanded by rememberSaveable { mutableStateOf(false) } - var valueTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) } - var filteringOptions by rememberSaveable { mutableStateOf(listOf()) } - - LaunchedEffect(configKey) { - if (availableKeys != null) { - withContext(Dispatchers.Default) { - filteringOptions = if (configKey.length >= 3) { - val filteredItems = availableKeys.filter { it.contains(configKey, ignoreCase = false) } - if (filteredItems.size > 7) { - filteredItems.subList(0, 7) - } else { - filteredItems - } - } else { - listOf() - } - } - } - } - - if (openEditPropertyDialog) { - EditPropertyDialog( - availableKeys, - configKey, - selectedValueType, - value, - keyDropdownExpanded, - valueTypeDropdownExpanded, - filteringOptions, - onConfigKeyChange = { configKey = it }, - onValueTypeChange = { selectedValueType = it }, - onValueChange = { value = it }, - onUpdate = onUpdate, - onKeyDropdownExpandedChange = { keyDropdownExpanded = it }, - onValueDropdownExpandedChange = { valueTypeDropdownExpanded = it }, - dismissDialog = { openEditPropertyDialog = false }, - ) - } - ClickablePropertyView(label = label, value = "") { - openEditPropertyDialog = true - } -} - -@Composable -fun ClickablePropertyView(label: String, value: String?, labelFontSize: TextUnit = 18.sp, valueFontSize: TextUnit = 14.sp, labelFontFamily: FontFamily? = null, valueFontFamily: FontFamily? = null, onClick: (() -> Unit)? = null) { - if (value == null) { - Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, fontSize = labelFontSize, modifier = Modifier.padding(bottom = 4.dp)) - Text(text = stringResource(R.string.unknown), color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize) - } - return - } - if (onClick != null) { - Surface(onClick = onClick, modifier = Modifier.fillMaxWidth()) { - Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, modifier = Modifier.padding(bottom = 4.dp), fontSize = labelFontSize, fontFamily = labelFontFamily) - Text(text = value, color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize, fontFamily = valueFontFamily) - } - } - } else { - Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { - Text(text = label, modifier = Modifier.padding(bottom = 4.dp), fontSize = labelFontSize, fontFamily = labelFontFamily) - Text(text = value, color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize, fontFamily = valueFontFamily) - } - } -} - -@Composable -fun InfiniteLoadingDialog() { - Dialog( - onDismissRequest = { }, - properties = DialogProperties(), - ) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(20.dp), - contentAlignment = Alignment.Center, - ) { - Card( - colors = CardDefaults.cardColors( - containerColor = AlertDialogDefaults.containerColor, - contentColor = AlertDialogDefaults.textContentColor, - ), - modifier = Modifier.fillMaxWidth(), - ) { - Row( - modifier = Modifier.padding(30.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - CircularProgressIndicator() - Text(text = stringResource(R.string.please_wait), modifier = Modifier.padding(start = 16.dp)) - } - } - } - } -} - -@Composable -fun FiniteLoadingDialog(current: Int, total: Int) { - Dialog( - onDismissRequest = { }, - properties = DialogProperties(), - ) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(20.dp), - contentAlignment = Alignment.Center, - ) { - Card( - colors = CardDefaults.cardColors( - containerColor = AlertDialogDefaults.containerColor, - contentColor = AlertDialogDefaults.textContentColor, - ), - modifier = Modifier.fillMaxWidth(), - ) { - Box(modifier = Modifier.padding(16.dp)) { - Column { - Text(stringResource(R.string.loading), fontWeight = FontWeight.Bold, fontSize = 24.sp) - LinearProgressIndicator( - modifier = Modifier - .semantics(mergeDescendants = true) {} - .padding(top = 24.dp, bottom = 4.dp) - .fillMaxWidth(), - progress = current.toFloat() / total, - ) - Text(stringResource(R.string.loaded, current, total)) - } - } - } - } - } -} - -@Preview -@Composable -fun HeaderTextPreview() { - HeaderText("Lorem Ipsum") -} - -@Preview -@Composable -fun BooleanPropertyViewPreview() { - var toggled by remember { mutableStateOf(false) } - BooleanPropertyView(label = "Lorem Ipsum", toggled = toggled) { toggled = !toggled } -} - -@Preview -@Composable -fun LowSDKBooleanPropertyViewPreview() { - var toggled by remember { mutableStateOf(false) } - BooleanPropertyView(label = "Lorem Ipsum", toggled = toggled, minSdk = 999) { toggled = !toggled } -} - -@Preview -@Composable -fun UserAgentPropertyViewPreview() { - UserAgentPropertyView("Lorem Ipsum", value = stringResource(R.string.ua_default)) -} - -@Preview -@Composable -fun StringPropertyViewPreview() { - var value by remember { mutableStateOf("") } - StringPropertyView("Lorem Ipsum", value) { value = it } -} - -@Preview -@Composable -fun KeyValueEditViewPreview() { - KeyValueEditView("Lorem Ipsum", "dolor sit amet consectetur adipiscing elit".split(" ")) { _, _, _ -> - false - } -} - -@Preview -@Composable -fun ClickablePropertyViewPreview() { - val value by remember { mutableStateOf("dolor sit amet") } - ClickablePropertyView("Lorem Ipsum", value) {} -} - -@Preview -@Composable -fun InfiniteLoadingDialogPreview() { - InfiniteLoadingDialog() -} - -@Preview -@Composable -fun FiniteLoadingDialogPreview() { - FiniteLoadingDialog(1, 2) -} - -@Preview -@Composable -fun UserAgentUpdateDialogPreview() { - val labels = arrayOf(stringResource(R.string.default_), stringResource(R.string.lgu)) - val values = arrayOf(stringResource(R.string.ua_default), stringResource(R.string.ua_lgu)) - - var typedText by rememberSaveable { mutableStateOf("") } - var openTextEditDialog by rememberSaveable { mutableStateOf(false) } - var dropdownExpanded by rememberSaveable { mutableStateOf(false) } - var selectedIndex by rememberSaveable { mutableIntStateOf(0) } - - UserAgentUpdateDialog( - labels, - values, - selectedIndex, - typedText, - dropdownExpanded, - onTextUpdate = { - typedText = it - }, - onIndexUpdate = { - selectedIndex = it - }, - onDismissRequest = { openTextEditDialog = false }, - onExpandedChange = { dropdownExpanded = it }, - ) -} - -@Preview -@Composable -fun EditPropertyDialogPreview() { - val availableKeys = "Lorem ipsum dolor sit amet consectetur adipiscing elit".split(" ") - var configKey by rememberSaveable { mutableStateOf("") } - var selectedValueType: ValueType? by rememberSaveable { mutableStateOf(null) } - var value by rememberSaveable { mutableStateOf("") } - var openEditPropertyDialog by rememberSaveable { mutableStateOf(false) } - var keyDropdownExpanded by rememberSaveable { mutableStateOf(false) } - var valueTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) } - val filteringOptions = listOf() - - EditPropertyDialog( - availableKeys, - configKey, - selectedValueType, - value, - keyDropdownExpanded, - valueTypeDropdownExpanded, - filteringOptions, - onConfigKeyChange = { configKey = it }, - onValueTypeChange = { selectedValueType = it }, - onValueChange = { value = it }, - onUpdate = { _, _, _ -> false }, - onKeyDropdownExpandedChange = { keyDropdownExpanded = it }, - onValueDropdownExpandedChange = { valueTypeDropdownExpanded = it }, - dismissDialog = { openEditPropertyDialog = false }, - ) -} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/HomeActivity.kt b/app/src/main/java/dev/bluehouse/enablevolte/HomeActivity.kt index 05d5d49..bc10ec5 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/HomeActivity.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/HomeActivity.kt @@ -45,6 +45,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.navigation import androidx.navigation.compose.rememberNavController +import dev.bluehouse.enablevolte.components.OnLifecycleEvent import dev.bluehouse.enablevolte.pages.Config import dev.bluehouse.enablevolte.pages.DumpedConfig import dev.bluehouse.enablevolte.pages.Editor diff --git a/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt b/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt index 48c7815..766cb8b 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/Moder.kt @@ -308,9 +308,12 @@ class SubscriptionModer(val subscriptionId: Int) : Moder() { @RequiresApi(VERSION_CODES.R) get() = this.getBooleanValue(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL) - val showVoWifiInNetworkName: Int + val wfcSpnFormatIndex: Int get() = this.getIntValue(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT) + val carrierName: String + get() = this.loadCachedInterface { telephony }.getSubscriptionCarrierName(this.subscriptionId) + val showVoWifiIcon: Boolean get() = this.getBooleanValue(CarrierConfigManager.KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL) diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/BooleanPropertyView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/BooleanPropertyView.kt new file mode 100644 index 0000000..4946e02 --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/BooleanPropertyView.kt @@ -0,0 +1,67 @@ +package dev.bluehouse.enablevolte.components + +import android.os.Build +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +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.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.bluehouse.enablevolte.R + +@Composable +fun BooleanPropertyView( + label: String, + toggled: Boolean?, + enabled: Boolean = true, + trueLabel: String = stringResource(R.string.yes), + falseLabel: String = stringResource(R.string.no), + minSdk: Int = Build.VERSION.SDK_INT, + onClick: ((Boolean) -> Unit)? = null, +) { + val localEnabled = enabled && Build.VERSION.SDK_INT >= minSdk + + if (toggled == null) { + Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, fontSize = 18.sp, modifier = Modifier.padding(bottom = 4.dp)) + Text(text = stringResource(R.string.unknown), fontSize = 14.sp, color = MaterialTheme.colorScheme.outline) + } + return + } + if (onClick != null) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, modifier = Modifier.weight(1F), fontSize = 18.sp) + Switch(checked = toggled, enabled = localEnabled, onCheckedChange = onClick) + } + } else { + Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, fontSize = 18.sp, modifier = Modifier.padding(bottom = 4.dp)) + Text(text = if (toggled) { trueLabel } else { falseLabel }, fontSize = 14.sp, color = MaterialTheme.colorScheme.outline) + } + } +} + +@Preview +@Composable +fun BooleanPropertyViewPreview() { + var toggled by remember { mutableStateOf(false) } + BooleanPropertyView(label = "Lorem Ipsum", toggled = toggled) { toggled = !toggled } +} + +@Preview +@Composable +fun LowSDKBooleanPropertyViewPreview() { + var toggled by remember { mutableStateOf(false) } + BooleanPropertyView(label = "Lorem Ipsum", toggled = toggled, minSdk = 999) { toggled = !toggled } +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/ClickablePropertyView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/ClickablePropertyView.kt new file mode 100644 index 0000000..1e3a3dd --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/ClickablePropertyView.kt @@ -0,0 +1,59 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +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.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.bluehouse.enablevolte.R + +@Composable +fun ClickablePropertyView( + label: String, + value: String?, + labelFontSize: TextUnit = 18.sp, + valueFontSize: TextUnit = 14.sp, + labelFontFamily: FontFamily? = null, + valueFontFamily: FontFamily? = null, + onClick: (() -> Unit)? = null, +) { + if (value == null) { + Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, fontSize = labelFontSize, modifier = Modifier.padding(bottom = 4.dp)) + Text(text = stringResource(R.string.unknown), color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize) + } + return + } + if (onClick != null) { + Surface(onClick = onClick, modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, modifier = Modifier.padding(bottom = 4.dp), fontSize = labelFontSize, fontFamily = labelFontFamily) + Text(text = value, color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize, fontFamily = valueFontFamily) + } + } + } else { + Column(modifier = Modifier.padding(top = 12.dp, bottom = 12.dp)) { + Text(text = label, modifier = Modifier.padding(bottom = 4.dp), fontSize = labelFontSize, fontFamily = labelFontFamily) + Text(text = value, color = MaterialTheme.colorScheme.outline, fontSize = valueFontSize, fontFamily = valueFontFamily) + } + } +} + +@Preview +@Composable +fun ClickablePropertyViewPreview() { + val value by remember { mutableStateOf("dolor sit amet") } + ClickablePropertyView("Lorem Ipsum", value) {} +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/Common.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/Common.kt new file mode 100644 index 0000000..230e2ff --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/Common.kt @@ -0,0 +1,47 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner + +@Composable +fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) { + val eventHandler = rememberUpdatedState(onEvent) + val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) + + DisposableEffect(lifecycleOwner.value) { + val lifecycle = lifecycleOwner.value.lifecycle + val observer = LifecycleEventObserver { owner, event -> + eventHandler.value(owner, event) + } + + lifecycle.addObserver(observer) + onDispose { + lifecycle.removeObserver(observer) + } + } +} + +@Composable +fun HeaderText(text: String) { + Row(modifier = Modifier.padding(top = 20.dp, bottom = 12.dp)) { + Text(text = text, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + } +} + +@Preview +@Composable +fun HeaderTextPreview() { + HeaderText("Lorem Ipsum") +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/KeyValueEditView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/KeyValueEditView.kt new file mode 100644 index 0000000..b1326ec --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/KeyValueEditView.kt @@ -0,0 +1,322 @@ +package dev.bluehouse.enablevolte.components + +import android.util.Log +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.AlertDialogDefaults +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import dev.bluehouse.enablevolte.R +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +enum class ValueType { + Int, + Long, + Bool, + String, + IntArray, + LongArray, + BoolArray, + StringArray, + Unknown, +} + +data class ArrayValueType(val v: T) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun EditPropertyDialog( + availableKeys: Iterable?, + configKey: String, + selectedValueType: ValueType?, + value: String, + keyDropdownExpanded: Boolean, + valueTypeDropdownExpanded: Boolean, + filteringOptions: List, + onConfigKeyChange: (String) -> Unit, + onValueTypeChange: (ValueType) -> Unit, + onValueChange: (String) -> Unit, + onUpdate: (String, ValueType?, String) -> Boolean, + onKeyDropdownExpandedChange: (Boolean) -> Unit, + onValueDropdownExpandedChange: (Boolean) -> Unit, + dismissDialog: () -> Unit, +) { + val TAG = "Components:EditPropertyDialog" + Dialog( + onDismissRequest = { dismissDialog() }, + properties = DialogProperties(), + ) { + Card( + colors = CardDefaults.cardColors( + containerColor = AlertDialogDefaults.containerColor, + contentColor = AlertDialogDefaults.textContentColor, + ), + ) { + Column(modifier = Modifier.padding(20.dp)) { + Text(stringResource(R.string.update_value), modifier = Modifier.padding(bottom = 16.dp), style = MaterialTheme.typography.titleMedium) + if (availableKeys != null) { + ExposedDropdownMenuBox( + expanded = keyDropdownExpanded, + onExpandedChange = { + Log.d(TAG, "Expand state change requested: ${!keyDropdownExpanded}") + onKeyDropdownExpandedChange(it) + }, + ) { + TextField( + // The `menuAnchor` modifier must be passed to the text field for correctness. + modifier = Modifier + .menuAnchor() + .fillMaxWidth() + .onFocusChanged { + onKeyDropdownExpandedChange(it.isFocused) + }, + value = configKey, + onValueChange = { onConfigKeyChange(it) }, + label = { Text(stringResource(R.string.property_name)) }, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = keyDropdownExpanded) }, + colors = ExposedDropdownMenuDefaults.textFieldColors(), + ) + if (filteringOptions.isNotEmpty() && keyDropdownExpanded) { + ExposedDropdownMenu( + expanded = true, + onDismissRequest = {}, + ) { + filteringOptions.forEach { selectionOption -> + DropdownMenuItem( + text = { Text(selectionOption) }, + onClick = { + onConfigKeyChange(selectionOption) + onKeyDropdownExpandedChange(false) + }, + contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, + ) + } + } + } + } + } else { + TextField( + value = configKey, + label = { Text(stringResource(R.string.property_name)) }, + onValueChange = { onConfigKeyChange(it) }, + ) + } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp), + verticalAlignment = if (selectedValueType == ValueType.Bool) { Alignment.CenterVertically } else { Alignment.Top }, + ) { + ExposedDropdownMenuBox( + expanded = valueTypeDropdownExpanded, + onExpandedChange = { onValueDropdownExpandedChange(it) }, + modifier = Modifier + .padding(bottom = 8.dp) + .weight(1.0F), + ) { + TextField( + // The `menuAnchor` modifier must be passed to the text field for correctness. + modifier = Modifier + .menuAnchor() + .weight(1.0F), + readOnly = true, + value = selectedValueType?.name ?: "", + onValueChange = {}, + label = { Text(stringResource(R.string.property_type)) }, + trailingIcon = { + ExposedDropdownMenuDefaults.TrailingIcon(expanded = valueTypeDropdownExpanded) + }, + colors = ExposedDropdownMenuDefaults.textFieldColors(), + ) + ExposedDropdownMenu( + expanded = valueTypeDropdownExpanded, + onDismissRequest = { onValueDropdownExpandedChange(false) }, + ) { + ValueType.values().forEach { valueType -> + DropdownMenuItem( + text = { Text(text = valueType.name) }, + onClick = { + if (selectedValueType != valueType) { + onValueTypeChange(valueType) + onValueChange("") + } + onValueDropdownExpandedChange(false) + }, + contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, + ) + } + } + } + Box(modifier = Modifier.weight(0.05F)) + Box(modifier = Modifier.weight(1.0F, fill = true)) { + when (selectedValueType) { + ValueType.Bool -> Row( + modifier = Modifier.selectableGroup(), + verticalAlignment = Alignment.CenterVertically, + ) { + RadioButton( + selected = value == "true", + onClick = { onValueChange("true") }, + ) + Text(stringResource(R.string.true_)) + RadioButton( + selected = value == "false", + onClick = { onValueChange("false") }, + ) + Text(stringResource(R.string.false_)) + } + ValueType.Int, ValueType.Long -> TextField( + value = value, + onValueChange = { onValueChange(it) }, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text), + ) + is ValueType -> TextField(value = value, onValueChange = { onValueChange(it) }) + else -> Box(modifier = Modifier.fillMaxWidth()) + } + } + } + Row(modifier = Modifier.align(Alignment.End).padding(top = 16.dp)) { + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + modifier = Modifier.padding(end = 8.dp), + shape = ButtonDefaults.outlinedShape, + onClick = { dismissDialog() }, + ) { Text(stringResource(R.string.dismiss)) } + TextButton( + border = if (selectedValueType != null) BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary) else null, + shape = ButtonDefaults.outlinedShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = { + if (onUpdate(configKey, selectedValueType, value)) { + dismissDialog() + } + }, + enabled = selectedValueType != null, + ) { Text(stringResource(R.string.confirm)) } + } + } + } + } +} + +@Composable +fun KeyValueEditView(label: String, availableKeys: Iterable? = null, onUpdate: ((String, ValueType?, String) -> Boolean)) { + var configKey by rememberSaveable { mutableStateOf("") } + var selectedValueType: ValueType? by rememberSaveable { mutableStateOf(null) } + var value by rememberSaveable { mutableStateOf("") } + var openEditPropertyDialog by rememberSaveable { mutableStateOf(false) } + var keyDropdownExpanded by rememberSaveable { mutableStateOf(false) } + var valueTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) } + var filteringOptions by rememberSaveable { mutableStateOf(listOf()) } + + LaunchedEffect(configKey) { + if (availableKeys != null) { + withContext(Dispatchers.Default) { + filteringOptions = if (configKey.length >= 3) { + val filteredItems = availableKeys.filter { it.contains(configKey, ignoreCase = false) } + if (filteredItems.size > 7) { + filteredItems.subList(0, 7) + } else { + filteredItems + } + } else { + listOf() + } + } + } + } + + if (openEditPropertyDialog) { + EditPropertyDialog( + availableKeys, + configKey, + selectedValueType, + value, + keyDropdownExpanded, + valueTypeDropdownExpanded, + filteringOptions, + onConfigKeyChange = { configKey = it }, + onValueTypeChange = { selectedValueType = it }, + onValueChange = { value = it }, + onUpdate = onUpdate, + onKeyDropdownExpandedChange = { keyDropdownExpanded = it }, + onValueDropdownExpandedChange = { valueTypeDropdownExpanded = it }, + dismissDialog = { openEditPropertyDialog = false }, + ) + } + ClickablePropertyView(label = label, value = "") { + openEditPropertyDialog = true + } +} + +@Preview +@Composable +fun KeyValueEditViewPreview() { + KeyValueEditView("Lorem Ipsum", "dolor sit amet consectetur adipiscing elit".split(" ")) { _, _, _ -> + false + } +} + +@Preview +@Composable +fun EditPropertyDialogPreview() { + val availableKeys = "Lorem ipsum dolor sit amet consectetur adipiscing elit".split(" ") + var configKey by rememberSaveable { mutableStateOf("") } + var selectedValueType: ValueType? by rememberSaveable { mutableStateOf(null) } + var value by rememberSaveable { mutableStateOf("") } + var openEditPropertyDialog by rememberSaveable { mutableStateOf(false) } + var keyDropdownExpanded by rememberSaveable { mutableStateOf(false) } + var valueTypeDropdownExpanded by rememberSaveable { mutableStateOf(false) } + val filteringOptions = listOf() + + EditPropertyDialog( + availableKeys, + configKey, + selectedValueType, + value, + keyDropdownExpanded, + valueTypeDropdownExpanded, + filteringOptions, + onConfigKeyChange = { configKey = it }, + onValueTypeChange = { selectedValueType = it }, + onValueChange = { value = it }, + onUpdate = { _, _, _ -> false }, + onKeyDropdownExpandedChange = { keyDropdownExpanded = it }, + onValueDropdownExpandedChange = { valueTypeDropdownExpanded = it }, + dismissDialog = { openEditPropertyDialog = false }, + ) +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/LoadingDialog.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/LoadingDialog.kt new file mode 100644 index 0000000..a9aa576 --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/LoadingDialog.kt @@ -0,0 +1,106 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.AlertDialogDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.LinearProgressIndicator +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.semantics.semantics +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import dev.bluehouse.enablevolte.R + +@Composable +fun InfiniteLoadingDialog() { + Dialog( + onDismissRequest = { }, + properties = DialogProperties(), + ) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(20.dp), + contentAlignment = Alignment.Center, + ) { + Card( + colors = CardDefaults.cardColors( + containerColor = AlertDialogDefaults.containerColor, + contentColor = AlertDialogDefaults.textContentColor, + ), + modifier = Modifier.fillMaxWidth(), + ) { + Row( + modifier = Modifier.padding(30.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + CircularProgressIndicator() + Text(text = stringResource(R.string.please_wait), modifier = Modifier.padding(start = 16.dp)) + } + } + } + } +} + +@Composable +fun FiniteLoadingDialog(current: Int, total: Int) { + Dialog( + onDismissRequest = { }, + properties = DialogProperties(), + ) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(20.dp), + contentAlignment = Alignment.Center, + ) { + Card( + colors = CardDefaults.cardColors( + containerColor = AlertDialogDefaults.containerColor, + contentColor = AlertDialogDefaults.textContentColor, + ), + modifier = Modifier.fillMaxWidth(), + ) { + Box(modifier = Modifier.padding(16.dp)) { + Column { + Text(stringResource(R.string.loading), fontWeight = FontWeight.Bold, fontSize = 24.sp) + LinearProgressIndicator( + modifier = Modifier + .semantics(mergeDescendants = true) {} + .padding(top = 24.dp, bottom = 4.dp) + .fillMaxWidth(), + progress = current.toFloat() / total, + ) + Text(stringResource(R.string.loaded, current, total)) + } + } + } + } + } +} + +@Preview +@Composable +fun InfiniteLoadingDialogPreview() { + InfiniteLoadingDialog() +} + +@Preview +@Composable +fun FiniteLoadingDialogPreview() { + FiniteLoadingDialog(1, 2) +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/RadioSelectPropertyView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/RadioSelectPropertyView.kt new file mode 100644 index 0000000..3f27ed6 --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/RadioSelectPropertyView.kt @@ -0,0 +1,139 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.BasicAlertDialog +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.RadioButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +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.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import dev.bluehouse.enablevolte.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RadioSelectPropertyUpdateDialog( + label: String, + values: Array, + selectedIndex: Int?, + onUpdate: (Int) -> Unit, + onClose: () -> Unit, +) { + var newIndex by remember { mutableIntStateOf(selectedIndex ?: 0) } + BasicAlertDialog(onDismissRequest = onClose) { + Surface( + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight(), + shape = RoundedCornerShape(10), + color = MaterialTheme.colorScheme.surface, + ) { + Column(modifier = Modifier.padding(all = 16.dp).fillMaxWidth()) { + Text(text = stringResource(R.string.update_value), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(bottom = 24.dp)) + values.forEachIndexed { index, s -> + Row(verticalAlignment = Alignment.CenterVertically) { + RadioButton(selected = newIndex == index, onClick = { newIndex = index }) + Text(s) + } + } + Row(modifier = Modifier.align(Alignment.End).padding(top = 16.dp)) { + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + modifier = Modifier.padding(end = 8.dp), + shape = ButtonDefaults.outlinedShape, + onClick = { onClose() }, + ) { + Text(stringResource(R.string.dismiss)) + } + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + shape = ButtonDefaults.outlinedShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = { + onUpdate(newIndex) + onClose() + }, + ) { + Text(stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) + } + } + } + } + } +} + +@Composable +fun RadioSelectPropertyView(label: String, values: Array, selectedIndex: Int?, onUpdate: ((Int) -> Unit)? = null) { + var openDialog by rememberSaveable { mutableStateOf(false) } + + if (onUpdate != null) { + if (openDialog) { + RadioSelectPropertyUpdateDialog( + label, + values, + selectedIndex, + onUpdate = { onUpdate(it) }, + onClose = { openDialog = false }, + ) + } + } + ClickablePropertyView(label = label, value = if (selectedIndex != null) values[selectedIndex] else "") { + openDialog = true + } +} + +val values = arrayOf( + "Phasellus sit amet urna ut.", + "Nullam sit amet diam sagittis, fermentum purus sed, blandit felis.", + "Nulla sed velit ac nibh fermentum efficitur.", + "Sed pharetra nibh at nisi lacinia imperdiet.", + "Nullam sollicitudin elit et hendrerit malesuada.", + "Cras in nulla sed nulla accumsan vehicula eget id augue.", + "Duis in urna quis massa bibendum sollicitudin.", + "Maecenas vel elit at libero sagittis tristique.", + "Vestibulum tempor felis a ex cursus, ut molestie lectus porttitor.", +) + +@Preview +@Composable +fun RadioSelectPropertyViewPreview() { + var selectedIndex: Int? by remember { mutableStateOf(null) } + RadioSelectPropertyView("Lorem Ipsum", values, selectedIndex) { + selectedIndex = it + } +} + +@Preview +@Composable +fun RadioSelectPropertyUpdateDialogPreview() { + var selectedIndex by remember { mutableIntStateOf(0) } + RadioSelectPropertyUpdateDialog( + "Lorem Ipsum", + values, + selectedIndex, + { selectedIndex = it }, + {}, + ) +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/StringPropertyView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/StringPropertyView.kt new file mode 100644 index 0000000..1c21fb6 --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/StringPropertyView.kt @@ -0,0 +1,99 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +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.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import dev.bluehouse.enablevolte.R + +@Composable +fun StringPropertyUpdateDialog(typedText: String, onUpdate: (String) -> Unit, onConfirm: () -> Unit, onClose: () -> Unit) { + AlertDialog( + onDismissRequest = { + // Dismiss the dialog when the user clicks outside the dialog or on the back + // button. If you want to disable that functionality, simply use an empty + // onDismissRequest. + onClose() + }, + dismissButton = { + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + modifier = Modifier.padding(end = 8.dp), + shape = ButtonDefaults.outlinedShape, + onClick = { onClose() }, + ) { + Text(stringResource(R.string.dismiss)) + } + }, + confirmButton = { + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + shape = ButtonDefaults.outlinedShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = { + onConfirm() + onClose() + }, + ) { + Text(stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) + } + }, + title = { Text(text = stringResource(R.string.update_value), style = MaterialTheme.typography.titleMedium) }, + text = { + TextField(value = typedText, onValueChange = onUpdate) + }, + ) +} + +@Composable +fun StringPropertyView(label: String, value: String?, onUpdate: ((String) -> Unit)? = null) { + var typedText by rememberSaveable { mutableStateOf("") } + var openTextEditDialog by rememberSaveable { mutableStateOf(false) } + + if (onUpdate != null) { + if (openTextEditDialog) { + StringPropertyUpdateDialog( + typedText, + onUpdate = { typedText = it }, + onConfirm = { onUpdate(typedText) }, + onClose = { openTextEditDialog = false }, + ) + } + } + ClickablePropertyView(label = label, value = value) { + if (value != null) { + typedText = value + openTextEditDialog = true + } + } +} + +@Preview +@Composable +fun StringPropertyViewPreview() { + var value by remember { mutableStateOf("") } + StringPropertyView("Lorem Ipsum", value) { value = it } +} + +@Preview +@Composable +fun StringPropertyUpdateDialogPreview() { + var typedText by remember { mutableStateOf("") } + StringPropertyUpdateDialog(typedText, { typedText = it }, {}, {}) +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/components/UserAgentPropertyView.kt b/app/src/main/java/dev/bluehouse/enablevolte/components/UserAgentPropertyView.kt new file mode 100644 index 0000000..df05bcf --- /dev/null +++ b/app/src/main/java/dev/bluehouse/enablevolte/components/UserAgentPropertyView.kt @@ -0,0 +1,192 @@ +package dev.bluehouse.enablevolte.components + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.BasicAlertDialog +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +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.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.bluehouse.enablevolte.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun UserAgentUpdateDialog( + labels: Array, + values: Array, + selectedIndex: Int, + typedText: String, + dropdownExpanded: Boolean, + onTextUpdate: (String) -> Unit, + onIndexUpdate: (Int) -> Unit, + onDismissRequest: () -> Unit, + onExpandedChange: (Boolean) -> Unit, +) { + BasicAlertDialog(onDismissRequest = onDismissRequest) { + Surface( + modifier = Modifier + .wrapContentWidth() + .wrapContentHeight(), + shape = RoundedCornerShape(10), + color = MaterialTheme.colorScheme.surface, + ) { + Column(modifier = Modifier.padding(all = 16.dp)) { + Text(text = stringResource(R.string.update_value), style = MaterialTheme.typography.labelMedium, modifier = Modifier.padding(bottom = 24.dp)) + ExposedDropdownMenuBox( + expanded = dropdownExpanded, + onExpandedChange = onExpandedChange, + modifier = Modifier.padding(bottom = 8.dp), + ) { + TextField( + // The `menuAnchor` modifier must be passed to the text field for correctness. + modifier = Modifier + .menuAnchor() + .wrapContentWidth(), + readOnly = true, + value = if (values[selectedIndex] == typedText) labels[selectedIndex] else "Custom", + onValueChange = {}, + label = { Text(stringResource(R.string.presets)) }, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = dropdownExpanded) }, + colors = ExposedDropdownMenuDefaults.textFieldColors(), + ) + ExposedDropdownMenu( + expanded = dropdownExpanded, + onDismissRequest = { onExpandedChange(false) }, + ) { + labels.forEachIndexed { i, label -> + DropdownMenuItem( + text = { Text(text = label) }, + onClick = { + onTextUpdate(values[i]) + onIndexUpdate(i) + onExpandedChange(false) + }, + contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, + ) + } + } + } + TextField(textStyle = TextStyle(fontSize = 14.sp), value = typedText, onValueChange = { onTextUpdate(it) }) + Row(modifier = Modifier.align(Alignment.End).padding(top = 16.dp)) { + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + modifier = Modifier.padding(end = 8.dp), + shape = ButtonDefaults.outlinedShape, + onClick = { onDismissRequest() }, + ) { + Text(stringResource(R.string.dismiss)) + } + TextButton( + border = BorderStroke(0.5.dp, MaterialTheme.colorScheme.primary), + shape = ButtonDefaults.outlinedShape, + colors = ButtonDefaults.filledTonalButtonColors( + containerColor = MaterialTheme.colorScheme.primary, + ), + onClick = { + onTextUpdate(typedText) + onDismissRequest() + }, + ) { + Text(stringResource(R.string.confirm), color = MaterialTheme.colorScheme.onPrimary) + } + } + } + } + } +} + +@Composable +fun UserAgentPropertyView(label: String, value: String?, onUpdate: ((String) -> Unit)? = null) { + val labels = arrayOf(stringResource(R.string.default_), stringResource(R.string.lgu)) + val values = arrayOf(stringResource(R.string.ua_default), stringResource(R.string.ua_lgu)) + + var typedText by rememberSaveable { mutableStateOf("") } + var openTextEditDialog by rememberSaveable { mutableStateOf(false) } + var dropdownExpanded by rememberSaveable { mutableStateOf(false) } + var selectedIndex by rememberSaveable { mutableIntStateOf(if (values.contains(value)) values.indexOf(value) else 0) } + + if (onUpdate != null) { + if (openTextEditDialog) { + UserAgentUpdateDialog( + labels, + values, + selectedIndex, + typedText, + dropdownExpanded, + onTextUpdate = { + typedText = it + onUpdate(typedText) + }, + onIndexUpdate = { + selectedIndex = it + }, + onDismissRequest = { openTextEditDialog = false }, + onExpandedChange = { dropdownExpanded = it }, + ) + } + } + ClickablePropertyView(label = label, value = value) { + if (value != null) { + typedText = value + openTextEditDialog = true + } + } +} + +@Preview +@Composable +fun UserAgentUpdateDialogPreview() { + val labels = arrayOf(stringResource(R.string.default_), stringResource(R.string.lgu)) + val values = arrayOf(stringResource(R.string.ua_default), stringResource(R.string.ua_lgu)) + + var typedText by rememberSaveable { mutableStateOf("") } + var openTextEditDialog by rememberSaveable { mutableStateOf(false) } + var dropdownExpanded by rememberSaveable { mutableStateOf(false) } + var selectedIndex by rememberSaveable { mutableIntStateOf(0) } + + UserAgentUpdateDialog( + labels, + values, + selectedIndex, + typedText, + dropdownExpanded, + onTextUpdate = { + typedText = it + }, + onIndexUpdate = { + selectedIndex = it + }, + onDismissRequest = { openTextEditDialog = false }, + onExpandedChange = { dropdownExpanded = it }, + ) +} + +@Preview +@Composable +fun UserAgentPropertyViewPreview() { + UserAgentPropertyView("Lorem Ipsum", value = stringResource(R.string.ua_default)) +} diff --git a/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt b/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt index 05c05d7..3cfc54d 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/pages/Config.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.verticalScroll 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 import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable @@ -23,16 +24,17 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.navigation.NavController -import dev.bluehouse.enablevolte.BooleanPropertyView import dev.bluehouse.enablevolte.CarrierModer -import dev.bluehouse.enablevolte.ClickablePropertyView -import dev.bluehouse.enablevolte.HeaderText -import dev.bluehouse.enablevolte.InfiniteLoadingDialog import dev.bluehouse.enablevolte.R import dev.bluehouse.enablevolte.ShizukuStatus import dev.bluehouse.enablevolte.SubscriptionModer -import dev.bluehouse.enablevolte.UserAgentPropertyView import dev.bluehouse.enablevolte.checkShizukuPermission +import dev.bluehouse.enablevolte.components.BooleanPropertyView +import dev.bluehouse.enablevolte.components.ClickablePropertyView +import dev.bluehouse.enablevolte.components.HeaderText +import dev.bluehouse.enablevolte.components.InfiniteLoadingDialog +import dev.bluehouse.enablevolte.components.RadioSelectPropertyView +import dev.bluehouse.enablevolte.components.UserAgentPropertyView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -44,6 +46,7 @@ fun Config(navController: NavController, subId: Int) { val moder = SubscriptionModer(subId) val carrierModer = CarrierModer(LocalContext.current) + val carrierName = moder.carrierName val scrollState = rememberScrollState() val context = LocalContext.current val cannotFindKeyText = stringResource(R.string.cannot_find_key) @@ -57,7 +60,7 @@ fun Config(navController: NavController, subId: Int) { var allowAddingAPNs by rememberSaveable { mutableStateOf(false) } var showVoWifiMode by rememberSaveable { mutableStateOf(false) } var showVoWifiRoamingMode by rememberSaveable { mutableStateOf(false) } - var showVoWifiInNetworkName by rememberSaveable { mutableStateOf(false) } + var wfcSpnFormatIndex by rememberSaveable { mutableIntStateOf(0) } var showVoWifiIcon by rememberSaveable { mutableStateOf(false) } var alwaysDataRATIcon by rememberSaveable { mutableStateOf(false) } var supportWfcWifiOnly by rememberSaveable { mutableStateOf(false) } @@ -92,7 +95,7 @@ fun Config(navController: NavController, subId: Int) { allowAddingAPNs = moder.allowAddingAPNs showVoWifiMode = VERSION.SDK_INT >= VERSION_CODES.R && moder.showVoWifiMode showVoWifiRoamingMode = VERSION.SDK_INT >= VERSION_CODES.R && moder.showVoWifiRoamingMode - showVoWifiInNetworkName = (moder.showVoWifiInNetworkName == 1) + wfcSpnFormatIndex = moder.wfcSpnFormatIndex showVoWifiIcon = moder.showVoWifiIcon alwaysDataRATIcon = VERSION.SDK_INT >= VERSION_CODES.R && moder.alwaysDataRATIcon supportWfcWifiOnly = moder.supportWfcWifiOnly @@ -277,15 +280,27 @@ fun Config(navController: NavController, subId: Int) { true } } - BooleanPropertyView(label = stringResource(R.string.add_wifi_calling_to_network_name), toggled = showVoWifiInNetworkName) { - showVoWifiInNetworkName = if (showVoWifiInNetworkName) { - moder.updateCarrierConfig(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT, 0) - false - } else { - moder.updateCarrierConfig(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT, 1) - moder.restartIMSRegistration() - true - } + RadioSelectPropertyView( + label = stringResource(R.string.wi_fi_calling_carrier_name_format), + values = arrayOf( + "%s".format(carrierName), + "%s Wi-Fi Calling".format(carrierName), + "WLAN Call", + "%s WLAN Call".format(carrierName), + "%s Wi-Fi".format(carrierName), + "WiFi Calling | %s".format(carrierName), + "%s VoWifi".format(carrierName), + "Wi-Fi Calling", + "Wi-Fi", + "WiFi Calling", + "VoWifi", + "%s WiFi Calling".format(carrierName), + "WiFi Call", + ), + selectedIndex = wfcSpnFormatIndex, + ) { + moder.updateCarrierConfig(CarrierConfigManager.KEY_WFC_SPN_FORMAT_IDX_INT, it) + wfcSpnFormatIndex = it } BooleanPropertyView(label = stringResource(R.string.show_wifi_only_for_vowifi), toggled = supportWfcWifiOnly) { supportWfcWifiOnly = if (supportWfcWifiOnly) { diff --git a/app/src/main/java/dev/bluehouse/enablevolte/pages/DumpedConfig.kt b/app/src/main/java/dev/bluehouse/enablevolte/pages/DumpedConfig.kt index 88f7972..a40c066 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/pages/DumpedConfig.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/pages/DumpedConfig.kt @@ -24,9 +24,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.Dp -import dev.bluehouse.enablevolte.InfiniteLoadingDialog import dev.bluehouse.enablevolte.R import dev.bluehouse.enablevolte.SubscriptionModer +import dev.bluehouse.enablevolte.components.InfiniteLoadingDialog import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/app/src/main/java/dev/bluehouse/enablevolte/pages/Editor.kt b/app/src/main/java/dev/bluehouse/enablevolte/pages/Editor.kt index 0c2edf5..3e1008d 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/pages/Editor.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/pages/Editor.kt @@ -55,12 +55,12 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import dev.bluehouse.enablevolte.ClickablePropertyView -import dev.bluehouse.enablevolte.FiniteLoadingDialog -import dev.bluehouse.enablevolte.InfiniteLoadingDialog import dev.bluehouse.enablevolte.R import dev.bluehouse.enablevolte.SubscriptionModer -import dev.bluehouse.enablevolte.ValueType +import dev.bluehouse.enablevolte.components.ClickablePropertyView +import dev.bluehouse.enablevolte.components.FiniteLoadingDialog +import dev.bluehouse.enablevolte.components.InfiniteLoadingDialog +import dev.bluehouse.enablevolte.components.ValueType import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.lang.reflect.Field diff --git a/app/src/main/java/dev/bluehouse/enablevolte/pages/Home.kt b/app/src/main/java/dev/bluehouse/enablevolte/pages/Home.kt index 76e6231..3428bb2 100644 --- a/app/src/main/java/dev/bluehouse/enablevolte/pages/Home.kt +++ b/app/src/main/java/dev/bluehouse/enablevolte/pages/Home.kt @@ -21,16 +21,16 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.Dp import androidx.core.content.ContextCompat.startActivity import androidx.navigation.NavController -import dev.bluehouse.enablevolte.BooleanPropertyView import dev.bluehouse.enablevolte.BuildConfig import dev.bluehouse.enablevolte.CarrierModer -import dev.bluehouse.enablevolte.ClickablePropertyView -import dev.bluehouse.enablevolte.HeaderText import dev.bluehouse.enablevolte.R import dev.bluehouse.enablevolte.ShizukuStatus -import dev.bluehouse.enablevolte.StringPropertyView import dev.bluehouse.enablevolte.SubscriptionModer import dev.bluehouse.enablevolte.checkShizukuPermission +import dev.bluehouse.enablevolte.components.BooleanPropertyView +import dev.bluehouse.enablevolte.components.ClickablePropertyView +import dev.bluehouse.enablevolte.components.HeaderText +import dev.bluehouse.enablevolte.components.StringPropertyView import dev.bluehouse.enablevolte.getLatestAppVersion import dev.bluehouse.enablevolte.uniqueName import net.swiftzer.semver.SemVer diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 6f358a3..c090ccd 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -19,7 +19,7 @@ 漫游时启用 VoWiFi 显示 VoWiFi 选项 显示 VoWiFi漫游 选项 - 网络名中添加 \"Wi-Fi Calling\" + Wi-Fi Calling network name format 在 SIM 信息中显示 IMS 状态 允许添加接入点APN VoWiFi 显示 \"仅WiFi\" 模式 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1c90b69..041dbdf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,7 @@ Show VoWiFi preference in Settings Show VoWiFi Roaming preference in Settings Show IMS Status in SIM Info - Add \"Wi-Fi Calling\" to Network Name + Wi-Fi Calling network name format Show \"WiFi only\" mode for VoWiFi Enable Video Calling (VT) Allow adding APNs