Migrate to Hilt.

This commit is contained in:
Sylwester Zieliński
2022-01-20 12:40:08 +01:00
parent 98e5b530d6
commit d8dce9a24c
14 changed files with 98 additions and 141 deletions

View File

@@ -73,7 +73,6 @@ dependencies {
implementation libs.nordic.ui.scanner
implementation libs.nordic.navigation
implementation libs.bundles.koin
implementation libs.bundles.hilt
kapt libs.bundles.hiltkapt

View File

@@ -15,7 +15,7 @@ class HomeViewModel @Inject constructor(
fun openProfile(destination: ProfileDestination) {
navigationManager.navigateTo(
ForwardDestination(destination.destination.id),
UUIDArgument(destination.uuid)
UUIDArgument(destination.destination.id, destination.uuid)
)
}
}

View File

@@ -2,19 +2,6 @@ package no.nordicsemi.android.nrftoolbox
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import no.nordicsemi.ui.scanner.scannerModule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
@HiltAndroidApp
class NrfToolboxApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
androidContext(this@NrfToolboxApplication)
modules(scannerModule)
}
}
}
class NrfToolboxApplication : Application()

View File

@@ -1,2 +1,7 @@
apply from: rootProject.file("library.gradle")
apply plugin: 'kotlin-parcelize'
dependencies {
implementation libs.nordic.navigation
implementation libs.nordic.ui.scanner
}

View File

@@ -5,6 +5,9 @@ import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.navigation.NavController
import no.nordicsemi.android.navigation.ParcelableArgument
import no.nordicsemi.android.navigation.SuccessDestinationResult
import no.nordicsemi.ui.scanner.DiscoveredBluetoothDevice
val <T> T.exhaustive
get() = this
@@ -18,6 +21,10 @@ fun Context.isServiceRunning(serviceClassName: String): Boolean {
return services.find { it.service.className == serviceClassName } != null
}
fun SuccessDestinationResult.getDevice(): DiscoveredBluetoothDevice {
return (argument as ParcelableArgument).value as DiscoveredBluetoothDevice
}
@Composable
fun <T> NavController.consumeResult(value: String): T? {

View File

@@ -15,12 +15,11 @@ import no.nordicsemi.android.bps.view.BPSScreenViewEvent
import no.nordicsemi.android.bps.view.DisconnectEvent
import no.nordicsemi.android.bps.view.DisplayDataState
import no.nordicsemi.android.bps.view.LoadingState
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.android.navigation.ParcelableArgument
import no.nordicsemi.android.navigation.SuccessDestinationResult
import no.nordicsemi.android.navigation.*
import no.nordicsemi.android.service.BleManagerStatus
import no.nordicsemi.android.service.ConnectionObserverAdapter
import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.android.utils.getDevice
import no.nordicsemi.ui.scanner.DiscoveredBluetoothDevice
import no.nordicsemi.ui.scanner.ScannerDestinationId
import javax.inject.Inject
@@ -32,11 +31,6 @@ internal class BPSViewModel @Inject constructor(
private val navigationManager: NavigationManager
) : ViewModel() {
private val args
get() = navigationManager.getResult(ScannerDestinationId)
private val device
get() = ((args as SuccessDestinationResult).argument as ParcelableArgument).value as DiscoveredBluetoothDevice
val state = repository.data.combine(repository.status) { data, status ->
when (status) {
BleManagerStatus.CONNECTING -> LoadingState
@@ -46,6 +40,12 @@ internal class BPSViewModel @Inject constructor(
}.stateIn(viewModelScope, SharingStarted.Lazily, LoadingState)
init {
navigationManager.recentResult.onEach {
if (it.destinationId == ScannerDestinationId) {
handleArgs(it)
}
}.launchIn(viewModelScope)
bpsManager.setConnectionObserver(object : ConnectionObserverAdapter() {
override fun onDeviceConnected(device: BluetoothDevice) {
super.onDeviceConnected(device)
@@ -70,13 +70,21 @@ internal class BPSViewModel @Inject constructor(
}.launchIn(viewModelScope)
}
private fun handleArgs(args: DestinationResult?) {
when (args) {
is CancelDestinationResult -> navigationManager.navigateUp()
is SuccessDestinationResult -> connectDevice(args.getDevice())
null -> navigationManager.navigateTo(ForwardDestination(ScannerDestinationId), UUIDArgument(ScannerDestinationId, GLS_SERVICE_UUID))
}.exhaustive
}
fun onEvent(event: BPSScreenViewEvent) {
when (event) {
DisconnectEvent -> onDisconnectButtonClick()
}.exhaustive
}
fun connectDevice() {
private fun connectDevice(device: DiscoveredBluetoothDevice) {
bpsManager.connect(device.device)
.useAutoConnect(false)
.retry(3, 100)

View File

@@ -1,11 +1,7 @@
package no.nordicsemi.android.csc.data
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.*
import no.nordicsemi.android.csc.view.SpeedUnit
import no.nordicsemi.android.service.BleManagerStatus
import javax.inject.Inject

View File

@@ -3,30 +3,18 @@ package no.nordicsemi.android.csc.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.*
import no.nordicsemi.android.csc.data.CSCRepository
import no.nordicsemi.android.csc.data.DisconnectCommand
import no.nordicsemi.android.csc.data.SetWheelSizeCommand
import no.nordicsemi.android.csc.repository.CSCService
import no.nordicsemi.android.csc.view.CSCViewEvent
import no.nordicsemi.android.csc.view.DisplayDataState
import no.nordicsemi.android.csc.view.LoadingState
import no.nordicsemi.android.csc.view.OnDisconnectButtonClick
import no.nordicsemi.android.csc.view.OnSelectedSpeedUnitSelected
import no.nordicsemi.android.csc.view.OnWheelSizeSelected
import no.nordicsemi.android.navigation.CancelDestinationResult
import no.nordicsemi.android.navigation.ForwardDestination
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.android.navigation.ParcelableArgument
import no.nordicsemi.android.navigation.SuccessDestinationResult
import no.nordicsemi.android.csc.repository.CSC_SERVICE_UUID
import no.nordicsemi.android.csc.view.*
import no.nordicsemi.android.navigation.*
import no.nordicsemi.android.service.BleManagerStatus
import no.nordicsemi.android.service.ServiceManager
import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.ui.scanner.DiscoveredBluetoothDevice
import no.nordicsemi.android.utils.getDevice
import no.nordicsemi.ui.scanner.ScannerDestinationId
import javax.inject.Inject
@@ -37,11 +25,6 @@ internal class CSCViewModel @Inject constructor(
private val navigationManager: NavigationManager
) : ViewModel() {
private val args
get() = navigationManager.getResult(ScannerDestinationId)
private val device
get() = ((args as SuccessDestinationResult).argument as ParcelableArgument).value as DiscoveredBluetoothDevice
val state = repository.data.combine(repository.status) { data, status ->
when (status) {
BleManagerStatus.CONNECTING -> LoadingState
@@ -51,11 +34,11 @@ internal class CSCViewModel @Inject constructor(
}.stateIn(viewModelScope, SharingStarted.Lazily, LoadingState)
init {
when (args) {
CancelDestinationResult -> navigationManager.navigateUp()
is SuccessDestinationResult -> serviceManager.startService(CSCService::class.java, device)
null -> navigationManager.navigateTo(ForwardDestination(ScannerDestinationId))
}.exhaustive
navigationManager.recentResult.onEach {
if (it.destinationId == ScannerDestinationId) {
handleArgs(it)
}
}.launchIn(viewModelScope)
repository.status.onEach {
if (it == BleManagerStatus.DISCONNECTED) {
@@ -64,6 +47,14 @@ internal class CSCViewModel @Inject constructor(
}.launchIn(viewModelScope)
}
private fun handleArgs(args: DestinationResult?) {
when (args) {
is CancelDestinationResult -> navigationManager.navigateUp()
is SuccessDestinationResult -> serviceManager.startService(CSCService::class.java, args.getDevice())
null -> navigationManager.navigateTo(ForwardDestination(ScannerDestinationId), UUIDArgument(ScannerDestinationId, CSC_SERVICE_UUID))
}.exhaustive
}
fun onEvent(event: CSCViewEvent) {
when (event) {
is OnSelectedSpeedUnitSelected -> onSelectedSpeedUnit(event)
@@ -82,6 +73,7 @@ internal class CSCViewModel @Inject constructor(
private fun onDisconnectButtonClick() {
repository.sendNewServiceCommand(DisconnectCommand)
repository.setNewStatus(BleManagerStatus.DISCONNECTED)
repository.clear()
}

View File

@@ -1,47 +1,28 @@
package no.nordicsemi.dfu.view
import android.content.Intent
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import no.nordicsemi.android.theme.view.BackIconAppBar
import no.nordicsemi.android.theme.view.DeviceConnectingView
import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.dfu.R
import no.nordicsemi.dfu.repository.DFUService
import no.nordicsemi.dfu.viewmodel.DFUViewModel
@Composable
fun DFUScreen(finishAction: () -> Unit) {
fun DFUScreen() {
val viewModel: DFUViewModel = hiltViewModel()
val state = viewModel.state.collectAsState().value
val context = LocalContext.current
LaunchedEffect(state.isActive) {
if (state.isActive) {
val intent = Intent(context, DFUService::class.java)
context.startService(intent)
} else {
finishAction()
}
}
DFUView(state.viewState) { viewModel.onEvent(it) }
}
@Composable
private fun DFUView(state: DFUViewState, onEvent: (DFUViewEvent) -> Unit) {
Column {
BackIconAppBar(stringResource(id = R.string.dfu_title)) {
onEvent(OnDisconnectButtonClick)
viewModel.onEvent(OnDisconnectButtonClick)
}
when (state) {
is DisplayDataState -> DFUContentView(state.data) { onEvent(it) }
is DisplayDataState -> DFUContentView(state.data) { viewModel.onEvent(it) }
LoadingState -> DeviceConnectingView()
}.exhaustive
}

View File

@@ -2,11 +2,6 @@ package no.nordicsemi.dfu.view
import no.nordicsemi.dfu.data.DFUData
internal data class DFUState(
val viewState: DFUViewState,
val isActive: Boolean = true
)
internal sealed class DFUViewState
internal object LoadingState : DFUViewState()

View File

@@ -6,30 +6,14 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.android.navigation.ParcelableArgument
import no.nordicsemi.android.navigation.SuccessDestinationResult
import no.nordicsemi.android.navigation.*
import no.nordicsemi.android.service.BleManagerStatus
import no.nordicsemi.android.service.ServiceManager
import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.dfu.data.Completed
import no.nordicsemi.dfu.data.DFUManager
import no.nordicsemi.dfu.data.DFUProgressManager
import no.nordicsemi.dfu.data.DFURepository
import no.nordicsemi.dfu.data.DFUServiceStatus
import no.nordicsemi.dfu.data.DisconnectCommand
import no.nordicsemi.dfu.data.Error
import no.nordicsemi.dfu.data.FileInstallingState
import no.nordicsemi.dfu.data.FileReadyState
import no.nordicsemi.dfu.data.ZipFile
import no.nordicsemi.dfu.view.DFUState
import no.nordicsemi.dfu.view.DFUViewEvent
import no.nordicsemi.dfu.view.DisplayDataState
import no.nordicsemi.dfu.view.LoadingState
import no.nordicsemi.dfu.view.OnDisconnectButtonClick
import no.nordicsemi.dfu.view.OnInstallButtonClick
import no.nordicsemi.dfu.view.OnPauseButtonClick
import no.nordicsemi.dfu.view.OnStopButtonClick
import no.nordicsemi.dfu.view.OnZipFileSelected
import no.nordicsemi.android.utils.getDevice
import no.nordicsemi.dfu.data.*
import no.nordicsemi.dfu.repository.DFUService
import no.nordicsemi.dfu.view.*
import no.nordicsemi.ui.scanner.DiscoveredBluetoothDevice
import no.nordicsemi.ui.scanner.ScannerDestinationId
import javax.inject.Inject
@@ -39,14 +23,11 @@ internal class DFUViewModel @Inject constructor(
private val repository: DFURepository,
private val progressManager: DFUProgressManager,
private val dfuManager: DFUManager,
private val serviceManager: ServiceManager,
private val navigationManager: NavigationManager
) : ViewModel() {
private val args
get() = navigationManager.getResult(ScannerDestinationId)
private val device
get() = ((args as SuccessDestinationResult).argument as ParcelableArgument).value as DiscoveredBluetoothDevice
private var device: DiscoveredBluetoothDevice? = null
val state = repository.data.combine(progressManager.status) { state, status ->
(state as? FileInstallingState)
@@ -54,26 +35,37 @@ internal class DFUViewModel @Inject constructor(
?: state
}.combine(repository.status) { data, status ->
when (status) {
BleManagerStatus.CONNECTING -> DFUState(LoadingState)
BleManagerStatus.OK -> DFUState(DisplayDataState(data))
BleManagerStatus.DISCONNECTED -> DFUState(DisplayDataState(data), false)
BleManagerStatus.CONNECTING -> LoadingState
BleManagerStatus.OK,
BleManagerStatus.DISCONNECTED -> DisplayDataState(data)
}
}.stateIn(viewModelScope, SharingStarted.Lazily, DFUState(LoadingState))
}.stateIn(viewModelScope, SharingStarted.Lazily, LoadingState)
init {
progressManager.registerListener()
}
private fun handleArgs(args: DestinationResult?) {
when (args) {
is CancelDestinationResult -> navigationManager.navigateUp()
is SuccessDestinationResult -> {
device = args.getDevice()
serviceManager.startService(DFUService::class.java, args.getDevice())
}
null -> navigationManager.navigateTo(ForwardDestination(ScannerDestinationId))
}.exhaustive
}
fun onEvent(event: DFUViewEvent) {
when (event) {
OnDisconnectButtonClick -> closeScreen()
OnInstallButtonClick -> {
dfuManager.install(requireFile(), device)
dfuManager.install(requireFile(), device!!)
repository.install()
}
OnPauseButtonClick -> closeScreen()
OnStopButtonClick -> closeScreen()
is OnZipFileSelected -> repository.setZipFile(event.file, device)
is OnZipFileSelected -> repository.setZipFile(event.file, device!!)
}.exhaustive
}

View File

@@ -3,7 +3,6 @@ package no.nordicsemi.android.gls.view
import android.util.Log
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
@@ -22,10 +21,6 @@ fun GLSScreen() {
Log.d("AAATESTAAA", "$viewModel") //TODO fix screen rotation
LaunchedEffect(Unit) {
viewModel.connectDevice()
}
GLSView(state) {
viewModel.onEvent(it)
}

View File

@@ -4,22 +4,18 @@ import android.bluetooth.BluetoothDevice
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.*
import no.nordicsemi.android.gls.data.GLSRepository
import no.nordicsemi.android.gls.data.WorkingMode
import no.nordicsemi.android.gls.repository.GLSManager
import no.nordicsemi.android.gls.repository.GLS_SERVICE_UUID
import no.nordicsemi.android.gls.view.DisplayDataState
import no.nordicsemi.android.gls.view.LoadingState
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.android.navigation.ParcelableArgument
import no.nordicsemi.android.navigation.SuccessDestinationResult
import no.nordicsemi.android.navigation.*
import no.nordicsemi.android.service.BleManagerStatus
import no.nordicsemi.android.service.ConnectionObserverAdapter
import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.android.utils.getDevice
import no.nordicsemi.ui.scanner.DiscoveredBluetoothDevice
import no.nordicsemi.ui.scanner.ScannerDestinationId
import javax.inject.Inject
@@ -31,11 +27,6 @@ internal class GLSViewModel @Inject constructor(
private val navigationManager: NavigationManager
) : ViewModel() {
private val args
get() = navigationManager.getResult(ScannerDestinationId)
private val device
get() = ((args as SuccessDestinationResult).argument as ParcelableArgument).value as DiscoveredBluetoothDevice
val state = repository.data.combine(repository.status) { data, status ->
when (status) {
BleManagerStatus.CONNECTING -> LoadingState
@@ -45,6 +36,12 @@ internal class GLSViewModel @Inject constructor(
}.stateIn(viewModelScope, SharingStarted.Lazily, LoadingState)
init {
navigationManager.recentResult.onEach {
if (it.destinationId == ScannerDestinationId) {
handleArgs(it)
}
}.launchIn(viewModelScope)
glsManager.setConnectionObserver(object : ConnectionObserverAdapter() {
override fun onDeviceConnected(device: BluetoothDevice) {
super.onDeviceConnected(device)
@@ -69,6 +66,14 @@ internal class GLSViewModel @Inject constructor(
}.launchIn(viewModelScope)
}
private fun handleArgs(args: DestinationResult?) {
when (args) {
is CancelDestinationResult -> navigationManager.navigateUp()
is SuccessDestinationResult -> connectDevice(args.getDevice())
null -> navigationManager.navigateTo(ForwardDestination(ScannerDestinationId), UUIDArgument(ScannerDestinationId, GLS_SERVICE_UUID))
}.exhaustive
}
fun onEvent(event: GLSScreenViewEvent) {
when (event) {
DisconnectEvent -> disconnect()
@@ -76,7 +81,7 @@ internal class GLSViewModel @Inject constructor(
}.exhaustive
}
fun connectDevice() {
private fun connectDevice(device: DiscoveredBluetoothDevice) {
glsManager.connect(device.device)
.useAutoConnect(false)
.retry(3, 100)

View File

@@ -51,11 +51,6 @@ dependencyResolutionManagement {
bundle('hilt', ['hilt-android', 'hilt-compose', 'hilt-lifecycle'])
bundle('hiltkapt', ['hilt-compiler', 'hilt-lifecyclecompiler'])
version('koin', '3.1.2')
alias('koin-android').to('io.insert-koin', 'koin-android').versionRef('koin')
alias('koin-compose').to('io.insert-koin', 'koin-androidx-compose').versionRef('koin')
bundle('koin', ['koin-android', 'koin-compose'])
alias('kotlin-coroutines').to('org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2')
alias('google-permissions').to('com.google.accompanist:accompanist-permissions:0.18.0')
alias('chart').to('com.github.PhilJay:MPAndroidChart:v3.1.0')