如何在 Horizo​​ntalPager 和包含该寻呼机的父可组合屏幕之间共享 HiltViewModel?

发布于 2025-01-10 15:18:16 字数 10102 浏览 0 评论 0原文

我有一个 SignupScreen 来容纳水平寻呼机。寻呼机有 3 个选项卡: Register Otp Questions 。这三个选项卡还更新并监听来自其父屏幕的 SignupViewModel 的数据 这些是我的代码:

@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()
        }
    }
}

这是我的 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 -> {
    
                        }
                    }
                }
            }
        }
    }

这是我的寻呼机选项卡。

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(

            )
        }
    )
}

Register Otp Question 屏幕中,我想访问 SignupViewModel

请帮助我。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文