Add GLS feature

This commit is contained in:
Sylwester Zieliński
2021-09-30 13:37:45 +02:00
parent 7a171a1402
commit b2da2f20eb
37 changed files with 1036 additions and 102 deletions

View File

@@ -1,10 +1,10 @@
package no.nordicsemi.android.csc.viewmodel
package no.nordicsemi.android.csc.data
import no.nordicsemi.android.csc.view.CSCSettings
import no.nordicsemi.android.csc.view.SpeedUnit
import java.util.*
internal data class CSCViewState(
internal data class CSCData(
val showDialog: Boolean = false,
val scanDevices: Boolean = false,
val selectedSpeedUnit: SpeedUnit = SpeedUnit.M_S,

View File

@@ -1,28 +0,0 @@
package no.nordicsemi.android.csc.events
import android.bluetooth.BluetoothDevice
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
internal sealed class CSCServiceEvent : Parcelable
@Parcelize
internal data class OnDistanceChangedEvent(
val bluetoothDevice: BluetoothDevice,
val speed: Float,
val distance: Float,
val totalDistance: Float
) : CSCServiceEvent()
@Parcelize
internal data class CrankDataChanged(
val bluetoothDevice: BluetoothDevice,
val crankCadence: Int,
val gearRatio: Float
) : CSCServiceEvent()
@Parcelize
internal data class OnBatteryLevelChanged(
val device: BluetoothDevice,
val batteryLevel: Int
) : CSCServiceEvent()

View File

@@ -3,13 +3,13 @@ package no.nordicsemi.android.csc.service
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import no.nordicsemi.android.csc.events.CSCServiceEvent
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.service.BluetoothDataReadBroadcast
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
internal class CSCDataReadBroadcast @Inject constructor() : BluetoothDataReadBroadcast<CSCServiceEvent>() {
internal class CSCDataReadBroadcast @Inject constructor() : BluetoothDataReadBroadcast<CSCData>() {
private val _wheelSize = MutableSharedFlow<Int>(
replay = 1,

View File

@@ -5,9 +5,7 @@ import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import no.nordicsemi.android.csc.events.CrankDataChanged
import no.nordicsemi.android.csc.events.OnBatteryLevelChanged
import no.nordicsemi.android.csc.events.OnDistanceChangedEvent
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.service.ForegroundBleService
import no.nordicsemi.android.service.LoggableBleManager
import javax.inject.Inject
@@ -15,6 +13,8 @@ import javax.inject.Inject
@AndroidEntryPoint
internal class CSCService : ForegroundBleService<CSCManager>(), CSCManagerCallbacks {
private var data = CSCData()
@Inject
lateinit var localBroadcast: CSCDataReadBroadcast
@@ -42,7 +42,7 @@ internal class CSCService : ForegroundBleService<CSCManager>(), CSCManagerCallba
distance: Float,
speed: Float
) {
localBroadcast.offer(OnDistanceChangedEvent(bluetoothDevice, speed, distance, totalDistance))
localBroadcast.offer(data.copy(speed = speed, distance = distance, totalDistance = totalDistance))
}
override fun onCrankDataChanged(
@@ -50,10 +50,10 @@ internal class CSCService : ForegroundBleService<CSCManager>(), CSCManagerCallba
crankCadence: Float,
gearRatio: Float
) {
localBroadcast.offer(CrankDataChanged(bluetoothDevice, crankCadence.toInt(), gearRatio))
localBroadcast.offer(data.copy(cadence = crankCadence.toInt(), gearRatio = gearRatio))
}
override fun onBatteryLevelChanged(device: BluetoothDevice, batteryLevel: Int) {
localBroadcast.offer(OnBatteryLevelChanged(bluetoothDevice, batteryLevel))
localBroadcast.offer(data.copy(batteryLevel = batteryLevel))
}
}

View File

@@ -17,11 +17,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import no.nordicsemi.android.csc.R
import no.nordicsemi.android.csc.viewmodel.CSCViewState
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.theme.NordicColors
@Composable
internal fun ContentView(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit) {
internal fun ContentView(state: CSCData, onEvent: (CSCViewEvent) -> Unit) {
if (state.showDialog) {
SelectWheelSizeDialog { onEvent(it) }
}
@@ -48,7 +48,7 @@ internal fun ContentView(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit) {
}
@Composable
private fun SettingsSection(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit) {
private fun SettingsSection(state: CSCData, onEvent: (CSCViewEvent) -> Unit) {
Card(
backgroundColor = NordicColors.NordicGray4.value(),
shape = RoundedCornerShape(10.dp),
@@ -70,5 +70,5 @@ private fun SettingsSection(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit
@Preview
@Composable
private fun ConnectedPreview() {
ContentView(CSCViewState()) { }
ContentView(CSCData()) { }
}

View File

@@ -12,7 +12,7 @@ import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import no.nordicsemi.android.csc.R
import no.nordicsemi.android.csc.service.CSCService
import no.nordicsemi.android.csc.viewmodel.CSCViewState
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.csc.viewmodel.CscViewModel
import no.nordicsemi.android.utils.isServiceRunning
@@ -43,7 +43,7 @@ fun CscScreen(finishAction: () -> Unit) {
}
@Composable
private fun CSCView(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit) {
private fun CSCView(state: CSCData, onEvent: (CSCViewEvent) -> Unit) {
Column {
TopAppBar(title = { Text(text = stringResource(id = R.string.csc_title)) })

View File

@@ -12,13 +12,13 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import no.nordicsemi.android.csc.R
import no.nordicsemi.android.csc.viewmodel.CSCViewState
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.theme.NordicColors
import no.nordicsemi.android.theme.view.BatteryLevelView
import no.nordicsemi.android.theme.view.KeyValueField
@Composable
internal fun SensorsReadingView(state: CSCViewState) {
internal fun SensorsReadingView(state: CSCData) {
Card(
backgroundColor = NordicColors.NordicGray4.value(),
shape = RoundedCornerShape(10.dp),
@@ -48,5 +48,5 @@ internal fun SensorsReadingView(state: CSCViewState) {
@Preview
@Composable
private fun Preview() {
SensorsReadingView(CSCViewState())
SensorsReadingView(CSCData())
}

View File

@@ -12,10 +12,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import no.nordicsemi.android.csc.R
import no.nordicsemi.android.csc.viewmodel.CSCViewState
import no.nordicsemi.android.csc.data.CSCData
@Composable
internal fun WheelSizeView(state: CSCViewState, onEvent: (CSCViewEvent) -> Unit) {
internal fun WheelSizeView(state: CSCData, onEvent: (CSCViewEvent) -> Unit) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = state.wheelSize,
@@ -36,5 +36,5 @@ private fun EditIcon(onEvent: (CSCViewEvent) -> Unit) {
@Preview
@Composable
private fun WheelSizeViewPreview() {
WheelSizeView(CSCViewState()) { }
WheelSizeView(CSCData()) { }
}

View File

@@ -8,10 +8,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import no.nordicsemi.android.csc.events.CSCServiceEvent
import no.nordicsemi.android.csc.events.CrankDataChanged
import no.nordicsemi.android.csc.events.OnBatteryLevelChanged
import no.nordicsemi.android.csc.events.OnDistanceChangedEvent
import no.nordicsemi.android.csc.data.CSCData
import no.nordicsemi.android.csc.service.CSCDataReadBroadcast
import no.nordicsemi.android.csc.view.CSCViewEvent
import no.nordicsemi.android.csc.view.OnDisconnectButtonClick
@@ -26,44 +23,14 @@ internal class CscViewModel @Inject constructor(
private val localBroadcast: CSCDataReadBroadcast
) : ViewModel() {
val state = MutableStateFlow(CSCViewState())
val state = MutableStateFlow(CSCData())
init {
localBroadcast.events.onEach {
withContext(Dispatchers.Main) { consumeEvent(it) }
withContext(Dispatchers.Main) { state.value = it }
}.launchIn(viewModelScope)
}
private fun consumeEvent(event: CSCServiceEvent) {
val newValue = when (event) {
is CrankDataChanged -> createNewState(event)
is OnBatteryLevelChanged -> createNewState(event)
is OnDistanceChangedEvent -> createNewState(event)
}
state.value = newValue
}
private fun createNewState(event: CrankDataChanged): CSCViewState {
return state.value.copy(
cadence = event.crankCadence,
gearRatio = event.gearRatio
)
}
private fun createNewState(event: OnBatteryLevelChanged): CSCViewState {
return state.value.copy(
batteryLevel = event.batteryLevel
)
}
private fun createNewState(event: OnDistanceChangedEvent): CSCViewState {
return state.value.copy(
speed = event.speed,
distance = event.distance,
totalDistance = event.totalDistance
)
}
fun onEvent(event: CSCViewEvent) {
when (event) {
is OnSelectedSpeedUnitSelected -> onSelectedSpeedUnit(event)