diff --git a/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/android/feature/claim/chat/ui/outcome/ClaimOutcomeNewClaimDestination.android.kt b/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/android/feature/claim/chat/ui/outcome/ClaimOutcomeNewClaimDestination.android.kt index 95ff085292..4b01a38b91 100644 --- a/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/android/feature/claim/chat/ui/outcome/ClaimOutcomeNewClaimDestination.android.kt +++ b/app/feature/feature-claim-chat/src/androidMain/kotlin/com/hedvig/android/feature/claim/chat/ui/outcome/ClaimOutcomeNewClaimDestination.android.kt @@ -18,8 +18,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp -import com.google.accompanist.permissions.isGranted -import com.google.accompanist.permissions.shouldShowRationale import com.hedvig.android.design.system.hedvig.HedvigBottomSheet import com.hedvig.android.design.system.hedvig.HedvigButton import com.hedvig.android.design.system.hedvig.HedvigText @@ -29,7 +27,9 @@ import com.hedvig.android.design.system.hedvig.api.HedvigBottomSheetState import com.hedvig.android.design.system.hedvig.rememberHedvigBottomSheetState import com.hedvig.android.design.system.hedvig.show import com.hedvig.android.notification.permission.NotificationPermissionState +import com.hedvig.android.notification.permission.isGranted import com.hedvig.android.notification.permission.rememberNotificationPermissionState +import com.hedvig.android.notification.permission.shouldShowRationale import hedvig.resources.CLAIMS_ACTIVATE_NOTIFICATIONS_BODY import hedvig.resources.CLAIMS_ACTIVATE_NOTIFICATIONS_CTA import hedvig.resources.CLAIM_CHAT_GET_NOTIFIED diff --git a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt index 9ee06c7164..b3f4353c4c 100644 --- a/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt +++ b/app/feature/feature-home/src/main/kotlin/com/hedvig/android/feature/home/home/ui/HomeDestination.kt @@ -93,7 +93,6 @@ import arrow.core.nonEmptyListOf import arrow.core.toNonEmptyListOrNull import coil3.ImageLoader import coil3.compose.AsyncImage -import com.google.accompanist.permissions.isGranted import com.hedvig.android.compose.pager.indicator.CardCarousel import com.hedvig.android.compose.ui.LocalClock import com.hedvig.android.compose.ui.dropUnlessResumed @@ -209,6 +208,7 @@ import com.hedvig.android.memberreminders.ui.homeInformationalReminders import com.hedvig.android.memberreminders.ui.missingPayinMethodReminder import com.hedvig.android.notification.permission.NotificationPermissionDialog import com.hedvig.android.notification.permission.NotificationPermissionState +import com.hedvig.android.notification.permission.isGranted import com.hedvig.android.notification.permission.rememberNotificationPermissionState import com.hedvig.android.notification.permission.rememberPreviewNotificationPermissionState import com.hedvig.android.pullrefresh.PullRefreshDefaults diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/settings/SettingsDestination.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/settings/SettingsDestination.kt index ead73b7f2e..f4fd3b8e85 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/settings/SettingsDestination.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/settings/SettingsDestination.kt @@ -26,9 +26,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.google.accompanist.permissions.PermissionStatus -import com.google.accompanist.permissions.PermissionStatus.Granted -import com.google.accompanist.permissions.isGranted import com.hedvig.android.data.settings.datastore.AnalyticsConsent import com.hedvig.android.design.system.hedvig.DialogDefaults.ButtonSize.BIG import com.hedvig.android.design.system.hedvig.HedvigAlertDialog @@ -52,6 +49,9 @@ import com.hedvig.android.language.label import com.hedvig.android.memberreminders.ui.ReminderCardEnableNotifications import com.hedvig.android.notification.permission.NotificationPermissionDialog import com.hedvig.android.notification.permission.NotificationPermissionState +import com.hedvig.android.notification.permission.PermissionStatus +import com.hedvig.android.notification.permission.PermissionStatus.Granted +import com.hedvig.android.notification.permission.isGranted import com.hedvig.android.notification.permission.rememberNotificationPermissionState import com.hedvig.android.theme.Theme import hedvig.resources.GENERAL_DISABLED diff --git a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt index 3992578a0d..3172d78f1b 100644 --- a/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt +++ b/app/feature/feature-profile/src/main/kotlin/com/hedvig/android/feature/profile/tab/ProfileDestination.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameter import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed -import com.google.accompanist.permissions.isGranted import com.hedvig.android.compose.ui.plus import com.hedvig.android.compose.ui.preview.PreviewContentWithProvidedParametersAnimatedOnClick import com.hedvig.android.data.coinsured.CoInsuredFlowType @@ -77,6 +76,7 @@ import com.hedvig.android.memberreminders.ui.MissingPayinMethodCard import com.hedvig.android.memberreminders.ui.cardReminders import com.hedvig.android.memberreminders.ui.missingPayinMethodReminder import com.hedvig.android.notification.permission.NotificationPermissionDialog +import com.hedvig.android.notification.permission.isGranted import com.hedvig.android.notification.permission.rememberNotificationPermissionState import com.hedvig.android.placeholder.PlaceholderHighlight import com.hedvig.android.pullrefresh.PullRefreshDefaults diff --git a/app/notification-permission/build.gradle.kts b/app/notification-permission/build.gradle.kts index df54831baf..50fb472326 100644 --- a/app/notification-permission/build.gradle.kts +++ b/app/notification-permission/build.gradle.kts @@ -1,5 +1,6 @@ plugins { - id("hedvig.android.library") + id("hedvig.multiplatform.library") + id("hedvig.multiplatform.library.android") id("hedvig.gradle.plugin") } @@ -7,10 +8,17 @@ hedvig { compose() } -dependencies { - api(libs.accompanist.permissions) - - implementation(libs.androidx.activity.compose) - implementation(projects.coreResources) - implementation(projects.designSystemHedvig) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.jetbrains.compose.runtime) + implementation(projects.coreResources) + implementation(projects.designSystemHedvig) + } + androidMain.dependencies { + implementation(libs.accompanist.permissions) + implementation(libs.androidx.activity.compose) + implementation(libs.jetbrains.compose.ui) + } + } } diff --git a/app/notification-permission/src/main/AndroidManifest.xml b/app/notification-permission/src/androidMain/AndroidManifest.xml similarity index 100% rename from app/notification-permission/src/main/AndroidManifest.xml rename to app/notification-permission/src/androidMain/AndroidManifest.xml diff --git a/app/notification-permission/src/main/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt b/app/notification-permission/src/androidMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.android.kt similarity index 58% rename from app/notification-permission/src/main/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt rename to app/notification-permission/src/androidMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.android.kt index 0d96b7681f..42c14b93b8 100644 --- a/app/notification-permission/src/main/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt +++ b/app/notification-permission/src/androidMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.android.kt @@ -19,30 +19,32 @@ import androidx.compose.ui.platform.LocalInspectionMode import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.MutablePermissionState import com.google.accompanist.permissions.PermissionLifecycleCheckerEffect -import com.google.accompanist.permissions.PermissionState -import com.google.accompanist.permissions.PermissionStatus -import com.google.accompanist.permissions.isGranted +import com.google.accompanist.permissions.PermissionState as AccompanistPermissionState +import com.google.accompanist.permissions.PermissionStatus as AccompanistPermissionStatus +import com.google.accompanist.permissions.isGranted as accompanistIsGranted import com.google.accompanist.permissions.rememberPermissionState -import com.google.accompanist.permissions.shouldShowRationale -import com.hedvig.android.design.system.hedvig.PermissionDialog -import hedvig.resources.CLAIMS_ACTIVATE_NOTIFICATIONS_BODY -import hedvig.resources.Res -import org.jetbrains.compose.resources.stringResource - -interface NotificationPermissionState : PermissionState { - val showDialog: Boolean - - fun dismissDialog() -} private class NotificationPermissionStateImpl( - private val permissionState: PermissionState, -) : NotificationPermissionState, PermissionState by permissionState { + private val permissionState: AccompanistPermissionState, +) : NotificationPermissionState { private var _showDialog by mutableStateOf(false) + override val permission: String + get() = permissionState.permission + + override val status: PermissionStatus + get() = when (val status = permissionState.status) { + AccompanistPermissionStatus.Granted -> PermissionStatus.Granted + is AccompanistPermissionStatus.Denied -> PermissionStatus.Denied(status.shouldShowRationale) + } + override val showDialog: Boolean get() = _showDialog + override fun launchPermissionRequest() { + permissionState.launchPermissionRequest() + } + override fun dismissDialog() { _showDialog = false } @@ -59,7 +61,7 @@ private class NotificationPermissionStateImpl( */ @SuppressLint("InlinedApi") @Composable -fun rememberNotificationPermissionState(onNotificationGranted: () -> Unit = {}): NotificationPermissionState { +actual fun rememberNotificationPermissionState(onNotificationGranted: () -> Unit): NotificationPermissionState { val context = LocalContext.current val activity = LocalActivity.current val permissionState = remember { @@ -87,43 +89,13 @@ fun rememberNotificationPermissionState(onNotificationGranted: () -> Unit = {}): return notificationPermissionState } -@Composable -fun NotificationPermissionDialog( - notificationPermissionState: NotificationPermissionState, - openAppSettings: () -> Unit, -) { - if (notificationPermissionState.showDialog) { - PermissionDialog( - permissionDescription = stringResource(Res.string.CLAIMS_ACTIVATE_NOTIFICATIONS_BODY), - isPermanentlyDeclined = !notificationPermissionState.status.shouldShowRationale, - onDismiss = notificationPermissionState::dismissDialog, - okClick = notificationPermissionState::launchPermissionRequest, - openAppSettings = openAppSettings, - ) - } -} - @OptIn(ExperimentalPermissionsApi::class) @Composable -fun rememberNotificationPermissionStatus(): Boolean { +actual fun rememberNotificationPermissionStatus(): Boolean { val isPreview = LocalInspectionMode.current return if (!isPreview && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS).status.isGranted + rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS).status.accompanistIsGranted } else { true } } - -fun rememberPreviewNotificationPermissionState( - permissionStatus: PermissionStatus = PermissionStatus.Granted, - isDialogShowing: Boolean = false, -): NotificationPermissionState = object : NotificationPermissionState { - override val showDialog: Boolean = isDialogShowing - - override fun dismissDialog() {} - - override val permission: String = "" - override val status: PermissionStatus = permissionStatus - - override fun launchPermissionRequest() {} -} diff --git a/app/notification-permission/src/commonMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt b/app/notification-permission/src/commonMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt new file mode 100644 index 0000000000..49d55371b8 --- /dev/null +++ b/app/notification-permission/src/commonMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.kt @@ -0,0 +1,73 @@ +package com.hedvig.android.notification.permission + +import androidx.compose.runtime.Composable +import com.hedvig.android.design.system.hedvig.PermissionDialog +import hedvig.resources.CLAIMS_ACTIVATE_NOTIFICATIONS_BODY +import hedvig.resources.Res +import org.jetbrains.compose.resources.stringResource + +interface NotificationPermissionState { + val permission: String + val status: PermissionStatus + val showDialog: Boolean + + fun launchPermissionRequest() + + fun dismissDialog() +} + +sealed interface PermissionStatus { + data object Granted : PermissionStatus + + data class Denied(val shouldShowRationale: Boolean) : PermissionStatus +} + +val PermissionStatus.isGranted: Boolean + get() = this == PermissionStatus.Granted + +val PermissionStatus.shouldShowRationale: Boolean + get() = when (this) { + PermissionStatus.Granted -> false + is PermissionStatus.Denied -> shouldShowRationale + } + +/** + * Notification permission state for the current screen. [onNotificationGranted] runs when a permission request is + * granted; a denied request makes [NotificationPermissionState.showDialog] true. Use in conjunction with + * [NotificationPermissionDialog]. + */ +@Composable +expect fun rememberNotificationPermissionState(onNotificationGranted: () -> Unit = {}): NotificationPermissionState + +@Composable +fun NotificationPermissionDialog( + notificationPermissionState: NotificationPermissionState, + openAppSettings: () -> Unit, +) { + if (notificationPermissionState.showDialog) { + PermissionDialog( + permissionDescription = stringResource(Res.string.CLAIMS_ACTIVATE_NOTIFICATIONS_BODY), + isPermanentlyDeclined = !notificationPermissionState.status.shouldShowRationale, + onDismiss = notificationPermissionState::dismissDialog, + okClick = notificationPermissionState::launchPermissionRequest, + openAppSettings = openAppSettings, + ) + } +} + +@Composable +expect fun rememberNotificationPermissionStatus(): Boolean + +fun rememberPreviewNotificationPermissionState( + permissionStatus: PermissionStatus = PermissionStatus.Granted, + isDialogShowing: Boolean = false, +): NotificationPermissionState = object : NotificationPermissionState { + override val showDialog: Boolean = isDialogShowing + + override fun dismissDialog() {} + + override val permission: String = "" + override val status: PermissionStatus = permissionStatus + + override fun launchPermissionRequest() {} +} diff --git a/app/notification-permission/src/jvmMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.jvm.kt b/app/notification-permission/src/jvmMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.jvm.kt new file mode 100644 index 0000000000..9006673499 --- /dev/null +++ b/app/notification-permission/src/jvmMain/kotlin/com/hedvig/android/notification/permission/NotificationPermission.jvm.kt @@ -0,0 +1,25 @@ +package com.hedvig.android.notification.permission + +import androidx.compose.runtime.Composable + +/** + * The JVM target has no notification permission to request, so the state always reads as denied and never shows a + * dialog. + */ +private object UnavailableNotificationPermissionState : NotificationPermissionState { + override val permission: String = "android.permission.POST_NOTIFICATIONS" + override val status: PermissionStatus = PermissionStatus.Denied(shouldShowRationale = false) + override val showDialog: Boolean = false + + override fun launchPermissionRequest() {} + + override fun dismissDialog() {} +} + +@Composable +actual fun rememberNotificationPermissionState(onNotificationGranted: () -> Unit): NotificationPermissionState { + return UnavailableNotificationPermissionState +} + +@Composable +actual fun rememberNotificationPermissionStatus(): Boolean = false