Home > OS >  Jetpack Compose How to access dependency injected view model from everywhere without sending the vie
Jetpack Compose How to access dependency injected view model from everywhere without sending the vie

Time:09-17

I am currently developing a customized PopupView to behave like ModalBottomSheetLayout but more manageable and advanced. I want to be able to access this PopupManager class from anywhere without passing it as a parameter to other functions so that the structure I will create is more robust and more manageable. Here is the code:

@HiltViewModel
class PopupManager @Inject constructor(
    initialValue: PopupViewStateValue = PopupViewStateValue.Hidden
) : ViewModel() {
    val popupViewState = mutableStateOf(initialValue)
}

class ActivityHelpCenterCompose : ComponentActivity() {

    private val popUpManager: PopupManager by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            Box {

                HelpCenterPageView(
                    modifier = Modifier.zIndex(1f),
                    popupManager = popUpManager
                )

                PopupView(
                    popupManager = popUpManager,
                    modifier = Modifier.zIndex(2f)
                ) {

                }

            }

        }

    }

}

As it can be seen, I am sending popup manager as a parameter to the composable functions which are HelpCenterPageView and PopupView and that is exactly what I want to avoid.

This is the code for the HelpCenterPageView and I am opening my popupview in the extension function that I wrote which is popupManager.expand in the NavigationBarView clickable.

@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun HelpCenterPageView(
    popupManager: PopupManager,
    modifier: Modifier?,
) {

    Scaffold(
        modifier = modifier ?: Modifier,
        topBar = {
        NavigationBarView(
            title = stringResource(id = R.string.profile_page_help),
            modifier = Modifier.clickable {
                popupManager.expand()
            }
        )
    }) {

        Column(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(rememberScrollState())
        ) {

            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 22.dp, start = 22.dp, end = 22.dp)
                    .background(
                        color = colorResource(
                            id = R.color.fz_background
                        )
                    )
            ) {

                TextView(
                    text = stringResource(id = R.string.help_page_training_center),
                    font = Font.F17SB.textStyle,
                    color = colorResource(id = R.color.fz_dark_colour),
                    modifier = null
                )

                Column(modifier = Modifier.padding(top = 22.dp)) {

                    UpComingTrainingView(
                        training = Trainings(),
                        onShareClick = { },
                        onWatchClick = { },
                        modifier = null
                    )

                    Spacer(modifier = Modifier.padding(top = 22.dp))

                    HelpCenterSectionView(
                        sectionTitle = stringResource(id = R.string.online_zoom_training_page_next_trainings),
                        sectionImage = painterResource(id = R.drawable.online_educations_icon),
                        modifier = null
                    ) {}

                    Spacer(modifier = Modifier.padding(top = 22.dp))

                    HelpCenterSectionView(
                        sectionTitle = stringResource(id = R.string.online_zoom_training_page_previous_trainings),
                        sectionImage = painterResource(id = R.drawable.education_records_history_property),
                        modifier = null
                    ) {

                    }

                }

            }

            Spacer(
                modifier = Modifier
                    .padding(top = 22.dp)
                    .fillMaxWidth()
                    .height(10.dp)
                    .background(
                        color = colorResource(
                            id = R.color.fz_cool_gray02
                        )
                    )
            )

            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 22.dp, start = 22.dp, end = 22.dp)
            ) {

                TextView(
                    text = stringResource(id = R.string.profile_page_help),
                    font = Font.F17SB.textStyle,
                    color = colorResource(id = R.color.fz_dark_colour),
                    modifier = null
                )

                Spacer(modifier = Modifier.padding(top = 22.dp))

                HelpCenterSectionView(
                    sectionTitle = stringResource(id = R.string.help_page_live_desk),
                    sectionImage = painterResource(id = R.drawable.settings_whatsapp_icon),
                    modifier = null
                ) {

                }

                Spacer(modifier = Modifier.padding(top = 22.dp))

                HelpCenterSectionView(
                    sectionTitle = stringResource(id = R.string.help_page_feature),
                    sectionImage = painterResource(id = R.drawable.request_suggestion_icon),
                    modifier = null
                ) {

                }

                Spacer(modifier = Modifier.padding(top = 22.dp))

                HelpCenterSectionView(
                    sectionTitle = stringResource(id = R.string.help_page_bug),
                    sectionImage = painterResource(id = R.drawable.bug_report_icon),
                    modifier = null
                ) {

                }

                Spacer(modifier = Modifier.padding(top = 22.dp))

                HelpCenterSectionView(
                    sectionTitle = stringResource(id = R.string.help_page_call_center),
                    sectionImage = painterResource(id = R.drawable.settings_call_property),
                    modifier = null
                ) {

                }

            }

            Column(
                modifier = Modifier
                    .padding(
                        top = 42.dp,
                        bottom = 42.dp,
                        start = 22.dp,
                        end = 22.dp
                    )
                    .fillMaxWidth(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {

                TextView(
                    text = "${R.string.help_page_version.localized()} ${BuildConfig.VERSION_NAME} ( ${BuildConfig.VERSION_CODE} )",
                    font = Font.F15SB.textStyle,
                    color = colorResource(id = R.color.fz_dark_colour),
                    modifier = null
                )

            }

        }

    }

}

Also, there are cases that I will need to open different popups in the same page for example 5 different popups. Do I have to assign different variables for each of the popups or is there a more generic way to handle this ?

CodePudding user response:

You can pass a Unit as a parameter.

@Composable
fun HelpCenterPageView(
    modifier: Modifier = Modifier, 
    onClick: () -> Unit, 
)

and

modifier = Modifier.clickable {
    onClick() 
}

and then

HelpCenterPageView(
    modifier = Modifier.zIndex(1f),
){
    popupManager.expand() 
} 

CodePudding user response:

You can use CompositionLocalProvider for this. This is a generic example.

  1. Create Composition local with type of viewmodel.This will be holding viewmodel instance

    val MyCompositionLocal = staticCompositionLocalOf<MyViewModel> {
         error("No  Viewmodel provided")
     }
    
  2. In fragment /activity, you should wrap composable view with CompositionLocalProvider and provide the viewmodel instance to the view tree.

    class MyFragment : Fragment() {
    
     private val viewModel by viewModels<MyViewModel>()
    
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
         savedInstanceState: Bundle?
     ): View {
         return ComposeView(requireContext()).apply {
             setContent {
                 CompositionLocalProvider(MyCompositionLocal provides viewModel) {
                     MyComposeScreen()
                 }
             }
         }
     }
    }
    
  1. In any composables in activity/fragment tree, you get viewmodel instance using CompositionLocal.current

     @Composable
     fun MyComposeScreen() {
     val viewmodel =  MyCompositionLocal.current //This will give viewmodel instance. 
     }
    
  • Related