'How to share HiltViewModel between HorizontalPager and Parent Composable screen that holds that pager?

I have a SignupScreen that holds horizontal pager. The pager has 3 tabs, Register Otp Questions . Those three tabs also update and listen to data from its parent screen's SignupViewModel These are my code :

@Composable
fun SignupScreen(
    navController: NavController
) {
    SignupView(navController = navController)
}

@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupView(
    navController: NavController
) {

    val vm: SignupViewModel = hiltViewModel()
    val signupUiState = vm.signupUiState.value
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    val pagerState = rememberPagerState()

    val signupTabs = listOf(
        SignupPagerTabs.Register,
        SignupPagerTabs.Otp,
        SignupPagerTabs.Questions,
        )

    LaunchedEffect(key1 = true) {
        vm.signupUiEvent.collect {
            when (it) {
                SignupUiEvent.GoNextPage -> {

                }
                SignupUiEvent.GoPreviousPage -> {

                }
                SignupUiEvent.NavigateToHomeScreen -> {
                    navController.popBackStack(AppDestination.Home.route, inclusive = true)
                    navController.navigate(Routes.HOME_ROUTE)
                }
                SignupUiEvent.Popup -> {
                    navController.popBackStack()
                }
                is SignupUiEvent.ShowSnackBar -> {
                    scaffoldState.snackbarHostState.showSnackbar(
                        message = it.message
                    )
                }
            }
        }
    }

    Scaffold(
        scaffoldState = scaffoldState,
        topBar = {
            TopBar2(
                navIcon = painterResource(id = R.drawable.ic_back),
                title = stringResource(id = R.string.top_bar_signup),
                onNavIconClicked = {
                    vm.onEvent(SignupUiAction.ClickPreviousPage)
                }
            )
        },
        content = {
            SignupContentView(
                tabs = signupTabs,
                pagerState = pagerState
            )
        }
    )
}

@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupContentView(
    tabs: List<SignupPagerTabs>,
    pagerState: PagerState
) {

    Column(modifier = Modifier.fillMaxSize()) {

        PagerIndicator(tabs.size, pagerState.currentPage)
        
        HorizontalPager(
            count = tabs.size,
            state = pagerState
        ) { index ->
            tabs[index].screenToLoad()
        }
    }
}

This is my ViewModel.

@HiltViewModel
    class SignupViewModel @Inject constructor(
        private val signupUseCase: SignupUseCase
    ) : ViewModel() {
    
        private val _signupUiState: MutableState<SignupUiState> = mutableStateOf(SignupUiState())
        val signupUiState: State<SignupUiState> get() = _signupUiState
    
        private val _signupUiEvent = MutableSharedFlow<SignupUiEvent>()
        val signupUiEvent = _signupUiEvent.asSharedFlow()
    
        private val currentPage = signupUiState.value.currentPage
        private val completedPage = signupUiState.value.completedPage
    
        fun onEvent(action: SignupUiAction) {
            when (action) {
                is SignupUiAction.ChangeFullName -> {
                    _signupUiState.value = signupUiState.value.copy(
                        fullName = action.name
                    )
                }
                is SignupUiAction.ChangePassword -> {
                    _signupUiState.value = signupUiState.value.copy(
                        password = action.password
                    )
    
                }
                is SignupUiAction.ChangePasswordConfirm -> {
                    _signupUiState.value = signupUiState.value.copy(
                        passwordConfirm = action.passwordConfirm
                    )
                }
                is SignupUiAction.ChangePhoneNumber -> {
                    _signupUiState.value = signupUiState.value.copy(
                        phoneNumber = action.phone
                    )
                }
                is SignupUiAction.ChangeRegion -> {
                    _signupUiState.value = signupUiState.value.copy(
                        region = action.country
                    )
                }
                SignupUiAction.ClickNextPage -> {
                    when (currentPage) {
                        SignupPage.REGISTER_PAGE -> {
                            _signupUiState.value = signupUiState.value.copy(
                                currentPage = currentPage + 1
                            )
                        }
                        SignupPage.OTP_PAGE -> {
                            _signupUiState.value = signupUiState.value.copy(
                                currentPage = currentPage + 1
                            )
                        }
                        SignupPage.SECURITY_QUESTION_PAGE -> {
                            //do request to server
                            viewModelScope.launch {
                                _signupUiEvent.emit(
                                    SignupUiEvent.NavigateToHomeScreen
                                )
                            }
                        }
                    }
    
                }
                SignupUiAction.ClickPreviousPage -> {
                    when (currentPage) {
                        SignupPage.REGISTER_PAGE -> {
                            viewModelScope.launch {
                                _signupUiEvent.emit(
                                    SignupUiEvent.Popup
                                )
                            }
    
                        }
                        SignupPage.OTP_PAGE -> {
                            _signupUiState.value = signupUiState.value.copy(
                                currentPage = currentPage - 1
                            )
                        }
                        SignupPage.SECURITY_QUESTION_PAGE -> {
                            _signupUiState.value = signupUiState.value.copy(
                                currentPage = currentPage - 1
                            )
                        }
                    }
                }
                SignupUiAction.ClickStart -> {
    
                }
                SignupUiAction.ClearFullName -> {
                    _signupUiState.value = signupUiState.value.copy(
                        fullName = ""
                    )
                }
                SignupUiAction.ClearPassword -> {
                    _signupUiState.value = signupUiState.value.copy(
                        password = ""
                    )
                }
                SignupUiAction.ClearPasswordConfirm -> {
                    _signupUiState.value = signupUiState.value.copy(
                        passwordConfirm = ""
                    )
                }
                SignupUiAction.ClearPhoneNumber -> {
                    _signupUiState.value = signupUiState.value.copy(
                        phoneNumber = ""
                    )
                }
                is SignupUiAction.ChangeOtpCode -> {
                    _signupUiState.value = signupUiState.value.copy(
                        otpCode = action.code
                    )
                }
                SignupUiAction.ClickResend -> {
                    //todo resend logic
                    viewModelScope.launch {
    
                    }
                }
            }
        }
    
        private fun signup() {
            val requestBody = SignupRequest(
                countryCodeId = signupUiState.value.region.id,
                name = signupUiState.value.fullName,
                mobile = signupUiState.value.phoneNumber,
                password = signupUiState.value.password,
                securityQuestionUsage = listOf()
            )
            viewModelScope.launch {
                signupUseCase(body = requestBody).collect {
                    when (it) {
                        is Resource.ErrorEvent -> {
                            _signupUiEvent.emit(
                                SignupUiEvent.ShowSnackBar(
                                    message =
                                    it.message ?: "Error"
                                )
                            )
                        }
                        is Resource.LoadingEvent -> {
                            _signupUiState.value = signupUiState.value.copy(
                                isLoading = true,
                                loadingMessageType = SignupStatus.SECURITY_QUESTION_PAGE
                            )
                        }
                        is Resource.SuccessEvent -> {
    
                        }
                    }
                }
            }
        }
    }

This is my Pager Tabs.

object SignupPage {
    const val REGISTER_PAGE = 0
    const val OTP_PAGE = 1
    const val SECURITY_QUESTION_PAGE = 2
}

enum class SignupStatus(val index: Int) {
    REGISTER_PAGE(index = SignupPage.REGISTER_PAGE),
    OTP_PAGE(index = SignupPage.OTP_PAGE),
    SECURITY_QUESTION_PAGE(index = SignupPage.SECURITY_QUESTION_PAGE),
}

sealed class SignupPagerTabs(
    val index: Int,
    val screenToLoad: @Composable () -> Unit,
) {
    object Register : SignupPagerTabs(
        index = 0,
        screenToLoad = {
            RegisterScreen(

            )
        }
    )

    object Otp : SignupPagerTabs(
        index = 1,
        screenToLoad = {
            OtpVerificationSignupScreen(

            )
        }
    )

    object Questions : SignupPagerTabs(
        index = 2,
        screenToLoad = {
            SecurityQuestionChooseScreen(

            )
        }
    )
}

In Register Otp Question Screens, I want to access the SignupViewModel.

Please Help Me.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source