mirror of
https://github.com/bitwarden/android.git
synced 2026-10-23 11:33:22 -05:00
BIT-2295: Simplify the pending requests UI (#1325)
This commit is contained in:
1 parent
b739be712a
commit
25c7ed0835
17 files changed
+77
-673
No files matched your search
-13
@@ -221,19 +221,6 @@ interface SettingsDiskSource {
|
||||
blockedAutofillUris: List<String>?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets whether or not the given [userId] has enabled approving passwordless logins.
|
||||
*/
|
||||
fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean?
|
||||
|
||||
/**
|
||||
* Stores whether or not [isApprovePasswordlessLoginsEnabled] for the given [userId].
|
||||
*/
|
||||
fun storeApprovePasswordlessLoginsEnabled(
|
||||
userId: String,
|
||||
isApprovePasswordlessLoginsEnabled: Boolean?,
|
||||
)
|
||||
|
||||
/**
|
||||
* Gets whether or not the given [userId] has enabled screen capture.
|
||||
*/
|
||||
|
||||
-19
@@ -26,7 +26,6 @@ private const val DEFAULT_URI_MATCH_TYPE_KEY = "defaultUriMatch"
|
||||
private const val DISABLE_AUTO_TOTP_COPY_KEY = "disableAutoTotpCopy"
|
||||
private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "autofillDisableSavePrompt"
|
||||
private const val DISABLE_ICON_LOADING_KEY = "disableFavicon"
|
||||
private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "approvePasswordlessLogins"
|
||||
private const val SCREEN_CAPTURE_ALLOW_KEY = "screenCaptureAllowed"
|
||||
private const val SYSTEM_BIOMETRIC_INTEGRITY_SOURCE_KEY = "biometricIntegritySource"
|
||||
private const val ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY = "accountBiometricIntegrityValid"
|
||||
@@ -139,10 +138,6 @@ class SettingsDiskSourceImpl(
|
||||
storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null)
|
||||
storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null)
|
||||
storeBlockedAutofillUris(userId = userId, blockedAutofillUris = null)
|
||||
storeApprovePasswordlessLoginsEnabled(
|
||||
userId = userId,
|
||||
isApprovePasswordlessLoginsEnabled = null,
|
||||
)
|
||||
storeLastSyncTime(userId = userId, lastSyncTime = null)
|
||||
storeClearClipboardFrequencySeconds(userId = userId, frequency = null)
|
||||
removeWithPrefix(prefix = ACCOUNT_BIOMETRIC_INTEGRITY_VALID_KEY.appendIdentifier(userId))
|
||||
@@ -356,20 +351,6 @@ class SettingsDiskSourceImpl(
|
||||
bufferedMutableSharedFlow(replay = 1)
|
||||
}
|
||||
|
||||
override fun getApprovePasswordlessLoginsEnabled(userId: String): Boolean? {
|
||||
return getBoolean(key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId))
|
||||
}
|
||||
|
||||
override fun storeApprovePasswordlessLoginsEnabled(
|
||||
userId: String,
|
||||
isApprovePasswordlessLoginsEnabled: Boolean?,
|
||||
) {
|
||||
putBoolean(
|
||||
key = APPROVE_PASSWORDLESS_LOGINS_KEY.appendIdentifier(userId),
|
||||
value = isApprovePasswordlessLoginsEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
override fun getScreenCaptureAllowed(userId: String): Boolean? {
|
||||
return getBoolean(key = SCREEN_CAPTURE_ALLOW_KEY.appendIdentifier(userId))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.platform.manager
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.model.PushTokenRequest
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.service.PushService
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
@@ -36,10 +35,8 @@ import javax.inject.Inject
|
||||
/**
|
||||
* Primary implementation of [PushManager].
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
class PushManagerImpl @Inject constructor(
|
||||
private val authDiskSource: AuthDiskSource,
|
||||
private val settingsDiskSource: SettingsDiskSource,
|
||||
private val pushDiskSource: PushDiskSource,
|
||||
private val pushService: PushService,
|
||||
private val clock: Clock,
|
||||
@@ -125,16 +122,14 @@ class PushManagerImpl @Inject constructor(
|
||||
NotificationType.AUTH_REQUEST,
|
||||
NotificationType.AUTH_REQUEST_RESPONSE,
|
||||
-> {
|
||||
if (settingsDiskSource.getApprovePasswordlessLoginsEnabled(userId) == true) {
|
||||
val payload: NotificationPayload.PasswordlessRequestNotification =
|
||||
json.decodeFromString(string = notification.payload)
|
||||
mutablePasswordlessRequestSharedFlow.tryEmit(
|
||||
PasswordlessRequestData(
|
||||
loginRequestId = payload.id,
|
||||
userId = payload.userId,
|
||||
),
|
||||
)
|
||||
}
|
||||
val payload: NotificationPayload.PasswordlessRequestNotification =
|
||||
json.decodeFromString(string = notification.payload)
|
||||
mutablePasswordlessRequestSharedFlow.tryEmit(
|
||||
PasswordlessRequestData(
|
||||
loginRequestId = payload.id,
|
||||
userId = payload.userId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
NotificationType.LOG_OUT -> {
|
||||
|
||||
-2
@@ -143,7 +143,6 @@ object PlatformManagerModule {
|
||||
@Singleton
|
||||
fun providePushManager(
|
||||
authDiskSource: AuthDiskSource,
|
||||
settingsDiskSource: SettingsDiskSource,
|
||||
pushDiskSource: PushDiskSource,
|
||||
pushService: PushService,
|
||||
dispatcherManager: DispatcherManager,
|
||||
@@ -151,7 +150,6 @@ object PlatformManagerModule {
|
||||
json: Json,
|
||||
): PushManager = PushManagerImpl(
|
||||
authDiskSource = authDiskSource,
|
||||
settingsDiskSource = settingsDiskSource,
|
||||
pushDiskSource = pushDiskSource,
|
||||
pushService = pushService,
|
||||
dispatcherManager = dispatcherManager,
|
||||
|
||||
@@ -118,11 +118,6 @@ interface SettingsRepository {
|
||||
*/
|
||||
var blockedAutofillUris: List<String>
|
||||
|
||||
/**
|
||||
* Whether or not approving passwordless logins is enabled for the current user.
|
||||
*/
|
||||
var isApprovePasswordlessLoginsEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Emits updates whenever there is a change in the app's status for supporting autofill.
|
||||
*
|
||||
|
||||
-13
@@ -245,19 +245,6 @@ class SettingsRepositoryImpl(
|
||||
)
|
||||
}
|
||||
|
||||
override var isApprovePasswordlessLoginsEnabled: Boolean
|
||||
get() = activeUserId
|
||||
?.let {
|
||||
settingsDiskSource.getApprovePasswordlessLoginsEnabled(it)
|
||||
}
|
||||
?: false
|
||||
set(value) {
|
||||
val userId = activeUserId ?: return
|
||||
settingsDiskSource.storeApprovePasswordlessLoginsEnabled(
|
||||
userId = userId,
|
||||
isApprovePasswordlessLoginsEnabled = value,
|
||||
)
|
||||
}
|
||||
override val isAutofillEnabledStateFlow: StateFlow<Boolean> =
|
||||
autofillEnabledManager.isAutofillEnabledStateFlow
|
||||
|
||||
|
||||
+7
-117
@@ -1,7 +1,5 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -58,10 +56,8 @@ import com.x8bit.bitwarden.ui.platform.components.toggle.BitwardenWideSwitch
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalBiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.biometrics.BiometricsManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialColors
|
||||
import com.x8bit.bitwarden.ui.platform.theme.LocalNonMaterialTypography
|
||||
import com.x8bit.bitwarden.ui.platform.util.displayLabel
|
||||
@@ -84,7 +80,6 @@ fun AccountSecurityScreen(
|
||||
viewModel: AccountSecurityViewModel = hiltViewModel(),
|
||||
biometricsManager: BiometricsManager = LocalBiometricsManager.current,
|
||||
intentManager: IntentManager = LocalIntentManager.current,
|
||||
permissionsManager: PermissionsManager = LocalPermissionsManager.current,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsState()
|
||||
val context = LocalContext.current
|
||||
@@ -149,7 +144,7 @@ fun AccountSecurityScreen(
|
||||
},
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
Modifier
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
@@ -160,31 +155,15 @@ fun AccountSecurityScreen(
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
ApprovePasswordlessLoginsRow(
|
||||
isApproveLoginRequestsEnabled = state.isApproveLoginRequestsEnabled,
|
||||
onApprovePasswordlessLoginsAction = remember(viewModel) {
|
||||
{ viewModel.trySendAction(it) }
|
||||
},
|
||||
permissionsManager = permissionsManager,
|
||||
onPushNotificationConfirm = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.PushNotificationConfirm) }
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.pending_log_in_requests),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.PendingLoginRequestsClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.testTag("ApproveLoginRequestsSwitch")
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
.testTag("PendingLogInRequestsLabel")
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
if (state.isApproveLoginRequestsEnabled) {
|
||||
BitwardenTextRow(
|
||||
text = stringResource(id = R.string.pending_log_in_requests),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AccountSecurityAction.PendingLoginRequestsClick) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.testTag("PendingLogInRequestsLabel")
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(16.dp))
|
||||
BitwardenListHeaderText(
|
||||
@@ -824,92 +803,3 @@ private fun FingerPrintPhraseDialog(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun ApprovePasswordlessLoginsRow(
|
||||
isApproveLoginRequestsEnabled: Boolean,
|
||||
@Suppress("MaxLineLength")
|
||||
onApprovePasswordlessLoginsAction: (AccountSecurityAction.ApprovePasswordlessLoginsToggle) -> Unit,
|
||||
onPushNotificationConfirm: () -> Unit,
|
||||
permissionsManager: PermissionsManager,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowConfirmationDialog by remember { mutableStateOf(false) }
|
||||
var shouldShowPermissionDialog by remember { mutableStateOf(false) }
|
||||
BitwardenWideSwitch(
|
||||
label = stringResource(
|
||||
id = R.string.use_this_device_to_approve_login_requests_made_from_other_devices,
|
||||
),
|
||||
isChecked = isApproveLoginRequestsEnabled,
|
||||
onCheckedChange = { isChecked ->
|
||||
if (isChecked) {
|
||||
onApprovePasswordlessLoginsAction(
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled,
|
||||
)
|
||||
shouldShowConfirmationDialog = true
|
||||
} else {
|
||||
onApprovePasswordlessLoginsAction(
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled,
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
)
|
||||
|
||||
if (shouldShowConfirmationDialog) {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = stringResource(id = R.string.approve_login_requests),
|
||||
message = stringResource(
|
||||
id = R.string.use_this_device_to_approve_login_requests_made_from_other_devices,
|
||||
),
|
||||
confirmButtonText = stringResource(id = R.string.yes),
|
||||
dismissButtonText = stringResource(id = R.string.no),
|
||||
onConfirmClick = {
|
||||
onApprovePasswordlessLoginsAction(
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled,
|
||||
)
|
||||
shouldShowConfirmationDialog = false
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
@Suppress("MaxLineLength")
|
||||
if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) {
|
||||
shouldShowPermissionDialog = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissClick = {
|
||||
onApprovePasswordlessLoginsAction(
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled,
|
||||
)
|
||||
shouldShowConfirmationDialog = false
|
||||
},
|
||||
onDismissRequest = {
|
||||
onApprovePasswordlessLoginsAction(
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled,
|
||||
)
|
||||
shouldShowConfirmationDialog = false
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if (shouldShowPermissionDialog) {
|
||||
BitwardenTwoButtonDialog(
|
||||
title = null,
|
||||
message = stringResource(
|
||||
id = R.string.receive_push_notifications_for_new_login_requests,
|
||||
),
|
||||
confirmButtonText = stringResource(id = R.string.settings),
|
||||
dismissButtonText = stringResource(id = R.string.no_thanks),
|
||||
onConfirmClick = {
|
||||
shouldShowPermissionDialog = false
|
||||
onPushNotificationConfirm()
|
||||
},
|
||||
onDismissClick = {
|
||||
shouldShowPermissionDialog = false
|
||||
},
|
||||
onDismissRequest = {
|
||||
shouldShowPermissionDialog = false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
+1
-48
@@ -41,14 +41,13 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
private val vaultRepository: VaultRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val environmentRepository: EnvironmentRepository,
|
||||
private val policyManager: PolicyManager,
|
||||
policyManager: PolicyManager,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : BaseViewModel<AccountSecurityState, AccountSecurityEvent, AccountSecurityAction>(
|
||||
initialState = savedStateHandle[KEY_STATE]
|
||||
?: AccountSecurityState(
|
||||
dialog = null,
|
||||
fingerprintPhrase = "".asText(), // This will be filled in dynamically
|
||||
isApproveLoginRequestsEnabled = settingsRepository.isApprovePasswordlessLoginsEnabled,
|
||||
isUnlockWithBiometricsEnabled = settingsRepository.isUnlockWithBiometricsEnabled,
|
||||
isUnlockWithPasswordEnabled = authRepository
|
||||
.userStateFlow
|
||||
@@ -118,11 +117,6 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
is AccountSecurityAction.UnlockWithPinToggle -> handleUnlockWithPinToggle(action)
|
||||
|
||||
is AccountSecurityAction.ApprovePasswordlessLoginsToggle -> {
|
||||
handleApprovePasswordlessLoginsToggle(action)
|
||||
}
|
||||
|
||||
is AccountSecurityAction.PushNotificationConfirm -> handlePushNotificationConfirm()
|
||||
is AccountSecurityAction.Internal -> handleInternalAction(action)
|
||||
}
|
||||
@@ -158,26 +152,6 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
vaultRepository.lockVaultForCurrentUser()
|
||||
}
|
||||
|
||||
private fun handleApprovePasswordlessLoginsToggle(
|
||||
action: AccountSecurityAction.ApprovePasswordlessLoginsToggle,
|
||||
) {
|
||||
when (action) {
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Disabled -> {
|
||||
settingsRepository.isApprovePasswordlessLoginsEnabled = false
|
||||
mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = false) }
|
||||
}
|
||||
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.Enabled -> {
|
||||
settingsRepository.isApprovePasswordlessLoginsEnabled = true
|
||||
mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) }
|
||||
}
|
||||
|
||||
AccountSecurityAction.ApprovePasswordlessLoginsToggle.PendingEnabled -> {
|
||||
mutableStateFlow.update { it.copy(isApproveLoginRequestsEnabled = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handlePushNotificationConfirm() {
|
||||
sendEvent(AccountSecurityEvent.NavigateToApplicationDataSettings)
|
||||
}
|
||||
@@ -368,7 +342,6 @@ class AccountSecurityViewModel @Inject constructor(
|
||||
data class AccountSecurityState(
|
||||
val dialog: AccountSecurityDialog?,
|
||||
val fingerprintPhrase: Text,
|
||||
val isApproveLoginRequestsEnabled: Boolean,
|
||||
val isUnlockWithBiometricsEnabled: Boolean,
|
||||
val isUnlockWithPasswordEnabled: Boolean,
|
||||
val isUnlockWithPinEnabled: Boolean,
|
||||
@@ -551,26 +524,6 @@ sealed class AccountSecurityAction {
|
||||
*/
|
||||
data object PushNotificationConfirm : AccountSecurityAction()
|
||||
|
||||
/**
|
||||
* User toggled the approve passwordless logins switch.
|
||||
*/
|
||||
sealed class ApprovePasswordlessLoginsToggle : AccountSecurityAction() {
|
||||
/**
|
||||
* The toggle was enabled and confirmed.
|
||||
*/
|
||||
data object Enabled : ApprovePasswordlessLoginsToggle()
|
||||
|
||||
/**
|
||||
* The toggle was enabled but not yet confirmed.
|
||||
*/
|
||||
data object PendingEnabled : ApprovePasswordlessLoginsToggle()
|
||||
|
||||
/**
|
||||
* The toggle was disabled.
|
||||
*/
|
||||
data object Disabled : ApprovePasswordlessLoginsToggle()
|
||||
}
|
||||
|
||||
/**
|
||||
* User toggled the unlock with pin switch.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.vault
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.scaleIn
|
||||
@@ -54,9 +56,11 @@ import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.util.rememberVectorPainter
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalIntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.handlers.VaultHandlers
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||
@@ -80,6 +84,7 @@ fun VaultScreen(
|
||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||
exitManager: ExitManager = LocalExitManager.current,
|
||||
intentManager: IntentManager = LocalIntentManager.current,
|
||||
permissionsManager: PermissionsManager = LocalPermissionsManager.current,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsState()
|
||||
val context = LocalContext.current
|
||||
@@ -120,6 +125,7 @@ fun VaultScreen(
|
||||
}
|
||||
}
|
||||
val vaultHandlers = remember(viewModel) { VaultHandlers.create(viewModel) }
|
||||
VaultScreenPushNotifications(permissionsManager = permissionsManager)
|
||||
VaultScreenScaffold(
|
||||
state = state,
|
||||
pullToRefreshState = pullToRefreshState,
|
||||
@@ -128,6 +134,25 @@ fun VaultScreen(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the notifications permission request.
|
||||
*/
|
||||
@Composable
|
||||
private fun VaultScreenPushNotifications(
|
||||
permissionsManager: PermissionsManager,
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
|
||||
val launcher = permissionsManager.getLauncher {
|
||||
// We do not actually care what the response is, we just need
|
||||
// to give the user a chance to give us the permission.
|
||||
}
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
if (!permissionsManager.checkPermission(Manifest.permission.POST_NOTIFICATIONS)) {
|
||||
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scaffold for the [VaultScreen]
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user