Skip to content

Commit

Permalink
Merge pull request #64 from boschglobal/feature-55
Browse files Browse the repository at this point in the history
feature: Move Stateful Data into ViewModels
  • Loading branch information
Chrylo authored Feb 22, 2024
2 parents ae270f3 + 8417d53 commit bd10cde
Show file tree
Hide file tree
Showing 20 changed files with 154 additions and 154 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".CompanionApplication"
android:name=".application.CompanionApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand Down
133 changes: 30 additions & 103 deletions app/src/main/kotlin/org/eclipse/kuksa/companion/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,11 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import org.eclipse.kuksa.DataBrokerConnection
import org.eclipse.kuksa.DataBrokerException
import org.eclipse.kuksa.DisconnectListener
import org.eclipse.kuksa.companion.extension.TAG
import org.eclipse.kuksa.companion.feature.connection.factory.DataBrokerConnectorFactory
import org.eclipse.kuksa.companion.feature.connection.repository.ConnectionInfoRepository
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionStatusViewModel
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionStatusViewModel.ConnectionState
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionViewModel
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionViewModel.ConnectionState
import org.eclipse.kuksa.companion.feature.door.surface.DoorVehicleScene
import org.eclipse.kuksa.companion.feature.door.surface.DoorVehicleSurface
import org.eclipse.kuksa.companion.feature.door.viewModel.DoorControlViewModel
Expand All @@ -51,7 +50,6 @@ import org.eclipse.kuksa.companion.feature.navigation.viewmodel.NavigationViewMo
import org.eclipse.kuksa.companion.feature.settings.viewModel.SettingsViewModel
import org.eclipse.kuksa.companion.feature.temperature.viewmodel.TemperatureViewModel
import org.eclipse.kuksa.companion.feature.wheel.pressure.viewmodel.WheelPressureViewModel
import org.eclipse.kuksa.companion.listener.FilteredVssSpecificationListener
import org.eclipse.kuksa.companion.ui.theme.KuksaCompanionTheme
import org.eclipse.kuksa.extension.vssProperty.not
import org.eclipse.kuksa.proto.v1.Types.Field
Expand All @@ -68,86 +66,28 @@ import javax.inject.Inject
@AndroidEntryPoint
@VssDefinition("vss_rel_4.0.yaml")
class MainActivity : ComponentActivity() {
private val companionApplication
get() = applicationContext as CompanionApplication

@Inject
lateinit var connectionInfoRepository: ConnectionInfoRepository

private lateinit var doorVehicleScene: DoorVehicleScene
private val doorVehicleSurface = DoorVehicleSurface()

private val disconnectListener = DisconnectListener {
dataBrokerConnection = null
connectionStatusViewModel.connectionState = ConnectionState.DISCONNECTED
}

private val connectionStatusViewModel: ConnectionStatusViewModel by viewModels()
private val connectionViewModel: ConnectionViewModel by viewModels()
private val navigationViewModel: NavigationViewModel by viewModels()

private val doorControlViewModel: DoorControlViewModel by viewModels()
private val temperatureViewModel: TemperatureViewModel by viewModels()
private val lightControlViewModel: LightControlViewModel by viewModels()
private val wheelPressureViewModel: WheelPressureViewModel by viewModels()

private val settingsViewModel: SettingsViewModel by viewModels()

// storing the connection in the Application keeps the Connection alive on orientation changes
private var dataBrokerConnection: DataBrokerConnection?
get() = companionApplication.dataBrokerConnection
set(value) {
companionApplication.dataBrokerConnection = value
}

private val dataBrokerConnectorFactory = DataBrokerConnectorFactory()

private val doorVehicleSurface = DoorVehicleSurface()

private val vssDoorListener = object : FilteredVssSpecificationListener<VssDoor>() {
override fun onSpecificationChanged(vssSpecification: VssDoor) {
doorVehicleScene.updateDoors(vssSpecification)
}

override fun onPostFilterError(throwable: Throwable) {
Log.e(TAG, "Failed to subscribe to specification: $throwable")
}
}
private val vssTrunkListener = object : FilteredVssSpecificationListener<VssTrunk>() {
override fun onSpecificationChanged(vssSpecification: VssTrunk) {
doorVehicleScene.updateTrunk(vssSpecification)
}

override fun onPostFilterError(throwable: Throwable) {
Log.e(TAG, "Failed to subscribe to specification: $throwable")
}
}
private val vssTemperatureListener = object : FilteredVssSpecificationListener<VssHvac>() {
override fun onSpecificationChanged(vssSpecification: VssHvac) {
temperatureViewModel.hvac = vssSpecification
}

override fun onPostFilterError(throwable: Throwable) {
Log.e(TAG, "Failed to subscribe to specification: $throwable")
}
}
private val vssWheelPressureListener = object : FilteredVssSpecificationListener<VssAxle>() {
override fun onSpecificationChanged(vssSpecification: VssAxle) {
wheelPressureViewModel.axle = vssSpecification
}

override fun onPostFilterError(throwable: Throwable) {
Log.e(TAG, "Failed to subscribe to specification: $throwable")
}
}

private val vssLightListener = object : FilteredVssSpecificationListener<VssLights>() {
override fun onSpecificationChanged(vssSpecification: VssLights) {
lightControlViewModel.vssLight = vssSpecification
}

override fun onPostFilterError(throwable: Throwable) {
Log.e(TAG, "Failed to subscribe to specification: $throwable")
// storing the connection in the ViewModel keeps the Connection alive on orientation changes
private var dataBrokerConnection: DataBrokerConnection?
get() = connectionViewModel.dataBrokerConnection
set(value) {
connectionViewModel.dataBrokerConnection = value
}
}

// region: Lifecycle
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
Expand All @@ -161,7 +101,7 @@ class MainActivity : ComponentActivity() {
KuksaCompanionTheme {
AdaptiveAppScreen(
callback = doorVehicleSurface,
connectionStatusViewModel = connectionStatusViewModel,
connectionViewModel = connectionViewModel,
navigationViewModel = navigationViewModel,
doorControlViewModel = doorControlViewModel,
temperatureViewModel = temperatureViewModel,
Expand All @@ -177,7 +117,17 @@ class MainActivity : ComponentActivity() {
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)

connectionStatusViewModel.onClickReconnect = {
doorControlViewModel.doorVehicleSceneDelegate = object : DoorVehicleScene {
override fun updateDoors(door: VssDoor) {
doorVehicleScene.updateDoors(door)
}

override fun updateTrunk(trunk: VssTrunk) {
doorVehicleScene.updateTrunk(trunk)
}
}

connectionViewModel.onClickReconnect = {
connectToDataBroker {
subscribe()
}
Expand Down Expand Up @@ -238,14 +188,6 @@ class MainActivity : ComponentActivity() {
doorVehicleSurface.stopRendering()
}

override fun onDestroy() {
super.onDestroy()

dataBrokerConnection?.disconnectListeners?.unregister(disconnectListener)

unsubscribe()
}

// endregion

private fun updatePlannedTemperature(plannedTemperature: Int) {
Expand All @@ -265,25 +207,11 @@ class MainActivity : ComponentActivity() {

private fun subscribe() {
dataBrokerConnection?.apply {
disconnectListeners.register(disconnectListener)

subscribe(VssDoor(), listener = vssDoorListener)
subscribe(VssTrunk(), listener = vssTrunkListener)
subscribe(VssHvac(), listener = vssTemperatureListener)
subscribe(VssAxle(), listener = vssWheelPressureListener)
subscribe(VssLights(), listener = vssLightListener)
}
}

private fun unsubscribe() {
dataBrokerConnection?.apply {
disconnectListeners.unregister(disconnectListener)

unsubscribe(VssDoor(), listener = vssDoorListener)
unsubscribe(VssTrunk(), listener = vssTrunkListener)
unsubscribe(VssHvac(), listener = vssTemperatureListener)
unsubscribe(VssAxle(), listener = vssWheelPressureListener)
unsubscribe(VssLights(), listener = vssLightListener)
subscribe(VssDoor(), listener = doorControlViewModel.vssDoorListener)
subscribe(VssTrunk(), listener = doorControlViewModel.vssTrunkListener)
subscribe(VssHvac(), listener = temperatureViewModel.vssTemperatureListener)
subscribe(VssAxle(), listener = wheelPressureViewModel.vssWheelPressureListener)
subscribe(VssLights(), listener = lightControlViewModel.vssLightListener)
}
}

Expand All @@ -304,8 +232,7 @@ class MainActivity : ComponentActivity() {

private fun connectToDataBroker(onConnected: () -> Unit = {}) {
// dataBrokerConnection is already established e.g. after an orientation change
if (dataBrokerConnection != null) {
onConnected()
if (connectionViewModel.connectionState == ConnectionState.CONNECTED) {
return
}

Expand All @@ -315,15 +242,15 @@ class MainActivity : ComponentActivity() {
try {
Log.d(TAG, "Connecting to DataBroker ${connectionInfo.host}:${connectionInfo.port}")

connectionStatusViewModel.connectionState = ConnectionState.CONNECTING
connectionViewModel.connectionState = ConnectionState.CONNECTING
val context = this@MainActivity
val dataBrokerConnector = dataBrokerConnectorFactory.create(context, connectionInfo)
dataBrokerConnection = dataBrokerConnector.connect()
connectionStatusViewModel.connectionState = ConnectionState.CONNECTED
connectionViewModel.connectionState = ConnectionState.CONNECTED
onConnected()
} catch (e: DataBrokerException) {
Log.w(TAG, "Connection to DataBroker failed: ", e)
connectionStatusViewModel.connectionState = ConnectionState.DISCONNECTED
connectionViewModel.connectionState = ConnectionState.DISCONNECTED
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023-2024 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.
Expand All @@ -17,19 +17,15 @@
*
*/

package org.eclipse.kuksa.companion
package org.eclipse.kuksa.companion.application

import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import org.eclipse.kuksa.DataBrokerConnection

const val PREVIEW_WIDTH_DP = 400
const val PREVIEW_HEIGHT_DP = 900

const val SHEET_EXPANDED_HEIGHT = 350
const val SHEET_COLLAPSED_HEIGHT = 50

@HiltAndroidApp
class CompanionApplication : Application() {
var dataBrokerConnection: DataBrokerConnection? = null
}
class CompanionApplication : Application()
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.eclipse.kuksa.companion.R
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionStatusViewModel
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionStatusViewModel.ConnectionState
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionViewModel
import org.eclipse.kuksa.companion.feature.connection.viewModel.ConnectionViewModel.ConnectionState

val StatusBarHeight = 50.dp
private val iconSize = 30.dp
Expand All @@ -52,7 +52,7 @@ private val paddingEnd = 5.dp

@Composable
fun HorizontalConnectionStatusView(
viewModel: ConnectionStatusViewModel,
viewModel: ConnectionViewModel,
modifier: Modifier = Modifier,
) {
val connectionState = viewModel.connectionState
Expand Down Expand Up @@ -113,7 +113,7 @@ fun HorizontalConnectionStatusView(
@Preview
@Composable
private fun HorizontalDisconnectedPreview() {
val viewModel = ConnectionStatusViewModel()
val viewModel = ConnectionViewModel()
viewModel.connectionState = ConnectionState.DISCONNECTED

HorizontalConnectionStatusView(viewModel = viewModel)
Expand All @@ -122,15 +122,15 @@ private fun HorizontalDisconnectedPreview() {
@Preview
@Composable
private fun HorizontalConnectingPreview() {
val viewModel = ConnectionStatusViewModel()
val viewModel = ConnectionViewModel()
viewModel.connectionState = ConnectionState.CONNECTING
HorizontalConnectionStatusView(viewModel = viewModel)
}

@Preview
@Composable
private fun HorizontalConnectedPreview() {
val viewModel = ConnectionStatusViewModel()
val viewModel = ConnectionViewModel()
viewModel.connectionState = ConnectionState.CONNECTED
HorizontalConnectionStatusView(viewModel = viewModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import org.eclipse.kuksa.DataBrokerConnection
import org.eclipse.kuksa.DisconnectListener
import kotlin.properties.Delegates

class ConnectionStatusViewModel : ViewModel() {
class ConnectionViewModel : ViewModel() {
enum class ConnectionState {
DISCONNECTED,
CONNECTING,
Expand All @@ -34,4 +37,14 @@ class ConnectionStatusViewModel : ViewModel() {
var onClickReconnect: () -> Unit = { }

var connectionState by mutableStateOf(ConnectionState.DISCONNECTED)

var dataBrokerConnection: DataBrokerConnection? by Delegates.observable(null) { _, oldValue, newValue ->
oldValue?.disconnectListeners?.unregister(disconnectListener)
newValue?.disconnectListeners?.register(disconnectListener)
}

private var disconnectListener: DisconnectListener = DisconnectListener {
dataBrokerConnection = null
connectionState = ConnectionState.DISCONNECTED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ class DoorVehicleSceneThread(

// region: VehicleScene
override fun updateDoors(door: VssDoor) {
viewModel.updateDoors(door)

addRunnableToThreadQueue {
door.findProperties(VssDoor.VssRow1.VssPassengerSide.VssIsOpen::class).apply {
doorRow1DriverSide = getOrDefault(doorRow1DriverSide.vssPath, doorRow1DriverSide)
Expand All @@ -198,8 +196,9 @@ class DoorVehicleSceneThread(
}

override fun updateTrunk(trunk: VssTrunk) {
viewModel.updateTrunk(trunk)
doorTrunkRear = trunk.findProperty(VssTrunk.VssRear.VssIsOpen())
addRunnableToThreadQueue {
doorTrunkRear = trunk.findProperty(VssTrunk.VssRear.VssIsOpen())
}
}
// endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class DoorVehicleSurface : AndroidRamsesSurface<DoorVehicleScene, DoorControlVie
pitchValue = pitchValue.toFloat(),
camDistanceValue = cameraDistanceValue.toFloat(),
)
doorVehicleSceneThread.updateDoors(viewModel.door)
doorVehicleSceneThread.updateTrunk(viewModel.trunk)

return doorVehicleSceneThread
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.eclipse.kuksa.companion.PREVIEW_WIDTH_DP
import org.eclipse.kuksa.companion.SHEET_EXPANDED_HEIGHT
import org.eclipse.kuksa.companion.application.PREVIEW_WIDTH_DP
import org.eclipse.kuksa.companion.application.SHEET_EXPANDED_HEIGHT
import org.eclipse.kuksa.companion.feature.door.viewModel.DoorControlViewModel

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import org.eclipse.kuksa.companion.PREVIEW_HEIGHT_DP
import org.eclipse.kuksa.companion.PREVIEW_WIDTH_DP
import org.eclipse.kuksa.companion.application.PREVIEW_HEIGHT_DP
import org.eclipse.kuksa.companion.application.PREVIEW_WIDTH_DP
import org.eclipse.kuksa.companion.extension.windowSizeClass
import org.eclipse.kuksa.companion.feature.door.viewModel.DoorControlViewModel
import org.eclipse.kuksa.companion.ramses.DriverBackDoorAnchor
Expand Down
Loading

0 comments on commit bd10cde

Please sign in to comment.