feat: select configured devices in scene editor
This commit is contained in:
+57
-39
@@ -81,6 +81,8 @@ import com.flagship.abox.manager.domain.SceneIcon
|
|||||||
import com.flagship.abox.manager.domain.SceneId
|
import com.flagship.abox.manager.domain.SceneId
|
||||||
import com.flagship.abox.manager.domain.SceneTrigger
|
import com.flagship.abox.manager.domain.SceneTrigger
|
||||||
import com.flagship.abox.manager.domain.SocketPowerState
|
import com.flagship.abox.manager.domain.SocketPowerState
|
||||||
|
import com.flagship.abox.manager.domain.DeviceType
|
||||||
|
import com.flagship.abox.manager.domain.DeviceDescriptor
|
||||||
import com.flagship.abox.manager.domain.infrared.RemoteKeyBinding
|
import com.flagship.abox.manager.domain.infrared.RemoteKeyBinding
|
||||||
import com.flagship.abox.manager.domain.infrared.VirtualRemote
|
import com.flagship.abox.manager.domain.infrared.VirtualRemote
|
||||||
|
|
||||||
@@ -569,6 +571,7 @@ private fun SceneEditorContent(
|
|||||||
|
|
||||||
if (showTriggerDialog) {
|
if (showTriggerDialog) {
|
||||||
AddTriggerDialog(
|
AddTriggerDialog(
|
||||||
|
availableDevices = state.availableDevices,
|
||||||
onDismiss = { showTriggerDialog = false },
|
onDismiss = { showTriggerDialog = false },
|
||||||
onAdd = { triggerType, devName, time, temp, hum, op ->
|
onAdd = { triggerType, devName, time, temp, hum, op ->
|
||||||
when (triggerType) {
|
when (triggerType) {
|
||||||
@@ -583,6 +586,7 @@ private fun SceneEditorContent(
|
|||||||
|
|
||||||
if (showConditionDialog) {
|
if (showConditionDialog) {
|
||||||
AddConditionDialog(
|
AddConditionDialog(
|
||||||
|
availableDevices = state.availableDevices,
|
||||||
onDismiss = { showConditionDialog = false },
|
onDismiss = { showConditionDialog = false },
|
||||||
onAddTemp = { devName, op, temp ->
|
onAddTemp = { devName, op, temp ->
|
||||||
viewModel.addTemperatureCondition(devName, op, temp)
|
viewModel.addTemperatureCondition(devName, op, temp)
|
||||||
@@ -606,6 +610,7 @@ private fun SceneEditorContent(
|
|||||||
if (showActionDialog) {
|
if (showActionDialog) {
|
||||||
AddActionDialog(
|
AddActionDialog(
|
||||||
availableRemotes = state.availableRemotes,
|
availableRemotes = state.availableRemotes,
|
||||||
|
availableDevices = state.availableDevices,
|
||||||
onDismiss = { showActionDialog = false },
|
onDismiss = { showActionDialog = false },
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
onAddSocket = { name, power ->
|
onAddSocket = { name, power ->
|
||||||
@@ -767,6 +772,7 @@ private fun SceneAction.describe(): String = when (this) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AddTriggerDialog(
|
private fun AddTriggerDialog(
|
||||||
|
availableDevices: List<DeviceDescriptor>,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onAdd: (type: Int, deviceName: String, time: String, temp: Double, hum: Double, op: ComparisonOperator) -> Unit,
|
onAdd: (type: Int, deviceName: String, time: String, temp: Double, hum: Double, op: ComparisonOperator) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -779,7 +785,11 @@ private fun AddTriggerDialog(
|
|||||||
|
|
||||||
val timeRegex = remember { Regex("^([01]\\d|2[0-3]):[0-5]\\d$") }
|
val timeRegex = remember { Regex("^([01]\\d|2[0-3]):[0-5]\\d$") }
|
||||||
val isTimeValid = timeRegex.matches(timeInput.trim())
|
val isTimeValid = timeRegex.matches(timeInput.trim())
|
||||||
val isDeviceValid = selectedType == 0 || deviceName.isNotBlank()
|
val matchingDevices = availableDevices.filter {
|
||||||
|
it.type == if (selectedType == 1 || selectedType == 2) DeviceType.TEMPERATURE_HUMIDITY else DeviceType.SOCKET
|
||||||
|
}
|
||||||
|
val isDeviceValid = selectedType == 0 && isTimeValid || selectedType != 0 &&
|
||||||
|
matchingDevices.any { it.name.value == deviceName }
|
||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
@@ -806,13 +816,16 @@ private fun AddTriggerDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
1, 2 -> {
|
1, 2 -> {
|
||||||
OutlinedTextField(
|
Text(stringResource(R.string.scene_device_name_label))
|
||||||
value = deviceName,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
onValueChange = { deviceName = it },
|
matchingDevices.forEach { device ->
|
||||||
label = { Text(stringResource(R.string.scene_device_name_label)) },
|
FilterChip(
|
||||||
singleLine = true,
|
selected = deviceName == device.name.value,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onClick = { deviceName = device.name.value },
|
||||||
|
label = { Text(device.name.value) },
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
||||||
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
||||||
@@ -845,6 +858,7 @@ private fun AddTriggerDialog(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AddConditionDialog(
|
private fun AddConditionDialog(
|
||||||
|
availableDevices: List<DeviceDescriptor>,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onAddTemp: (deviceName: String, ComparisonOperator, Double) -> Unit,
|
onAddTemp: (deviceName: String, ComparisonOperator, Double) -> Unit,
|
||||||
onAddHumidity: (deviceName: String, ComparisonOperator, Double) -> Unit,
|
onAddHumidity: (deviceName: String, ComparisonOperator, Double) -> Unit,
|
||||||
@@ -867,10 +881,13 @@ private fun AddConditionDialog(
|
|||||||
val isEndTimeValid = timeRegex.matches(endTime.trim())
|
val isEndTimeValid = timeRegex.matches(endTime.trim())
|
||||||
val isTimeRangeValid = isStartTimeValid && isEndTimeValid
|
val isTimeRangeValid = isStartTimeValid && isEndTimeValid
|
||||||
|
|
||||||
|
val sensors = availableDevices.filter { it.type == DeviceType.TEMPERATURE_HUMIDITY }
|
||||||
|
val sockets = availableDevices.filter { it.type == DeviceType.SOCKET }
|
||||||
|
|
||||||
val isDeviceValid = when (selectedType) {
|
val isDeviceValid = when (selectedType) {
|
||||||
0 -> tempDeviceName.isNotBlank()
|
0 -> sensors.any { it.name.value == tempDeviceName }
|
||||||
1 -> humDeviceName.isNotBlank()
|
1 -> sensors.any { it.name.value == humDeviceName }
|
||||||
2 -> socketDeviceName.isNotBlank()
|
2 -> sockets.any { it.name.value == socketDeviceName }
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -887,13 +904,12 @@ private fun AddConditionDialog(
|
|||||||
}
|
}
|
||||||
when (selectedType) {
|
when (selectedType) {
|
||||||
0 -> {
|
0 -> {
|
||||||
OutlinedTextField(
|
Text(stringResource(R.string.scene_device_name_label))
|
||||||
value = tempDeviceName,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
onValueChange = { tempDeviceName = it },
|
sensors.forEach { device ->
|
||||||
label = { Text(stringResource(R.string.scene_device_name_label)) },
|
FilterChip(selected = tempDeviceName == device.name.value, onClick = { tempDeviceName = device.name.value }, label = { Text(device.name.value) })
|
||||||
singleLine = true,
|
}
|
||||||
modifier = Modifier.fillMaxWidth(),
|
}
|
||||||
)
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
||||||
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
||||||
@@ -902,13 +918,12 @@ private fun AddConditionDialog(
|
|||||||
Slider(value = tempVal.toFloat(), onValueChange = { tempVal = it.toDouble() }, valueRange = 10f..40f)
|
Slider(value = tempVal.toFloat(), onValueChange = { tempVal = it.toDouble() }, valueRange = 10f..40f)
|
||||||
}
|
}
|
||||||
1 -> {
|
1 -> {
|
||||||
OutlinedTextField(
|
Text(stringResource(R.string.scene_device_name_label))
|
||||||
value = humDeviceName,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
onValueChange = { humDeviceName = it },
|
sensors.forEach { device ->
|
||||||
label = { Text(stringResource(R.string.scene_device_name_label)) },
|
FilterChip(selected = humDeviceName == device.name.value, onClick = { humDeviceName = device.name.value }, label = { Text(device.name.value) })
|
||||||
singleLine = true,
|
}
|
||||||
modifier = Modifier.fillMaxWidth(),
|
}
|
||||||
)
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
FilterChip(selected = operator == ComparisonOperator.GREATER_THAN, onClick = { operator = ComparisonOperator.GREATER_THAN }, label = { Text(stringResource(R.string.scene_chip_above)) })
|
||||||
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
FilterChip(selected = operator == ComparisonOperator.LESS_THAN, onClick = { operator = ComparisonOperator.LESS_THAN }, label = { Text(stringResource(R.string.scene_chip_below)) })
|
||||||
@@ -917,13 +932,12 @@ private fun AddConditionDialog(
|
|||||||
Slider(value = humVal.toFloat(), onValueChange = { humVal = it.toDouble() }, valueRange = 10f..90f)
|
Slider(value = humVal.toFloat(), onValueChange = { humVal = it.toDouble() }, valueRange = 10f..90f)
|
||||||
}
|
}
|
||||||
2 -> {
|
2 -> {
|
||||||
OutlinedTextField(
|
Text(stringResource(R.string.scene_device_name_label))
|
||||||
value = socketDeviceName,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
onValueChange = { socketDeviceName = it },
|
sockets.forEach { device ->
|
||||||
label = { Text(stringResource(R.string.scene_device_name_label)) },
|
FilterChip(selected = socketDeviceName == device.name.value, onClick = { socketDeviceName = device.name.value }, label = { Text(device.name.value) })
|
||||||
singleLine = true,
|
}
|
||||||
modifier = Modifier.fillMaxWidth(),
|
}
|
||||||
)
|
|
||||||
Text(stringResource(R.string.scene_target_socket_state))
|
Text(stringResource(R.string.scene_target_socket_state))
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
FilterChip(selected = socketPower == SocketPowerState.ON, onClick = { socketPower = SocketPowerState.ON }, label = { Text(stringResource(R.string.scene_chip_power_on)) })
|
FilterChip(selected = socketPower == SocketPowerState.ON, onClick = { socketPower = SocketPowerState.ON }, label = { Text(stringResource(R.string.scene_chip_power_on)) })
|
||||||
@@ -982,6 +996,7 @@ private fun AddConditionDialog(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun AddActionDialog(
|
private fun AddActionDialog(
|
||||||
availableRemotes: List<VirtualRemote>,
|
availableRemotes: List<VirtualRemote>,
|
||||||
|
availableDevices: List<com.flagship.abox.manager.domain.DeviceDescriptor>,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
viewModel: SceneEditorViewModel,
|
viewModel: SceneEditorViewModel,
|
||||||
onAddSocket: (deviceName: String, powerState: SocketPowerState) -> Unit,
|
onAddSocket: (deviceName: String, powerState: SocketPowerState) -> Unit,
|
||||||
@@ -994,7 +1009,7 @@ private fun AddActionDialog(
|
|||||||
val defaultNotifyTitle = stringResource(R.string.scene_default_notify_title)
|
val defaultNotifyTitle = stringResource(R.string.scene_default_notify_title)
|
||||||
val defaultNotifyMsg = stringResource(R.string.scene_default_notify_msg)
|
val defaultNotifyMsg = stringResource(R.string.scene_default_notify_msg)
|
||||||
|
|
||||||
var socketName by remember { mutableStateOf("") }
|
var socketName by remember { mutableStateOf(availableDevices.firstOrNull { it.type == DeviceType.SOCKET }?.name?.value.orEmpty()) }
|
||||||
var socketPower by remember { mutableStateOf(SocketPowerState.ON) }
|
var socketPower by remember { mutableStateOf(SocketPowerState.ON) }
|
||||||
|
|
||||||
var selectedRemoteIndex by remember { mutableIntStateOf(0) }
|
var selectedRemoteIndex by remember { mutableIntStateOf(0) }
|
||||||
@@ -1037,13 +1052,16 @@ private fun AddActionDialog(
|
|||||||
}
|
}
|
||||||
when (actionType) {
|
when (actionType) {
|
||||||
0 -> {
|
0 -> {
|
||||||
OutlinedTextField(
|
Text(stringResource(R.string.scene_select_socket))
|
||||||
value = socketName,
|
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||||
onValueChange = { socketName = it },
|
availableDevices.filter { it.type == DeviceType.SOCKET }.forEach { device ->
|
||||||
label = { Text(stringResource(R.string.scene_select_socket)) },
|
FilterChip(
|
||||||
singleLine = true,
|
selected = socketName == device.name.value,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onClick = { socketName = device.name.value },
|
||||||
|
label = { Text(device.name.value) },
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Text(stringResource(R.string.scene_socket_power_state))
|
Text(stringResource(R.string.scene_socket_power_state))
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
FilterChip(selected = socketPower == SocketPowerState.ON, onClick = { socketPower = SocketPowerState.ON }, label = { Text(stringResource(R.string.scene_chip_power_on)) })
|
FilterChip(selected = socketPower == SocketPowerState.ON, onClick = { socketPower = SocketPowerState.ON }, label = { Text(stringResource(R.string.scene_chip_power_on)) })
|
||||||
@@ -1102,7 +1120,7 @@ private fun AddActionDialog(
|
|||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
val canConfirm = when (actionType) {
|
val canConfirm = when (actionType) {
|
||||||
0 -> socketName.isNotBlank()
|
0 -> availableDevices.any { it.type == DeviceType.SOCKET && it.name.value == socketName }
|
||||||
1 -> availableRemotes.isNotEmpty() && selectedButtonId.isNotBlank()
|
1 -> availableRemotes.isNotEmpty() && selectedButtonId.isNotBlank()
|
||||||
3 -> notifyTitle.isNotBlank()
|
3 -> notifyTitle.isNotBlank()
|
||||||
else -> true
|
else -> true
|
||||||
|
|||||||
+22
@@ -6,6 +6,9 @@ import com.flagship.abox.manager.domain.AutomationType
|
|||||||
import com.flagship.abox.manager.domain.ComparisonOperator
|
import com.flagship.abox.manager.domain.ComparisonOperator
|
||||||
import com.flagship.abox.manager.domain.ConcurrencyMode
|
import com.flagship.abox.manager.domain.ConcurrencyMode
|
||||||
import com.flagship.abox.manager.domain.DeviceName
|
import com.flagship.abox.manager.domain.DeviceName
|
||||||
|
import com.flagship.abox.manager.domain.DeviceCatalog
|
||||||
|
import com.flagship.abox.manager.domain.DeviceDescriptor
|
||||||
|
import com.flagship.abox.manager.domain.DeviceType
|
||||||
import com.flagship.abox.manager.domain.DomainResult
|
import com.flagship.abox.manager.domain.DomainResult
|
||||||
import com.flagship.abox.manager.domain.ExecutionStrategy
|
import com.flagship.abox.manager.domain.ExecutionStrategy
|
||||||
import com.flagship.abox.manager.domain.ProviderProfileStore
|
import com.flagship.abox.manager.domain.ProviderProfileStore
|
||||||
@@ -50,6 +53,7 @@ data class SceneEditorState(
|
|||||||
val concurrencyMode: ConcurrencyMode = ConcurrencyMode.SEQUENTIAL,
|
val concurrencyMode: ConcurrencyMode = ConcurrencyMode.SEQUENTIAL,
|
||||||
val enableLogging: Boolean = true,
|
val enableLogging: Boolean = true,
|
||||||
val availableRemotes: List<VirtualRemote> = emptyList(),
|
val availableRemotes: List<VirtualRemote> = emptyList(),
|
||||||
|
val availableDevices: List<DeviceDescriptor> = emptyList(),
|
||||||
val isLoading: Boolean = false,
|
val isLoading: Boolean = false,
|
||||||
val isSaving: Boolean = false,
|
val isSaving: Boolean = false,
|
||||||
val isSaved: Boolean = false,
|
val isSaved: Boolean = false,
|
||||||
@@ -64,6 +68,7 @@ class SceneEditorViewModel @Inject constructor(
|
|||||||
private val sceneRepository: SceneRepository,
|
private val sceneRepository: SceneRepository,
|
||||||
private val virtualRemoteRepository: VirtualRemoteRepository,
|
private val virtualRemoteRepository: VirtualRemoteRepository,
|
||||||
private val profileStore: ProviderProfileStore,
|
private val profileStore: ProviderProfileStore,
|
||||||
|
private val deviceCatalog: DeviceCatalog,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _state = MutableStateFlow(SceneEditorState())
|
private val _state = MutableStateFlow(SceneEditorState())
|
||||||
@@ -74,6 +79,23 @@ class SceneEditorViewModel @Inject constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
observeAvailableRemotes()
|
observeAvailableRemotes()
|
||||||
|
observeAvailableDevices()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeAvailableDevices() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
profileStore.observeActiveProfile().collectLatest { profile ->
|
||||||
|
if (profile == null) {
|
||||||
|
_state.update { it.copy(availableDevices = emptyList()) }
|
||||||
|
} else {
|
||||||
|
deviceCatalog.observeDevices(profile.id).collectLatest { result ->
|
||||||
|
if (result is DomainResult.Success) {
|
||||||
|
_state.update { it.copy(availableDevices = result.value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeAvailableRemotes() {
|
private fun observeAvailableRemotes() {
|
||||||
|
|||||||
+9
-7
@@ -20,6 +20,7 @@ import com.flagship.abox.manager.domain.SocketPowerState
|
|||||||
import com.flagship.abox.manager.testing.MainDispatcherRule
|
import com.flagship.abox.manager.testing.MainDispatcherRule
|
||||||
import com.flagship.abox.manager.testing.fakes.FakeProviderProfileStore
|
import com.flagship.abox.manager.testing.fakes.FakeProviderProfileStore
|
||||||
import com.flagship.abox.manager.testing.fakes.FakeSceneRepository
|
import com.flagship.abox.manager.testing.fakes.FakeSceneRepository
|
||||||
|
import com.flagship.abox.manager.testing.fakes.FakeDeviceCatalog
|
||||||
import com.flagship.abox.manager.testing.fakes.FakeVirtualRemoteRepository
|
import com.flagship.abox.manager.testing.fakes.FakeVirtualRemoteRepository
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.advanceUntilIdle
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
@@ -39,6 +40,7 @@ class SceneEditorViewModelTest {
|
|||||||
private val profileStore = FakeProviderProfileStore()
|
private val profileStore = FakeProviderProfileStore()
|
||||||
private val sceneRepository = FakeSceneRepository()
|
private val sceneRepository = FakeSceneRepository()
|
||||||
private val virtualRemoteRepository = FakeVirtualRemoteRepository()
|
private val virtualRemoteRepository = FakeVirtualRemoteRepository()
|
||||||
|
private val deviceCatalog = FakeDeviceCatalog()
|
||||||
private val profileId = ProviderProfileId("local-experience")
|
private val profileId = ProviderProfileId("local-experience")
|
||||||
|
|
||||||
private val existingScene = Scene(
|
private val existingScene = Scene(
|
||||||
@@ -66,7 +68,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun initializeWithNullPreparesNewScene() = runTest {
|
fun initializeWithNullPreparesNewScene() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(null, AutomationType.MANUAL)
|
viewModel.initialize(null, AutomationType.MANUAL)
|
||||||
|
|
||||||
val state = viewModel.state.value
|
val state = viewModel.state.value
|
||||||
@@ -79,7 +81,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun initializeWithExistingSceneLoadsState() = runTest {
|
fun initializeWithExistingSceneLoadsState() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(existingScene.id)
|
viewModel.initialize(existingScene.id)
|
||||||
|
|
||||||
// Immediately binds sceneId and enters loading state
|
// Immediately binds sceneId and enters loading state
|
||||||
@@ -101,7 +103,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun addingAndReorderingActionsUpdatesState() = runTest {
|
fun addingAndReorderingActionsUpdatesState() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(null, AutomationType.MANUAL)
|
viewModel.initialize(null, AutomationType.MANUAL)
|
||||||
viewModel.updateName("My New Scene")
|
viewModel.updateName("My New Scene")
|
||||||
|
|
||||||
@@ -129,7 +131,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun addingTriggersAndConditionsForAutomaticRule() = runTest {
|
fun addingTriggersAndConditionsForAutomaticRule() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(null, AutomationType.AUTOMATIC)
|
viewModel.initialize(null, AutomationType.AUTOMATIC)
|
||||||
viewModel.updateName("Auto Rule")
|
viewModel.updateName("Auto Rule")
|
||||||
|
|
||||||
@@ -153,7 +155,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun saveNewScenePersistsToRepository() = runTest {
|
fun saveNewScenePersistsToRepository() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(null, AutomationType.MANUAL)
|
viewModel.initialize(null, AutomationType.MANUAL)
|
||||||
viewModel.updateName("Brand New Scene")
|
viewModel.updateName("Brand New Scene")
|
||||||
viewModel.addSocketAction("socket-main", SocketPowerState.OFF)
|
viewModel.addSocketAction("socket-main", SocketPowerState.OFF)
|
||||||
@@ -170,7 +172,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun automaticSceneWithoutTriggersIsInvalid() = runTest {
|
fun automaticSceneWithoutTriggersIsInvalid() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(null, AutomationType.AUTOMATIC)
|
viewModel.initialize(null, AutomationType.AUTOMATIC)
|
||||||
viewModel.updateName("Auto Without Trigger")
|
viewModel.updateName("Auto Without Trigger")
|
||||||
viewModel.addSocketAction("socket-1", SocketPowerState.ON)
|
viewModel.addSocketAction("socket-1", SocketPowerState.ON)
|
||||||
@@ -188,7 +190,7 @@ class SceneEditorViewModelTest {
|
|||||||
@Test
|
@Test
|
||||||
fun initializeIsIdempotentAndPreservesDraftState() = runTest {
|
fun initializeIsIdempotentAndPreservesDraftState() = runTest {
|
||||||
setupProfile()
|
setupProfile()
|
||||||
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore)
|
val viewModel = SceneEditorViewModel(sceneRepository, virtualRemoteRepository, profileStore, deviceCatalog)
|
||||||
viewModel.initialize(existingScene.id)
|
viewModel.initialize(existingScene.id)
|
||||||
advanceUntilIdle()
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user