I think I got navigation working?
This commit is contained in:
parent
db7264c3b9
commit
dd0cc9ba2f
10 changed files with 153 additions and 45 deletions
|
@ -4,36 +4,71 @@ import android.os.Bundle
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.navigation
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import ing.bikeshedengineer.debtpirate.theme.DebtPirateTheme
|
||||
import ing.bikeshedengineer.debtpirate.auth.presentation.login.LoginScreen
|
||||
import ing.bikeshedengineer.debtpirate.auth.presentation.register.RegistrationScreen
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
object LoginRoute
|
||||
|
||||
@Serializable
|
||||
object RegistrationRoute
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Destination
|
||||
import ing.bikeshedengineer.debtpirate.navigation.NavigationAction
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Navigator
|
||||
import ing.bikeshedengineer.debtpirate.theme.DebtPirateTheme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
@Inject
|
||||
lateinit var navigator: Navigator
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
|
||||
setContent {
|
||||
val navController = rememberNavController()
|
||||
|
||||
ObserveAsEvents(navigator.navigationActions) { action ->
|
||||
when (action) {
|
||||
is NavigationAction.Navigate -> {
|
||||
navController.navigate(action.destination) {
|
||||
action.navOptions(this)
|
||||
}
|
||||
}
|
||||
NavigationAction.NavigateUp -> {
|
||||
navController.navigateUp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DebtPirateTheme {
|
||||
NavHost(navController = navController, startDestination = LoginRoute) {
|
||||
composable<LoginRoute>() { LoginScreen(navController = navController) }
|
||||
composable<RegistrationRoute>() { RegistrationScreen() }
|
||||
NavHost(navController = navController, startDestination = Destination.AuthGraph) {
|
||||
navigation<Destination.AuthGraph>(startDestination = Destination.LoginScreen) {
|
||||
composable<Destination.LoginScreen>() { LoginScreen(navController = navController) }
|
||||
composable<Destination.RegistrationScreen>() { RegistrationScreen() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T> ObserveAsEvents(flow: Flow<T>, onEvent: (T) -> Unit) {
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
LaunchedEffect(lifecycleOwner.lifecycle) {
|
||||
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
flow.collect(onEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,31 +3,31 @@ package ing.bikeshedengineer.debtpirate.auth.di
|
|||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import dagger.hilt.android.components.ViewModelComponent
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.repository.AuthRepositoryImpl
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.SubmitLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.ValidateLoginCredentialsUseCase
|
||||
import retrofit2.Retrofit
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@InstallIn(ViewModelComponent::class)
|
||||
object AuthDiModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ViewModelScoped
|
||||
fun provideAuthRepository(httpClient: Retrofit): AuthRepository {
|
||||
return AuthRepositoryImpl(httpClient)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ViewModelScoped
|
||||
fun provideSubmitLoginCredentialsUseCase(authRepository: AuthRepository): SubmitLoginCredentialsUseCase {
|
||||
return SubmitLoginCredentialsUseCase(authRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@ViewModelScoped
|
||||
fun provideValidateLoginCredentialsUseCase() = ValidateLoginCredentialsUseCase()
|
||||
}
|
|
@ -3,10 +3,10 @@ package ing.bikeshedengineer.debtpirate.auth.domain.repository
|
|||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.endpoint.AuthEndpoint
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginRequest
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.model.AuthLoginResponse
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.data.remote.ApiResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.Retrofit
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package ing.bikeshedengineer.debtpirate.auth.navigation
|
||||
|
||||
sealed class AuthNavigationEvent {
|
||||
object NavigateToRegistrationScreen : AuthNavigationEvent()
|
||||
object NavigateToLoginScreen : AuthNavigationEvent()
|
||||
}
|
|
@ -25,7 +25,6 @@ import androidx.compose.material3.OutlinedTextField
|
|||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -42,8 +41,6 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavController
|
||||
import ing.bikeshedengineer.debtpirate.R
|
||||
import ing.bikeshedengineer.debtpirate.app.host.RegistrationRoute
|
||||
import ing.bikeshedengineer.debtpirate.auth.navigation.AuthNavigationEvent
|
||||
|
||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||
@Composable
|
||||
|
@ -51,17 +48,17 @@ fun LoginScreen(
|
|||
navController: NavController,
|
||||
viewModel: LoginScreenViewModel = hiltViewModel<LoginScreenViewModel>()
|
||||
) {
|
||||
LaunchedEffect(viewModel.navigationEvent) {
|
||||
viewModel.navigationEvent.collect { event ->
|
||||
when (event) {
|
||||
is AuthNavigationEvent.NavigateToRegistrationScreen -> {
|
||||
navController.navigate(RegistrationRoute)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// LaunchedEffect(viewModel.navigationEvent) {
|
||||
// viewModel.navigationEvent.collect { event ->
|
||||
// when (event) {
|
||||
// is AuthNavigationEvent.NavigateToRegistrationScreen -> {
|
||||
// navController.navigate(RegistrationRoute)
|
||||
// }
|
||||
//
|
||||
// else -> {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
|
|
|
@ -5,13 +5,13 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import ing.bikeshedengineer.debtpirate.PrefsDataStore
|
||||
import ing.bikeshedengineer.debtpirate.app.host.RegistrationRoute
|
||||
import ing.bikeshedengineer.debtpirate.auth.data.remote.repository.AuthRepository
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.LoginCredentialsValidationResult
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.SubmitLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.auth.domain.usecase.ValidateLoginCredentialsUseCase
|
||||
import ing.bikeshedengineer.debtpirate.auth.navigation.AuthNavigationEvent
|
||||
import ing.bikeshedengineer.debtpirate.domain.model.Token
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Destination
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Navigator
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -37,6 +37,7 @@ enum class InvalidReason {
|
|||
|
||||
@HiltViewModel
|
||||
class LoginScreenViewModel @Inject constructor(
|
||||
private val navigator: Navigator,
|
||||
private val authRepository: AuthRepository,
|
||||
private val prefsStore: DataStore<PrefsDataStore>,
|
||||
private val submitLoginCredentials: SubmitLoginCredentialsUseCase,
|
||||
|
@ -44,9 +45,6 @@ class LoginScreenViewModel @Inject constructor(
|
|||
) : ViewModel() {
|
||||
// private val storeLoginData = StoreLoginDataUseCase(dataStore)
|
||||
|
||||
private val _navigationEvent = MutableStateFlow<AuthNavigationEvent?>(null)
|
||||
val navigationEvent = _navigationEvent.asStateFlow()
|
||||
|
||||
private val _emailAddress = MutableStateFlow("")
|
||||
val emailAddress = _emailAddress.asStateFlow()
|
||||
|
||||
|
@ -101,6 +99,8 @@ class LoginScreenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onRegisterButtonClick() {
|
||||
_navigationEvent.value = AuthNavigationEvent.NavigateToRegistrationScreen
|
||||
viewModelScope.launch {
|
||||
navigator.navigate(destination = Destination.RegistrationScreen)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package ing.bikeshedengineer.debtpirate.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Destination
|
||||
import ing.bikeshedengineer.debtpirate.navigation.Navigator
|
||||
import ing.bikeshedengineer.debtpirate.navigation.NavigatorImpl
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object NavigatorModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideNavigator(): Navigator = NavigatorImpl(startDestination = Destination.AuthGraph)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package ing.bikeshedengineer.debtpirate.navigation
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
sealed interface Destination {
|
||||
|
||||
/* Auth Destinations */
|
||||
@Serializable
|
||||
data object AuthGraph : Destination
|
||||
|
||||
@Serializable
|
||||
data object LoginScreen : Destination
|
||||
|
||||
@Serializable
|
||||
data object RegistrationScreen : Destination
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package ing.bikeshedengineer.debtpirate.navigation
|
||||
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
|
||||
sealed interface NavigationAction {
|
||||
|
||||
data class Navigate(
|
||||
val destination: Destination,
|
||||
val navOptions: NavOptionsBuilder.() -> Unit = {}
|
||||
) : NavigationAction
|
||||
|
||||
data object NavigateUp : NavigationAction
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package ing.bikeshedengineer.debtpirate.navigation
|
||||
|
||||
import androidx.navigation.NavOptionsBuilder
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
interface Navigator {
|
||||
val startDestination: Destination
|
||||
val navigationActions: Flow<NavigationAction>
|
||||
|
||||
suspend fun navigate(destination: Destination, navOptions: NavOptionsBuilder.() -> Unit = {})
|
||||
|
||||
suspend fun navigateUp()
|
||||
}
|
||||
|
||||
class NavigatorImpl(
|
||||
override val startDestination: Destination
|
||||
) : Navigator {
|
||||
private val _navigationActions = Channel<NavigationAction>()
|
||||
override val navigationActions = _navigationActions.receiveAsFlow()
|
||||
|
||||
override suspend fun navigate(
|
||||
destination: Destination,
|
||||
navOptions: NavOptionsBuilder.() -> Unit
|
||||
) {
|
||||
_navigationActions.send(NavigationAction.Navigate(destination, navOptions))
|
||||
}
|
||||
|
||||
override suspend fun navigateUp() {
|
||||
_navigationActions.send(NavigationAction.NavigateUp)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue