diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/extension/UriExtension.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/extension/UriExtension.kt new file mode 100644 index 0000000..9053574 --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/extension/UriExtension.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Contributors to the Eclipse Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.eclipse.kuksa.companion.extension + +import android.content.Context +import android.net.Uri +import android.provider.OpenableColumns + +fun Uri.fetchFileName(context: Context): String? { + var fileName: String? = null + val cursor = context.contentResolver.query(this, null, null, null, null) + cursor?.use { + val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + + if (cursor.moveToFirst()) { + fileName = cursor.getString(nameIndex) + } + } + return fileName +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/CategorySetting.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/CategorySetting.kt new file mode 100644 index 0000000..88783d1 --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/CategorySetting.kt @@ -0,0 +1,39 @@ +package org.eclipse.kuksa.companion.feature.settings.view + +import androidx.compose.foundation.layout.Row +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.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview + +@Suppress("SameParameterValue") // re-usability +@Composable +fun CategorySetting( + label: String, + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier.padding(SettingsElementPadding), + ) { + Text( + text = label, + fontSize = SettingsCategoryFontSize, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +@Composable +@Preview +private fun CategorySettingPreview() { + Surface { + CategorySetting(label = "Connection") + } +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/EditableTextSetting.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/EditableTextSetting.kt new file mode 100644 index 0000000..ef7e0ea --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/EditableTextSetting.kt @@ -0,0 +1,223 @@ +package org.eclipse.kuksa.companion.feature.settings.view + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextFieldDefaults +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.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties + +@Composable +fun EditableTextSetting( + label: String, + value: String, + modifier: Modifier = Modifier, + onValueChanged: (String) -> Unit, +) { + var isDialogOpen: Boolean by remember { mutableStateOf(false) } + + Row( + modifier = modifier + .fillMaxWidth() + .clickable { + isDialogOpen = true + } + .padding(SettingsElementPadding), + ) { + Column( + Modifier + .fillMaxWidth(), + ) { + Text( + text = label, + fontSize = SettingPrimaryFontSize, + fontWeight = FontWeight.Bold, + ) + Text( + text = value, + fontSize = SettingSecondaryFontSize, + ) + } + } + + if (isDialogOpen) { + EditTextDialog( + label = label, + initialValue = value, + onDismissRequest = { + isDialogOpen = false + }, + onClickOk = onValueChanged, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) +@Composable +fun EditTextDialog( + label: String, + initialValue: String, + modifier: Modifier = Modifier, + onDismissRequest: () -> Unit = {}, + onClickCancel: () -> Unit = {}, + onClickOk: (String) -> Unit = {}, +) { + val containerColor = MaterialTheme.colorScheme.secondaryContainer + + val keyboardController = LocalSoftwareKeyboardController.current + + val focusRequester = remember { FocusRequester() } + LaunchedEffect(Unit) { + focusRequester.requestFocus() + } + + val direction = LocalLayoutDirection.current + var textFieldValue by remember { + val selection = if (direction == LayoutDirection.Ltr) { // move Cursor to end + TextRange(initialValue.length) + } else { + TextRange.Zero + } + + mutableStateOf(TextFieldValue(initialValue, selection)) + } + + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties( + dismissOnClickOutside = true, + dismissOnBackPress = true, + ), + ) { + Box(modifier) { + val interactionSource = remember { MutableInteractionSource() } + Column( + Modifier + .background(containerColor, RoundedCornerShape(15.dp)) + .padding(25.dp), + ) { + Text( + text = label, + fontSize = SettingPrimaryFontSize, + fontWeight = FontWeight.Bold, + ) + + Spacer(modifier = Modifier.height(10.dp)) + + BasicTextField( + value = textFieldValue, + onValueChange = { newValue -> + textFieldValue = newValue + }, + textStyle = TextStyle( + fontSize = SettingSecondaryFontSize, + ), + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done, + ), + keyboardActions = KeyboardActions( + onDone = { + keyboardController?.hide() + onDismissRequest() + onClickOk(textFieldValue.text) + }, + ), + modifier = Modifier + .fillMaxWidth() + .focusRequester(focusRequester), + ) { innerTextField -> + TextFieldDefaults.DecorationBox( + value = initialValue, + enabled = true, + innerTextField = innerTextField, + interactionSource = interactionSource, + singleLine = true, + visualTransformation = VisualTransformation.None, + contentPadding = PaddingValues(0.dp), + colors = TextFieldDefaults.colors( + focusedContainerColor = containerColor, + unfocusedContainerColor = containerColor, + ), + ) + } + Spacer(modifier = Modifier.height(10.dp)) + Row(horizontalArrangement = Arrangement.End, modifier = Modifier.fillMaxWidth()) { + TextButton(onClick = { + onDismissRequest() + onClickCancel() + }) { + Text("Cancel") + } + TextButton(onClick = { + onDismissRequest() + onClickOk(textFieldValue.text) + }) { + Text("OK") + } + } + } + } + } +} + +@Preview +@Composable +private fun EditableTextSettingPreview() { + Surface { + EditableTextSetting( + label = "Gerätename", + value = "Pixel", + ) { + // unused in preview + } + } +} + +@Preview +@Composable +private fun EditTextDialogPreview() { + EditTextDialog( + label = "Gerätename", + initialValue = "Pixel 3", + onDismissRequest = {}, + ) +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/FileSelectorSetting.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/FileSelectorSetting.kt new file mode 100644 index 0000000..ff205ae --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/FileSelectorSetting.kt @@ -0,0 +1,103 @@ +@file:JvmName("FileSelectorSettingKt") + +package org.eclipse.kuksa.companion.feature.settings.view + +import android.content.Intent +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension +import org.eclipse.kuksa.companion.R + +@Suppress("SameParameterValue") // re-usability +@Composable +fun FileSelectorSetting( + label: String, + value: String, + modifier: Modifier = Modifier, + onResult: (Uri) -> Unit, +) { + val context = LocalContext.current + + val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { + val uri = it ?: return@rememberLauncherForActivityResult + + context.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) + + onResult(uri) + } + + ConstraintLayout( + modifier + .fillMaxWidth() + .padding(SettingsElementPadding) + .clickable { + val fileTypes = arrayOf("*/*") + launcher.launch(fileTypes) + }, + ) { + val (labelRef, valueRef, imageRef) = createRefs() + + Text( + text = label, + fontSize = SettingPrimaryFontSize, + fontWeight = FontWeight.Bold, + modifier = Modifier + .padding(end = SettingsTextPaddingEnd) + .constrainAs(labelRef) { + width = Dimension.fillToConstraints + start.linkTo(parent.start) + end.linkTo(imageRef.start) + }, + ) + Text( + text = value, + fontSize = SettingSecondaryFontSize, + modifier = Modifier + .padding(end = SettingsTextPaddingEnd) + .constrainAs(valueRef) { + width = Dimension.fillToConstraints + start.linkTo(parent.start) + end.linkTo(imageRef.start) + top.linkTo(labelRef.bottom) + }, + ) + Image( + painter = painterResource(id = R.drawable.baseline_upload_file_24), + contentDescription = "Select Certificate", + modifier = Modifier + .size(40.dp) + .constrainAs(imageRef) { + end.linkTo(parent.end) + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + height = Dimension.fillToConstraints + }, + ) + } +} + +@Composable +@Preview +private fun SwitchSettingPreview() { + Surface { + FileSelectorSetting(label = "File Selector Setting", value = "Some Value") { + // unused in preview + } + } +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SettingsView.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SettingsView.kt index f4c699f..5660565 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SettingsView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SettingsView.kt @@ -19,63 +19,40 @@ package org.eclipse.kuksa.companion.feature.settings.view -import android.content.Intent import android.net.Uri -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentHeight -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.material3.Button -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.material3.contentColorFor 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.Alignment.Companion.CenterVertically -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -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.lifecycle.compose.collectAsStateWithLifecycle +import org.eclipse.kuksa.companion.extension.fetchFileName import org.eclipse.kuksa.companion.feature.connection.model.ConnectionInfo import org.eclipse.kuksa.companion.feature.connection.repository.ConnectionInfoRepository import org.eclipse.kuksa.companion.feature.settings.viewModel.SettingsViewModel +import org.eclipse.kuksa.companion.ui.theme.KuksaCompanionTheme + +val SettingsElementPadding = 10.dp +val SettingsTextPaddingEnd = 15.dp + +val SettingsCategoryFontSize = 20.sp +val SettingPrimaryFontSize = 18.sp +val SettingSecondaryFontSize = 16.sp -@OptIn(ExperimentalLayoutApi::class) @Composable fun SettingsView( settingsViewModel: SettingsViewModel, modifier: Modifier = Modifier, ) { + val context = LocalContext.current val connectionInfoState by settingsViewModel.connectionInfoFlow.collectAsStateWithLifecycle(initialValue = ConnectionInfo()) @@ -83,26 +60,25 @@ fun SettingsView( mutableStateOf(connectionInfoState) } - Scaffold( - modifier = modifier.fillMaxSize(), - ) { paddingValues -> - Surface( - modifier = Modifier - .padding(paddingValues) - .consumeWindowInsets(paddingValues), - ) { + KuksaCompanionTheme { + Surface(modifier) { Column( modifier = Modifier - .padding(10.dp, 0.dp) - .consumeWindowInsets(paddingValues), + .padding(10.dp, 0.dp), ) { - Category(label = "Connection") - EditableTextSetting("Host", connectionInfo.host) { newValue -> + CategorySetting(label = "Connection") + EditableTextSetting( + "Host", + connectionInfo.host, + ) { newValue -> connectionInfo = connectionInfoState.copy(host = newValue) settingsViewModel.updateConnectionInfo(connectionInfo) } - EditableTextSetting("Port", connectionInfo.port.toString()) { newValue -> + EditableTextSetting( + "Port", + connectionInfo.port.toString(), + ) { newValue -> try { val port = newValue.toInt() connectionInfo = connectionInfoState.copy(port = port) @@ -112,223 +88,32 @@ fun SettingsView( } } - SwitchSetting("Enable TLS", connectionInfo.isTlsEnabled) { newValue -> + SwitchSetting( + "Enable TLS", + connectionInfo.isTlsEnabled, + ) { newValue -> connectionInfo = connectionInfoState.copy(isTlsEnabled = newValue) settingsViewModel.updateConnectionInfo(connectionInfo) } - FileSelectorSetting( - label = "Certificate", - value = connectionInfo.certificate.uriPath, - ) { uri: Uri? -> - val certificate = connectionInfoState.certificate.copy(uriPath = uri.toString()) - connectionInfo = connectionInfoState.copy(certificate = certificate) - settingsViewModel.updateConnectionInfo(connectionInfo) - } - } - } - } -} - -@Suppress("SameParameterValue") // re-usability -@Composable -private fun Category(label: String) { - Row( - modifier = Modifier.padding(10.dp), - ) { - Text( - text = label, - fontSize = 15.sp, - fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.fillMaxWidth(), - ) - } -} - -@Composable -private fun EditableTextSetting( - label: String, - value: String, - onValueChanged: (String) -> Unit, -) { - var isDialogOpen by remember { mutableStateOf(false) } - - Row( - modifier = Modifier - .fillMaxWidth() - .height(75.dp) - .offset(10.dp), - ) { - Column( - Modifier - .fillMaxWidth() - .fillMaxHeight() - .weight(1F) - .clickable { - isDialogOpen = true - }, - ) { - Text(text = label, fontSize = 20.sp) - Spacer(modifier = Modifier.height(3.dp)) - Text(text = value) - } - } - - if (isDialogOpen) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .fillMaxSize() - .background( - color = contentColorFor(MaterialTheme.colorScheme.background).copy(alpha = 0.6f), - ) - .clickable { isDialogOpen = true }, - ) { - TextDialog(label, value, onClickOk = { - isDialogOpen = false - onValueChanged(it) - }, onClickCancel = { - isDialogOpen = false - }) - } - } -} - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun TextDialog( - label: String, - value: String, - onClickOk: (String) -> Unit, - modifier: Modifier = Modifier, - onClickCancel: () -> Unit, -) { - val keyboardController = LocalSoftwareKeyboardController.current - - var newValue by remember { mutableStateOf(value) } - - Column( - modifier = modifier - .clip(RoundedCornerShape(4.dp)) - .background(MaterialTheme.colorScheme.background) - .padding(8.dp), - ) { - Column( - modifier = Modifier.padding(16.dp), - ) { - Text(text = label) + if (connectionInfo.isTlsEnabled) { + val uri = connectionInfo.certificate.uri + val fileName = uri.fetchFileName(context) ?: "Select certificate..." - Spacer(modifier = Modifier.height(8.dp)) - - TextField( - value = newValue, - onValueChange = { newValue = it }, - singleLine = true, - keyboardActions = KeyboardActions( - onDone = { - keyboardController?.hide() - onClickOk(newValue.trim()) - }, - ), - ) - } - - Spacer(modifier = Modifier.height(8.dp)) - - Row( - modifier = Modifier.align(Alignment.End), - ) { - Button(onClick = { - keyboardController?.hide() - onClickCancel() - }) { - Text("Cancel") - } - - Spacer(modifier = Modifier.width(8.dp)) - - Button(onClick = { - keyboardController?.hide() - onClickOk(newValue.trim()) - }) { - Text("OK") + FileSelectorSetting( + label = "Certificate", + value = fileName, + ) { selectedUri: Uri? -> + val certificate = connectionInfoState.certificate.copy(uriPath = selectedUri.toString()) + connectionInfo = connectionInfoState.copy(certificate = certificate) + settingsViewModel.updateConnectionInfo(connectionInfo) + } + } } } } } -@Suppress( - // re-usability - "SameParameterValue", - // it does not make sense to create a constant for each elements weight - "MagicNumber", -) -@Composable -private fun SwitchSetting( - label: String, - enabled: Boolean, - modifier: Modifier = Modifier, - onValueChanged: (Boolean) -> Unit, -) { - Row( - modifier = modifier.padding(10.dp), - ) { - Text( - text = label, - fontSize = 20.sp, - modifier = Modifier - .fillMaxWidth() - .wrapContentHeight() - .weight(3F) - .align(CenterVertically), - ) - Switch(checked = enabled, onCheckedChange = { - onValueChanged(it) - }, modifier = Modifier.weight(1F)) - } -} - -@Suppress("SameParameterValue") // Reusability for the label parameter -@Composable -private fun FileSelectorSetting( - label: String, - value: String, - onResult: (Uri) -> Unit, -) { - val context = LocalContext.current - - val launcher = rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) { - val uri = it ?: return@rememberLauncherForActivityResult - - context.contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) - - onResult(uri) - } - - Row( - modifier = Modifier - .fillMaxWidth() - .height(75.dp) - .offset(10.dp), - ) { - Column( - Modifier - .fillMaxWidth() - .fillMaxHeight() - .weight(1F) - .clickable { - val fileTypes = arrayOf("*/*") - launcher.launch(fileTypes) - }, - ) { - Text(text = label, fontSize = 20.sp) - Spacer(modifier = Modifier.height(3.dp)) - Text(text = value) - } - } -} - @Preview @Composable private fun SettingsViewPreview() { diff --git a/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SwitchSetting.kt b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SwitchSetting.kt new file mode 100644 index 0000000..8cad0cf --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/companion/feature/settings/view/SwitchSetting.kt @@ -0,0 +1,72 @@ +package org.eclipse.kuksa.companion.feature.settings.view + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Surface +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension + +@Suppress("SameParameterValue") // re-usability +@Composable +fun SwitchSetting( + label: String, + enabled: Boolean, + modifier: Modifier = Modifier, + onValueChanged: (Boolean) -> Unit, +) { + ConstraintLayout( + modifier = modifier + .fillMaxWidth() + .clickable { + onValueChanged(!enabled) + } + .padding(SettingsElementPadding), + ) { + val (textView, switchView) = createRefs() + + Text( + text = label, + fontSize = SettingPrimaryFontSize, + fontWeight = FontWeight.Bold, + modifier = Modifier + .padding(end = SettingsTextPaddingEnd) + .constrainAs(textView) { + start.linkTo(parent.start) + end.linkTo(switchView.start) + + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + width = Dimension.fillToConstraints + }, + ) + Switch( + checked = enabled, + onCheckedChange = { + onValueChanged(it) + }, + modifier = Modifier.constrainAs(switchView) { + end.linkTo(parent.end) + + top.linkTo(parent.top) + bottom.linkTo(parent.bottom) + }, + ) + } +} + +@Composable +@Preview +private fun SwitchSettingPreview() { + Surface { + SwitchSetting(label = "Switch Setting", enabled = true) { + // unused in preview + } + } +} diff --git a/app/src/main/res/drawable/baseline_upload_file_24.xml b/app/src/main/res/drawable/baseline_upload_file_24.xml new file mode 100644 index 0000000..90e8cd8 --- /dev/null +++ b/app/src/main/res/drawable/baseline_upload_file_24.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 64e2d9b..8fc81b5 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -19,5 +19,12 @@ - + + +