Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Move Stateful Data into ViewModels #64

Merged
merged 2 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Chrylo marked this conversation as resolved.
Show resolved Hide resolved

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
Loading