diff --git a/components/bridge/connection/config/api/build.gradle.kts b/components/bridge/connection/config/api/build.gradle.kts index 26993b9f4c..c967afbac2 100644 --- a/components/bridge/connection/config/api/build.gradle.kts +++ b/components/bridge/connection/config/api/build.gradle.kts @@ -7,6 +7,8 @@ plugins { android.namespace = "com.flipperdevices.bridge.connection.config.api" commonDependencies { + implementation(projects.components.core.preference) + implementation(libs.kotlin.coroutines) implementation(libs.kotlin.serialization.json) } diff --git a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt index ef37eca0fc..8f4d1a803f 100644 --- a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt +++ b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/FDevicePersistedStorage.kt @@ -1,6 +1,7 @@ package com.flipperdevices.bridge.connection.config.api import com.flipperdevices.bridge.connection.config.api.model.FDeviceBaseModel +import com.flipperdevices.core.preference.pb.SavedDevice import kotlinx.coroutines.flow.Flow interface FDevicePersistedStorage { @@ -9,4 +10,5 @@ interface FDevicePersistedStorage { suspend fun addDevice(device: FDeviceBaseModel) suspend fun removeDevice(id: String) fun getAllDevices(): Flow> + suspend fun updateCurrentDevice(block: (FDeviceBaseModel) -> FDeviceBaseModel) } diff --git a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/model/FDeviceFlipperZeroBleModel.kt b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/model/FDeviceFlipperZeroBleModel.kt index 4e19118528..17f431f10b 100644 --- a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/model/FDeviceFlipperZeroBleModel.kt +++ b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/model/FDeviceFlipperZeroBleModel.kt @@ -1,6 +1,8 @@ package com.flipperdevices.bridge.connection.config.api.model import com.flipperdevices.bridge.connection.config.api.FDeviceType +import com.flipperdevices.bridge.connection.config.api.serialization.HardwareColorSerializer +import com.flipperdevices.core.preference.pb.FlipperZeroBle import kotlinx.serialization.Serializable import java.util.UUID @@ -9,7 +11,9 @@ data class FDeviceFlipperZeroBleModel( val name: String, val address: String, override val uniqueId: String = UUID.randomUUID().toString(), - override val humanReadableName: String = "Flipper $name" + override val humanReadableName: String = "Flipper $name", + @Serializable(HardwareColorSerializer::class) + val hardwareColor: FlipperZeroBle.HardwareColor ) : FDeviceBaseModel { override val type = FDeviceType.FLIPPER_ZERO_BLE } diff --git a/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt new file mode 100644 index 0000000000..2820aff094 --- /dev/null +++ b/components/bridge/connection/config/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/api/serialization/HardwareColorSerializer.kt @@ -0,0 +1,25 @@ +package com.flipperdevices.bridge.connection.config.api.serialization + +import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +internal object HardwareColorSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor( + serialName = "com.flipperdevices.SavedDevice.HardwareColor", + kind = PrimitiveKind.INT + ) + + override fun deserialize(decoder: Decoder): HardwareColor { + val intValue = decoder.decodeInt() + return HardwareColor.fromValue(intValue) + } + + override fun serialize(encoder: Encoder, value: HardwareColor) { + encoder.encodeInt(value.value) + } +} \ No newline at end of file diff --git a/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt b/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt index 4dc67be59e..78b1e42839 100644 --- a/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt +++ b/components/bridge/connection/config/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/config/impl/FDevicePersistedStorageImpl.kt @@ -9,6 +9,7 @@ import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.info import com.flipperdevices.core.log.warn import com.flipperdevices.core.preference.pb.FlipperZeroBle +import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor import com.flipperdevices.core.preference.pb.NewPairSettings import com.flipperdevices.core.preference.pb.SavedDevice import com.squareup.anvil.annotations.ContributesBinding @@ -85,7 +86,8 @@ class FDevicePersistedStorageImpl @Inject constructor( return FDeviceFlipperZeroBleModel( name = device.name, uniqueId = device.id, - address = flipperZeroBle.address + address = flipperZeroBle.address, + hardwareColor = flipperZeroBle.hardware_color ) } return null @@ -104,4 +106,23 @@ class FDevicePersistedStorageImpl @Inject constructor( else -> error("Can't find parser for $device") } } + + override suspend fun updateCurrentDevice(block: (FDeviceBaseModel) -> FDeviceBaseModel) { + newPairSettings.updateData { newPairSettings -> + newPairSettings.copy( + devices = newPairSettings.devices.toMutableList().apply { + replaceAll { device -> + if (device.id == newPairSettings.current_selected_device_id) { + mapSavedDevice(device) + ?.let(block::invoke) + ?.let(::mapDeviceBaseModelToSavedDevice) + ?: device + } else { + device + } + } + }.toList() + ) + } + } } diff --git a/components/bridge/connection/device/fzero/impl/build.gradle.kts b/components/bridge/connection/device/fzero/impl/build.gradle.kts index ffb56865bb..662db55269 100644 --- a/components/bridge/connection/device/fzero/impl/build.gradle.kts +++ b/components/bridge/connection/device/fzero/impl/build.gradle.kts @@ -26,6 +26,8 @@ commonDependencies { implementation(projects.components.bridge.connection.feature.storage.api) implementation(projects.components.bridge.connection.feature.storageinfo.api) implementation(projects.components.bridge.connection.feature.getinfo.api) + implementation(projects.components.bridge.connection.feature.alarm.api) + implementation(projects.components.bridge.connection.feature.deviceColor.api) implementation(libs.kotlin.coroutines) implementation(libs.kotlin.immutable.collections) diff --git a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt index b2ae40edb8..e6afff3bc2 100644 --- a/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt +++ b/components/bridge/connection/device/fzero/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/device/fzero/impl/utils/FZeroFeatureClassToEnumMapper.kt @@ -1,7 +1,10 @@ package com.flipperdevices.bridge.connection.device.fzero.impl.utils +import com.flipperdevices.bridge.connection.feature.alarm.api.FAlarmFeatureApi import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.devicecolor.api.FDeviceColorFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGattInfoFeatureApi import com.flipperdevices.bridge.connection.feature.getinfo.api.FGetInfoFeatureApi import com.flipperdevices.bridge.connection.feature.protocolversion.api.FVersionFeatureApi import com.flipperdevices.bridge.connection.feature.restartrpc.api.FRestartRpcFeatureApi @@ -30,6 +33,9 @@ object FZeroFeatureClassToEnumMapper { FDeviceFeature.STORAGE_INFO -> FStorageInfoFeatureApi::class FDeviceFeature.GET_INFO -> FGetInfoFeatureApi::class FDeviceFeature.STORAGE -> FStorageFeatureApi::class + FDeviceFeature.ALARM -> FAlarmFeatureApi::class + FDeviceFeature.DEVICE_COLOR -> FDeviceColorFeatureApi::class + FDeviceFeature.GATT_INFO -> FGattInfoFeatureApi::class } } diff --git a/components/bridge/connection/feature/alarm/api/build.gradle.kts b/components/bridge/connection/feature/alarm/api/build.gradle.kts new file mode 100644 index 0000000000..46e51ce0ed --- /dev/null +++ b/components/bridge/connection/feature/alarm/api/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.alarm.api" + +commonDependencies { + implementation(projects.components.core.data) + implementation(projects.components.core.ktx) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + + implementation(libs.kotlin.immutable.collections) + implementation(libs.kotlin.coroutines) +} diff --git a/components/bridge/connection/feature/alarm/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/api/FAlarmFeatureApi.kt b/components/bridge/connection/feature/alarm/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/api/FAlarmFeatureApi.kt new file mode 100644 index 0000000000..3105e99abb --- /dev/null +++ b/components/bridge/connection/feature/alarm/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/api/FAlarmFeatureApi.kt @@ -0,0 +1,7 @@ +package com.flipperdevices.bridge.connection.feature.alarm.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi + +interface FAlarmFeatureApi : FDeviceFeatureApi { + suspend fun makeSound() +} diff --git a/components/bridge/connection/feature/alarm/impl/build.gradle.kts b/components/bridge/connection/feature/alarm/impl/build.gradle.kts new file mode 100644 index 0000000000..c9b95cdd67 --- /dev/null +++ b/components/bridge/connection/feature/alarm/impl/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") + id("flipper.anvil-multiplatform") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.alarm.impl" + +commonDependencies { + implementation(projects.components.bridge.connection.feature.alarm.api) + + implementation(projects.components.core.di) + implementation(projects.components.core.log) + implementation(projects.components.core.ktx) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.rpc.api) + implementation(projects.components.bridge.connection.feature.rpc.model) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + + implementation(projects.components.bridge.connection.pbutils) + + implementation(libs.kotlin.coroutines) +} diff --git a/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureApiImpl.kt b/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureApiImpl.kt new file mode 100644 index 0000000000..c9d8b1b651 --- /dev/null +++ b/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureApiImpl.kt @@ -0,0 +1,33 @@ +package com.flipperdevices.bridge.connection.feature.alarm.impl.api + +import com.flipperdevices.bridge.connection.feature.alarm.api.FAlarmFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.model.wrapToRequest +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.protobuf.Main +import com.flipperdevices.protobuf.system.PlayAudiovisualAlertRequest +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class FAlarmFeatureApiImpl @AssistedInject constructor( + @Assisted private val rpcFeatureApi: FRpcFeatureApi, +) : FAlarmFeatureApi, + LogTagProvider { + override val TAG = "FAlarmFeatureApi" + + override suspend fun makeSound() { + rpcFeatureApi.requestWithoutAnswer( + Main( + system_play_audiovisual_alert_request = PlayAudiovisualAlertRequest() + ).wrapToRequest() + ) + } + + @AssistedFactory + fun interface InternalFactory { + operator fun invoke( + rpcFeatureApi: FRpcFeatureApi, + ): FAlarmFeatureApiImpl + } +} diff --git a/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureFactoryImpl.kt b/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureFactoryImpl.kt new file mode 100644 index 0000000000..411e399a7d --- /dev/null +++ b/components/bridge/connection/feature/alarm/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/alarm/impl/api/FAlarmFeatureFactoryImpl.kt @@ -0,0 +1,29 @@ +package com.flipperdevices.bridge.connection.feature.alarm.impl.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureQualifier +import com.flipperdevices.bridge.connection.feature.common.api.FUnsafeDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.rpc.api.FRpcFeatureApi +import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi +import com.flipperdevices.core.di.AppGraph +import com.squareup.anvil.annotations.ContributesMultibinding +import kotlinx.coroutines.CoroutineScope +import javax.inject.Inject + +@FDeviceFeatureQualifier(FDeviceFeature.ALARM) +@ContributesMultibinding(AppGraph::class, FDeviceFeatureApi.Factory::class) +class FAlarmFeatureFactoryImpl @Inject constructor( + private val factory: FAlarmFeatureApiImpl.InternalFactory +) : FDeviceFeatureApi.Factory { + override suspend fun invoke( + unsafeFeatureDeviceApi: FUnsafeDeviceFeatureApi, + scope: CoroutineScope, + connectedDevice: FConnectedDeviceApi + ): FDeviceFeatureApi? { + val rpcApi = unsafeFeatureDeviceApi.getUnsafe(FRpcFeatureApi::class) ?: return null + return factory( + rpcFeatureApi = rpcApi, + ) + } +} diff --git a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt index a300622913..c1a7344462 100644 --- a/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt +++ b/components/bridge/connection/feature/common/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/common/api/FDeviceFeature.kt @@ -11,7 +11,10 @@ enum class FDeviceFeature { RPC_INFO, STORAGE, STORAGE_INFO, - GET_INFO + GET_INFO, + ALARM, + DEVICE_COLOR, + GATT_INFO, } @Retention(AnnotationRetention.RUNTIME) diff --git a/components/bridge/connection/feature/device-color/api/build.gradle.kts b/components/bridge/connection/feature/device-color/api/build.gradle.kts new file mode 100644 index 0000000000..96a6834200 --- /dev/null +++ b/components/bridge/connection/feature/device-color/api/build.gradle.kts @@ -0,0 +1,19 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.devicecolor.api" + +commonDependencies { + implementation(projects.components.core.data) + implementation(projects.components.core.ktx) + implementation(projects.components.core.preference) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + + implementation(libs.kotlin.immutable.collections) + implementation(libs.kotlin.coroutines) +} diff --git a/components/bridge/connection/feature/device-color/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/api/FDeviceColorFeatureApi.kt b/components/bridge/connection/feature/device-color/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/api/FDeviceColorFeatureApi.kt new file mode 100644 index 0000000000..a796c92b52 --- /dev/null +++ b/components/bridge/connection/feature/device-color/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/api/FDeviceColorFeatureApi.kt @@ -0,0 +1,13 @@ +package com.flipperdevices.bridge.connection.feature.devicecolor.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor +import kotlinx.coroutines.flow.Flow + +interface FDeviceColorFeatureApi : FDeviceFeatureApi { + /** + * Receive color from flipper and save it into settings + * @param default default value on response failure + */ + fun updateAndGetColorFlow(default: HardwareColor = HardwareColor.WHITE): Flow +} diff --git a/components/bridge/connection/feature/device-color/impl/build.gradle.kts b/components/bridge/connection/feature/device-color/impl/build.gradle.kts new file mode 100644 index 0000000000..6ed556331a --- /dev/null +++ b/components/bridge/connection/feature/device-color/impl/build.gradle.kts @@ -0,0 +1,26 @@ +plugins { + id("flipper.multiplatform") + id("flipper.multiplatform-dependencies") + id("flipper.anvil-multiplatform") +} + +android.namespace = "com.flipperdevices.bridge.connection.feature.devicecolor.impl" + +commonDependencies { + implementation(projects.components.bridge.connection.feature.deviceColor.api) + + implementation(projects.components.core.di) + implementation(projects.components.core.log) + implementation(projects.components.core.ktx) + implementation(projects.components.core.preference) + implementation(projects.components.core.data) + + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.transport.common.api) + implementation(projects.components.bridge.connection.feature.getinfo.api) + implementation(projects.components.bridge.connection.config.api) + + implementation(projects.components.bridge.connection.pbutils) + + implementation(libs.kotlin.coroutines) +} diff --git a/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt new file mode 100644 index 0000000000..41207c0fa5 --- /dev/null +++ b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureApiImpl.kt @@ -0,0 +1,61 @@ +package com.flipperdevices.bridge.connection.feature.devicecolor.impl.api + +import com.flipperdevices.bridge.connection.config.api.FDevicePersistedStorage +import com.flipperdevices.bridge.connection.config.api.model.FDeviceFlipperZeroBleModel +import com.flipperdevices.bridge.connection.feature.devicecolor.api.FDeviceColorFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGetInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.model.FGetInfoApiProperty +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error +import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flow + +class FDeviceColorFeatureApiImpl @AssistedInject constructor( + @Assisted private val fGetInfoFeatureApi: FGetInfoFeatureApi, + private val fDevicePersistedStorage: FDevicePersistedStorage +) : FDeviceColorFeatureApi, + LogTagProvider { + override val TAG = "FDeviceColorFeatureApi" + + override fun updateAndGetColorFlow(default: HardwareColor): Flow = flow { + val currentColoredDevice = fDevicePersistedStorage + .getCurrentDevice() + .first() as? FDeviceFlipperZeroBleModel + if (currentColoredDevice != null) { + emit(currentColoredDevice.hardwareColor) + } + + val intHardwareColor = fGetInfoFeatureApi.get(FGetInfoApiProperty.DeviceInfo.HARDWARE_COLOR) + .onFailure { error( + it + ) { "#updateAndGetColorFlow could not fetch ${FGetInfoApiProperty.DeviceInfo.HARDWARE_COLOR}" } } + .map { it.toIntOrNull() } + .getOrNull() + + val hardwareColor = when (intHardwareColor) { + HardwareColor.WHITE.value -> HardwareColor.WHITE + HardwareColor.BLACK.value -> HardwareColor.BLACK + HardwareColor.TRANSPARENT.value -> HardwareColor.TRANSPARENT + else -> default + } + + fDevicePersistedStorage.updateCurrentDevice { fDeviceBaseModel -> + (fDeviceBaseModel as? FDeviceFlipperZeroBleModel) + ?.copy(hardwareColor = hardwareColor) + ?: fDeviceBaseModel + } + emit(hardwareColor) + } + + @AssistedFactory + fun interface InternalFactory { + operator fun invoke( + fGetInfoFeatureApi: FGetInfoFeatureApi, + ): FDeviceColorFeatureApiImpl + } +} diff --git a/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureFactoryImpl.kt b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureFactoryImpl.kt new file mode 100644 index 0000000000..2649352a97 --- /dev/null +++ b/components/bridge/connection/feature/device-color/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/devicecolor/impl/api/FDeviceColorFeatureFactoryImpl.kt @@ -0,0 +1,34 @@ +package com.flipperdevices.bridge.connection.feature.devicecolor.impl.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureQualifier +import com.flipperdevices.bridge.connection.feature.common.api.FUnsafeDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGetInfoFeatureApi +import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi +import com.flipperdevices.core.di.AppGraph +import com.flipperdevices.core.log.LogTagProvider +import com.squareup.anvil.annotations.ContributesMultibinding +import kotlinx.coroutines.CoroutineScope +import javax.inject.Inject + +@FDeviceFeatureQualifier(FDeviceFeature.DEVICE_COLOR) +@ContributesMultibinding(AppGraph::class, FDeviceFeatureApi.Factory::class) +class FDeviceColorFeatureFactoryImpl @Inject constructor( + private val factory: FDeviceColorFeatureApiImpl.InternalFactory +) : FDeviceFeatureApi.Factory, LogTagProvider { + override val TAG = "FDeviceColorFeatureFactory" + + override suspend fun invoke( + unsafeFeatureDeviceApi: FUnsafeDeviceFeatureApi, + scope: CoroutineScope, + connectedDevice: FConnectedDeviceApi + ): FDeviceFeatureApi? { + val fGetInfoFeatureApi = unsafeFeatureDeviceApi + .getUnsafe(FGetInfoFeatureApi::class) + ?: return null + return factory( + fGetInfoFeatureApi = fGetInfoFeatureApi, + ) + } +} diff --git a/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/api/FGattInfoFeatureApi.kt b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/api/FGattInfoFeatureApi.kt new file mode 100644 index 0000000000..4607f0ac43 --- /dev/null +++ b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/api/FGattInfoFeatureApi.kt @@ -0,0 +1,9 @@ +package com.flipperdevices.bridge.connection.feature.getinfo.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.model.FGattInformation +import kotlinx.coroutines.flow.StateFlow + +interface FGattInfoFeatureApi : FDeviceFeatureApi { + fun getGattInfoFlow(): StateFlow +} diff --git a/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGattInformation.kt b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGattInformation.kt new file mode 100644 index 0000000000..58cf914488 --- /dev/null +++ b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGattInformation.kt @@ -0,0 +1,10 @@ +package com.flipperdevices.bridge.connection.feature.getinfo.model + +data class FGattInformation( + val deviceName: String? = null, + val manufacturerName: String? = null, + val hardwareRevision: String? = null, + val softwareVersion: String? = null, + val batteryLevel: Float? = null, + val isCharging: Boolean = false +) diff --git a/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGetInfoApiProperty.kt b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGetInfoApiProperty.kt index 5b119f2c73..fc37cf9155 100644 --- a/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGetInfoApiProperty.kt +++ b/components/bridge/connection/feature/getinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/model/FGetInfoApiProperty.kt @@ -25,7 +25,8 @@ sealed interface FGetInfoApiProperty { RADIO_STACK_TYPE("radio.stack.type"), RADIO_STACK_SUB("radio.stack.sub"), FIRMWARE_FORK("firmware.origin.fork"), - FIRMWARE_ORIGIN("firmware.origin.git"); + FIRMWARE_ORIGIN("firmware.origin.git"), + HARDWARE_COLOR("hardware.color"); override val group = FGetInfoApiGroup.DEVICE_INFO } diff --git a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureApiImpl.kt b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureApiImpl.kt new file mode 100644 index 0000000000..0969ae82c1 --- /dev/null +++ b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureApiImpl.kt @@ -0,0 +1,111 @@ +package com.flipperdevices.bridge.connection.feature.getinfo.impl.api + +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGattInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.getinfo.model.FGattInformation +import com.flipperdevices.bridge.connection.transport.common.api.meta.FTransportMetaInfoApi +import com.flipperdevices.bridge.connection.transport.common.api.meta.TransportMetaInfoKey +import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.log.error +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlin.experimental.and + +class FGattInfoFeatureApiImpl @AssistedInject constructor( + @Assisted private val metaInfoApi: FTransportMetaInfoApi, + @Assisted private val scope: CoroutineScope, +) : FGattInfoFeatureApi, LogTagProvider { + override val TAG: String = "FGetInfoFeatureApi" + + private val gattInfo = MutableStateFlow(FGattInformation()) + + override fun getGattInfoFlow() = gattInfo.asStateFlow() + + private fun collectGattInfo() { + listOf( + TransportMetaInfoKey.DEVICE_NAME, + TransportMetaInfoKey.MANUFACTURER, + TransportMetaInfoKey.BATTERY_LEVEL, + TransportMetaInfoKey.BATTERY_POWER_STATE, + TransportMetaInfoKey.SOFTWARE_VERSION, + TransportMetaInfoKey.HARDWARE_VERSION + ).forEach { key -> + val flow = metaInfoApi.get(key) + .onFailure { error(it) { "#collectGattInfo could not find flow for key $key" } } + .getOrNull() + (flow ?: emptyFlow()) + .filterNotNull() + .onEach { byteArray -> + gattInfo.update { state -> + when (key) { + TransportMetaInfoKey.DEVICE_NAME -> { + state.copy(deviceName = String(byteArray)) + } + + TransportMetaInfoKey.MANUFACTURER -> { + state.copy(manufacturerName = String(byteArray)) + } + + TransportMetaInfoKey.BATTERY_LEVEL -> { + state.copy( + batteryLevel = byteArray.firstOrNull() + ?.toFloat() + ?.div(MAX_BATTERY_LEVEL) + ?.coerceIn(0f, 1f) + ) + } + + TransportMetaInfoKey.BATTERY_POWER_STATE -> { + state.copy( + isCharging = byteArray.firstOrNull() + ?.and(BATTERY_POWER_STATE_MASK) + ?.equals(BATTERY_POWER_STATE_MASK) + ?: false + ) + } + + TransportMetaInfoKey.SOFTWARE_VERSION -> { + state.copy( + softwareVersion = String(byteArray) + ) + } + + TransportMetaInfoKey.HARDWARE_VERSION -> { + state.copy( + hardwareRevision = String(byteArray) + ) + } + + else -> state + } + } + }.launchIn(scope) + } + } + + init { + collectGattInfo() + } + + @AssistedFactory + fun interface InternalFactory { + operator fun invoke( + metaInfoApi: FTransportMetaInfoApi, + scope: CoroutineScope, + ): FGattInfoFeatureApiImpl + } + + companion object { + private const val MAX_BATTERY_LEVEL = 100 + const val BATTERY_POWER_STATE_MASK: Byte = 0b0011_0000 + } +} diff --git a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureFactoryImpl.kt b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureFactoryImpl.kt new file mode 100644 index 0000000000..6db0a980be --- /dev/null +++ b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGattInfoFeatureFactoryImpl.kt @@ -0,0 +1,34 @@ +package com.flipperdevices.bridge.connection.feature.getinfo.impl.api + +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeature +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureApi +import com.flipperdevices.bridge.connection.feature.common.api.FDeviceFeatureQualifier +import com.flipperdevices.bridge.connection.feature.common.api.FUnsafeDeviceFeatureApi +import com.flipperdevices.bridge.connection.transport.common.api.FConnectedDeviceApi +import com.flipperdevices.bridge.connection.transport.common.api.meta.FTransportMetaInfoApi +import com.flipperdevices.core.di.AppGraph +import com.flipperdevices.core.log.LogTagProvider +import com.squareup.anvil.annotations.ContributesMultibinding +import kotlinx.coroutines.CoroutineScope +import javax.inject.Inject + +@FDeviceFeatureQualifier(FDeviceFeature.GATT_INFO) +@ContributesMultibinding(AppGraph::class, FDeviceFeatureApi.Factory::class) +class FGattInfoFeatureFactoryImpl @Inject constructor( + private val factory: FGattInfoFeatureApiImpl.InternalFactory +) : FDeviceFeatureApi.Factory, LogTagProvider { + override val TAG = "FGattInfoFeatureFactory" + + override suspend fun invoke( + unsafeFeatureDeviceApi: FUnsafeDeviceFeatureApi, + scope: CoroutineScope, + connectedDevice: FConnectedDeviceApi + ): FDeviceFeatureApi? { + val metaInfoApi = connectedDevice as? FTransportMetaInfoApi ?: return null + + return factory( + metaInfoApi = metaInfoApi, + scope = scope + ) + } +} diff --git a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureApiImpl.kt b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureApiImpl.kt index 6d4412f4fa..b81e556bce 100644 --- a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureApiImpl.kt +++ b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureApiImpl.kt @@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull class FGetInfoFeatureApiImpl @AssistedInject constructor( - @Assisted private val rpcFeatureApi: FRpcFeatureApi + @Assisted private val rpcFeatureApi: FRpcFeatureApi, ) : FGetInfoFeatureApi { private val mapper = FGetInfoApiKeyMapper() diff --git a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureFactoryImpl.kt b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureFactoryImpl.kt index 814d2f085f..7b9ae87c21 100644 --- a/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureFactoryImpl.kt +++ b/components/bridge/connection/feature/getinfo/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/getinfo/impl/api/FGetInfoFeatureFactoryImpl.kt @@ -16,6 +16,7 @@ import com.squareup.anvil.annotations.ContributesMultibinding import kotlinx.coroutines.CoroutineScope import javax.inject.Inject +// todo move to shared const private val API_SUPPORTED_GET_REQUEST = SemVer( majorVersion = 0, minorVersion = 14 @@ -45,7 +46,7 @@ class FGetInfoFeatureFactoryImpl @Inject constructor( val rpcApi = unsafeFeatureDeviceApi.getUnsafe(FRpcFeatureApi::class) ?: return null return factory( - rpcApi + rpcFeatureApi = rpcApi, ) } } diff --git a/components/bridge/connection/feature/storageinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/storageinfo/api/FStorageInfoFeatureApi.kt b/components/bridge/connection/feature/storageinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/storageinfo/api/FStorageInfoFeatureApi.kt index 78ba6da5db..1fe20a6d12 100644 --- a/components/bridge/connection/feature/storageinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/storageinfo/api/FStorageInfoFeatureApi.kt +++ b/components/bridge/connection/feature/storageinfo/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/feature/storageinfo/api/FStorageInfoFeatureApi.kt @@ -8,10 +8,19 @@ import kotlinx.coroutines.flow.StateFlow interface FStorageInfoFeatureApi : FDeviceFeatureApi { fun getStorageInformationFlow(): StateFlow + /** + * Update current [getStorageInformationFlow] + * @param scope parent scope to be launched in + * @param force if true, will cancel last invalidation and start new. + * If true and invalidation in progress, will be skipped + */ suspend fun invalidate( scope: CoroutineScope, force: Boolean = false ) + /** + * Cancels current [invalidate] and reset [getStorageInformationFlow] + */ suspend fun reset() } diff --git a/components/bridge/connection/service/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/api/FConnectionService.kt b/components/bridge/connection/service/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/api/FConnectionService.kt index 45ef23b5c7..b2a7fdbe36 100644 --- a/components/bridge/connection/service/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/api/FConnectionService.kt +++ b/components/bridge/connection/service/api/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/api/FConnectionService.kt @@ -19,4 +19,9 @@ interface FConnectionService { * @param force if true, will not reconnect until [forceReconnect] */ fun disconnect(force: Boolean = false) -} \ No newline at end of file + + /** + * Forget current device and disconnect from it as side effect + */ + fun forgetCurrentDevice() +} diff --git a/components/bridge/connection/service/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/impl/FConnectionServiceImpl.kt b/components/bridge/connection/service/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/impl/FConnectionServiceImpl.kt index 99bea6d2cc..b6b02bf152 100644 --- a/components/bridge/connection/service/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/impl/FConnectionServiceImpl.kt +++ b/components/bridge/connection/service/impl/src/commonMain/kotlin/com/flipperdevices/bridge/connection/service/impl/FConnectionServiceImpl.kt @@ -7,17 +7,13 @@ import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.ktx.jre.FlipperDispatchers import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.log.warn -import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel import com.squareup.anvil.annotations.ContributesBinding import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -70,4 +66,14 @@ class FConnectionServiceImpl @Inject constructor( orchestrator.disconnectCurrent() } } -} \ No newline at end of file + + override fun forgetCurrentDevice() { + scope.launch { + fDevicePersistedStorage.getCurrentDevice() + .first() + ?.let { currentDevice -> + fDevicePersistedStorage.removeDevice(currentDevice.uniqueId) + } + } + } +} diff --git a/components/bridge/connection/transport/ble/impl/src/androidMain/kotlin/com/flipperdevices/bridge/connection/transport/ble/impl/meta/FTransportMetaInfoApiImpl.kt b/components/bridge/connection/transport/ble/impl/src/androidMain/kotlin/com/flipperdevices/bridge/connection/transport/ble/impl/meta/FTransportMetaInfoApiImpl.kt index 11730426bc..85561bc99b 100644 --- a/components/bridge/connection/transport/ble/impl/src/androidMain/kotlin/com/flipperdevices/bridge/connection/transport/ble/impl/meta/FTransportMetaInfoApiImpl.kt +++ b/components/bridge/connection/transport/ble/impl/src/androidMain/kotlin/com/flipperdevices/bridge/connection/transport/ble/impl/meta/FTransportMetaInfoApiImpl.kt @@ -11,8 +11,10 @@ import kotlinx.collections.immutable.ImmutableMap import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt import no.nordicsemi.android.kotlin.ble.client.main.service.ClientBleGattServices import no.nordicsemi.android.kotlin.ble.core.data.BleGattProperty @@ -57,6 +59,10 @@ class FTransportMetaInfoApiImpl( return flowOf(characteristic.read().value) } info { "Subscribe on $address characteristic" } - return characteristic.getNotifications().map { it.value } + // Don't block one flow by another + return listOf( + flow { emit(characteristic.read().value) }, + characteristic.getNotifications().map { it.value } + ).merge() } } diff --git a/components/core/preference/src/commonMain/proto/new_pair.proto b/components/core/preference/src/commonMain/proto/new_pair.proto index ba5921ae52..98dc771373 100644 --- a/components/core/preference/src/commonMain/proto/new_pair.proto +++ b/components/core/preference/src/commonMain/proto/new_pair.proto @@ -23,4 +23,12 @@ message SavedDevice { message FlipperZeroBle { string address = 1; -} \ No newline at end of file + + enum HardwareColor { + WHITE = 0; + BLACK = 1; + TRANSPARENT = 2; + } + + HardwareColor hardware_color = 2; +} diff --git a/components/firstpair/impl/build.gradle.kts b/components/firstpair/impl/build.gradle.kts index 02a53dce72..6a5e0d12e5 100644 --- a/components/firstpair/impl/build.gradle.kts +++ b/components/firstpair/impl/build.gradle.kts @@ -29,11 +29,6 @@ dependencies { implementation(libs.ble.common) implementation(libs.ble.scan) - // BLE-new -// implementation(projects.components.bridge.connection.transport.ble.api) -// implementation(projects.components.bridge.connection.transport.common.api) -// implementation(projects.components.bridge.connection.orchestrator.api) -// implementation(projects.components.bridge.connection.device.common.api) implementation(projects.components.bridge.connection.config.api) implementation(libs.appcompat) diff --git a/components/firstpair/impl/src/main/java/com/flipperdevices/firstpair/impl/storage/FirstPairStorageImpl.kt b/components/firstpair/impl/src/main/java/com/flipperdevices/firstpair/impl/storage/FirstPairStorageImpl.kt index 962d807053..6ca788b46a 100644 --- a/components/firstpair/impl/src/main/java/com/flipperdevices/firstpair/impl/storage/FirstPairStorageImpl.kt +++ b/components/firstpair/impl/src/main/java/com/flipperdevices/firstpair/impl/storage/FirstPairStorageImpl.kt @@ -7,6 +7,7 @@ import com.flipperdevices.bridge.connection.config.api.model.FDeviceFlipperZeroB import com.flipperdevices.core.di.AppGraph import com.flipperdevices.core.ktx.jre.runBlockingWithLog import com.flipperdevices.core.log.LogTagProvider +import com.flipperdevices.core.preference.pb.FlipperZeroBle import com.flipperdevices.core.preference.pb.PairSettings import com.squareup.anvil.annotations.ContributesBinding import kotlinx.coroutines.flow.first @@ -58,7 +59,8 @@ class FirstPairStorageImpl @Inject constructor( val device = FDeviceFlipperZeroBleModel( name = deviceNameFormatted, address = address.orEmpty(), - uniqueId = deviceId ?: UUID.randomUUID().toString() + uniqueId = deviceId ?: UUID.randomUUID().toString(), + hardwareColor = FlipperZeroBle.HardwareColor.fromValue(pairSetting.hardware_color.value) ) persistedStorage.addDevice(device) persistedStorage.setCurrentDevice(deviceId) diff --git a/components/info/impl/build.gradle.kts b/components/info/impl/build.gradle.kts index d01a68f01b..758cd3f913 100644 --- a/components/info/impl/build.gradle.kts +++ b/components/info/impl/build.gradle.kts @@ -36,11 +36,20 @@ dependencies { implementation(projects.components.rootscreen.api) implementation(projects.components.analytics.metric.api) - implementation(projects.components.bridge.api) implementation(projects.components.bridge.synchronization.api) - implementation(projects.components.bridge.service.api) - implementation(projects.components.bridge.pbutils) - implementation(projects.components.bridge.rpcinfo.api) + implementation(projects.components.bridge.connection.service.api) + implementation(projects.components.bridge.connection.orchestrator.api) + implementation(projects.components.bridge.connection.config.api) + implementation(projects.components.bridge.connection.service.api) + implementation(projects.components.bridge.connection.feature.common.api) + implementation(projects.components.bridge.connection.feature.provider.api) + implementation(projects.components.bridge.connection.feature.getinfo.api) + implementation(projects.components.bridge.connection.feature.storageinfo.api) + implementation(projects.components.bridge.connection.feature.alarm.api) + implementation(projects.components.bridge.connection.feature.deviceColor.api) + implementation(projects.components.bridge.connection.feature.protocolversion.api) + implementation(projects.components.bridge.connection.feature.rpcinfo.api) + implementation(projects.components.bridge.connection.feature.rpcstats.api) // Core deps implementation(libs.ktx) diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/api/UpdateScreenDecomposeComponent.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/api/UpdateScreenDecomposeComponent.kt index 443e985fe8..d17fca2675 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/api/UpdateScreenDecomposeComponent.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/api/UpdateScreenDecomposeComponent.kt @@ -9,6 +9,7 @@ import com.arkivanov.decompose.ComponentContext import com.arkivanov.decompose.router.stack.StackNavigator import com.arkivanov.decompose.router.stack.pushToFront import com.flipperdevices.bottombar.handlers.ResetTabDecomposeHandler +import com.flipperdevices.core.preference.pb.HardwareColor import com.flipperdevices.core.ui.lifecycle.viewModelWithFactory import com.flipperdevices.deeplink.model.Deeplink import com.flipperdevices.info.impl.compose.screens.ComposableDeviceInfoScreen @@ -99,9 +100,10 @@ class UpdateScreenDecomposeComponent @AssistedInject constructor( deeplink = deeplink, deviceStatus = deviceStatus, connectViewModel = connectViewModel, - hardwareColor = flipperColor, + hardwareColor = HardwareColor.fromValue(flipperColor.value), // TODO change after full migration supportedState = supportState, updateState = updateState, + hasAlarm = alarmViewModel.hasAlarm.collectAsState().value, alarmOnFlipper = alarmViewModel::alarmOnFlipper, deviceInfo = basicInfo, scrollState = scrollState, diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableConnectedDeviceActionCard.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableConnectedDeviceActionCard.kt index b17b6ce410..8c32931882 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableConnectedDeviceActionCard.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableConnectedDeviceActionCard.kt @@ -3,7 +3,7 @@ package com.flipperdevices.info.impl.compose.elements import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState +import com.flipperdevices.bridge.connection.feature.protocolversion.model.FlipperSupportedState import com.flipperdevices.core.ui.theme.LocalPallet import com.flipperdevices.info.impl.R import com.flipperdevices.info.impl.model.DeviceStatus @@ -18,6 +18,7 @@ fun ComposableConnectedDeviceActionCard( supportedState: FlipperSupportedState, requestSynchronize: () -> Unit, alarmOnFlipper: () -> Unit, + hasAlarm: Boolean, modifier: Modifier = Modifier, ) { if (deviceStatus is DeviceStatus.NoDevice) { @@ -34,7 +35,7 @@ fun ComposableConnectedDeviceActionCard( ) ComposableInfoDivider() ComposableAlarmElement( - enabled = enabled, + enabled = hasAlarm && enabled, alarmOnFlipper = alarmOnFlipper ) } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableFirmwareUnsupported.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableFirmwareUnsupported.kt index 3c1326d779..d0f389ed23 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableFirmwareUnsupported.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableFirmwareUnsupported.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState +import com.flipperdevices.bridge.connection.feature.protocolversion.model.FlipperSupportedState import com.flipperdevices.core.markdown.ClickableUrlText import com.flipperdevices.core.ui.theme.LocalPallet import com.flipperdevices.core.ui.theme.LocalTypography diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableInfoCardContent.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableInfoCardContent.kt index 0582f57636..87ef0ce257 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableInfoCardContent.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/elements/ComposableInfoCardContent.kt @@ -5,14 +5,14 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.rpcinfo.model.FlipperStorageInformation -import com.flipperdevices.bridge.rpcinfo.model.StorageStats -import com.flipperdevices.bridge.rpcinfo.model.dataOrNull -import com.flipperdevices.bridge.rpcinfo.model.externalStorageRequestInProgress -import com.flipperdevices.bridge.rpcinfo.model.flashSdStats -import com.flipperdevices.bridge.rpcinfo.model.isExtStorageEnding -import com.flipperdevices.bridge.rpcinfo.model.toString +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus +import com.flipperdevices.bridge.connection.feature.storageinfo.model.FlipperStorageInformation +import com.flipperdevices.bridge.connection.feature.storageinfo.model.StorageStats +import com.flipperdevices.bridge.connection.feature.storageinfo.model.dataOrNull +import com.flipperdevices.bridge.connection.feature.storageinfo.model.externalStorageRequestInProgress +import com.flipperdevices.bridge.connection.feature.storageinfo.model.flashSdStats +import com.flipperdevices.bridge.connection.feature.storageinfo.model.isExtStorageEnding +import com.flipperdevices.bridge.connection.feature.storageinfo.model.toString import com.flipperdevices.core.ui.theme.FlipperThemeInternal import com.flipperdevices.core.ui.theme.LocalPallet import com.flipperdevices.info.impl.R diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/info/ComposableInfoCard.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/info/ComposableInfoCard.kt index ecf10265bb..022ffe686a 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/info/ComposableInfoCard.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/info/ComposableInfoCard.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState +import com.flipperdevices.bridge.connection.feature.protocolversion.model.FlipperSupportedState import com.flipperdevices.core.ui.ktx.clickableRipple import com.flipperdevices.core.ui.ktx.elements.animatedDots import com.flipperdevices.core.ui.theme.LocalPallet diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableDeviceInfoScreen.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableDeviceInfoScreen.kt index b99ac18c97..5b07f99577 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableDeviceInfoScreen.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableDeviceInfoScreen.kt @@ -15,7 +15,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.arkivanov.decompose.ComponentContext -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState +import com.flipperdevices.bridge.connection.feature.protocolversion.model.FlipperSupportedState import com.flipperdevices.core.preference.pb.HardwareColor import com.flipperdevices.core.ui.ktx.elements.SwipeRefresh import com.flipperdevices.core.ui.theme.LocalPallet @@ -49,6 +49,7 @@ fun ComposableDeviceInfoScreen( deviceInfo: FlipperBasicInfo, onOpenFullDeviceInfo: () -> Unit, onOpenOptions: () -> Unit, + hasAlarm: Boolean, alarmOnFlipper: () -> Unit, onOpenRemoteControl: () -> Unit, onStartUpdateRequest: (UpdateRequest) -> Unit, @@ -107,7 +108,8 @@ fun ComposableDeviceInfoScreen( deviceStatus = deviceStatus, supportedState = supportedState, requestSynchronize = connectViewModel::requestSynchronize, - alarmOnFlipper = alarmOnFlipper + alarmOnFlipper = alarmOnFlipper, + hasAlarm = hasAlarm ) ComposablePairDeviceActionCard( modifier = Modifier.padding(top = 14.dp, bottom = 14.dp), diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableFullDeviceInfoScreen.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableFullDeviceInfoScreen.kt index 872a27ca66..8ad9cebba5 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableFullDeviceInfoScreen.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/ComposableFullDeviceInfoScreen.kt @@ -10,9 +10,9 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.rpcinfo.model.FlipperRpcInformation -import com.flipperdevices.bridge.rpcinfo.model.dataOrNull +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperRpcInformation +import com.flipperdevices.bridge.connection.feature.storageinfo.model.dataOrNull import com.flipperdevices.core.ui.ktx.OrangeAppBar import com.flipperdevices.core.ui.ktx.clickableRipple import com.flipperdevices.core.ui.theme.LocalPallet @@ -42,10 +42,10 @@ fun ComposableFullDeviceInfoScreen( val inProgress = when (localDeviceStatus) { is DeviceStatus.NoDeviceInformation -> localDeviceStatus.connectInProgress is DeviceStatus.Connected -> - flipperRpcInformation !is FlipperInformationStatus.Ready || - basicInfo.storageInfo.externalStorageStatus !is FlipperInformationStatus.Ready || - basicInfo.storageInfo.internalStorageStatus !is FlipperInformationStatus.Ready || - basicInfo.firmwareVersion !is FlipperInformationStatus.Ready + flipperRpcInformation !is FlipperInformationStatus.Ready<*> || + basicInfo.storageInfo.externalStorageStatus !is FlipperInformationStatus.Ready<*> || + basicInfo.storageInfo.internalStorageStatus !is FlipperInformationStatus.Ready<*> || + basicInfo.firmwareVersion !is FlipperInformationStatus.Ready<*> else -> false } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFirmwareInfo.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFirmwareInfo.kt index 742756150f..674e8da4e4 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFirmwareInfo.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFirmwareInfo.kt @@ -2,7 +2,7 @@ package com.flipperdevices.info.impl.compose.screens.fullinfo import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color -import com.flipperdevices.bridge.rpcinfo.model.FirmwareInfo +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FirmwareInfo import com.flipperdevices.info.impl.R import com.flipperdevices.info.shared.ComposableDeviceInfoRow import com.flipperdevices.info.shared.ComposableDeviceInfoRowWithText diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFlipperDevicesInfo.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFlipperDevicesInfo.kt index 7e9d0656cd..3f0875947b 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFlipperDevicesInfo.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFlipperDevicesInfo.kt @@ -3,7 +3,7 @@ package com.flipperdevices.info.impl.compose.screens.fullinfo import androidx.compose.foundation.layout.Row import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment -import com.flipperdevices.bridge.rpcinfo.model.FlipperDeviceInfo +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperDeviceInfo import com.flipperdevices.info.impl.R import com.flipperdevices.info.shared.ComposableDeviceInfoRow import com.flipperdevices.info.shared.ComposableDeviceInfoRowText diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFullInfoDevice.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFullInfoDevice.kt index 72451671eb..020db28e92 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFullInfoDevice.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableFullInfoDevice.kt @@ -8,7 +8,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import com.flipperdevices.bridge.rpcinfo.model.FlipperRpcInformation +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperRpcInformation import com.flipperdevices.core.ktx.jre.titlecaseFirstCharIfItIsLowercase import com.flipperdevices.core.ui.ktx.elements.SwipeRefresh import com.flipperdevices.info.impl.R diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableRadioStackInfo.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableRadioStackInfo.kt index def4a428e4..facb764f1d 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableRadioStackInfo.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/compose/screens/fullinfo/ComposableRadioStackInfo.kt @@ -2,8 +2,8 @@ package com.flipperdevices.info.impl.compose.screens.fullinfo import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource -import com.flipperdevices.bridge.rpcinfo.model.RadioStackInfo -import com.flipperdevices.bridge.rpcinfo.model.RadioStackType +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.RadioStackInfo +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.RadioStackType import com.flipperdevices.core.ktx.jre.isNotNull import com.flipperdevices.info.impl.R import com.flipperdevices.info.shared.ComposableDeviceInfoRowWithText diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/model/FlipperBasicInfo.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/model/FlipperBasicInfo.kt index 2e2ffbab10..6606dbd1fa 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/model/FlipperBasicInfo.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/model/FlipperBasicInfo.kt @@ -1,8 +1,8 @@ package com.flipperdevices.info.impl.model import androidx.compose.runtime.Stable -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.rpcinfo.model.FlipperStorageInformation +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus +import com.flipperdevices.bridge.connection.feature.storageinfo.model.FlipperStorageInformation import com.flipperdevices.updater.model.FirmwareVersion @Stable diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/AlarmViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/AlarmViewModel.kt index 8cb747f6b2..abd22587af 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/AlarmViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/AlarmViewModel.kt @@ -1,30 +1,27 @@ package com.flipperdevices.info.impl.viewmodel -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.alarm.api.FAlarmFeatureApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get +import com.flipperdevices.bridge.connection.feature.provider.api.getSync import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.system.playAudiovisualAlertRequest +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject class AlarmViewModel @Inject constructor( - private val serviceProvider: FlipperServiceProvider + private val featureProvider: FFeatureProvider ) : DecomposeViewModel() { + val hasAlarm = featureProvider.get() + .map { status -> status is FFeatureStatus.Supported } + .stateIn(viewModelScope, SharingStarted.Eagerly, false) + fun alarmOnFlipper() { - serviceProvider.provideServiceApi(this) { serviceApi -> - viewModelScope.launch { - alarmOnFlipperInternal(serviceApi) - } + viewModelScope.launch { + featureProvider.getSync()?.makeSound() } } - - private suspend fun alarmOnFlipperInternal(serviceApi: FlipperServiceApi) { - serviceApi.requestApi.requestWithoutAnswer( - main { - systemPlayAudiovisualAlertRequest = playAudiovisualAlertRequest { } - }.wrapToRequest() - ) - } } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/ConnectViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/ConnectViewModel.kt index 1fbd6dd701..a624227d28 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/ConnectViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/ConnectViewModel.kt @@ -1,7 +1,7 @@ package com.flipperdevices.info.impl.viewmodel import androidx.datastore.core.DataStore -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.service.api.FConnectionService import com.flipperdevices.bridge.synchronization.api.SynchronizationApi import com.flipperdevices.core.preference.pb.PairSettings import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel @@ -13,9 +13,9 @@ import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject class ConnectViewModel @Inject constructor( - private val serviceProvider: FlipperServiceProvider, private val synchronizationApi: SynchronizationApi, - private val dataStoreFirstPair: DataStore + private val dataStoreFirstPair: DataStore, + private val fConnectionService: FConnectionService ) : DecomposeViewModel() { private val connectRequestState = MutableStateFlow( ConnectRequestState.NOT_REQUESTED @@ -27,21 +27,17 @@ class ConnectViewModel @Inject constructor( return } connectRequestState.update { ConnectRequestState.CONNECTING_AND_SYNCHRONIZING } - serviceProvider.provideServiceApi(this) { - viewModelScope.launch { - it.reconnect() - synchronizationApi.startSynchronization(force = true) - connectRequestState.update { ConnectRequestState.NOT_REQUESTED } - alreadyRequestConnect.compareAndSet(true, false) - } + viewModelScope.launch { + fConnectionService.forceReconnect() + synchronizationApi.startSynchronization(force = true) + connectRequestState.update { ConnectRequestState.NOT_REQUESTED } + alreadyRequestConnect.compareAndSet(true, false) } } fun onDisconnect() { - serviceProvider.provideServiceApi(this) { - viewModelScope.launch { - it.disconnect() - } + viewModelScope.launch { + fConnectionService.disconnect(true) } } @@ -51,6 +47,7 @@ class ConnectViewModel @Inject constructor( fun forgetFlipper() { viewModelScope.launch { + fConnectionService.forgetCurrentDevice() dataStoreFirstPair.updateData { it.copy( device_name = "", diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/DeviceStatusViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/DeviceStatusViewModel.kt index 7e9fd55a86..b1c2d5d5fb 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/DeviceStatusViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/DeviceStatusViewModel.kt @@ -1,51 +1,47 @@ package com.flipperdevices.info.impl.viewmodel import androidx.datastore.core.DataStore -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGattInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get +import com.flipperdevices.bridge.connection.orchestrator.api.FDeviceOrchestrator +import com.flipperdevices.bridge.connection.orchestrator.api.model.FDeviceConnectStatus import com.flipperdevices.core.preference.pb.PairSettings import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel import com.flipperdevices.info.impl.model.DeviceStatus -import com.flipperdevices.updater.api.UpdateStateApi +import com.flipperdevices.updater.api.FirmwareVersionBuilderApi +import com.flipperdevices.updater.api.UpdaterApi import com.flipperdevices.updater.model.FlipperUpdateState -import kotlinx.coroutines.flow.MutableStateFlow +import com.flipperdevices.updater.model.UpdatingState +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import javax.inject.Inject class DeviceStatusViewModel @Inject constructor( - serviceProvider: FlipperServiceProvider, - private val dataStorePair: DataStore, - private val updateStateApi: UpdateStateApi -) : DecomposeViewModel(), FlipperBleServiceConsumer { - private val deviceStatus = MutableStateFlow(DeviceStatus.NoDevice) - private val updateStatus = MutableStateFlow(FlipperUpdateState.NotConnected) + dataStorePair: DataStore, + fFeatureProvider: FFeatureProvider, + fDeviceOrchestrator: FDeviceOrchestrator, + private val updaterApi: UpdaterApi, + private val firmwareVersionBuilderApi: FirmwareVersionBuilderApi +) : DecomposeViewModel() { - init { - serviceProvider.provideServiceApi(consumer = this, lifecycleOwner = this) - } - - fun getState(): StateFlow = deviceStatus - fun getUpdateState(): StateFlow = updateStatus - - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - updateStateApi.getFlipperUpdateState(serviceApi, viewModelScope).onEach { - updateStatus.emit(it) - }.launchIn(viewModelScope) - - combine( - serviceApi.connectionInformationApi.getConnectionStateFlow(), - serviceApi.flipperInformationApi.getInformationFlow(), - dataStorePair.data - ) { connectionState, flipperInformation, pairSettings -> - return@combine when (connectionState) { - is ConnectionState.Disconnected -> if (pairSettings.device_name.isBlank() || - pairSettings.device_id.isBlank() - ) { + private val deviceState = combine( + flow = fDeviceOrchestrator.getState(), + flow2 = fFeatureProvider.get() + .map { status -> status as? FFeatureStatus.Supported } + .flatMapLatest { status -> status?.featureApi?.getGattInfoFlow() ?: emptyFlow() }, + flow3 = dataStorePair.data + ) { connectionState, flipperInformation, pairSettings -> + when (connectionState) { + is FDeviceConnectStatus.Disconnected -> { + if (pairSettings.device_name.isBlank() || pairSettings.device_id.isBlank()) { DeviceStatus.NoDevice } else { DeviceStatus.NoDeviceInformation( @@ -53,32 +49,77 @@ class DeviceStatusViewModel @Inject constructor( connectInProgress = false ) } - ConnectionState.Connecting, - ConnectionState.Disconnecting, - ConnectionState.Initializing, - is ConnectionState.Ready, - ConnectionState.RetrievingInformation -> { - var deviceName = pairSettings.device_name - if (deviceName.isBlank()) { - deviceName = "Unknown" - } - val batteryLevel = flipperInformation.batteryLevel - if (batteryLevel == null) { - DeviceStatus.NoDeviceInformation( - deviceName, - connectInProgress = true - ) + } + + is FDeviceConnectStatus.Connecting, + is FDeviceConnectStatus.Disconnecting, + is FDeviceConnectStatus.Connected -> { + var deviceName = pairSettings.device_name + if (deviceName.isBlank()) { + deviceName = "Unknown" + } + val batteryLevel = flipperInformation.batteryLevel + if (batteryLevel == null) { + DeviceStatus.NoDeviceInformation( + deviceName, + connectInProgress = true + ) + } else { + DeviceStatus.Connected( + deviceName, + batteryLevel, + flipperInformation.isCharging + ) + } + } + } + }.stateIn(viewModelScope, SharingStarted.Eagerly, DeviceStatus.NoDevice) + + fun getState(): StateFlow = deviceState + + private val updateStatus = combine( + flow = updaterApi.getState(), + flow2 = fFeatureProvider.get() + .map { it as? FFeatureStatus.Supported } + .flatMapLatest { it?.featureApi?.getGattInfoFlow() ?: flowOf(null) } + .map { gattInfo -> gattInfo?.softwareVersion } + .map { firmwareVersion -> + firmwareVersion?.let(firmwareVersionBuilderApi::buildFirmwareVersionFromString) + }, + flow3 = fDeviceOrchestrator.getState(), + transform = { updaterState, firmwareVersion, orchestratorState -> + when (orchestratorState) { + is FDeviceConnectStatus.Connected -> { + if (firmwareVersion != null) { + when (updaterState.state) { + is UpdatingState.Rebooting -> { + updaterApi.onDeviceConnected(firmwareVersion) + FlipperUpdateState.Ready + } + + is UpdatingState.Complete -> { + FlipperUpdateState.Complete(updaterState.request?.updateTo) + } + + is UpdatingState.Failed -> { + FlipperUpdateState.Failed(updaterState.request?.updateTo) + } + + else -> FlipperUpdateState.Ready + } + } else if (updaterState.state is UpdatingState.Rebooting) { + FlipperUpdateState.Updating } else { - DeviceStatus.Connected( - deviceName, - batteryLevel, - flipperInformation.isCharging - ) + FlipperUpdateState.ConnectingInProgress } } + + is FDeviceConnectStatus.Connecting -> FlipperUpdateState.ConnectingInProgress + is FDeviceConnectStatus.Disconnecting -> FlipperUpdateState.ConnectingInProgress + is FDeviceConnectStatus.Disconnected -> FlipperUpdateState.NotConnected } - }.onEach { - deviceStatus.emit(it) - }.launchIn(viewModelScope) - } + } + ).stateIn(viewModelScope, SharingStarted.Eagerly, FlipperUpdateState.NotConnected) + + fun getUpdateState(): StateFlow = updateStatus } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FirmwareUpdateViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FirmwareUpdateViewModel.kt index 91e762c0cc..60cdd87575 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FirmwareUpdateViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FirmwareUpdateViewModel.kt @@ -1,40 +1,37 @@ package com.flipperdevices.info.impl.viewmodel -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider +import com.flipperdevices.bridge.connection.feature.protocolversion.api.FVersionFeatureApi +import com.flipperdevices.bridge.connection.feature.protocolversion.model.FlipperSupportedState +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get import com.flipperdevices.core.log.LogTagProvider -import com.flipperdevices.core.log.info import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import javax.inject.Inject class FirmwareUpdateViewModel @Inject constructor( - serviceProvider: FlipperServiceProvider -) : DecomposeViewModel(), FlipperBleServiceConsumer, LogTagProvider { + private val fFeatureProvider: FFeatureProvider +) : DecomposeViewModel(), LogTagProvider { override val TAG = "FirmwareUpdateViewModel" - private val connectionState = MutableStateFlow( - FlipperSupportedState.READY - ) - - init { - serviceProvider.provideServiceApi(consumer = this, lifecycleOwner = this) - } - - fun getState(): StateFlow = connectionState - - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - serviceApi.connectionInformationApi.getConnectionStateFlow().onEach { - info { "Receive connection state: $it" } - if (it is ConnectionState.Ready) { - connectionState.emit(it.supportedState) + fun getState(): StateFlow { + return fFeatureProvider.get().flatMapLatest { status -> + when (status) { + FFeatureStatus.NotFound -> flowOf(FlipperSupportedState.DEPRECATED_FLIPPER) + FFeatureStatus.Unsupported -> flowOf(FlipperSupportedState.DEPRECATED_FLIPPER) + FFeatureStatus.Retrieving -> flowOf(FlipperSupportedState.READY) + is FFeatureStatus.Supported -> { + status.featureApi + .getSupportedStateFlow() + .map { state -> state ?: FlipperSupportedState.DEPRECATED_FLIPPER } + } } - }.launchIn(viewModelScope) + }.stateIn(viewModelScope, SharingStarted.Eagerly, FlipperSupportedState.READY) } } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt index 450cd6162a..82140a5a0e 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/FlipperColorViewModel.kt @@ -1,66 +1,25 @@ package com.flipperdevices.info.impl.viewmodel -import androidx.datastore.core.DataStore -import com.flipperdevices.bridge.api.model.FlipperRequestPriority -import com.flipperdevices.bridge.api.model.wrapToRequest -import com.flipperdevices.bridge.api.utils.Constants -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.core.preference.pb.HardwareColor -import com.flipperdevices.core.preference.pb.PairSettings +import com.flipperdevices.bridge.connection.config.api.FDevicePersistedStorage +import com.flipperdevices.bridge.connection.config.api.model.FDeviceFlipperZeroBleModel +import com.flipperdevices.core.preference.pb.FlipperZeroBle +import com.flipperdevices.core.preference.pb.FlipperZeroBle.HardwareColor +import com.flipperdevices.core.preference.pb.SavedDevice import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel -import com.flipperdevices.protobuf.main -import com.flipperdevices.protobuf.property.getRequest -import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn import javax.inject.Inject -private const val RPC_KEY_HARDWARE_COLOR = "hardware.color" - class FlipperColorViewModel @Inject constructor( - private val settings: DataStore -) : DecomposeViewModel(), FlipperBleServiceConsumer { - private val colorFlipperState = MutableStateFlow(HardwareColor.fromValue(-1)) - - init { - settings.data.onEach { - colorFlipperState.emit(it.hardware_color) - }.launchIn(viewModelScope) - } + fDevicePersistedStorage: FDevicePersistedStorage, +) : DecomposeViewModel() { + private val colorFlipperState = fDevicePersistedStorage.getCurrentDevice() + .filterIsInstance() + .map { coloredDevice -> coloredDevice.hardwareColor } + .stateIn(viewModelScope, SharingStarted.Eagerly, HardwareColor.fromValue(-1)) fun getFlipperColor(): StateFlow = colorFlipperState - - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - viewModelScope.launch { - if (!serviceApi.flipperVersionApi.isSupported(Constants.API_SUPPORTED_GET_REQUEST)) { - return@launch - } - val response = serviceApi.requestApi.request( - flowOf( - main { - propertyGetRequest = getRequest { - key = RPC_KEY_HARDWARE_COLOR - } - }.wrapToRequest(FlipperRequestPriority.BACKGROUND) - ) - ) - if (response.hasPropertyGetResponse().not()) { - return@launch - } - val hardwareColor = when (response.propertyGetResponse.value.toIntOrNull()) { - HardwareColor.WHITE.value -> HardwareColor.WHITE - HardwareColor.BLACK.value -> HardwareColor.BLACK - else -> HardwareColor.WHITE - } - settings.updateData { - it.copy( - hardware_color = hardwareColor - ) - } - } - } } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/BasicInfoViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/BasicInfoViewModel.kt index e64125b0fc..ffa9e24608 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/BasicInfoViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/BasicInfoViewModel.kt @@ -1,77 +1,81 @@ package com.flipperdevices.info.impl.viewmodel.deviceinfo -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState -import com.flipperdevices.bridge.rpcinfo.api.FlipperStorageInformationApi -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider -import com.flipperdevices.core.ktx.jre.cancelAndClear +import com.flipperdevices.bridge.connection.feature.getinfo.api.FGattInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus +import com.flipperdevices.bridge.connection.feature.storageinfo.api.FStorageInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.storageinfo.model.FlipperStorageInformation import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel import com.flipperdevices.info.impl.model.FlipperBasicInfo -import com.flipperdevices.updater.api.FlipperVersionProviderApi -import kotlinx.coroutines.Job +import com.flipperdevices.updater.api.FirmwareVersionBuilderApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import kotlinx.coroutines.plus import javax.inject.Inject class BasicInfoViewModel @Inject constructor( - serviceProvider: FlipperServiceProvider, - private val flipperVersionProviderApi: FlipperVersionProviderApi, - private val flipperStorageInformationApi: FlipperStorageInformationApi -) : DecomposeViewModel(), FlipperBleServiceConsumer, LogTagProvider { + private val fFeatureProvider: FFeatureProvider, + private val firmwareVersionBuilderApi: FirmwareVersionBuilderApi +) : DecomposeViewModel(), LogTagProvider { override val TAG = "DeviceInfoViewModel" private val flipperBasicInfoState = MutableStateFlow(FlipperBasicInfo()) - private val jobs = mutableListOf() + fun getDeviceInfo() = flipperBasicInfoState.asStateFlow() - init { - serviceProvider.provideServiceApi(this, this) + private fun collectStorageInfo() { + fFeatureProvider.get() + .map { it as? FFeatureStatus.Supported } + .flatMapLatest { + it?.featureApi + ?.getStorageInformationFlow() + ?: flowOf(FlipperStorageInformation()) + }.onEach { storageInfo -> + flipperBasicInfoState.update { basicInfo -> basicInfo.copy(storageInfo = storageInfo) } + }.launchIn(viewModelScope) } - fun getDeviceInfo() = flipperBasicInfoState.asStateFlow() + private fun invalidateStorageInfo() { + fFeatureProvider.get() + .filterIsInstance>() + .onEach { status -> status.featureApi.invalidate(viewModelScope, true) } + .launchIn(viewModelScope) + } - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - jobs.cancelAndClear() - jobs += flipperVersionProviderApi.getCurrentFlipperVersion(viewModelScope, serviceApi) - .onEach { firmwareVersion -> - flipperBasicInfoState.update { - it.copy( - firmwareVersion = FlipperInformationStatus.Ready( - firmwareVersion + private fun collectFirmwareInformation() { + fFeatureProvider.get() + .map { it as? FFeatureStatus.Supported } + .flatMapLatest { it?.featureApi?.getGattInfoFlow() ?: flowOf(null) } + .map { it?.softwareVersion } + .onEach { softwareVersion -> + if (softwareVersion == null) { + flipperBasicInfoState.update { basicInfo -> + basicInfo.copy(firmwareVersion = FlipperInformationStatus.NotStarted()) + } + } else { + flipperBasicInfoState.update { basicInfo -> + basicInfo.copy( + firmwareVersion = FlipperInformationStatus.Ready( + data = firmwareVersionBuilderApi.buildFirmwareVersionFromString( + firmwareVersion = softwareVersion + ) + ) ) - ) + } } }.launchIn(viewModelScope) + } - jobs += serviceApi.connectionInformationApi.getConnectionStateFlow().onEach { - when (it) { - is ConnectionState.Ready -> if (it.supportedState == FlipperSupportedState.READY) { - flipperStorageInformationApi.invalidate( - viewModelScope, - serviceApi, - force = false - ) - } - else -> flipperStorageInformationApi.reset() - } - }.launchIn(viewModelScope) - - jobs += flipperStorageInformationApi.getStorageInformationFlow().onEach { storageInfo -> - flipperBasicInfoState.update { it.copy(storageInfo = storageInfo) } - }.launchIn(viewModelScope) - - jobs += viewModelScope.launch { - flipperStorageInformationApi.invalidate( - viewModelScope, - serviceApi - ) - } + init { + collectStorageInfo() + invalidateStorageInfo() + collectFirmwareInformation() } } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/FullInfoViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/FullInfoViewModel.kt index 12c3f3cc54..23cd1c7f38 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/FullInfoViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/FullInfoViewModel.kt @@ -1,82 +1,45 @@ package com.flipperdevices.info.impl.viewmodel.deviceinfo -import com.flipperdevices.bridge.api.manager.ktx.state.ConnectionState -import com.flipperdevices.bridge.api.manager.ktx.state.FlipperSupportedState -import com.flipperdevices.bridge.rpcinfo.api.FlipperRpcInformationApi -import com.flipperdevices.bridge.rpcinfo.model.FlipperInformationStatus -import com.flipperdevices.bridge.rpcinfo.model.FlipperRpcInformation -import com.flipperdevices.bridge.service.api.FlipperServiceApi -import com.flipperdevices.bridge.service.api.provider.FlipperBleServiceConsumer -import com.flipperdevices.bridge.service.api.provider.FlipperServiceProvider -import com.flipperdevices.core.ktx.jre.cancelAndClear +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureProvider +import com.flipperdevices.bridge.connection.feature.provider.api.FFeatureStatus +import com.flipperdevices.bridge.connection.feature.provider.api.get +import com.flipperdevices.bridge.connection.feature.provider.api.getSync +import com.flipperdevices.bridge.connection.feature.rpcinfo.api.FRpcInfoFeatureApi +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperInformationStatus import com.flipperdevices.core.log.LogTagProvider import com.flipperdevices.core.ui.lifecycle.DecomposeViewModel import com.flipperdevices.updater.api.FirmwareVersionBuilderApi import com.flipperdevices.updater.model.FirmwareChannel -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import kotlinx.coroutines.plus import javax.inject.Inject class FullInfoViewModel @Inject constructor( - private val serviceProvider: FlipperServiceProvider, - private val flipperRpcInformationApi: FlipperRpcInformationApi, - private val firmwareVersionBuilderApi: FirmwareVersionBuilderApi + private val firmwareVersionBuilderApi: FirmwareVersionBuilderApi, + private val fFeatureProvider: FFeatureProvider ) : DecomposeViewModel(), - FlipperBleServiceConsumer, LogTagProvider { override val TAG = "FullInfoViewModel" - private val jobs = mutableListOf() - private val flipperRpcInformationState = - MutableStateFlow>( - FlipperInformationStatus.NotStarted() - ) - init { - serviceProvider.provideServiceApi(this, this) - } - - fun getFlipperRpcInformation() = flipperRpcInformationState.asStateFlow() - - fun refresh() { - viewModelScope.launch { - flipperRpcInformationApi.invalidate( - viewModelScope, - serviceProvider.getServiceApi(), - force = true - ) - } - } - - override fun onServiceApiReady(serviceApi: FlipperServiceApi) { - jobs.cancelAndClear() - jobs += serviceApi.connectionInformationApi.getConnectionStateFlow().onEach { - when (it) { - is ConnectionState.Ready -> if (it.supportedState == FlipperSupportedState.READY) { - flipperRpcInformationApi.invalidate( - viewModelScope, - serviceApi, - force = true - ) - } - else -> flipperRpcInformationApi.reset() - } - }.launchIn(viewModelScope) + private val flipperRpcInformation = fFeatureProvider.get() + .map { status -> status as? FFeatureStatus.Supported } + .flatMapLatest { status -> status?.featureApi?.getRpcInformationFlow() ?: flowOf(null) } + .map { informationStatus -> informationStatus ?: FlipperInformationStatus.NotStarted() } + .stateIn(viewModelScope, SharingStarted.Eagerly, FlipperInformationStatus.NotStarted()) - jobs += flipperRpcInformationApi.getRpcInformationFlow().onEach { rpcInformation -> - flipperRpcInformationState.emit(rpcInformation) - }.launchIn(viewModelScope) + fun getFlipperRpcInformation() = flipperRpcInformation - jobs += viewModelScope.launch { - flipperRpcInformationApi.invalidate( - viewModelScope, - serviceApi - ) - } + private fun invalidateRpcInfo() { + fFeatureProvider.get() + .map { status -> status as? FFeatureStatus.Supported } + .onEach { status -> status?.featureApi?.invalidate(viewModelScope, force = true) } + .launchIn(viewModelScope) } fun getFirmwareChannel(commit: String?): FirmwareChannel? { @@ -86,4 +49,15 @@ class FullInfoViewModel @Inject constructor( val branch = preparedCommit.first() return firmwareVersionBuilderApi.getFirmwareChannel(branch) } + + fun refresh() { + viewModelScope.launch { + fFeatureProvider.getSync() + ?.invalidate(viewModelScope, force = true) + } + } + + init { + invalidateRpcInfo() + } } diff --git a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/ShareFullInfoFileViewModel.kt b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/ShareFullInfoFileViewModel.kt index 2ed75d9075..2565f9dfeb 100644 --- a/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/ShareFullInfoFileViewModel.kt +++ b/components/info/impl/src/main/java/com/flipperdevices/info/impl/viewmodel/deviceinfo/ShareFullInfoFileViewModel.kt @@ -1,10 +1,10 @@ package com.flipperdevices.info.impl.viewmodel.deviceinfo import android.app.Application -import com.flipperdevices.bridge.rpcinfo.model.FlipperRpcInformation -import com.flipperdevices.bridge.rpcinfo.model.StorageStats -import com.flipperdevices.bridge.rpcinfo.model.flashIntStats -import com.flipperdevices.bridge.rpcinfo.model.flashSdStats +import com.flipperdevices.bridge.connection.feature.rpcinfo.model.FlipperRpcInformation +import com.flipperdevices.bridge.connection.feature.storageinfo.model.StorageStats +import com.flipperdevices.bridge.connection.feature.storageinfo.model.flashIntStats +import com.flipperdevices.bridge.connection.feature.storageinfo.model.flashSdStats import com.flipperdevices.core.ktx.jre.createClearNewFileWithMkDirs import com.flipperdevices.core.log.error import com.flipperdevices.core.share.SharableFile diff --git a/instances/android/app/build.gradle.kts b/instances/android/app/build.gradle.kts index f2a3fdf428..82f582ccbd 100644 --- a/instances/android/app/build.gradle.kts +++ b/instances/android/app/build.gradle.kts @@ -184,6 +184,10 @@ dependencies { implementation(projects.components.bridge.connection.feature.storage.impl) implementation(projects.components.bridge.connection.feature.storageinfo.api) implementation(projects.components.bridge.connection.feature.storageinfo.impl) + implementation(projects.components.bridge.connection.feature.alarm.api) + implementation(projects.components.bridge.connection.feature.alarm.impl) + implementation(projects.components.bridge.connection.feature.deviceColor.api) + implementation(projects.components.bridge.connection.feature.deviceColor.impl) implementation(projects.components.analytics.shake2report.api) if (IS_SENTRY_ENABLED) { diff --git a/settings.gradle.kts b/settings.gradle.kts index 94626a3631..9239ebf125 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -87,6 +87,10 @@ include( ":components:bridge:connection:feature:actionnotifier:api", ":components:bridge:connection:feature:serialspeed:api", ":components:bridge:connection:feature:serialspeed:impl", + ":components:bridge:connection:feature:alarm:api", + ":components:bridge:connection:feature:alarm:impl", + ":components:bridge:connection:feature:device-color:api", + ":components:bridge:connection:feature:device-color:impl", ":components:filemngr:util", ":components:filemanager:api",