feat: establish Android project foundation
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(21)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(libs.kotlinx.coroutines.core)
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.kotlinx.coroutines.test)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.flagship.abox.manager.domain
|
||||
|
||||
sealed interface DomainResult<out T> {
|
||||
data class Success<T>(val value: T) : DomainResult<T>
|
||||
|
||||
data class Failure(val error: DomainError) : DomainResult<Nothing>
|
||||
}
|
||||
|
||||
sealed interface DomainError {
|
||||
val externalCode: String?
|
||||
val detail: String?
|
||||
|
||||
data class Authentication(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class TokenInvalid(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class Network(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class DeviceNotFound(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class DeviceOffline(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class InvalidRequest(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class OperationFailed(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class NoData(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
|
||||
data class Unknown(
|
||||
override val externalCode: String? = null,
|
||||
override val detail: String? = null,
|
||||
) : DomainError
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.flagship.abox.manager.domain
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface SessionGateway {
|
||||
fun observeSession(profileId: ProviderProfileId): Flow<Session?>
|
||||
|
||||
suspend fun login(
|
||||
profileId: ProviderProfileId,
|
||||
credentials: LoginCredentials,
|
||||
): DomainResult<Session>
|
||||
|
||||
suspend fun validateSession(profileId: ProviderProfileId): DomainResult<SessionValidity>
|
||||
|
||||
suspend fun logout(profileId: ProviderProfileId): DomainResult<Unit>
|
||||
}
|
||||
|
||||
interface DeviceCatalog {
|
||||
fun observeDevices(
|
||||
profileId: ProviderProfileId,
|
||||
): Flow<DomainResult<List<DeviceDescriptor>>>
|
||||
}
|
||||
|
||||
interface SocketGateway {
|
||||
suspend fun getStatus(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
): DomainResult<SocketStatus>
|
||||
|
||||
suspend fun setPower(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
powerState: SocketPowerState,
|
||||
): DomainResult<SocketStatus>
|
||||
}
|
||||
|
||||
interface TemperatureHumidityGateway {
|
||||
suspend fun getReading(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
): DomainResult<TemperatureHumidityReading>
|
||||
}
|
||||
|
||||
interface InfraredGateway {
|
||||
suspend fun sendKey(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
key: String,
|
||||
): DomainResult<Unit>
|
||||
|
||||
suspend fun learnKey(
|
||||
profileId: ProviderProfileId,
|
||||
deviceName: DeviceName,
|
||||
key: String,
|
||||
): DomainResult<Unit>
|
||||
|
||||
suspend fun downloadCodes(
|
||||
profileId: ProviderProfileId,
|
||||
codes: List<InfraredCode>,
|
||||
): DomainResult<List<InfraredCodeDownloadResult>>
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.flagship.abox.manager.domain
|
||||
|
||||
@JvmInline
|
||||
value class ProviderProfileId(val value: String)
|
||||
|
||||
@JvmInline
|
||||
value class DeviceId(val value: String)
|
||||
|
||||
@JvmInline
|
||||
value class DeviceName(val value: String)
|
||||
|
||||
@JvmInline
|
||||
value class Username(val value: String)
|
||||
|
||||
@JvmInline
|
||||
value class Password(val value: String)
|
||||
|
||||
enum class ProviderType {
|
||||
ABOX,
|
||||
COMPATIBLE_BACKEND,
|
||||
LOCAL_EXPERIENCE,
|
||||
}
|
||||
|
||||
data class ProviderProfile(
|
||||
val id: ProviderProfileId,
|
||||
val type: ProviderType,
|
||||
val displayName: String,
|
||||
)
|
||||
|
||||
enum class DeviceType {
|
||||
SOCKET,
|
||||
TEMPERATURE_HUMIDITY,
|
||||
INFRARED,
|
||||
}
|
||||
|
||||
data class DeviceDescriptor(
|
||||
val id: DeviceId,
|
||||
val profileId: ProviderProfileId,
|
||||
val name: DeviceName,
|
||||
val type: DeviceType,
|
||||
)
|
||||
|
||||
data class LoginCredentials(
|
||||
val username: Username,
|
||||
val password: Password,
|
||||
)
|
||||
|
||||
data class Session(
|
||||
val profileId: ProviderProfileId,
|
||||
val username: Username,
|
||||
)
|
||||
|
||||
enum class SessionValidity {
|
||||
VALID,
|
||||
INVALID,
|
||||
}
|
||||
|
||||
enum class SocketPowerState {
|
||||
OFF,
|
||||
ON,
|
||||
}
|
||||
|
||||
data class SocketStatus(
|
||||
val profileId: ProviderProfileId,
|
||||
val deviceName: DeviceName,
|
||||
val powerState: SocketPowerState,
|
||||
)
|
||||
|
||||
data class TemperatureHumidityReading(
|
||||
val profileId: ProviderProfileId,
|
||||
val deviceName: DeviceName,
|
||||
val temperature: String,
|
||||
val humidity: String,
|
||||
)
|
||||
|
||||
data class InfraredCode(
|
||||
val profileId: ProviderProfileId,
|
||||
val deviceName: DeviceName,
|
||||
val key: String,
|
||||
val code: String,
|
||||
)
|
||||
|
||||
data class InfraredCodeDownloadResult(
|
||||
val infraredCode: InfraredCode,
|
||||
val successful: Boolean,
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.flagship.abox.manager.domain
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class DomainResultTest {
|
||||
@Test
|
||||
fun successContainsTypedValue() {
|
||||
val result: DomainResult<SocketPowerState> = DomainResult.Success(SocketPowerState.ON)
|
||||
|
||||
assertEquals(SocketPowerState.ON, (result as DomainResult.Success).value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun failureKeepsExternalCodeWithoutSdkTypes() {
|
||||
val error = DomainError.DeviceOffline(externalCode = "20504")
|
||||
val result: DomainResult<Unit> = DomainResult.Failure(error)
|
||||
|
||||
assertTrue(result is DomainResult.Failure)
|
||||
assertEquals("20504", (result as DomainResult.Failure).error.externalCode)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user