Last active
June 27, 2024 16:18
-
-
Save anitaa1990/579077ba20e48054641368420a95324a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@OptIn(ExperimentalPermissionsApi::class) | |
@Composable | |
fun MainApp() { | |
// The theme of our app | |
ContactsAppTheme { | |
// Defines a default Scaffold with a default TopAppBar called `MainTopAppBar()` | |
Scaffold( | |
modifier = Modifier.fillMaxSize(), | |
topBar = { MainTopAppBar() } | |
) { innerPadding -> | |
/** | |
* Reacting to state changes is the core behavior of Compose. You will notice a couple new | |
* keywords that are compose related - remember & mutableStateOf. remember{} is a helper | |
* composable that calculates the value passed to it only during the first composition. It then | |
* returns the same value for every subsequent composition. Next, you can think of | |
* mutableStateOf as an observable value where updates to this variable will redraw all | |
* the composable functions that access it. We don't need to explicitly subscribe at all. Any | |
* composable that reads its value will be recomposed any time the value changes. This ensures | |
* that only the composables that depend on this will be redraw while the rest remain unchanged. | |
* This ensures efficiency and is a performance optimization. | |
*/ | |
// If true, then the permission has been granted so | |
// the main app content will be displayed | |
val showMainContent = remember { mutableStateOf(false) } | |
// If true, then the default permission has been denied so we | |
// we need to display a rationale dialog | |
val showRationale = remember { mutableStateOf(false) } | |
val permissionState = rememberPermissionState(Manifest.permission.READ_CONTACTS) | |
val requestPermissionLauncher = rememberLauncherForActivityResult( | |
ActivityResultContracts.RequestPermission() | |
) { isGranted -> showMainContent.value = isGranted } | |
when { | |
// request to read contacts permission was granted so we no longer need to | |
// display the rationale dialog | |
permissionState.status.isGranted -> { | |
showMainContent.value = true | |
showRationale.value = false | |
} | |
// request to read contacts permission was denied and permission is not granted | |
// so we need to display the rationale dialog | |
!permissionState.status.isGranted && permissionState.status.shouldShowRationale -> showRationale.value = true | |
else -> { | |
// request read contacts permission for the first time | |
LaunchedEffect(permissionState) { | |
requestPermissionLauncher.launch(Manifest.permission.READ_CONTACTS) | |
} | |
} | |
} | |
if (showRationale.value) { | |
val context = LocalContext.current | |
// display a rationale dialog by calling the `PermissionDialog` composable | |
PermissionDialog( | |
// open the settings page of the app to enable read contact permission | |
// when the ok button is clicked in the rationale dialog | |
onPermissionRequest = { | |
val intent = Intent( | |
Settings.ACTION_APPLICATION_DETAILS_SETTINGS, | |
Uri.fromParts("package", context.packageName, null) | |
) | |
context.startActivity(intent) | |
showRationale.value = false | |
}, | |
// rationale dialog dismiss button is clicked | |
onDismissRequest = { showRationale.value = false } | |
) | |
} | |
if(showMainContent.value) { | |
// Calls the MainAppContent() composable since the permission | |
// has been granted to access contacts. | |
PermissionGrantedScreen(Modifier.padding(innerPadding)) | |
} | |
} | |
} | |
} | |
@Composable | |
private fun PermissionGrantedScreen( | |
modifier: Modifier | |
) { | |
val viewModel: ContactsViewModel = hiltViewModel() | |
val state by viewModel.uiState.collectAsStateWithLifecycle( | |
lifecycleOwner = LocalLifecycleOwner.current | |
) | |
MainAppContent(modifier = modifier, state = state) | |
} | |
@OptIn(ExperimentalMaterial3Api::class) | |
@Composable | |
fun MainTopAppBar() { | |
TopAppBar( | |
colors = TopAppBarDefaults.topAppBarColors( | |
containerColor = MaterialTheme.colorScheme.primaryContainer, | |
titleContentColor = MaterialTheme.colorScheme.primary, | |
), | |
title = { | |
Text(text = stringResource(id = R.string.app_name)) | |
}, | |
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) | |
) | |
} | |
@Composable | |
fun MainAppContent( | |
modifier: Modifier = Modifier, | |
state: ContactUiState | |
) { | |
Box(modifier = modifier | |
.fillMaxSize() | |
) { | |
// the loader indicator | |
AnimatedVisibility(visible = state.loading) { | |
LinearProgressIndicator( | |
Modifier.fillMaxWidth() | |
) | |
} | |
// the contact list | |
ContactsList( | |
modifier = Modifier.fillMaxSize(), | |
contacts = state.contacts | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment