Extract scanner to Common Libraries

This commit is contained in:
Sylwester Zieliński
2021-12-03 11:02:19 +01:00
parent 4d15ada6eb
commit af21919ed9
25 changed files with 26 additions and 861 deletions

View File

@@ -2,6 +2,7 @@ package no.nordicsemi.android.nrftoolbox
import android.app.Activity
import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@@ -14,70 +15,44 @@ import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import no.nordicsemi.android.bps.view.BPSScreen
import no.nordicsemi.android.cgms.view.CGMScreen
import no.nordicsemi.android.csc.view.CSCScreen
import no.nordicsemi.android.gls.view.GLSScreen
import no.nordicsemi.android.hrs.view.HRSScreen
import no.nordicsemi.android.hts.view.HTSScreen
import no.nordicsemi.android.permission.bonding.view.BondingScreen
import no.nordicsemi.android.permission.view.BluetoothNotAvailableScreen
import no.nordicsemi.android.permission.view.BluetoothNotEnabledScreen
import no.nordicsemi.android.permission.view.RequestPermissionScreen
import no.nordicsemi.android.prx.view.PRXScreen
import no.nordicsemi.android.rscs.view.RSCSScreen
import no.nordicsemi.android.scanner.view.ScanDeviceScreen
import no.nordicsemi.android.scanner.view.ScanDeviceScreenResult
import no.nordicsemi.android.theme.view.CloseIconAppBar
import no.nordicsemi.android.utils.exhaustive
@Composable
internal fun HomeScreen() {
val navController = rememberNavController()
val viewModel = hiltViewModel<NavigationViewModel>()
val continueAction: () -> Unit = { viewModel.finish() }
val state = viewModel.state.collectAsState().value
BackHandler { viewModel.navigateUp() }
NavHost(navController = navController, startDestination = NavDestination.HOME.id) {
composable(NavDestination.HOME.id) { HomeView { viewModel.navigate(it) } }
composable(NavDestination.CSC.id) { CSCScreen { viewModel.navigateUp() } }
composable(NavDestination.HRS.id) { HRSScreen { viewModel.navigateUp() } }
composable(NavDestination.HTS.id) { HTSScreen { viewModel.navigateUp() } }
composable(NavDestination.GLS.id) { GLSScreen { viewModel.navigateUp() } }
composable(NavDestination.BPS.id) { BPSScreen { viewModel.navigateUp() } }
composable(NavDestination.PRX.id) { PRXScreen { viewModel.navigateUp() } }
composable(NavDestination.RSCS.id) { RSCSScreen { viewModel.navigateUp() } }
composable(NavDestination.CGMS.id) { CGMScreen { viewModel.navigateUp() } }
composable(NavDestination.REQUEST_PERMISSION.id) { RequestPermissionScreen(continueAction) }
composable(NavDestination.BLUETOOTH_NOT_AVAILABLE.id) { BluetoothNotAvailableScreen { viewModel.finish() } }
composable(NavDestination.BLUETOOTH_NOT_ENABLED.id) {
BluetoothNotEnabledScreen(continueAction)
val activity = LocalContext.current as Activity
BackHandler {
if (navController.currentDestination?.navigatorName != NavDestination.HOME.id) {
navController.popBackStack()
} else {
activity.finish()
}
composable(
NavDestination.DEVICE_NOT_CONNECTED.id,
arguments = listOf(navArgument("args") { type = NavType.StringType })
) {
ScanDeviceScreen(it.arguments?.getString(ARGS_KEY)!!) {
when (it) {
ScanDeviceScreenResult.OK -> viewModel.finish()
ScanDeviceScreenResult.CANCEL -> viewModel.navigateUp()
}.exhaustive
}
}
composable(NavDestination.BONDING.id) { BondingScreen(continueAction) }
}
LaunchedEffect(state) {
navController.navigate(state.url)
val goHome = { navController.navigate(NavDestination.HOME.id) }
NavHost(navController = navController, startDestination = NavDestination.HOME.id) {
composable(NavDestination.HOME.id) { HomeView { goHome() } }
composable(NavDestination.CSC.id) { CSCScreen { goHome() } }
composable(NavDestination.HRS.id) { HRSScreen { goHome() } }
composable(NavDestination.HTS.id) { HTSScreen { goHome() } }
composable(NavDestination.GLS.id) { GLSScreen { goHome() } }
composable(NavDestination.BPS.id) { BPSScreen { goHome() } }
composable(NavDestination.PRX.id) { PRXScreen { goHome() } }
composable(NavDestination.RSCS.id) { RSCSScreen { goHome() } }
composable(NavDestination.CGMS.id) { CGMScreen { goHome() } }
}
}

View File

@@ -11,10 +11,5 @@ enum class NavDestination(val id: String, val pairingRequired: Boolean) {
BPS("bps-screen", false),
PRX("prx-screen", true),
RSCS("rscs-screen", false),
CGMS("cgms-screen", false),
REQUEST_PERMISSION("request-permission", false),
BLUETOOTH_NOT_AVAILABLE("bluetooth-not-available", false),
BLUETOOTH_NOT_ENABLED("bluetooth-not-enabled", false),
DEVICE_NOT_CONNECTED("device-not-connected/{$ARGS_KEY}", false),
BONDING("bonding", false);
CGMS("cgms-screen", false);
}

View File

@@ -1,99 +0,0 @@
package no.nordicsemi.android.nrftoolbox
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import no.nordicsemi.android.bps.repository.BPS_SERVICE_UUID
import no.nordicsemi.android.cgms.repository.CGMS_UUID
import no.nordicsemi.android.csc.service.CYCLING_SPEED_AND_CADENCE_SERVICE_UUID
import no.nordicsemi.android.gls.repository.GLS_SERVICE_UUID
import no.nordicsemi.android.hrs.service.HR_SERVICE_UUID
import no.nordicsemi.android.hts.service.HT_SERVICE_UUID
import no.nordicsemi.android.permission.tools.NordicBleScanner
import no.nordicsemi.android.permission.tools.PermissionHelper
import no.nordicsemi.android.permission.tools.ScannerStatus
import no.nordicsemi.android.permission.viewmodel.BluetoothPermissionState
import no.nordicsemi.android.prx.service.IMMEDIATE_ALERT_SERVICE_UUID
import no.nordicsemi.android.rscs.service.RSCS_SERVICE_UUID
import no.nordicsemi.android.service.SelectedBluetoothDeviceHolder
import javax.inject.Inject
@HiltViewModel
class NavigationViewModel @Inject constructor(
private val bleScanner: NordicBleScanner,
private val permissionHelper: PermissionHelper,
private val selectedDevice: SelectedBluetoothDeviceHolder
): ViewModel() {
val state= MutableStateFlow(NavigationTarget(NavDestination.HOME))
private var targetDestination = NavDestination.HOME
fun navigate(destination: NavDestination) {
targetDestination = destination
navigateToNextScreen()
}
fun navigateUp() {
targetDestination = NavDestination.HOME
state.value = NavigationTarget(NavDestination.HOME)
}
fun finish() {
if (state.value.destination != targetDestination) {
navigateToNextScreen()
}
}
private fun getBluetoothState(): BluetoothPermissionState {
return if (!permissionHelper.isRequiredPermissionGranted()) {
BluetoothPermissionState.PERMISSION_REQUIRED
} else when (bleScanner.getBluetoothStatus()) {
ScannerStatus.NOT_AVAILABLE -> BluetoothPermissionState.BLUETOOTH_NOT_AVAILABLE
ScannerStatus.DISABLED -> BluetoothPermissionState.BLUETOOTH_NOT_ENABLED
ScannerStatus.ENABLED -> selectedDevice.device?.let {
if (targetDestination.pairingRequired && selectedDevice.isBondingRequired()) {
BluetoothPermissionState.BONDING_REQUIRED
} else {
BluetoothPermissionState.READY
}
} ?: BluetoothPermissionState.DEVICE_NOT_CONNECTED
}
}
private fun navigateToNextScreen() {
val destination = when (getBluetoothState()) {
BluetoothPermissionState.PERMISSION_REQUIRED -> NavDestination.REQUEST_PERMISSION
BluetoothPermissionState.BLUETOOTH_NOT_AVAILABLE -> NavDestination.BLUETOOTH_NOT_AVAILABLE
BluetoothPermissionState.BLUETOOTH_NOT_ENABLED -> NavDestination.BLUETOOTH_NOT_ENABLED
BluetoothPermissionState.DEVICE_NOT_CONNECTED -> NavDestination.DEVICE_NOT_CONNECTED
BluetoothPermissionState.BONDING_REQUIRED -> NavDestination.BONDING
BluetoothPermissionState.READY -> targetDestination
}
val args = if (destination == NavDestination.DEVICE_NOT_CONNECTED) {
createServiceId(targetDestination)
} else {
null
}
state.tryEmit(NavigationTarget(destination, args))
}
private fun createServiceId(destination: NavDestination): String {
return when (destination) {
NavDestination.CSC -> CYCLING_SPEED_AND_CADENCE_SERVICE_UUID.toString()
NavDestination.HRS -> HR_SERVICE_UUID.toString()
NavDestination.HTS -> HT_SERVICE_UUID.toString()
NavDestination.GLS -> GLS_SERVICE_UUID.toString()
NavDestination.BPS -> BPS_SERVICE_UUID.toString()
NavDestination.RSCS -> RSCS_SERVICE_UUID.toString()
NavDestination.PRX -> IMMEDIATE_ALERT_SERVICE_UUID.toString()
NavDestination.CGMS -> CGMS_UUID.toString()
NavDestination.HOME,
NavDestination.REQUEST_PERMISSION,
NavDestination.BLUETOOTH_NOT_AVAILABLE,
NavDestination.BLUETOOTH_NOT_ENABLED,
NavDestination.BONDING,
NavDestination.DEVICE_NOT_CONNECTED -> throw IllegalArgumentException("There is no serivce related to the destination: $destination")
}
}
}