Skip to content

Commit 051b8b5

Browse files
committed
feat(libs/permissions): overhaul permission state management
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 4dbd8e8 commit 051b8b5

18 files changed

Lines changed: 474 additions & 405 deletions

File tree

apps/flipcash/app/src/main/kotlin/com/flipcash/app/MainActivity.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ import com.getcode.opencode.controllers.TransactionController
4343
import com.getcode.opencode.exchange.Exchange
4444
import com.getcode.solana.rpc.RpcConfig
4545
import com.getcode.ui.testing.LocalUiTesting
46-
import com.getcode.util.permissions.LocalPermissionChecker
4746
import com.getcode.util.permissions.PermissionChecker
4847
import com.getcode.util.resources.LocalResources
4948
import com.getcode.util.resources.LocalSystemSettings
@@ -153,7 +152,6 @@ class MainActivity : FragmentActivity() {
153152
LocalUserManager provides userManager,
154153
LocalSessionController provides sessionController,
155154
LocalBillingClient provides billing,
156-
LocalPermissionChecker provides permissionChecker,
157155
LocalShareController provides shareController,
158156
LocalAppSettings provides appSettingsCoordinator,
159157
LocalFeatureFlags provides featureFlagController,

apps/flipcash/features/backupkey/src/main/kotlin/com/flipcash/app/backupkey/internal/BackupKeyScreenContent.kt

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.flipcash.app.backupkey.internal
22

3-
import android.Manifest
43
import android.os.Build
54
import androidx.compose.animation.AnimatedVisibility
65
import androidx.compose.animation.core.MutableTransitionState
@@ -51,10 +50,7 @@ import com.getcode.ui.core.measured
5150
import com.getcode.ui.theme.ButtonState
5251
import com.getcode.ui.theme.CodeButton
5352
import com.getcode.util.permissions.PermissionResult
54-
import com.getcode.util.permissions.getPermissionLauncher
55-
import com.getcode.util.permissions.rememberPermissionHandler
56-
import kotlinx.coroutines.delay
57-
import kotlin.time.Duration.Companion.seconds
53+
import com.getcode.util.permissions.rememberStoragePermission
5854

5955
@Composable
6056
internal fun BackupKeyScreenContent(viewModel: BackupKeyScreenViewModel) {
@@ -84,9 +80,7 @@ internal fun BackupKeyScreenContent(viewModel: BackupKeyScreenViewModel) {
8480
}
8581
}
8682

87-
val launcher =
88-
getPermissionLauncher(Manifest.permission.WRITE_EXTERNAL_STORAGE, onPermissionResult)
89-
val permissionChecker = rememberPermissionHandler()
83+
val storage = rememberStoragePermission { onPermissionResult(it) }
9084

9185
LaunchedEffect(isExportSeedRequested, isStoragePermissionGranted) {
9286
if (isExportSeedRequested && isStoragePermissionGranted) {
@@ -103,11 +97,7 @@ internal fun BackupKeyScreenContent(viewModel: BackupKeyScreenViewModel) {
10397
if (Build.VERSION.SDK_INT > 29) {
10498
isStoragePermissionGranted = true
10599
} else {
106-
permissionChecker.request(
107-
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
108-
onPermissionResult = onPermissionResult,
109-
launcher = launcher
110-
)
100+
storage.launch()
111101
}
112102
}
113103

apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/accesskey/AccessKeyScreen.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import com.flipcash.app.login.internal.AccessKeyScreen
1212
import com.flipcash.features.login.R
1313
import com.getcode.navigation.core.LocalCodeNavigator
1414
import com.getcode.ui.components.AppBarWithTitle
15+
import com.getcode.util.permissions.rememberNotificationPermission
1516

1617
@Composable
1718
fun AccessKeyScreen() {
1819
val viewModel = hiltViewModel<LoginAccessKeyViewModel>()
1920
val navigator = LocalCodeNavigator.current
21+
val notificationPermissions = rememberNotificationPermission()
2022
Column(
2123
modifier = Modifier.fillMaxSize(),
2224
horizontalAlignment = Alignment.CenterHorizontally,
@@ -31,7 +33,11 @@ fun AccessKeyScreen() {
3133
if (requiresIap) {
3234
navigator.push(AppRoute.Onboarding.Purchase())
3335
} else {
34-
navigator.replaceAll(AppRoute.Main.Scanner)
36+
if (notificationPermissions.isPermanentlyDenied) {
37+
navigator.push(AppRoute.Onboarding.NotificationPermissionRationale(true))
38+
} else {
39+
navigator.push(AppRoute.Onboarding.NotificationPermission(true))
40+
}
3541
}
3642
}
3743
}

apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/internal/AccessKeyScreenContent.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ import com.getcode.ui.core.measured
6161
import com.getcode.ui.theme.ButtonState
6262
import com.getcode.ui.theme.CodeButton
6363
import com.getcode.util.permissions.PermissionResult
64-
import com.getcode.util.permissions.getPermissionLauncher
65-
import com.getcode.util.permissions.rememberPermissionHandler
64+
import com.getcode.util.permissions.rememberStoragePermission
6665
import kotlinx.coroutines.delay
6766
import kotlinx.coroutines.launch
6867

@@ -96,9 +95,7 @@ internal fun AccessKeyScreen(viewModel: LoginAccessKeyViewModel, onCompleted: (r
9695
}
9796
}
9897

99-
val launcher =
100-
getPermissionLauncher(Manifest.permission.WRITE_EXTERNAL_STORAGE, onPermissionResult)
101-
val permissionChecker = rememberPermissionHandler()
98+
val storage = rememberStoragePermission { onPermissionResult(it) }
10299

103100
LaunchedEffect(isExportSeedRequested, isStoragePermissionGranted) {
104101
if (isExportSeedRequested && isStoragePermissionGranted) {
@@ -119,11 +116,7 @@ internal fun AccessKeyScreen(viewModel: LoginAccessKeyViewModel, onCompleted: (r
119116
if (Build.VERSION.SDK_INT > 29) {
120117
isStoragePermissionGranted = true
121118
} else {
122-
permissionChecker.request(
123-
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
124-
onPermissionResult = onPermissionResult,
125-
launcher = launcher
126-
)
119+
storage.launch()
127120
}
128121
}
129122

apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/internal/PurchaseAccountScreenContent.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.flipcash.app.purchase.internal
22

3-
import android.Manifest
43
import androidx.compose.foundation.layout.Arrangement
54
import androidx.compose.foundation.layout.Box
65
import androidx.compose.foundation.layout.Column
@@ -22,12 +21,12 @@ import androidx.compose.ui.platform.LocalContext
2221
import androidx.compose.ui.res.stringResource
2322
import androidx.compose.ui.text.style.TextAlign
2423
import androidx.compose.ui.tooling.preview.Preview
25-
import com.flipcash.app.core.AppRoute
26-
import com.flipcash.app.core.ui.BrandedGradientIcon
27-
import com.flipcash.features.purchase.R
2824
import com.flipcash.app.billing.IapProduct
2925
import com.flipcash.app.billing.ProductPrice
26+
import com.flipcash.app.core.AppRoute
27+
import com.flipcash.app.core.ui.BrandedGradientIcon
3028
import com.flipcash.app.theme.FlipcashPreview
29+
import com.flipcash.features.purchase.R
3130
import com.getcode.navigation.core.LocalCodeNavigator
3231
import com.getcode.opencode.model.financial.CurrencyCode
3332
import com.getcode.theme.CodeTheme
@@ -37,7 +36,6 @@ import com.getcode.ui.theme.CodeButtonSpacer
3736
import com.getcode.ui.theme.CodeCircularProgressIndicator
3837
import com.getcode.ui.theme.CodeScaffold
3938
import com.getcode.util.getActivity
40-
import com.getcode.util.permissions.LocalPermissionChecker
4139
import com.getcode.view.LoadingSuccessState
4240
import kotlinx.coroutines.flow.filterIsInstance
4341
import kotlinx.coroutines.flow.launchIn
@@ -46,7 +44,6 @@ import kotlinx.coroutines.flow.onEach
4644
@Composable
4745
internal fun PurchaseAccountScreen(viewModel: PurchaseAccountViewModel) {
4846
val navigator = LocalCodeNavigator.current
49-
val permissions = LocalPermissionChecker.current
5047

5148
val state by viewModel.stateFlow.collectAsState()
5249

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/bills/BillContainerView.kt

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.flipcash.app.scanner.internal.bills
22

3-
import android.Manifest
43
import androidx.activity.compose.BackHandler
54
import androidx.compose.animation.AnimatedVisibility
65
import androidx.compose.animation.EnterExitState
@@ -36,7 +35,6 @@ import androidx.compose.ui.platform.LocalContext
3635
import androidx.compose.ui.platform.testTag
3736
import androidx.compose.ui.unit.dp
3837
import androidx.lifecycle.compose.collectAsStateWithLifecycle
39-
import com.flipcash.app.bill.customization.LocalBillPlaygroundController
4038
import com.flipcash.app.bills.AnimatedBill
4139
import com.flipcash.app.core.android.extensions.launchAppSettings
4240
import com.flipcash.app.core.bill.Bill
@@ -58,8 +56,7 @@ import com.getcode.ui.scanner.views.CameraDisabledView
5856
import com.getcode.ui.scanner.views.CameraPermissionsMissingView
5957
import com.getcode.ui.utils.AnimationUtils
6058
import com.getcode.util.permissions.PermissionResult
61-
import com.getcode.util.permissions.getPermissionLauncher
62-
import com.getcode.util.permissions.rememberPermissionHandler
59+
import com.getcode.util.permissions.rememberCameraPermission
6360
import kotlinx.coroutines.delay
6461

6562
@OptIn(ExperimentalMaterialApi::class)
@@ -77,7 +74,7 @@ internal fun BillContainer(
7774
val context = LocalContext.current
7875
val onPermissionResult = { result: PermissionResult ->
7976
session.onCameraPermissionResult(result)
80-
if (result == PermissionResult.ShouldShowRationale) {
77+
if (result == PermissionResult.PermanentlyDenied) {
8178
BottomBarManager.showError(
8279
title = context.getString(R.string.action_allowCameraAccess),
8380
message = context.getString(R.string.error_description_cameraAccessRequired),
@@ -94,22 +91,10 @@ internal fun BillContainer(
9491
}
9592
}
9693

97-
val cameraPermissionLauncher =
98-
getPermissionLauncher(Manifest.permission.CAMERA, onPermissionResult)
99-
100-
val permissionChecker = rememberPermissionHandler()
101-
102-
val checkPermission = { shouldRequest: Boolean ->
103-
permissionChecker.request(
104-
permission = Manifest.permission.CAMERA,
105-
shouldRequest = shouldRequest,
106-
onPermissionResult = onPermissionResult,
107-
launcher = cameraPermissionLauncher
108-
)
109-
}
94+
val cameraPermission = rememberCameraPermission { onPermissionResult(it) }
11095

11196
SideEffect {
112-
checkPermission(false)
97+
onPermissionResult(cameraPermission.status)
11398
}
11499

115100
val state by session.state.collectAsState()
@@ -148,7 +133,7 @@ internal fun BillContainer(
148133
CameraPermissionsMissingView(
149134
modifier = Modifier.fillMaxSize(),
150135
backgroundColor = Color.Black,
151-
onClick = { checkPermission(true) }
136+
onClick = { cameraPermission.launch() }
152137
)
153138
}
154139
}

apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/internal/TokenTxProcessingScreen.kt

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.flipcash.app.tokens.internal
22

33
import android.Manifest
4-
import androidx.compose.animation.Crossfade
5-
import androidx.compose.foundation.Image
64
import androidx.compose.foundation.layout.Arrangement
75
import androidx.compose.foundation.layout.Box
86
import androidx.compose.foundation.layout.Column
@@ -14,14 +12,8 @@ import androidx.compose.foundation.layout.padding
1412
import androidx.compose.material.Text
1513
import androidx.compose.runtime.Composable
1614
import androidx.compose.runtime.getValue
17-
import androidx.compose.runtime.mutableStateOf
18-
import androidx.compose.runtime.remember
19-
import androidx.compose.runtime.setValue
2015
import androidx.compose.ui.Alignment
2116
import androidx.compose.ui.Modifier
22-
import androidx.compose.ui.graphics.Color
23-
import androidx.compose.ui.graphics.StrokeCap
24-
import androidx.compose.ui.res.painterResource
2517
import androidx.compose.ui.res.stringResource
2618
import androidx.compose.ui.text.AnnotatedString
2719
import androidx.compose.ui.text.style.TextAlign
@@ -37,10 +29,9 @@ import com.getcode.theme.CodeTheme
3729
import com.getcode.ui.components.AppBarWithTitle
3830
import com.getcode.ui.theme.ButtonState
3931
import com.getcode.ui.theme.CodeButton
40-
import com.getcode.ui.theme.CodeCircularProgressIndicator
4132
import com.getcode.ui.theme.CodeScaffold
42-
import com.getcode.util.permissions.LocalPermissionChecker
43-
import com.getcode.util.permissions.notificationPermissionCheck
33+
import com.getcode.util.permissions.ProvideTestPermissions
34+
import com.getcode.util.permissions.rememberNotificationPermission
4435
import com.getcode.view.LoadingSuccessState
4536

4637
@Composable
@@ -62,12 +53,7 @@ private fun TokenTxProcessingScreen(
6253
state: BuySellSwapTokenViewModel.State,
6354
dispatch: (BuySellSwapTokenViewModel.Event) -> Unit,
6455
) {
65-
val permissions = LocalPermissionChecker.current
66-
var hasPushPerms by remember {
67-
mutableStateOf(permissions.isGranted(Manifest.permission.POST_NOTIFICATIONS))
68-
}
69-
70-
val notificationPermissionCheck = notificationPermissionCheck { hasPushPerms = it }
56+
val notifications = rememberNotificationPermission()
7157

7258
CodeScaffold(
7359
topBar = {
@@ -100,20 +86,20 @@ private fun TokenTxProcessingScreen(
10086
.padding(horizontal = CodeTheme.dimens.inset)
10187
.padding(bottom = CodeTheme.dimens.grid.x2)
10288
.navigationBarsPadding(),
103-
text = if (hasPushPerms) {
89+
text = if (notifications.isGranted) {
10490
notifyLabel.first
10591
} else {
10692
AnnotatedString(stringResource(R.string.action_notifyMeWhenComplete))
10793
},
108-
inlineContent = if (hasPushPerms) {
94+
inlineContent = if (notifications.isGranted) {
10995
notifyLabel.second
11096
} else {
11197
emptyMap()
11298
},
11399
buttonState = ButtonState.Filled,
114-
enabled = !hasPushPerms,
100+
enabled = !notifications.isGranted,
115101
onClick = {
116-
notificationPermissionCheck(true)
102+
notifications.launch()
117103
}
118104
)
119105
}
@@ -201,10 +187,12 @@ private fun TokenTxProcessingScreen(
201187
@Composable
202188
private fun TxProcessiongPreview() {
203189
FlipcashPreview {
204-
TokenTxProcessingScreen(
205-
state = BuySellSwapTokenViewModel.State(
206-
processingProgress = LoadingSuccessState(loading = true)
207-
)
208-
) { }
190+
ProvideTestPermissions(granted = setOf(Manifest.permission.POST_NOTIFICATIONS)) {
191+
TokenTxProcessingScreen(
192+
state = BuySellSwapTokenViewModel.State(
193+
processingProgress = LoadingSuccessState(loading = true)
194+
)
195+
) { }
196+
}
209197
}
210198
}

0 commit comments

Comments
 (0)