From 77fbd4a4af7f7fe213b4900e4513100993f3923f Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Wed, 6 Dec 2023 10:15:13 +0100 Subject: [PATCH 01/10] feature(TestApp): Slimline ConnectedView Move Disconnect Button into TopBar Signed-off-by: Andre Weber --- .../view/DataBrokerConnectionView.kt | 27 ++-- .../testapp/databroker/view/DataBrokerView.kt | 118 ++++++++++++------ app/src/main/res/drawable/round_power_24.xml | 5 + .../main/res/drawable/round_power_off_24.xml | 24 ++++ 4 files changed, 126 insertions(+), 48 deletions(-) create mode 100644 app/src/main/res/drawable/round_power_24.xml create mode 100644 app/src/main/res/drawable/round_power_off_24.xml diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt index 68ba2e0c..6c55c779 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt @@ -52,7 +52,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.eclipse.kuksa.testapp.databroker.model.ConnectionInfo import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel -import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel.* +import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel.ConnectionViewState import org.eclipse.kuksa.testapp.extension.compose.Headline import org.eclipse.kuksa.testapp.extension.compose.RememberCountdown import org.eclipse.kuksa.testapp.extension.fetchFileName @@ -71,7 +71,9 @@ fun DataBrokerConnection(viewModel: ConnectionViewModel) { mutableStateOf(connectionInfoState.value) } - Headline("Connection") + if (!viewModel.isConnected) { + Headline("Connection") + } Column { AnimatedVisibility(visible = viewModel.isDisconnected) { Column { @@ -223,13 +225,9 @@ fun DataBrokerConnection(viewModel: ConnectionViewModel) { Text(text = "Connecting... ($timeoutSeconds)", textAlign = TextAlign.Center) } - ConnectionViewState.CONNECTED -> - Button( - onClick = { viewModel.onDisconnect() }, - modifier = Modifier.requiredWidth(MinimumButtonWidth), - ) { - Text(text = "Disconnect") - } + ConnectionViewState.CONNECTED -> { + // intentionally left empty + } } } } @@ -238,7 +236,16 @@ fun DataBrokerConnection(viewModel: ConnectionViewModel) { @Preview @Composable -fun DataBrokerConnectionPreview() { +fun DataBrokerConnectionPreview_Disconnected() { val connectionInfoRepository = ConnectionInfoRepository(LocalContext.current) DataBrokerConnection(viewModel = ConnectionViewModel(connectionInfoRepository)) } + +@Preview +@Composable +fun DataBrokerConnectionPreview_Connected() { + val connectionInfoRepository = ConnectionInfoRepository(LocalContext.current) + val viewModel = ConnectionViewModel(connectionInfoRepository) + viewModel.updateConnectionState(ConnectionViewState.CONNECTED) + DataBrokerConnection(viewModel = viewModel) +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index 7542c4b8..fd1125db 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -66,6 +66,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontStyle @@ -73,10 +74,13 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import org.eclipse.kuksa.proto.v1.Types.Datapoint.ValueCase +import org.eclipse.kuksa.testapp.R import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel -import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel.* import org.eclipse.kuksa.testapp.databroker.viewmodel.OutputViewModel import org.eclipse.kuksa.testapp.databroker.viewmodel.TopAppBarViewModel import org.eclipse.kuksa.testapp.databroker.viewmodel.TopAppBarViewModel.DataBrokerMode @@ -149,46 +153,84 @@ private fun TopBar( containerColor = MaterialTheme.colorScheme.primaryContainer, ), actions = { - OverflowMenu { - Row( - modifier = Modifier - .clickable( - enabled = connectionViewModel.isDisconnected, - ) { - val newValue = !topAppBarViewModel.isCompatibilityModeEnabled - topAppBarViewModel.isCompatibilityModeEnabled = newValue - } - .padding(horizontal = 16.dp), + ConnectionStatusIcon(connectionViewModel) + HamburgerMenu(connectionViewModel, topAppBarViewModel) + }, + ) +} + +@Composable +private fun HamburgerMenu( + connectionViewModel: ConnectionViewModel, + topAppBarViewModel: TopAppBarViewModel, +) { + OverflowMenu { + Row( + modifier = Modifier + .clickable( + enabled = connectionViewModel.isDisconnected, ) { - Checkbox( - checked = topAppBarViewModel.isCompatibilityModeEnabled, - onCheckedChange = null, - enabled = connectionViewModel.isDisconnected, - ) - Text(text = "Java Compatibility Mode", modifier = Modifier.padding(start = 16.dp)) + val newValue = !topAppBarViewModel.isCompatibilityModeEnabled + topAppBarViewModel.isCompatibilityModeEnabled = newValue } - Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) - Row( - modifier = Modifier - .clickable { - val newMode = if (!topAppBarViewModel.isSpecificationModeEnabled) { - DataBrokerMode.SPECIFICATION - } else { - DataBrokerMode.VSS_PATH - } - topAppBarViewModel.updateDataBrokerMode(newMode) - } - .padding(horizontal = 16.dp), - ) { - Checkbox( - checked = topAppBarViewModel.isSpecificationModeEnabled, - onCheckedChange = null, - ) - Text(text = "Specification Mode", modifier = Modifier.padding(start = 16.dp)) + .padding(horizontal = 16.dp), + ) { + Checkbox( + checked = topAppBarViewModel.isCompatibilityModeEnabled, + onCheckedChange = null, + enabled = connectionViewModel.isDisconnected, + ) + Text( + text = "Java Compatibility Mode", + modifier = Modifier.padding(start = 16.dp), + ) + } + Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) + Row( + modifier = Modifier + .clickable { + val newMode = if (!topAppBarViewModel.isSpecificationModeEnabled) { + DataBrokerMode.SPECIFICATION + } else { + DataBrokerMode.VSS_PATH + } + topAppBarViewModel.updateDataBrokerMode(newMode) } - } - }, - ) + .padding(horizontal = 16.dp), + ) { + Checkbox( + checked = topAppBarViewModel.isSpecificationModeEnabled, + onCheckedChange = null, + ) + Text(text = "Specification Mode", modifier = Modifier.padding(start = 16.dp)) + } + } +} + +@Composable +private fun ConnectionStatusIcon( + connectionViewModel: ConnectionViewModel, +) { + val modifier: Modifier = Modifier + if (connectionViewModel.isConnected) { + Icon( + painter = painterResource(id = R.drawable.round_power_24), + contentDescription = "Disconnect", + modifier = modifier.clickable { connectionViewModel.onDisconnect() }, + ) + } else { + Icon( + painter = painterResource(id = R.drawable.round_power_off_24), + contentDescription = "Connect", + modifier = modifier.clickable { + val coroutineScope = CoroutineScope(Dispatchers.Default) + coroutineScope.launch { + val connectionInfo = connectionViewModel.connectionInfoFlow.first() + connectionViewModel.onConnect(connectionInfo) + } + }, + ) + } } @Composable diff --git a/app/src/main/res/drawable/round_power_24.xml b/app/src/main/res/drawable/round_power_24.xml new file mode 100644 index 00000000..59ed4e0c --- /dev/null +++ b/app/src/main/res/drawable/round_power_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/round_power_off_24.xml b/app/src/main/res/drawable/round_power_off_24.xml new file mode 100644 index 00000000..ec5d47ae --- /dev/null +++ b/app/src/main/res/drawable/round_power_off_24.xml @@ -0,0 +1,24 @@ + + + + + From 9221f0b5def9ff67eb92a87a54eb0bd23e380e91 Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Wed, 6 Dec 2023 10:21:07 +0100 Subject: [PATCH 02/10] feature(TestApp): Add Suggestions for VSS Path Closes: #16 Signed-off-by: Andre Weber --- .../testapp/databroker/view/DataBrokerView.kt | 145 ++++++++----- .../view/suggestions/SuggestionAdapter.kt | 30 +++ .../view/suggestions/SuggestionTextView.kt | 203 ++++++++++++++++++ 3 files changed, 321 insertions(+), 57 deletions(-) create mode 100644 app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionAdapter.kt create mode 100644 app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index fd1125db..c7595ef0 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -32,14 +32,12 @@ 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.requiredHeight import androidx.compose.foundation.layout.requiredWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown @@ -55,6 +53,7 @@ import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -67,9 +66,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -80,6 +76,8 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import org.eclipse.kuksa.proto.v1.Types.Datapoint.ValueCase import org.eclipse.kuksa.testapp.R +import org.eclipse.kuksa.testapp.databroker.view.suggestions.SuggestionAdapter +import org.eclipse.kuksa.testapp.databroker.view.suggestions.SuggestionTextView import org.eclipse.kuksa.testapp.databroker.viewmodel.ConnectionViewModel import org.eclipse.kuksa.testapp.databroker.viewmodel.OutputViewModel import org.eclipse.kuksa.testapp.databroker.viewmodel.TopAppBarViewModel @@ -87,11 +85,13 @@ import org.eclipse.kuksa.testapp.databroker.viewmodel.TopAppBarViewModel.DataBro import org.eclipse.kuksa.testapp.databroker.viewmodel.VSSPropertiesViewModel import org.eclipse.kuksa.testapp.databroker.viewmodel.VssSpecificationsViewModel import org.eclipse.kuksa.testapp.extension.compose.Headline -import org.eclipse.kuksa.testapp.extension.compose.LazyDropdownMenu import org.eclipse.kuksa.testapp.extension.compose.OverflowMenu import org.eclipse.kuksa.testapp.extension.compose.SimpleExposedDropdownMenuBox import org.eclipse.kuksa.testapp.preferences.ConnectionInfoRepository import org.eclipse.kuksa.testapp.ui.theme.KuksaAppAndroidTheme +import org.eclipse.kuksa.vss.VssVehicle +import org.eclipse.kuksa.vsscore.model.VssSpecification +import org.eclipse.kuksa.vsscore.model.heritage val DefaultEdgePadding = 25.dp val DefaultElementPadding = 10.dp @@ -238,17 +238,23 @@ fun DataBrokerSpecifications(viewModel: VssSpecificationsViewModel) { Column { Headline(name = "Specifications") - var selectedIndex by remember { mutableStateOf(0) } - LazyDropdownMenu( + val adapter = object : SuggestionAdapter { + override fun toString(item: VssSpecification): String { + return item.vssPath.substringAfter(".") + } + } + + val suggestions = VssVehicle().heritage + SuggestionTextView( + suggestions = suggestions, + adapter = adapter, + onItemSelected = { + val specification = it ?: VssVehicle() + viewModel.updateSpecification(specification) + }, modifier = Modifier + .fillMaxWidth() .padding(start = DefaultEdgePadding, end = DefaultEdgePadding), - items = viewModel.specifications, - selectedIndex = selectedIndex, - itemToString = { it.vssPath.substringAfter(".") }, - onItemSelected = { index, item -> - selectedIndex = index - viewModel.updateSpecification(item) - }, ) Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) Row( @@ -289,60 +295,85 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { Column { Headline(name = "Properties") - TextField( + val suggestions = remember { + val vssVehicle = VssVehicle() + val heritage = vssVehicle.heritage + heritage.map { it.vssPath } + } + SuggestionTextView( + suggestions = suggestions, value = viewModel.vssProperties.vssPath, - onValueChange = { + onItemSelected = { + val vssPath = it ?: "Vehicle" val newVssProperties = viewModel.vssProperties.copy( - vssPath = it, + vssPath = vssPath, valueType = ValueCase.VALUE_NOT_SET, ) viewModel.updateVssProperties(newVssProperties) }, - modifier = Modifier - .fillMaxWidth() - .padding(start = DefaultEdgePadding, end = DefaultEdgePadding), - singleLine = true, label = { Text(text = "VSS Path") }, - suffix = { - Row(modifier = Modifier.offset(x = 15.dp)) { - ClickableText( - text = AnnotatedString(": ${viewModel.vssProperties.valueType}"), - onClick = { expanded = !expanded }, - style = TextStyle(fontStyle = FontStyle.Italic), - ) - Box(modifier = Modifier.requiredHeight(23.dp)) { - IconButton(onClick = { expanded = !expanded }) { - Icon( - modifier = Modifier.size(23.dp), - imageVector = Icons.Default.ArrowDropDown, - contentDescription = "More", - ) - } - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - modifier = Modifier.height(400.dp), - ) { - viewModel.valueTypes.forEach { - DropdownMenuItem( - text = { - Text(it.toString()) - }, - onClick = { - expanded = false + singleLine = true, + modifier = Modifier + .fillMaxWidth() + .padding(start = DefaultEdgePadding, end = DefaultEdgePadding), + ) + Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) + Row { + TextField( + value = "${viewModel.vssProperties.valueType}", + onValueChange = {}, + label = { + Text("Field Type") + }, + readOnly = true, + enabled = false, + trailingIcon = { + IconButton(onClick = { expanded = !expanded }) { + Icon( + modifier = Modifier.size(23.dp), + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "More", + ) + } + }, + colors = TextFieldDefaults.colors( + disabledTextColor = Color.Black, + disabledLabelColor = Color.Black, + disabledTrailingIconColor = Color.Black, + ), + modifier = Modifier + .fillMaxWidth() + .padding(start = DefaultEdgePadding, end = DefaultEdgePadding) + .clickable { + expanded = true + }, - val newVssProperties = viewModel.vssProperties.copy(valueType = it) - viewModel.updateVssProperties(newVssProperties) - }, - ) - } - } + ) + Box(modifier = Modifier.requiredHeight(23.dp)) { + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.height(400.dp), + ) { + viewModel.valueTypes.forEach { + DropdownMenuItem( + text = { + Text(it.toString()) + }, + onClick = { + expanded = false + + val newVssProperties = + viewModel.vssProperties.copy(valueType = it) + viewModel.updateVssProperties(newVssProperties) + }, + ) } } - }, - ) + } + } Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) Row { TextField( diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionAdapter.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionAdapter.kt new file mode 100644 index 00000000..72387096 --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionAdapter.kt @@ -0,0 +1,30 @@ +/* + * 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.testapp.databroker.view.suggestions + +interface SuggestionAdapter { + fun toString(item: T): String +} + +class DefaultSuggestionAdapter : SuggestionAdapter { + override fun toString(item: T): String { + return item.toString() + } +} diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt new file mode 100644 index 00000000..eb24183b --- /dev/null +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt @@ -0,0 +1,203 @@ +/* + * 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.testapp.databroker.view.suggestions + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Clear +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults +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.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.unit.toSize + +@Composable +fun SuggestionTextView( + suggestions: Collection, + adapter: SuggestionAdapter = DefaultSuggestionAdapter(), + value: String = "", + onItemSelected: ((T?) -> Unit)? = null, + label: @Composable (() -> Unit)? = null, + singleLine: Boolean = false, + modifier: Modifier, +) { + var text by remember { + mutableStateOf(value) + } + + val heightTextFields by remember { + mutableStateOf(55.dp) + } + + var textFieldSize by remember { + mutableStateOf(Size.Zero) + } + + var expanded by remember { + mutableStateOf(false) + } + val interactionSource = remember { + MutableInteractionSource() + } + + val focusManager = LocalFocusManager.current + + Column( + modifier = modifier + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = { + expanded = false + }, + ), + ) { + Column(modifier = Modifier.fillMaxWidth()) { + Row(modifier = Modifier.fillMaxWidth()) { + TextField( + label = label, + modifier = Modifier + .fillMaxWidth() + .height(heightTextFields) + .onGloballyPositioned { coordinates -> + textFieldSize = coordinates.size.toSize() + } + .background(Color.Transparent), + value = text, + onValueChange = { + text = it + expanded = true + }, + colors = TextFieldDefaults.colors( + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + cursorColor = Color.Black, + ), + textStyle = TextStyle( + color = Color.Black, + fontSize = 16.sp, + ), + keyboardOptions = KeyboardOptions( + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done, + ), + singleLine = singleLine, + trailingIcon = { + if (text.isNotEmpty()) { + IconButton(onClick = { + text = "" + expanded = false + onItemSelected?.invoke(null) + }) { + Icon( + modifier = Modifier.size(24.dp), + imageVector = Icons.Rounded.Clear, + contentDescription = "clear", + tint = Color.Black, + ) + } + } + }, + ) + } + + AnimatedVisibility(visible = expanded) { + Card( + modifier = Modifier + .padding(horizontal = 5.dp) + .width(textFieldSize.width.dp), + elevation = CardDefaults.elevatedCardElevation(), + shape = RoundedCornerShape(10.dp), + ) { + LazyColumn( + modifier = Modifier.heightIn(max = 150.dp), + ) { + items( + suggestions.filter { + adapter.toString(it).lowercase().contains(text.lowercase()) + }, + ) { + SuggestionItem( + item = it, + itemText = adapter.toString(it), + ) { item -> + text = adapter.toString(item) + expanded = false + focusManager.clearFocus() + onItemSelected?.invoke(it) + } + } + } + } + } + } + } +} + +@Composable +private fun SuggestionItem( + item: T, + itemText: String, + onSelect: (T) -> Unit, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + onSelect(item) + } + .padding(10.dp), + ) { + Text(text = itemText, fontSize = 16.sp) + } +} From e6e3bdb9efc19cb459fe7fa7482c4d68fc336be7 Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Wed, 6 Dec 2023 13:17:07 +0100 Subject: [PATCH 03/10] chore: Make Non-Specification Mode usable with Freetext --- .../testapp/databroker/view/DataBrokerView.kt | 5 +- .../view/suggestions/SuggestionTextView.kt | 56 ++++++++++++++----- .../drawable/baseline_arrow_drop_down_24.xml | 5 ++ .../drawable/baseline_arrow_drop_up_24.xml | 5 ++ 4 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_arrow_drop_down_24.xml create mode 100644 app/src/main/res/drawable/baseline_arrow_drop_up_24.xml diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index c7595ef0..b5e774f9 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -303,10 +303,9 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { SuggestionTextView( suggestions = suggestions, value = viewModel.vssProperties.vssPath, - onItemSelected = { - val vssPath = it ?: "Vehicle" + onValueChanged = { val newVssProperties = viewModel.vssProperties.copy( - vssPath = vssPath, + vssPath = it, valueType = ValueCase.VALUE_NOT_SET, ) viewModel.updateVssProperties(newVssProperties) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt index eb24183b..3427a005 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt @@ -29,11 +29,11 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Clear @@ -54,12 +54,14 @@ import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.toSize +import org.eclipse.kuksa.testapp.R @Composable fun SuggestionTextView( @@ -67,6 +69,7 @@ fun SuggestionTextView( adapter: SuggestionAdapter = DefaultSuggestionAdapter(), value: String = "", onItemSelected: ((T?) -> Unit)? = null, + onValueChanged: ((String) -> Unit)? = null, label: @Composable (() -> Unit)? = null, singleLine: Boolean = false, modifier: Modifier, @@ -117,6 +120,7 @@ fun SuggestionTextView( onValueChange = { text = it expanded = true + onValueChanged?.invoke(it) }, colors = TextFieldDefaults.colors( focusedIndicatorColor = Color.Transparent, @@ -127,24 +131,47 @@ fun SuggestionTextView( color = Color.Black, fontSize = 16.sp, ), + keyboardActions = KeyboardActions( + onDone = { + expanded = false + focusManager.clearFocus() + }, + ), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Done, ), singleLine = singleLine, trailingIcon = { - if (text.isNotEmpty()) { - IconButton(onClick = { - text = "" - expanded = false - onItemSelected?.invoke(null) - }) { - Icon( - modifier = Modifier.size(24.dp), - imageVector = Icons.Rounded.Clear, - contentDescription = "clear", - tint = Color.Black, - ) + Row { + if (text.isNotEmpty()) { + IconButton(onClick = { + text = "" + expanded = false + onValueChanged?.invoke(text) + onItemSelected?.invoke(null) + }) { + Icon( + imageVector = Icons.Rounded.Clear, + contentDescription = "clear", + tint = Color.Black, + ) + } + } + if (suggestions.isNotEmpty()) { + IconButton(onClick = { expanded = !expanded }) { + val drawableRes = if (expanded) { + R.drawable.baseline_arrow_drop_up_24 + } else { + R.drawable.baseline_arrow_drop_down_24 + } + + Icon( + painter = painterResource(id = drawableRes), + contentDescription = "suggestions", + tint = Color.Black, + ) + } } } }, @@ -154,7 +181,7 @@ fun SuggestionTextView( AnimatedVisibility(visible = expanded) { Card( modifier = Modifier - .padding(horizontal = 5.dp) + .padding(5.dp) .width(textFieldSize.width.dp), elevation = CardDefaults.elevatedCardElevation(), shape = RoundedCornerShape(10.dp), @@ -174,6 +201,7 @@ fun SuggestionTextView( text = adapter.toString(item) expanded = false focusManager.clearFocus() + onValueChanged?.invoke(text) onItemSelected?.invoke(it) } } diff --git a/app/src/main/res/drawable/baseline_arrow_drop_down_24.xml b/app/src/main/res/drawable/baseline_arrow_drop_down_24.xml new file mode 100644 index 00000000..c1c897af --- /dev/null +++ b/app/src/main/res/drawable/baseline_arrow_drop_down_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/baseline_arrow_drop_up_24.xml b/app/src/main/res/drawable/baseline_arrow_drop_up_24.xml new file mode 100644 index 00000000..10c5932c --- /dev/null +++ b/app/src/main/res/drawable/baseline_arrow_drop_up_24.xml @@ -0,0 +1,5 @@ + + + From 873b407fa6ff745a0406fc98cedaf72a8271521b Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Wed, 6 Dec 2023 14:00:43 +0100 Subject: [PATCH 04/10] chore: Load Suggestions from DataBroker --- .../kuksa/testapp/KuksaDataBrokerActivity.kt | 34 +++++++++++++++++++ .../testapp/databroker/view/DataBrokerView.kt | 7 +--- .../viewmodel/VssPropertiesViewModel.kt | 2 ++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt index e79e9f95..3b310ecb 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt @@ -58,6 +58,7 @@ import org.eclipse.kuksa.testapp.preferences.ConnectionInfoRepository import org.eclipse.kuksa.testapp.ui.theme.KuksaAppAndroidTheme import org.eclipse.kuksa.vsscore.annotation.VssDefinition import org.eclipse.kuksa.vsscore.model.VssSpecification +import java.util.TreeSet @VssDefinition("vss_rel_4.0.yaml") class KuksaDataBrokerActivity : ComponentActivity() { @@ -75,6 +76,8 @@ class KuksaDataBrokerActivity : ComponentActivity() { override fun onSuccess(result: DataBrokerConnection?) { outputViewModel.appendOutput("Connection to DataBroker successful established") connectionViewModel.updateConnectionState(ConnectionViewState.CONNECTED) + + loadVssPathSuggestions() } override fun onError(error: Throwable) { @@ -282,4 +285,35 @@ class KuksaDataBrokerActivity : ComponentActivity() { }, ) } + + private fun loadVssPathSuggestions() { + val property = Property("Vehicle", listOf(Field.FIELD_VALUE)) + + dataBrokerEngine.fetch( + property, + object : CoroutineCallback() { + override fun onSuccess(result: GetResponse?) { + val entriesList = result?.entriesList + val paths = entriesList?.map { it.path } ?: emptyList() + + val pathSet = TreeSet() + paths.forEach { + pathSet.add(it) + + var value = it + while (value.indexOf(".") > -1) { + value = value.substringBeforeLast(".") + pathSet.add(value) + } + } + + vssPropertiesViewModel.suggestions = pathSet + } + + override fun onError(error: Throwable) { + outputViewModel.appendOutput(error.toString()) + } + }, + ) + } } diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index b5e774f9..5413f8be 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -295,13 +295,8 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { Column { Headline(name = "Properties") - val suggestions = remember { - val vssVehicle = VssVehicle() - val heritage = vssVehicle.heritage - heritage.map { it.vssPath } - } SuggestionTextView( - suggestions = suggestions, + suggestions = viewModel.suggestions, value = viewModel.vssProperties.vssPath, onValueChanged = { val newVssProperties = viewModel.vssProperties.copy( diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt index cf153143..b1794766 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt @@ -50,6 +50,8 @@ class VSSPropertiesViewModel : ViewModel() { val valueTypes: List = ValueCase.values().toList() val fieldTypes: List = listOf(Field.FIELD_VALUE, Field.FIELD_ACTUATOR_TARGET) + var suggestions: Collection by mutableStateOf(listOf()) + val datapoint: Datapoint get() = vssProperties.valueType.createDatapoint(vssProperties.value) From d189c6294f561c9f70a711043c31890a006ed99a Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 16 Jan 2024 10:53:11 +0100 Subject: [PATCH 05/10] chore: View Improvements --- .../view/DataBrokerConnectionView.kt | 9 +++-- .../testapp/databroker/view/DataBrokerView.kt | 35 ++++++++++--------- .../view/suggestions/SuggestionTextView.kt | 4 +-- .../viewmodel/VssPropertiesViewModel.kt | 4 +-- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt index 6c55c779..f51e9eb0 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt @@ -71,10 +71,9 @@ fun DataBrokerConnection(viewModel: ConnectionViewModel) { mutableStateOf(connectionInfoState.value) } - if (!viewModel.isConnected) { - Headline("Connection") - } Column { + Headline("Connection") + AnimatedVisibility(visible = viewModel.isDisconnected) { Column { Row( @@ -243,9 +242,9 @@ fun DataBrokerConnectionPreview_Disconnected() { @Preview @Composable -fun DataBrokerConnectionPreview_Connected() { +fun DataBrokerConnectionPreview_Connecting() { val connectionInfoRepository = ConnectionInfoRepository(LocalContext.current) val viewModel = ConnectionViewModel(connectionInfoRepository) - viewModel.updateConnectionState(ConnectionViewState.CONNECTED) + viewModel.updateConnectionState(ConnectionViewState.CONNECTING) DataBrokerConnection(viewModel = viewModel) } diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index 5413f8be..fb1bf374 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -91,8 +91,8 @@ import org.eclipse.kuksa.testapp.preferences.ConnectionInfoRepository import org.eclipse.kuksa.testapp.ui.theme.KuksaAppAndroidTheme import org.eclipse.kuksa.vss.VssVehicle import org.eclipse.kuksa.vsscore.model.VssSpecification -import org.eclipse.kuksa.vsscore.model.heritage +val SettingsMenuPadding = 16.dp val DefaultEdgePadding = 25.dp val DefaultElementPadding = 10.dp val MinimumButtonWidth = 150.dp @@ -120,7 +120,9 @@ fun DataBrokerView( ) { Column { val dataBrokerMode = topAppBarViewModel.dataBrokerMode - DataBrokerConnection(connectionViewModel) + if (!connectionViewModel.isConnected) { + DataBrokerConnection(connectionViewModel) + } if (connectionViewModel.isConnected) { AnimatedContent( targetState = dataBrokerMode, @@ -154,13 +156,13 @@ private fun TopBar( ), actions = { ConnectionStatusIcon(connectionViewModel) - HamburgerMenu(connectionViewModel, topAppBarViewModel) + SettingsMenu(connectionViewModel, topAppBarViewModel) }, ) } @Composable -private fun HamburgerMenu( +private fun SettingsMenu( connectionViewModel: ConnectionViewModel, topAppBarViewModel: TopAppBarViewModel, ) { @@ -173,7 +175,7 @@ private fun HamburgerMenu( val newValue = !topAppBarViewModel.isCompatibilityModeEnabled topAppBarViewModel.isCompatibilityModeEnabled = newValue } - .padding(horizontal = 16.dp), + .padding(horizontal = SettingsMenuPadding), ) { Checkbox( checked = topAppBarViewModel.isCompatibilityModeEnabled, @@ -182,7 +184,7 @@ private fun HamburgerMenu( ) Text( text = "Java Compatibility Mode", - modifier = Modifier.padding(start = 16.dp), + modifier = Modifier.padding(start = SettingsMenuPadding), ) } Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) @@ -196,13 +198,13 @@ private fun HamburgerMenu( } topAppBarViewModel.updateDataBrokerMode(newMode) } - .padding(horizontal = 16.dp), + .padding(horizontal = SettingsMenuPadding), ) { Checkbox( checked = topAppBarViewModel.isSpecificationModeEnabled, onCheckedChange = null, ) - Text(text = "Specification Mode", modifier = Modifier.padding(start = 16.dp)) + Text(text = "Specification Mode", modifier = Modifier.padding(start = SettingsMenuPadding)) } } } @@ -216,13 +218,15 @@ private fun ConnectionStatusIcon( Icon( painter = painterResource(id = R.drawable.round_power_24), contentDescription = "Disconnect", - modifier = modifier.clickable { connectionViewModel.onDisconnect() }, + modifier = modifier.clickable(enabled = connectionViewModel.isConnected) { + connectionViewModel.onDisconnect() + }, ) } else { Icon( painter = painterResource(id = R.drawable.round_power_off_24), contentDescription = "Connect", - modifier = modifier.clickable { + modifier = modifier.clickable(enabled = connectionViewModel.isDisconnected) { val coroutineScope = CoroutineScope(Dispatchers.Default) coroutineScope.launch { val connectionInfo = connectionViewModel.connectionInfoFlow.first() @@ -240,13 +244,13 @@ fun DataBrokerSpecifications(viewModel: VssSpecificationsViewModel) { val adapter = object : SuggestionAdapter { override fun toString(item: VssSpecification): String { - return item.vssPath.substringAfter(".") + return item.vssPath } } - val suggestions = VssVehicle().heritage SuggestionTextView( - suggestions = suggestions, + value = "Vehicle", + suggestions = viewModel.specifications, adapter = adapter, onItemSelected = { val specification = it ?: VssVehicle() @@ -344,7 +348,7 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { expanded = true }, - ) + ) Box(modifier = Modifier.requiredHeight(23.dp)) { DropdownMenu( expanded = expanded, @@ -359,8 +363,7 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { onClick = { expanded = false - val newVssProperties = - viewModel.vssProperties.copy(valueType = it) + val newVssProperties = viewModel.vssProperties.copy(valueType = it) viewModel.updateVssProperties(newVssProperties) }, ) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt index 3427a005..0d559bf8 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/suggestions/SuggestionTextView.kt @@ -181,10 +181,10 @@ fun SuggestionTextView( AnimatedVisibility(visible = expanded) { Card( modifier = Modifier - .padding(5.dp) + .padding(top = 5.dp) .width(textFieldSize.width.dp), elevation = CardDefaults.elevatedCardElevation(), - shape = RoundedCornerShape(10.dp), + shape = RoundedCornerShape(topStart = 5.dp, topEnd = 5.dp), ) { LazyColumn( modifier = Modifier.heightIn(max = 150.dp), diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt index b1794766..24fd02ef 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt @@ -66,8 +66,8 @@ class VSSPropertiesViewModel : ViewModel() { @Immutable data class VSSProperties( - val vssPath: String = "Vehicle.Speed", + val vssPath: String = "Vehicle", val valueType: ValueCase = ValueCase.VALUE_NOT_SET, - val value: String = "130", + val value: String = "", val fieldType: Field = Field.FIELD_VALUE, ) From c7e5c8b3d9adeebd8c8e0bbab3d6b6c6b298818d Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 16 Jan 2024 10:53:41 +0100 Subject: [PATCH 06/10] chore: Extract VssPathHierarchy-related Code to separate Function --- .../kuksa/testapp/KuksaDataBrokerActivity.kt | 32 +++++++++++-------- .../testapp/databroker/view/DataBrokerView.kt | 3 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt index 3b310ecb..5581f70b 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt @@ -294,20 +294,10 @@ class KuksaDataBrokerActivity : ComponentActivity() { object : CoroutineCallback() { override fun onSuccess(result: GetResponse?) { val entriesList = result?.entriesList - val paths = entriesList?.map { it.path } ?: emptyList() + val vssPaths = entriesList?.map { it.path } ?: emptyList() - val pathSet = TreeSet() - paths.forEach { - pathSet.add(it) - - var value = it - while (value.indexOf(".") > -1) { - value = value.substringBeforeLast(".") - pathSet.add(value) - } - } - - vssPropertiesViewModel.suggestions = pathSet + val vssPathHierarchySet = createVssPathHierarchy(vssPaths) + vssPropertiesViewModel.suggestions = vssPathHierarchySet } override fun onError(error: Throwable) { @@ -316,4 +306,20 @@ class KuksaDataBrokerActivity : ComponentActivity() { }, ) } + + private fun createVssPathHierarchy(paths: List): TreeSet { + val pathSet = TreeSet() + + paths.forEach { + pathSet.add(it) + + var value = it + while (value.indexOf(".") > -1) { + value = value.substringBeforeLast(".") + pathSet.add(value) + } + } + + return pathSet + } } diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index fb1bf374..22203bc8 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -347,8 +347,7 @@ fun DataBrokerProperties(viewModel: VSSPropertiesViewModel) { .clickable { expanded = true }, - - ) + ) Box(modifier = Modifier.requiredHeight(23.dp)) { DropdownMenu( expanded = expanded, From 3a5f48717824ae3ce67e6141ecb807ad4d8ececf Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 16 Jan 2024 11:39:38 +0100 Subject: [PATCH 07/10] chore: Remove AnimatedContent from Properties- and SpecificationView --- .../testapp/databroker/view/DataBrokerView.kt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt index 22203bc8..0cc37d51 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerView.kt @@ -19,7 +19,6 @@ package org.eclipse.kuksa.testapp.databroker.view -import androidx.compose.animation.AnimatedContent import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -119,19 +118,14 @@ fun DataBrokerView( verticalArrangement = Arrangement.SpaceBetween, ) { Column { - val dataBrokerMode = topAppBarViewModel.dataBrokerMode if (!connectionViewModel.isConnected) { DataBrokerConnection(connectionViewModel) } + val dataBrokerMode = topAppBarViewModel.dataBrokerMode if (connectionViewModel.isConnected) { - AnimatedContent( - targetState = dataBrokerMode, - label = "DataBrokerModeAnimation", - ) { mode -> - when (mode) { - DataBrokerMode.VSS_PATH -> DataBrokerProperties(vssPropertiesViewModel) - DataBrokerMode.SPECIFICATION -> DataBrokerSpecifications(vssSpecificationsViewModel) - } + when (dataBrokerMode) { + DataBrokerMode.VSS_PATH -> DataBrokerProperties(vssPropertiesViewModel) + DataBrokerMode.SPECIFICATION -> DataBrokerSpecifications(vssSpecificationsViewModel) } } Spacer(modifier = Modifier.padding(top = DefaultElementPadding)) From 6c4215ca0226827ffdd1d952e269580658497d5e Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 30 Jan 2024 12:51:03 +0100 Subject: [PATCH 08/10] chore: Rename Preview Names --- .../databroker/view/DataBrokerConnectionView.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt index f51e9eb0..04955eb6 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/view/DataBrokerConnectionView.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.Checkbox +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable @@ -235,16 +236,21 @@ fun DataBrokerConnection(viewModel: ConnectionViewModel) { @Preview @Composable -fun DataBrokerConnectionPreview_Disconnected() { +private fun ConnectedPreview() { val connectionInfoRepository = ConnectionInfoRepository(LocalContext.current) - DataBrokerConnection(viewModel = ConnectionViewModel(connectionInfoRepository)) + val viewModel = ConnectionViewModel(connectionInfoRepository) + Surface { + DataBrokerConnection(viewModel = viewModel) + } } @Preview @Composable -fun DataBrokerConnectionPreview_Connecting() { +private fun DisconnectedPreview() { val connectionInfoRepository = ConnectionInfoRepository(LocalContext.current) val viewModel = ConnectionViewModel(connectionInfoRepository) viewModel.updateConnectionState(ConnectionViewState.CONNECTING) - DataBrokerConnection(viewModel = viewModel) + Surface { + DataBrokerConnection(viewModel = viewModel) + } } From 5b94cb19b8bf4cc4e56718b55d2aabb77246ed9a Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 30 Jan 2024 13:33:05 +0100 Subject: [PATCH 09/10] chore: Move VssPathHierarchy Logic inside VssPropertiesViewModel --- .../kuksa/testapp/KuksaDataBrokerActivity.kt | 20 +------------- .../viewmodel/VssPropertiesViewModel.kt | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt index 1a72b3ef..5f72b44b 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/KuksaDataBrokerActivity.kt @@ -60,7 +60,6 @@ import org.eclipse.kuksa.testapp.preferences.ConnectionInfoRepository import org.eclipse.kuksa.testapp.ui.theme.KuksaAppAndroidTheme import org.eclipse.kuksa.vsscore.annotation.VssDefinition import org.eclipse.kuksa.vsscore.model.VssSpecification -import java.util.TreeSet @VssDefinition("vss_rel_4.0.yaml") class KuksaDataBrokerActivity : ComponentActivity() { @@ -327,8 +326,7 @@ class KuksaDataBrokerActivity : ComponentActivity() { val entriesList = result?.entriesList val vssPaths = entriesList?.map { it.path } ?: emptyList() - val vssPathHierarchySet = createVssPathHierarchy(vssPaths) - vssPropertiesViewModel.suggestions = vssPathHierarchySet + vssPropertiesViewModel.updateSuggestions(vssPaths) } override fun onError(error: Throwable) { @@ -337,20 +335,4 @@ class KuksaDataBrokerActivity : ComponentActivity() { }, ) } - - private fun createVssPathHierarchy(paths: List): TreeSet { - val pathSet = TreeSet() - - paths.forEach { - pathSet.add(it) - - var value = it - while (value.indexOf(".") > -1) { - value = value.substringBeforeLast(".") - pathSet.add(value) - } - } - - return pathSet - } } diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt index 531acfaf..c2204a56 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt @@ -31,6 +31,7 @@ import org.eclipse.kuksa.model.Property import org.eclipse.kuksa.proto.v1.Types.Datapoint import org.eclipse.kuksa.proto.v1.Types.Datapoint.ValueCase import org.eclipse.kuksa.proto.v1.Types.Field +import java.util.TreeSet class VSSPropertiesViewModel : ViewModel() { var onGetProperty: (property: Property) -> Unit = { } @@ -47,14 +48,16 @@ class VSSPropertiesViewModel : ViewModel() { var vssProperties: VSSProperties by mutableStateOf(VSSProperties()) private set - val valueTypes: List = ValueCase.values().toList() + val valueTypes: List = ValueCase.entries val fieldTypes: List = listOf( Field.FIELD_VALUE, Field.FIELD_ACTUATOR_TARGET, Field.FIELD_METADATA, ) - var suggestions: Collection by mutableStateOf(listOf()) + private var _suggestions: Collection by mutableStateOf(listOf()) + val suggestions + get() = _suggestions val datapoint: Datapoint get() = vssProperties.valueType.createDatapoint(vssProperties.value) @@ -66,6 +69,26 @@ class VSSPropertiesViewModel : ViewModel() { fun updateVssProperties(vssProperties: VSSProperties = VSSProperties()) { this.vssProperties = vssProperties } + + fun updateSuggestions(vssPaths: Collection) { + this._suggestions = createVssPathHierarchy(vssPaths) + } + + private fun createVssPathHierarchy(paths: Collection): TreeSet { + val pathSet = TreeSet() + + paths.forEach { + pathSet.add(it) + + var value = it + while (value.indexOf(".") > -1) { + value = value.substringBeforeLast(".") + pathSet.add(value) + } + } + + return pathSet + } } @Immutable From e4568aab5ae1c38d1058854ff7cc228466014ec7 Mon Sep 17 00:00:00 2001 From: Andre Weber Date: Tue, 30 Jan 2024 13:53:57 +0100 Subject: [PATCH 10/10] chore: Minor Name Changes --- .../databroker/viewmodel/VssPropertiesViewModel.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt index c2204a56..0ba78623 100644 --- a/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt +++ b/app/src/main/kotlin/org/eclipse/kuksa/testapp/databroker/viewmodel/VssPropertiesViewModel.kt @@ -55,14 +55,12 @@ class VSSPropertiesViewModel : ViewModel() { Field.FIELD_METADATA, ) - private var _suggestions: Collection by mutableStateOf(listOf()) - val suggestions - get() = _suggestions + var suggestions: Set by mutableStateOf(setOf()) + private set val datapoint: Datapoint get() = vssProperties.valueType.createDatapoint(vssProperties.value) - // Meta data are always part of the properties val property: Property get() = Property(vssProperties.vssPath, listOf(vssProperties.fieldType)) @@ -71,10 +69,10 @@ class VSSPropertiesViewModel : ViewModel() { } fun updateSuggestions(vssPaths: Collection) { - this._suggestions = createVssPathHierarchy(vssPaths) + suggestions = generateVssPathHierarchy(vssPaths) } - private fun createVssPathHierarchy(paths: Collection): TreeSet { + private fun generateVssPathHierarchy(paths: Collection): TreeSet { val pathSet = TreeSet() paths.forEach {