feat(infrared): refactor virtual remote hub with multi-device presets and quota management
This commit is contained in:
+3
@@ -129,6 +129,9 @@ class FakeInfraredGateway : InfraredGateway {
|
||||
learnResults[InfraredOperationKey(profileId, deviceName, key)] = result
|
||||
}
|
||||
|
||||
val downloadedCodes: List<InfraredCode>
|
||||
get() = downloadCalls.flatMap { it.codes }
|
||||
|
||||
override suspend fun downloadCodes(
|
||||
profileId: ProviderProfileId,
|
||||
codes: List<InfraredCode>,
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package com.flagship.abox.manager.testing.fakes
|
||||
|
||||
import com.flagship.abox.manager.domain.DeviceName
|
||||
import com.flagship.abox.manager.domain.DomainResult
|
||||
import com.flagship.abox.manager.domain.ProviderProfileId
|
||||
import com.flagship.abox.manager.domain.infrared.AcStateSnapshot
|
||||
import com.flagship.abox.manager.domain.infrared.RemoteKeyBinding
|
||||
import com.flagship.abox.manager.domain.infrared.SlotQuotaSummary
|
||||
import com.flagship.abox.manager.domain.infrared.VirtualRemote
|
||||
import com.flagship.abox.manager.domain.infrared.VirtualRemoteId
|
||||
import com.flagship.abox.manager.domain.infrared.VirtualRemoteRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class FakeVirtualRemoteRepository : VirtualRemoteRepository {
|
||||
|
||||
private val remotes = ConcurrentHashMap<VirtualRemoteId, VirtualRemote>()
|
||||
private val bindings = ConcurrentHashMap<VirtualRemoteId, MutableList<RemoteKeyBinding>>()
|
||||
private val changeTrigger = MutableStateFlow(0L)
|
||||
|
||||
override fun observeRemotes(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
): Flow<DomainResult<List<VirtualRemote>>> = changeTrigger.map {
|
||||
DomainResult.Success(
|
||||
remotes.values.filter { it.profileId == profileId && it.deviceName == deviceName }
|
||||
.sortedByDescending { it.createdAtEpochMillis },
|
||||
)
|
||||
}
|
||||
|
||||
override fun observeRemote(
|
||||
profileId: ProviderProfileId,
|
||||
remoteId: VirtualRemoteId,
|
||||
): Flow<DomainResult<VirtualRemote?>> = changeTrigger.map {
|
||||
val remote = remotes[remoteId]?.takeIf { it.profileId == profileId }
|
||||
DomainResult.Success(remote)
|
||||
}
|
||||
|
||||
override fun observeKeyBindings(
|
||||
remoteId: VirtualRemoteId,
|
||||
): Flow<DomainResult<List<RemoteKeyBinding>>> = changeTrigger.map {
|
||||
DomainResult.Success(bindings[remoteId]?.toList().orEmpty())
|
||||
}
|
||||
|
||||
override fun observeSlotQuota(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
): Flow<DomainResult<SlotQuotaSummary>> = changeTrigger.map {
|
||||
val relevantBindings = remotes.values
|
||||
.filter { it.profileId == profileId && it.deviceName == deviceName }
|
||||
.flatMap { bindings[it.id].orEmpty() }
|
||||
val usedSlots = relevantBindings.mapNotNull { it.assignedSlot?.toIntOrNull() }.toSet()
|
||||
DomainResult.Success(
|
||||
SlotQuotaSummary(
|
||||
totalCapacity = 100,
|
||||
dynamicScratchSlot = 100,
|
||||
assignedStaticSlots = usedSlots,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getRemote(
|
||||
profileId: ProviderProfileId,
|
||||
remoteId: VirtualRemoteId,
|
||||
): DomainResult<VirtualRemote?> {
|
||||
val remote = remotes[remoteId]?.takeIf { it.profileId == profileId }
|
||||
return DomainResult.Success(remote)
|
||||
}
|
||||
|
||||
override suspend fun getKeyBindings(
|
||||
remoteId: VirtualRemoteId,
|
||||
): DomainResult<List<RemoteKeyBinding>> =
|
||||
DomainResult.Success(bindings[remoteId]?.toList().orEmpty())
|
||||
|
||||
override suspend fun createRemote(
|
||||
remote: VirtualRemote,
|
||||
initialBindings: List<RemoteKeyBinding>,
|
||||
): DomainResult<VirtualRemoteId> {
|
||||
remotes[remote.id] = remote
|
||||
bindings[remote.id] = initialBindings.toMutableList()
|
||||
changeTrigger.value = System.currentTimeMillis()
|
||||
return DomainResult.Success(remote.id)
|
||||
}
|
||||
|
||||
override suspend fun updateRemote(remote: VirtualRemote): DomainResult<Unit> {
|
||||
remotes[remote.id] = remote
|
||||
changeTrigger.value = System.currentTimeMillis()
|
||||
return DomainResult.Success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun deleteRemote(
|
||||
profileId: ProviderProfileId,
|
||||
remoteId: VirtualRemoteId,
|
||||
): DomainResult<Unit> {
|
||||
remotes.remove(remoteId)
|
||||
bindings.remove(remoteId)
|
||||
changeTrigger.value = System.currentTimeMillis()
|
||||
return DomainResult.Success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updateKeyBinding(binding: RemoteKeyBinding): DomainResult<Unit> {
|
||||
val list = bindings[binding.remoteId] ?: mutableListOf()
|
||||
val index = list.indexOfFirst { it.id == binding.id || it.buttonId == binding.buttonId }
|
||||
if (index >= 0) {
|
||||
list[index] = binding
|
||||
} else {
|
||||
list.add(binding)
|
||||
}
|
||||
bindings[binding.remoteId] = list
|
||||
changeTrigger.value = System.currentTimeMillis()
|
||||
return DomainResult.Success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun updateAcState(
|
||||
profileId: ProviderProfileId,
|
||||
remoteId: VirtualRemoteId,
|
||||
state: AcStateSnapshot,
|
||||
): DomainResult<Unit> {
|
||||
val existing = remotes[remoteId] ?: return DomainResult.Success(Unit)
|
||||
remotes[remoteId] = existing.copy(acState = state)
|
||||
changeTrigger.value = System.currentTimeMillis()
|
||||
return DomainResult.Success(Unit)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user