Switch to new navigation.

This commit is contained in:
Sylwester Zieliński
2022-01-19 14:28:42 +01:00
parent 2c304e80f6
commit 2dd3e4bec3
50 changed files with 295 additions and 424 deletions

View File

@@ -0,0 +1,44 @@
package no.nordicsemi.android.nrftoolbox
import no.nordicsemi.android.bps.repository.BPS_SERVICE_UUID
import no.nordicsemi.android.bps.view.BPSScreen
import no.nordicsemi.android.cgms.repository.CGMS_SERVICE_UUID
import no.nordicsemi.android.cgms.view.CGMScreen
import no.nordicsemi.android.csc.repository.CSC_SERVICE_UUID
import no.nordicsemi.android.csc.view.CSCScreen
import no.nordicsemi.android.gls.repository.GLS_SERVICE_UUID
import no.nordicsemi.android.gls.view.GLSScreen
import no.nordicsemi.android.hrs.service.HRS_SERVICE_UUID
import no.nordicsemi.android.hrs.view.HRSScreen
import no.nordicsemi.android.hts.repository.HTS_SERVICE_UUID
import no.nordicsemi.android.hts.view.HTSScreen
import no.nordicsemi.android.navigation.ComposeDestination
import no.nordicsemi.android.navigation.ComposeDestinations
import no.nordicsemi.android.prx.service.PRX_SERVICE_UUID
import no.nordicsemi.android.prx.view.PRXScreen
import no.nordicsemi.android.rscs.service.RSCS_SERVICE_UUID
import no.nordicsemi.android.rscs.view.RSCSScreen
import no.nordicsemi.android.uart.repository.UART_SERVICE_UUID
import no.nordicsemi.android.uart.view.UARTScreen
import no.nordicsemi.ui.scanner.navigation.view.FindDeviceScreen
import java.util.*
val HomeDestinations = ComposeDestinations(HomeDestination.values().map { it.destination })
val ProfileDestinations = ComposeDestinations(ProfileDestination.values().map { it.destination })
enum class HomeDestination(val destination: ComposeDestination) {
HOME(ComposeDestination("home-destination") { HomeScreen() }),
SCANNER(ComposeDestination("scanner-destination") { FindDeviceScreen() });
}
enum class ProfileDestination(val destination: ComposeDestination, val uuid: UUID) {
CSC(ComposeDestination("csc-destination") { CSCScreen() }, CSC_SERVICE_UUID),
HRS(ComposeDestination("hrs-destination") { HRSScreen() }, HRS_SERVICE_UUID),
HTS(ComposeDestination("hts-destination") { HTSScreen() }, HTS_SERVICE_UUID),
GLS(ComposeDestination("gls-destination") { GLSScreen() }, GLS_SERVICE_UUID),
BPS(ComposeDestination("bps-destination") { BPSScreen() }, BPS_SERVICE_UUID),
PRX(ComposeDestination("prx-destination") { PRXScreen() }, PRX_SERVICE_UUID),
RSCS(ComposeDestination("rscs-destination") { RSCSScreen() }, RSCS_SERVICE_UUID),
CGMS(ComposeDestination("cgms-destination") { CGMScreen() }, CGMS_SERVICE_UUID),
UART(ComposeDestination("uart-destination") { UARTScreen() }, UART_SERVICE_UUID);
}

View File

@@ -1,98 +0,0 @@
package no.nordicsemi.android.nrftoolbox
import android.app.Activity
import android.os.ParcelUuid
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
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.prx.view.PRXScreen
import no.nordicsemi.android.rscs.view.RSCSScreen
import no.nordicsemi.android.uart.view.UARTScreen
import no.nordicsemi.ui.scanner.navigation.view.FindDeviceScreen
import no.nordicsemi.ui.scanner.ui.exhaustive
@Composable
internal fun HomeScreen() {
val navController = rememberNavController()
val viewModel: HomeViewModel = hiltViewModel()
val activity = LocalContext.current as Activity
BackHandler {
if (navController.currentDestination?.navigatorName != NavigationId.HOME.id) {
navController.popBackStack()
} else {
activity.finish()
}
}
val destination = viewModel.destination.collectAsState()
val navigateUp = { viewModel.navigateUp() }
NavHost(
navController = navController,
startDestination = NavigationId.HOME.id
) {
composable(NavigationId.HOME.id) {
HomeView(viewModel)
}
composable(NavigationId.SCANNER.id) {
val profile = viewModel.profile!!
FindDeviceScreen(ParcelUuid(profile.uuid)) {
viewModel.onScannerFlowResult(it)
}
}
composable(NavigationId.CSC.id) {
CSCScreen(navigateUp)
}
composable(NavigationId.HRS.id) {
HRSScreen(navigateUp)
}
composable(NavigationId.HTS.id) {
HTSScreen(navigateUp)
}
composable(NavigationId.GLS.id) {
GLSScreen(navigateUp)
}
composable(NavigationId.BPS.id) {
BPSScreen(navigateUp)
}
composable(NavigationId.PRX.id) {
PRXScreen(navigateUp)
}
composable(NavigationId.RSCS.id) {
RSCSScreen(navigateUp)
}
composable(NavigationId.CGMS.id) {
CGMScreen(navigateUp)
}
composable(NavigationId.UART.id) {
UARTScreen(navigateUp)
}
}
val context = LocalContext.current as Activity
LaunchedEffect(destination.value) {
when (val destination = destination.value) {
FinishDestination -> context.finish()
HomeDestination -> navController.navigateUp()
is ProfileDestination -> {
navController.navigateUp()
navController.navigate(destination.id.id)
}
is ScannerDestination -> navController.navigate(destination.id.id)
}.exhaustive
}
}

View File

@@ -18,10 +18,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import no.nordicsemi.android.theme.view.CloseIconAppBar
@Composable
fun HomeView(viewModel: HomeViewModel) {
fun HomeScreen() {
val viewModel: HomeViewModel = hiltViewModel()
Column {
val context = LocalContext.current
CloseIconAppBar(stringResource(id = R.string.app_name)) {
@@ -43,12 +46,12 @@ fun HomeView(viewModel: HomeViewModel) {
DoubleSection(
leftView = {
FeatureButton(R.drawable.ic_csc, R.string.csc_module, R.string.csc_module_full) {
viewModel.openProfile(Profile.CSC)
viewModel.openProfile(ProfileDestination.CSC)
}
},
rightView = {
FeatureButton(R.drawable.ic_hrs, R.string.hrs_module, R.string.hrs_module_full) {
viewModel.openProfile(Profile.HRS)
viewModel.openProfile(ProfileDestination.HRS)
}
}
)
@@ -58,12 +61,12 @@ fun HomeView(viewModel: HomeViewModel) {
DoubleSection(
leftView = {
FeatureButton(R.drawable.ic_gls, R.string.gls_module, R.string.gls_module_full) {
viewModel.openProfile(Profile.GLS)
viewModel.openProfile(ProfileDestination.GLS)
}
},
rightView = {
FeatureButton(R.drawable.ic_hts, R.string.hts_module, R.string.hts_module_full) {
viewModel.openProfile(Profile.HTS)
viewModel.openProfile(ProfileDestination.HTS)
}
}
)
@@ -73,12 +76,12 @@ fun HomeView(viewModel: HomeViewModel) {
DoubleSection(
leftView = {
FeatureButton(R.drawable.ic_bps, R.string.bps_module, R.string.bps_module_full) {
viewModel.openProfile(Profile.BPS)
viewModel.openProfile(ProfileDestination.BPS)
}
},
rightView = {
FeatureButton(R.drawable.ic_rscs, R.string.rscs_module, R.string.rscs_module_full) {
viewModel.openProfile(Profile.RSCS)
viewModel.openProfile(ProfileDestination.RSCS)
}
}
)
@@ -88,12 +91,12 @@ fun HomeView(viewModel: HomeViewModel) {
DoubleSection(
leftView = {
FeatureButton(R.drawable.ic_prx, R.string.prx_module, R.string.prx_module_full) {
viewModel.openProfile(Profile.PRX)
viewModel.openProfile(ProfileDestination.PRX)
}
},
rightView = {
FeatureButton(R.drawable.ic_cgm, R.string.cgm_module, R.string.cgm_module_full) {
viewModel.openProfile(Profile.CGMS)
viewModel.openProfile(ProfileDestination.CGMS)
}
}
)
@@ -101,7 +104,7 @@ fun HomeView(viewModel: HomeViewModel) {
Spacer(modifier = Modifier.height(16.dp))
FeatureButton(R.drawable.ic_uart, R.string.uart_module, R.string.uart_module_full) {
viewModel.openProfile(Profile.UART)
viewModel.openProfile(ProfileDestination.UART)
}
Spacer(modifier = Modifier.height(16.dp))

View File

@@ -2,50 +2,22 @@ package no.nordicsemi.android.nrftoolbox
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import no.nordicsemi.android.navigation.ForwardDestination
import no.nordicsemi.android.navigation.NavigationManager
import no.nordicsemi.android.navigation.UUIDArgument
import no.nordicsemi.android.service.SelectedBluetoothDeviceHolder
import no.nordicsemi.ui.scanner.navigation.view.FindDeviceCloseResult
import no.nordicsemi.ui.scanner.navigation.view.FindDeviceFlowStatus
import no.nordicsemi.ui.scanner.navigation.view.FindDeviceSuccessResult
import no.nordicsemi.ui.scanner.ui.exhaustive
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val deviceHolder: SelectedBluetoothDeviceHolder
private val deviceHolder: SelectedBluetoothDeviceHolder,
private val navigationManager: NavigationManager
) : ViewModel() {
private val _destination = MutableStateFlow<NavDestination>(HomeDestination)
val destination = _destination.asStateFlow()
var profile: Profile? = null //to pass argument between nav destinations
fun onScannerFlowResult(status: FindDeviceFlowStatus) {
when (status) {
FindDeviceCloseResult -> navigateUp()
is FindDeviceSuccessResult -> onDeviceSelected(status)
}.exhaustive
}
fun openProfile(profile: Profile) {
this.profile = profile
_destination.value = ScannerDestination(profile)
}
fun navigateUp() {
val currentDestination = _destination.value
_destination.value = when (currentDestination) {
FinishDestination -> FinishDestination
HomeDestination -> FinishDestination
is ProfileDestination -> HomeDestination
is ScannerDestination -> HomeDestination
}
}
private fun onDeviceSelected(result: FindDeviceSuccessResult) {
val profile = requireNotNull(profile)
deviceHolder.attachDevice(result.device)
_destination.value = ProfileDestination(profile.toNavigationId(), profile.isPairingRequired)
fun openProfile(destination: ProfileDestination) {
navigationManager.navigateTo(
ForwardDestination(destination.destination.id),
UUIDArgument(destination.uuid)
)
}
}

View File

@@ -9,6 +9,8 @@ import androidx.compose.ui.Modifier
import dagger.hilt.android.AndroidEntryPoint
import no.nordicsemi.android.material.you.NordicActivity
import no.nordicsemi.android.material.you.NordicTheme
import no.nordicsemi.android.navigation.NavigationView
import no.nordicsemi.ui.scanner.ScannerDestinations
@AndroidEntryPoint
class MainActivity : NordicActivity() {
@@ -22,7 +24,9 @@ class MainActivity : NordicActivity() {
color = MaterialTheme.colorScheme.surface,
modifier = Modifier.fillMaxSize()
) {
HomeScreen()
NavigationView(
HomeDestinations + ProfileDestinations + ScannerDestinations
)
}
}
}

View File

@@ -1,22 +0,0 @@
package no.nordicsemi.android.nrftoolbox
sealed class NavDestination
object FinishDestination : NavDestination()
sealed class ForwardDestination : NavDestination() {
abstract val id: NavigationId
}
object HomeDestination : ForwardDestination() {
override val id: NavigationId = NavigationId.HOME
}
data class ScannerDestination(val profile: Profile) : ForwardDestination() {
override val id: NavigationId = NavigationId.SCANNER
}
data class ProfileDestination(
override val id: NavigationId,
val isPairingRequired: Boolean
) : ForwardDestination()

View File

@@ -1,55 +0,0 @@
package no.nordicsemi.android.nrftoolbox
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import no.nordicsemi.android.bps.repository.BPS_SERVICE_UUID
import no.nordicsemi.android.cgms.repository.CGMS_SERVICE_UUID
import no.nordicsemi.android.csc.repository.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.repository.HT_SERVICE_UUID
import no.nordicsemi.android.prx.service.PRX_SERVICE_UUID
import no.nordicsemi.android.rscs.service.RSCS_SERVICE_UUID
import no.nordicsemi.android.uart.repository.UART_SERVICE_UUID
import java.util.*
enum class NavigationId(val id: String) {
HOME("home-screen"),
SCANNER("scanner-screen"),
CSC("csc-screen"),
HRS("hrs-screen"),
HTS("hts-screen"),
GLS("gls-screen"),
BPS("bps-screen"),
PRX("prx-screen"),
RSCS("rscs-screen"),
CGMS("cgms-screen"),
UART("uart-screen");
}
@Parcelize
enum class Profile(val uuid: UUID, val isPairingRequired: Boolean) : Parcelable {
CSC(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID, false),
HRS(HR_SERVICE_UUID, false),
HTS(HT_SERVICE_UUID, false),
GLS(GLS_SERVICE_UUID, true),
BPS(BPS_SERVICE_UUID, false),
PRX(PRX_SERVICE_UUID, true),
RSCS(RSCS_SERVICE_UUID, false),
CGMS(CGMS_SERVICE_UUID, false),
UART(UART_SERVICE_UUID, false);
}
fun Profile.toNavigationId(): NavigationId {
return when (this) {
Profile.CSC -> NavigationId.CSC
Profile.HRS -> NavigationId.HRS
Profile.HTS -> NavigationId.HTS
Profile.GLS -> NavigationId.GLS
Profile.BPS -> NavigationId.BPS
Profile.PRX -> NavigationId.PRX
Profile.RSCS -> NavigationId.RSCS
Profile.CGMS -> NavigationId.CGMS
Profile.UART -> NavigationId.UART
}
}