forked from dsutanto/bChot-android
First Commit
This commit is contained in:
20
libraries/permissions/api/build.gradle.kts
Normal file
20
libraries/permissions/api/build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.permissions.api"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface PermissionStateProvider {
|
||||
fun isPermissionGranted(permission: String): Boolean
|
||||
suspend fun setPermissionDenied(permission: String, value: Boolean)
|
||||
fun isPermissionDenied(permission: String): Flow<Boolean>
|
||||
|
||||
suspend fun setPermissionAsked(permission: String, value: Boolean)
|
||||
fun isPermissionAsked(permission: String): Flow<Boolean>
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
sealed interface PermissionsEvents {
|
||||
data object RequestPermissions : PermissionsEvents
|
||||
data object CloseDialog : PermissionsEvents
|
||||
data object OpenSystemSettingAndCloseDialog : PermissionsEvents
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
|
||||
interface PermissionsPresenter : Presenter<PermissionsState> {
|
||||
interface Factory {
|
||||
fun create(permission: String): PermissionsPresenter
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
data class PermissionsState(
|
||||
// For instance Manifest.permission.POST_NOTIFICATIONS
|
||||
val permission: String,
|
||||
val permissionGranted: Boolean,
|
||||
val shouldShowRationale: Boolean,
|
||||
val showDialog: Boolean,
|
||||
val permissionAlreadyAsked: Boolean,
|
||||
// If true, there is no need to ask again, the system dialog will not be displayed
|
||||
val permissionAlreadyDenied: Boolean,
|
||||
val eventSink: (PermissionsEvents) -> Unit
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
||||
open class PermissionsStateProvider : PreviewParameterProvider<PermissionsState> {
|
||||
override val values: Sequence<PermissionsState>
|
||||
get() = sequenceOf(
|
||||
aPermissionsState(showDialog = true, permission = Manifest.permission.POST_NOTIFICATIONS),
|
||||
aPermissionsState(showDialog = true, permission = Manifest.permission.CAMERA),
|
||||
aPermissionsState(showDialog = true, permission = Manifest.permission.RECORD_AUDIO),
|
||||
aPermissionsState(showDialog = true, permission = Manifest.permission.INTERNET),
|
||||
)
|
||||
}
|
||||
|
||||
fun aPermissionsState(
|
||||
showDialog: Boolean,
|
||||
permission: String = Manifest.permission.POST_NOTIFICATIONS,
|
||||
permissionGranted: Boolean = false,
|
||||
) = PermissionsState(
|
||||
permission = permission,
|
||||
permissionGranted = permissionGranted,
|
||||
shouldShowRationale = false,
|
||||
showDialog = showDialog,
|
||||
permissionAlreadyAsked = false,
|
||||
permissionAlreadyDenied = false,
|
||||
eventSink = {}
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface PermissionsStore {
|
||||
suspend fun setPermissionDenied(permission: String, value: Boolean)
|
||||
fun isPermissionDenied(permission: String): Flow<Boolean>
|
||||
|
||||
suspend fun setPermissionAsked(permission: String, value: Boolean)
|
||||
fun isPermissionAsked(permission: String): Flow<Boolean>
|
||||
|
||||
suspend fun resetPermission(permission: String)
|
||||
|
||||
// To debug
|
||||
suspend fun resetStore()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun PermissionsView(
|
||||
state: PermissionsState,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = stringResource(id = CommonStrings.common_permission),
|
||||
content: String? = null,
|
||||
icon: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
if (state.showDialog.not()) return
|
||||
|
||||
ConfirmationDialog(
|
||||
modifier = modifier,
|
||||
title = title,
|
||||
content = content ?: state.permission.toDialogContent(),
|
||||
submitText = stringResource(id = CommonStrings.action_open_settings),
|
||||
onSubmitClick = {
|
||||
state.eventSink.invoke(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
},
|
||||
onDismiss = { state.eventSink.invoke(PermissionsEvents.CloseDialog) },
|
||||
icon = icon,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
private fun String.toDialogContent(): String {
|
||||
return when (this) {
|
||||
Manifest.permission.POST_NOTIFICATIONS -> stringResource(id = R.string.dialog_permission_notification)
|
||||
Manifest.permission.CAMERA -> stringResource(id = R.string.dialog_permission_camera)
|
||||
Manifest.permission.RECORD_AUDIO -> stringResource(id = R.string.dialog_permission_microphone)
|
||||
else -> stringResource(id = R.string.dialog_permission_generic)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun PermissionsViewPreview(@PreviewParameter(PermissionsStateProvider::class) state: PermissionsState) = ElementPreview {
|
||||
PermissionsView(
|
||||
state = state,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
fun createDummyPostNotificationPermissionsState() = PermissionsState(
|
||||
permission = "Manifest.permission.POST_NOTIFICATIONS",
|
||||
permissionGranted = true,
|
||||
shouldShowRationale = false,
|
||||
showDialog = false,
|
||||
permissionAlreadyAsked = false,
|
||||
permissionAlreadyDenied = false,
|
||||
eventSink = { }
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Каб дазволіць праграме выкарыстоўваць камеру, дайце дазвол у наладах сістэмы."</string>
|
||||
<string name="dialog_permission_generic">"Калі ласка, дайце дазвол у наладах сістэмы."</string>
|
||||
<string name="dialog_permission_microphone">"Каб дазволіць праграме выкарыстоўваць мікрафон, дайце дазвол у наладах сістэмы."</string>
|
||||
<string name="dialog_permission_notification">"Каб дазволіць праграме паказваць апавяшчэнні, дайце дазвол у наладах сістэмы."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Aby mohla aplikace používat fotoaparát, udělte prosím oprávnění v nastavení systému."</string>
|
||||
<string name="dialog_permission_generic">"Udělte prosím oprávnění v nastavení systému."</string>
|
||||
<string name="dialog_permission_microphone">"Aby aplikace mohla používat mikrofon, udělte prosím oprávnění v nastavení systému."</string>
|
||||
<string name="dialog_permission_notification">"Aby aplikace mohla zobrazovat upozornění, udělte prosím oprávnění v nastavení systému."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Er mwyn gadael i\'r rhaglen ddefnyddio\'r camera, rhowch ganiatâd iddo yn y gosodiadau system."</string>
|
||||
<string name="dialog_permission_generic">"Rhowch ganiatâd yn y gosodiadau system."</string>
|
||||
<string name="dialog_permission_microphone">"Er mwyn gadael i\'r cais ddefnyddio\'r meicroffon, rhowch ganiatâd yng ngosodiadau\'r system."</string>
|
||||
<string name="dialog_permission_notification">"Er mwyn gadael i\'r ap ddangos hysbysiadau, rhowch ganiatâd yn y gosodiadau system."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"For at lade applikationen bruge kameraet, skal du give tilladelsen i systemindstillingerne."</string>
|
||||
<string name="dialog_permission_generic">"Giv venligst tilladelsen i systemindstillingerne."</string>
|
||||
<string name="dialog_permission_microphone">"For at lade applikationen bruge mikrofonen, skal du give tilladelsen i systemindstillingerne."</string>
|
||||
<string name="dialog_permission_notification">"For at lade applikationen vise notifikationer, skal du give tilladelsen i systemindstillingerne."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Damit die Anwendung die Kamera verwenden kann, erteile bitte die Berechtigung in den Systemeinstellungen."</string>
|
||||
<string name="dialog_permission_generic">"Bitte erteile die Berechtigung in den Systemeinstellungen."</string>
|
||||
<string name="dialog_permission_microphone">"Damit die App das Mikrofon nutzen kann, gib bitte die Berechtigung in den Systemeinstellungen frei."</string>
|
||||
<string name="dialog_permission_notification">"Damit die App Benachrichtigungen anzeigen kann, gib bitte die Berechtigung in den Systemeinstellungen frei."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Για να επιτρέψεις στην εφαρμογή να χρησιμοποιεί την κάμερα, παραχώρησε την άδεια στις ρυθμίσεις συστήματος."</string>
|
||||
<string name="dialog_permission_generic">"Παρακαλώ παραχώρησε την άδεια στις ρυθμίσεις συστήματος."</string>
|
||||
<string name="dialog_permission_microphone">"Για να επιτρέψεις στην εφαρμογή να χρησιμοποιεί το μικρόφωνο, παραχώρησε την άδεια στις ρυθμίσεις συστήματος."</string>
|
||||
<string name="dialog_permission_notification">"Για να επιτρέψεις στην εφαρμογή να εμφανίζει ειδοποιήσεις, παραχώρησε την άδεια στις ρυθμίσεις συστήματος."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Para permitir que la aplicación utilice la cámara, por favor concede el permiso en los ajustes del sistema."</string>
|
||||
<string name="dialog_permission_generic">"Por favor concede el permiso en los ajustes del sistema."</string>
|
||||
<string name="dialog_permission_microphone">"Para permitir que la aplicación utilice el micrófono, por favor conceda el permiso en los ajustes del sistema."</string>
|
||||
<string name="dialog_permission_notification">"Para permitir que la aplicación muestre notificaciones, por favor concede el permiso en los ajustes del sistema."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Selleks, et rakendus saaks kaamerat kasutada, palun luba see süsteemi seadistuses."</string>
|
||||
<string name="dialog_permission_generic">"Palun luba süsteemi seadistustest vajalikud õigused."</string>
|
||||
<string name="dialog_permission_microphone">"Selleks, et rakendus saaks mikrofoni kasutada, palun luba see süsteemi seadistuses."</string>
|
||||
<string name="dialog_permission_notification">"Selleks, et rakendus saaks kuvada teavitusi, palun anna vajalikud õiguse süsteemi seadistustes."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Aplikazioak kamera erabiltzeko, eman baimena sistemaren ezarpenetan."</string>
|
||||
<string name="dialog_permission_generic">"Eman baimena sistemaren ezarpenetan."</string>
|
||||
<string name="dialog_permission_microphone">"Aplikazioak mikrofonoa erabiltzeko, eman baimena sistemaren ezarpenetan."</string>
|
||||
<string name="dialog_permission_notification">"Aplikazioak jakinarazpenak bistaratzeko, eman baimena sistemaren ezarpenetan."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"برای اینکه برنامه از دوربین استفاده کند، لطفا در تنظیمات سیستم مجوز بدهید."</string>
|
||||
<string name="dialog_permission_generic">"لطفاً در تنظیمات سامانه اجازه بدهید."</string>
|
||||
<string name="dialog_permission_microphone">"برای اینکه برنامه از میکروفون استفاده کند، لطفا اجازه دهید در تنظیمات سیستم مجوز بدهید."</string>
|
||||
<string name="dialog_permission_notification">"برای اینکه برنامه اعلان ها را نمایش دهد، لطفا مجوز را در تنظیمات سیستم اعطا کنید."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Jotta sovellus voisi käyttää kameraa, anna lupa järjestelmän asetuksista."</string>
|
||||
<string name="dialog_permission_generic">"Anna lupa järjestelmän asetuksista."</string>
|
||||
<string name="dialog_permission_microphone">"Jotta sovellus voisi käyttää mikrofonia, anna lupa järjestelmän asetuksista."</string>
|
||||
<string name="dialog_permission_notification">"Jotta sovellus voisi näyttää ilmoituksia, anna lupa järjestelmän asetuksista."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Pour permettre à l’application d’utiliser l’appareil photo, veuillez accorder l’autorisation dans les paramètres du système."</string>
|
||||
<string name="dialog_permission_generic">"Veuillez accorder l’autorisation dans les paramètres du système."</string>
|
||||
<string name="dialog_permission_microphone">"Pour permettre à l’application d’utiliser le microphone, veuillez accorder l’autorisation dans les paramètres du système."</string>
|
||||
<string name="dialog_permission_notification">"Pour permettre à l’application d’afficher les notifications, veuillez accorder l’autorisation dans les paramètres du système."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Hogy az alkalmazás használhassa a kamerát, adja meg az engedélyt a rendszerbeállításokban."</string>
|
||||
<string name="dialog_permission_generic">"Adja meg az engedélyt a rendszerbeállításokban."</string>
|
||||
<string name="dialog_permission_microphone">"Hogy az alkalmazás használhassa a mikrofont, adja meg az engedélyt a rendszerbeállításokban."</string>
|
||||
<string name="dialog_permission_notification">"Hogy az alkalmazás megjeleníthesse az értesítéseket, adja meg az engedélyt a rendszerbeállításokban."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Supaya aplikasinya dapat menggunakan kamera, berikan izin dalam pengaturan sistem."</string>
|
||||
<string name="dialog_permission_generic">"Silakan memberikan izin dalam pengaturan sistem."</string>
|
||||
<string name="dialog_permission_microphone">"Supaya aplikasinya dapat menggunakan mikrofon, berikan izin dalam pengaturan sistem."</string>
|
||||
<string name="dialog_permission_notification">"Supaya aplikasinya dapat menampilkan notifikasi, berikan izin dalam pengaturan sistem."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Per permettere all\'applicazione di usare la fotocamera, concedi l\'autorizzazione nelle impostazioni di sistema."</string>
|
||||
<string name="dialog_permission_generic">"Concedi l\'autorizzazione nelle impostazioni di sistema."</string>
|
||||
<string name="dialog_permission_microphone">"Per permettere all\'applicazione di usare il microfono, concedi l\'autorizzazione nelle impostazioni di sistema."</string>
|
||||
<string name="dialog_permission_notification">"Per permettere all\'applicazione di mostrare notifiche, concedi l\'autorizzazione nelle impostazioni di sistema."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"იმისათვის, რომ აპლიკაციამ გამოიყენოს კამერა, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."</string>
|
||||
<string name="dialog_permission_generic">"გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."</string>
|
||||
<string name="dialog_permission_microphone">"იმისათვის, რომ აპლიკაციამ მიკროფონი გამოიყენოს, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."</string>
|
||||
<string name="dialog_permission_notification">"იმისათვის, რომ აპლიკაციამ გამოაჩინოს შეტყობინებები, გთხოვთ, მიანიჭოთ ნებართვა სისტემის პარამეტრებში."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"애플리케이션이 카메라를 사용할 수 있도록 시스템 설정에서 권한을 허용해주세요."</string>
|
||||
<string name="dialog_permission_generic">"시스템 설정에서 권한을 허용해주세요."</string>
|
||||
<string name="dialog_permission_microphone">"애플리케이션이 마이크를 사용할 수 있도록 시스템 설정에서 권한을 허용해주세요."</string>
|
||||
<string name="dialog_permission_notification">"애플리케이션이 알림을 표시할 수 있도록 시스템 설정에서 권한을 허용해주세요."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"For å la programmet bruke kameraet, vennligst gi tillatelse i systeminnstillingene."</string>
|
||||
<string name="dialog_permission_generic">"Vennligst gi tillatelse i systeminnstillingene."</string>
|
||||
<string name="dialog_permission_microphone">"For å la applikasjonen bruke mikrofonen, må du gi tillatelse i systeminnstillingene."</string>
|
||||
<string name="dialog_permission_notification">"For å la applikasjonen vise varsler, må du gi tillatelse til dette i systeminnstillingene."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Geef toestemming in de systeeminstellingen om de applicatie de camera te laten gebruiken."</string>
|
||||
<string name="dialog_permission_generic">"Geef hiervoor toestemming in de systeeminstellingen."</string>
|
||||
<string name="dialog_permission_microphone">"Geef toestemming in de systeeminstellingen om de applicatie de microfoon te laten gebruiken."</string>
|
||||
<string name="dialog_permission_notification">"Geef toestemming in de systeeminstellingen om de applicatie meldingen te laten weergeven."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Aby umożliwić aplikacji korzystanie z aparatu, prosimy o udzielenie zezwolenia w ustawieniach systemowych."</string>
|
||||
<string name="dialog_permission_generic">"Proszę nadać uprawnienia w ustawieniach systemowych."</string>
|
||||
<string name="dialog_permission_microphone">"Aby umożliwić aplikacji korzystanie z mikrofonu, prosimy o udzielenie zezwolenia w ustawieniach systemowych."</string>
|
||||
<string name="dialog_permission_notification">"Aby aplikacja mogła wyświetlać powiadomienia, udziel uprawnienia w ustawieniach systemowych."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Para permitir que o aplicativo use a câmera, conceda a permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_generic">"Por favor, conceda a permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_microphone">"Para permitir que o aplicativo use o microfone, conceda a permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_notification">"Para permitir que o aplicativo exiba notificações, conceda a permissão nas configurações do sistema."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Para que a aplicação possa utilizar a câmara, concede a permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_generic">"Concede a permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_microphone">"Para que a aplicação possa utilizar o microfone, concede essa permissão nas configurações do sistema."</string>
|
||||
<string name="dialog_permission_notification">"Para permitir que a aplicação apresente notificações, concede a permissão nas configurações do sistema."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Pentru a permite aplicației să utilizeze camera, vă rugăm să acordați permisiunea în setările sistemului."</string>
|
||||
<string name="dialog_permission_generic">"Vă rugăm să acordați permisiunea în setările sistemului."</string>
|
||||
<string name="dialog_permission_microphone">"Pentru a permite aplicației să utilizeze microfonul, vă rugăm să acordați permisiunea în setările sistemului."</string>
|
||||
<string name="dialog_permission_notification">"Pentru a permite aplicației să afișeze notificări, vă rugăm să acordați permisiunea în setările sistemului."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Чтобы приложение могло использовать камеру, предоставьте разрешение в системных настройках."</string>
|
||||
<string name="dialog_permission_generic">"Пожалуйста, предоставьте разрешение в системных настройках."</string>
|
||||
<string name="dialog_permission_microphone">"Чтобы приложение могло использовать микрофон, предоставьте разрешение в системных настройках."</string>
|
||||
<string name="dialog_permission_notification">"Чтобы приложение отображало уведомления, предоставьте разрешение в системных настройках."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Aby aplikácia mohla používať fotoaparát, udeľte povolenie v systémových nastaveniach."</string>
|
||||
<string name="dialog_permission_generic">"Udeľte prosím povolenie v systémových nastaveniach."</string>
|
||||
<string name="dialog_permission_microphone">"Aby aplikácia mohla používať mikrofón, udeľte povolenie v systémových nastaveniach."</string>
|
||||
<string name="dialog_permission_notification">"Ak chcete, aby aplikácia zobrazovala oznámenia, udeľte povolenie v nastaveniach systému."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"För att låta programmet använda kameran, vänligen ge behörigheten i systeminställningarna."</string>
|
||||
<string name="dialog_permission_generic">"Vänligen ge behörigheten i systeminställningarna."</string>
|
||||
<string name="dialog_permission_microphone">"För att låta programmet använda mikrofonen, vänligen ge behörigheten i systeminställningarna."</string>
|
||||
<string name="dialog_permission_notification">"För att låta applikationen visa aviseringar, vänligen bevilja behörighet i systeminställningarna."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Uygulamanın kamerayı kullanmasına izin vermek için lütfen sistem ayarlarından izin verin."</string>
|
||||
<string name="dialog_permission_generic">"Lütfen sistem ayarlarından izin verin."</string>
|
||||
<string name="dialog_permission_microphone">"Uygulamanın mikrofonu kullanmasına izin vermek için lütfen sistem ayarlarından izin verin."</string>
|
||||
<string name="dialog_permission_notification">"Uygulamanın bildirimleri görüntülemesine izin vermek için lütfen sistem ayarlarından izin verin."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Щоб дозволити застосунку використовувати камеру, надайте дозвіл у системних налаштуваннях."</string>
|
||||
<string name="dialog_permission_generic">"Надайте дозвіл в системних налаштуваннях."</string>
|
||||
<string name="dialog_permission_microphone">"Щоб дозволити застосунку використовувати мікрофон, надайте дозвіл у налаштуваннях системи."</string>
|
||||
<string name="dialog_permission_notification">"Щоб застосунок показував сповіщення, надайте дозвіл у налаштуваннях системи."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"اطلاقیے کو تصویرگر استعمال کرنے دینے کے لیے، برائے مہربانی نظام کی ترتیبات میں اجازت دیں۔"</string>
|
||||
<string name="dialog_permission_generic">"برائے مہربانی نظام کی ترتیبات میں اجازت دیں۔"</string>
|
||||
<string name="dialog_permission_microphone">"اطلاقیے کو صوتگر استعمال کرنے دینے کے لیے، برائے مہربانی نظام کی ترتیبات میں اجازت دیں۔"</string>
|
||||
<string name="dialog_permission_notification">"اطلاقیے کو اطلاعات ظاہر کرنے دینے کے لیے، برائے مہربانی نظام کی ترتیبات میں اجازت دیں۔"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"Ilovaga kameradan foydalanishiga ruxsat berish uchun tizim sozlamalarida ruxsat bering."</string>
|
||||
<string name="dialog_permission_generic">"Iltimos, tizim sozlamalarida ruxsat bering."</string>
|
||||
<string name="dialog_permission_microphone">"Ilovaga mikrofondan foydalanishiga ruxsat berish uchun tizim sozlamalarida ruxsat bering."</string>
|
||||
<string name="dialog_permission_notification">"Ilova bildirishnomalarni ko\'rsatishi uchun tizim sozlamalarida ruxsat bering."</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"為了讓應用程式使用相機,請到系統設定中開啟權限。"</string>
|
||||
<string name="dialog_permission_generic">"請到系統設定中開啟權限。"</string>
|
||||
<string name="dialog_permission_microphone">"為了讓應用程式使用麥克風,請到系統設定中開啟權限。"</string>
|
||||
<string name="dialog_permission_notification">"為了讓應用程式顯示通知,請到系統設定中開啟權限。"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"为了让应用程序使用相机,请在系统设置中授予权限。"</string>
|
||||
<string name="dialog_permission_generic">"请在系统设置中授予权限。"</string>
|
||||
<string name="dialog_permission_microphone">"为了让应用程序使用麦克风,请在系统设置中授予权限。"</string>
|
||||
<string name="dialog_permission_notification">"为了让应用程序显示通知,请在系统设置中授予权限。"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="dialog_permission_camera">"In order to let the application use the camera, please grant the permission in the system settings."</string>
|
||||
<string name="dialog_permission_generic">"Please grant the permission in the system settings."</string>
|
||||
<string name="dialog_permission_microphone">"In order to let the application use the microphone, please grant the permission in the system settings."</string>
|
||||
<string name="dialog_permission_notification">"In order to let the application display notifications, please grant the permission in the system settings."</string>
|
||||
</resources>
|
||||
49
libraries/permissions/impl/build.gradle.kts
Normal file
49
libraries/permissions/impl/build.gradle.kts
Normal file
@@ -0,0 +1,49 @@
|
||||
import extension.setupDependencyInjection
|
||||
import extension.testCommonDependencies
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2022-2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.permissions.impl"
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
isIncludeAndroidResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupDependencyInjection()
|
||||
|
||||
dependencies {
|
||||
implementation(libs.accompanist.permission)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.matrixui)
|
||||
implementation(projects.libraries.troubleshoot.api)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
implementation(projects.libraries.preferences.api)
|
||||
implementation(projects.services.toolbox.api)
|
||||
api(projects.libraries.permissions.api)
|
||||
|
||||
testCommonDependencies(libs)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
testImplementation(projects.libraries.permissions.test)
|
||||
testImplementation(projects.libraries.troubleshoot.test)
|
||||
testImplementation(projects.services.toolbox.test)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
|
||||
interface ComposablePermissionStateProvider {
|
||||
@Composable
|
||||
fun provide(permission: String, onPermissionResult: (Boolean) -> Unit): PermissionState
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class AccompanistPermissionStateProvider : ComposablePermissionStateProvider {
|
||||
@Composable
|
||||
override fun provide(permission: String, onPermissionResult: (Boolean) -> Unit): PermissionState {
|
||||
return rememberPermissionState(
|
||||
permission = permission,
|
||||
onPermissionResult = onPermissionResult
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPermissionStateProvider(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val permissionsStore: PermissionsStore,
|
||||
) : PermissionStateProvider {
|
||||
override fun isPermissionGranted(permission: String): Boolean {
|
||||
return ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
permission,
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
override suspend fun setPermissionDenied(permission: String, value: Boolean) = permissionsStore.setPermissionDenied(permission, value)
|
||||
|
||||
override fun isPermissionDenied(permission: String): Flow<Boolean> = permissionsStore.isPermissionDenied(permission)
|
||||
|
||||
override suspend fun setPermissionAsked(permission: String, value: Boolean) = permissionsStore.setPermissionAsked(permission, value)
|
||||
|
||||
override fun isPermissionAsked(permission: String): Flow<Boolean> = permissionsStore.isPermissionAsked(permission)
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.PermissionStatus
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.shouldShowRationale
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.Assisted
|
||||
import dev.zacsweers.metro.AssistedFactory
|
||||
import dev.zacsweers.metro.AssistedInject
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
import io.element.android.libraries.permissions.impl.action.PermissionActions
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
private val loggerTag = LoggerTag("DefaultPermissionsPresenter")
|
||||
|
||||
@AssistedInject
|
||||
class DefaultPermissionsPresenter(
|
||||
@Assisted val permission: String,
|
||||
private val permissionsStore: PermissionsStore,
|
||||
private val composablePermissionStateProvider: ComposablePermissionStateProvider,
|
||||
private val permissionActions: PermissionActions,
|
||||
) : PermissionsPresenter {
|
||||
@AssistedFactory
|
||||
@ContributesBinding(AppScope::class)
|
||||
interface Factory : PermissionsPresenter.Factory {
|
||||
override fun create(permission: String): DefaultPermissionsPresenter
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@SuppressLint("InlinedApi")
|
||||
@Composable
|
||||
override fun present(): PermissionsState {
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
|
||||
// To reset the store: ResetStore()
|
||||
|
||||
val isAlreadyDenied: Boolean by remember {
|
||||
permissionsStore.isPermissionDenied(permission)
|
||||
}.collectAsState(initial = false)
|
||||
|
||||
val isAlreadyAsked: Boolean by remember {
|
||||
permissionsStore.isPermissionAsked(permission)
|
||||
}.collectAsState(initial = false)
|
||||
|
||||
var permissionState: PermissionState? = null
|
||||
|
||||
fun onPermissionResult(result: Boolean) {
|
||||
Timber.tag(loggerTag.value).d("onPermissionResult: $result")
|
||||
localCoroutineScope.launch {
|
||||
permissionsStore.setPermissionAsked(permission, true)
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
// Should show rational true -> denied.
|
||||
if (permissionState?.status?.shouldShowRationale == true) {
|
||||
Timber.tag(loggerTag.value).d("onPermissionResult: setPermissionDenied to true")
|
||||
localCoroutineScope.launch {
|
||||
permissionsStore.setPermissionDenied(permission, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
permissionState = composablePermissionStateProvider.provide(
|
||||
permission = permission,
|
||||
onPermissionResult = ::onPermissionResult
|
||||
)
|
||||
|
||||
LaunchedEffect(this) {
|
||||
if (permissionState.status.isGranted) {
|
||||
// User may have granted permission from the settings, so reset the store regarding this permission
|
||||
permissionsStore.resetPermission(permission)
|
||||
}
|
||||
}
|
||||
|
||||
val showDialog = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
fun handleEvent(event: PermissionsEvents) {
|
||||
when (event) {
|
||||
PermissionsEvents.CloseDialog -> {
|
||||
showDialog.value = false
|
||||
}
|
||||
PermissionsEvents.RequestPermissions -> {
|
||||
if (permissionState.status !is PermissionStatus.Granted && isAlreadyDenied) {
|
||||
showDialog.value = true
|
||||
} else {
|
||||
permissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
PermissionsEvents.OpenSystemSettingAndCloseDialog -> {
|
||||
permissionActions.openSettings()
|
||||
showDialog.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PermissionsState(
|
||||
permission = permissionState.permission,
|
||||
permissionGranted = permissionState.status.isGranted,
|
||||
shouldShowRationale = permissionState.status.shouldShowRationale,
|
||||
showDialog = showDialog.value,
|
||||
permissionAlreadyAsked = isAlreadyAsked,
|
||||
permissionAlreadyDenied = isAlreadyDenied,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
@Composable
|
||||
private fun ResetStore() {
|
||||
LaunchedEffect(this@DefaultPermissionsPresenter) {
|
||||
launch {
|
||||
permissionsStore.resetStore()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPermissionsStore(
|
||||
preferenceDataStoreFactory: PreferenceDataStoreFactory,
|
||||
) : PermissionsStore {
|
||||
private val store = preferenceDataStoreFactory.create("permissions_store")
|
||||
|
||||
override suspend fun setPermissionDenied(permission: String, value: Boolean) {
|
||||
store.edit { prefs ->
|
||||
prefs[getDeniedPreferenceKey(permission)] = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPermissionDenied(permission: String): Flow<Boolean> {
|
||||
return store.data.map {
|
||||
it[getDeniedPreferenceKey(permission)].orFalse()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setPermissionAsked(permission: String, value: Boolean) {
|
||||
store.edit { prefs ->
|
||||
prefs[getAskedPreferenceKey(permission)] = value
|
||||
}
|
||||
}
|
||||
|
||||
override fun isPermissionAsked(permission: String): Flow<Boolean> {
|
||||
return store.data.map {
|
||||
it[getAskedPreferenceKey(permission)].orFalse()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun resetPermission(permission: String) {
|
||||
setPermissionAsked(permission, false)
|
||||
setPermissionDenied(permission, false)
|
||||
}
|
||||
|
||||
override suspend fun resetStore() {
|
||||
store.edit { it.clear() }
|
||||
}
|
||||
|
||||
private fun getDeniedPreferenceKey(permission: String) = booleanPreferencesKey("${permission}_denied")
|
||||
private fun getAskedPreferenceKey(permission: String) = booleanPreferencesKey("${permission}_asked")
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
import android.content.Context
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class AndroidPermissionActions(
|
||||
@ApplicationContext private val context: Context
|
||||
) : PermissionActions {
|
||||
override fun openSettings() {
|
||||
context.startNotificationSettingsIntent()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
interface PermissionActions {
|
||||
fun openSettings()
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl.troubleshoot
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesIntoSet
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.libraries.permissions.impl.R
|
||||
import io.element.android.libraries.permissions.impl.action.PermissionActions
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootNavigator
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState
|
||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@ContributesIntoSet(AppScope::class)
|
||||
@Inject
|
||||
class NotificationTroubleshootCheckPermissionTest(
|
||||
private val permissionStateProvider: PermissionStateProvider,
|
||||
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
||||
private val permissionActions: PermissionActions,
|
||||
stringProvider: StringProvider,
|
||||
) : NotificationTroubleshootTest {
|
||||
override val order: Int = 0
|
||||
|
||||
private val delegate = NotificationTroubleshootTestDelegate(
|
||||
defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_title),
|
||||
defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_description),
|
||||
hasQuickFix = true,
|
||||
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
|
||||
)
|
||||
|
||||
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
|
||||
|
||||
override suspend fun run(coroutineScope: CoroutineScope) {
|
||||
delegate.start()
|
||||
val result = if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
||||
permissionStateProvider.isPermissionGranted(Manifest.permission.POST_NOTIFICATIONS)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
delegate.done(result)
|
||||
}
|
||||
|
||||
override suspend fun reset() = delegate.reset()
|
||||
|
||||
override suspend fun quickFix(
|
||||
coroutineScope: CoroutineScope,
|
||||
navigator: NotificationTroubleshootNavigator,
|
||||
) {
|
||||
// Do not bother about asking the permission inline, just lead the user to the settings
|
||||
permissionActions.openSettings()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Пераканайцеся, што праграма можа паказваць апавяшчэнні."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Праверце дазволы"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Проверка дали приложението може да показва известия."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Проверка на разрешенията"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Ujistěte se, že aplikace může zobrazovat oznámení."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Kontrola oprávnění"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Gwiriwch y gall y rhaglen ddangos hysbysiadau."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Gwirio caniatâd"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Kontroller, at applikationen kan vise underretninger."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Kontroller tilladelser"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Prüfe, dass die Anwendung Benachrichtigungen anzeigen kann."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Berechtigungen überprüfen"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Έλεγξε ότι η εφαρμογή μπορεί να εμφανίζει ειδοποιήσεις."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Έλεγχος δικαιωμάτων"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Verificar que la aplicación pueda mostrar notificaciones."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Verificar permisos"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Kontrolli, kas rakendus võib kuvada teavitusi."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Täpsusta õigusi"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Egiaztatu aplikazioak jakinarazpenak erakutsi ditzakeela."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Egiaztatu baimenak"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"بررسی اجازهها"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Tarkistaa, että sovellus voi näyttää ilmoituksia."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Lupien tarkistus"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Vérifie que l’application peut afficher des notifications."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Vérifier les autorisations"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Ellenőrizze, hogy az alkalmazás képes-e értesítéseket megjeleníteni."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Engedélyek ellenőrzése"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Pastikan aplikasi dapat menampilkan notifikasi."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Periksa izin"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Verifica che l\'applicazione possa mostrare le notifiche."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Controlla autorizzazioni"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"შეამოწმეთ რომ აპლიკაციას შეტყობინებების ჩვენება შეუძლია."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"ნებართვების შემოწმება"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"애플리케이션에서 알림을 표시할 수 있는지 확인하세요."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"권한 확인"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Kontroller at programmet kan vise varsler."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Sjekk tillatelser"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Controleren of de applicatie meldingen kan weergeven."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Controleer machtigingen"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Sprawdź, czy aplikacja może wyświetlać powiadomienia."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Sprawdź uprawnienia"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Verifique se o aplicativo pode mostrar notificações."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Verifique as permissões"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Verificar se a aplicação consegue mostrar notificações."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Verificar permissões"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Verificați dacă aplicația poate afișa notificări."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Verificați permisiunile"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Убедитесь, что приложение может показывать уведомления."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Проверка разрешений"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Uistite sa, že aplikácia dokáže zobrazovať upozornenia."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Skontrolovať povolenia"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Kontrollera att applikationen kan visa aviseringar."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Kontrollera behörigheter"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Uygulamanın bildirimleri gösterebildiğini kontrol edin."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"İzinleri kontrol et"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Перевірте, чи може застосунок показувати сповіщення."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Перевірте дозволи"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"پڑتال کریں کہ اطلاقیہ اطلاعات دکھا سکتا ہے"</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"اجازتوں کی پڑتال کریں"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Ilova bildirishnomalarni ko‘rsata olishini tekshiring."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Ruxsatlarni tekshiring"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"檢查應用程式是否可以顯示通知。"</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"檢查權限"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"检查应用程序是否可以显示通知。"</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"检查权限"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="troubleshoot_notifications_test_check_permission_description">"Check that the application can show notifications."</string>
|
||||
<string name="troubleshoot_notifications_test_check_permission_title">"Check permissions"</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionStatus
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.impl.action.FakePermissionActions
|
||||
import io.element.android.libraries.permissions.test.InMemoryPermissionsStore
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
const val A_PERMISSION = "A_PERMISSION"
|
||||
|
||||
class DefaultPermissionsPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Granted
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.permission).isEqualTo(A_PERMISSION)
|
||||
assertThat(initialState.permissionGranted).isTrue()
|
||||
assertThat(initialState.shouldShowRationale).isFalse()
|
||||
assertThat(initialState.permissionAlreadyAsked).isFalse()
|
||||
assertThat(initialState.permissionAlreadyDenied).isFalse()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user closes dialog`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore(
|
||||
permissionDenied = true,
|
||||
permissionAsked = true
|
||||
)
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
withDialogState.eventSink.invoke(PermissionsEvents.CloseDialog)
|
||||
assertThat(awaitItem().showDialog).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user open settings`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore(
|
||||
permissionDenied = true,
|
||||
permissionAsked = true
|
||||
)
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val permissionActions = FakePermissionActions()
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
permissionActions,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
assertThat(permissionActions.openSettingsCalled).isFalse()
|
||||
withDialogState.eventSink.invoke(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
assertThat(awaitItem().showDialog).isFalse()
|
||||
assertThat(permissionActions.openSettingsCalled).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user does not grant permission`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User does not grant permission
|
||||
permissionStateProvider.userGiveAnswer(answer = false, firstTime = true)
|
||||
skipItems(1)
|
||||
val state = awaitItem()
|
||||
assertThat(state.permissionGranted).isFalse()
|
||||
assertThat(state.showDialog).isFalse()
|
||||
assertThat(state.permissionAlreadyDenied).isFalse()
|
||||
assertThat(state.permissionAlreadyAsked).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user does not grant permission second time`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = true)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User does not grant permission
|
||||
permissionStateProvider.userGiveAnswer(answer = false, firstTime = false)
|
||||
skipItems(2)
|
||||
val state = awaitItem()
|
||||
assertThat(state.permissionGranted).isFalse()
|
||||
assertThat(state.showDialog).isFalse()
|
||||
assertThat(state.permissionAlreadyDenied).isTrue()
|
||||
assertThat(state.permissionAlreadyAsked).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user does not grant permission third time`() = runTest {
|
||||
val permissionsStore =
|
||||
InMemoryPermissionsStore(
|
||||
permissionDenied = true,
|
||||
permissionAsked = true
|
||||
)
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
assertThat(withDialogState.permissionGranted).isFalse()
|
||||
assertThat(withDialogState.permissionAlreadyDenied).isTrue()
|
||||
assertThat(withDialogState.permissionAlreadyAsked).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user grants permission`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User grants permission
|
||||
permissionStateProvider.userGiveAnswer(answer = true, firstTime = true)
|
||||
skipItems(1)
|
||||
val state = awaitItem()
|
||||
assertThat(state.permissionGranted).isTrue()
|
||||
assertThat(state.showDialog).isFalse()
|
||||
assertThat(state.permissionAlreadyDenied).isFalse()
|
||||
assertThat(state.permissionAlreadyAsked).isTrue()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPermissionsApi::class)
|
||||
|
||||
package io.element.android.libraries.permissions.impl
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.PermissionStatus
|
||||
|
||||
class FakeComposablePermissionStateProvider(
|
||||
private val permissionState: FakePermissionState
|
||||
) : ComposablePermissionStateProvider {
|
||||
private lateinit var onPermissionResult: (Boolean) -> Unit
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
override fun provide(permission: String, onPermissionResult: (Boolean) -> Unit): PermissionState {
|
||||
this.onPermissionResult = onPermissionResult
|
||||
return permissionState
|
||||
}
|
||||
|
||||
fun userGiveAnswer(answer: Boolean, firstTime: Boolean) {
|
||||
onPermissionResult.invoke(answer)
|
||||
permissionState.givenPermissionStatus(answer, firstTime)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
class FakePermissionState(
|
||||
override val permission: String,
|
||||
initialStatus: PermissionStatus,
|
||||
) : PermissionState {
|
||||
override var status: PermissionStatus by mutableStateOf(initialStatus)
|
||||
|
||||
var launchPermissionRequestCalled = false
|
||||
private set
|
||||
|
||||
override fun launchPermissionRequest() {
|
||||
launchPermissionRequestCalled = true
|
||||
}
|
||||
|
||||
fun givenPermissionStatus(hasPermission: Boolean, shouldShowRationale: Boolean) {
|
||||
status = if (hasPermission) PermissionStatus.Granted else PermissionStatus.Denied(shouldShowRationale)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
class FakePermissionActions(
|
||||
val openSettingsAction: () -> Unit = {}
|
||||
) : PermissionActions {
|
||||
var openSettingsCalled = false
|
||||
private set
|
||||
|
||||
override fun openSettings() {
|
||||
openSettingsAction()
|
||||
openSettingsCalled = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2024, 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.impl.troubleshoot
|
||||
|
||||
import android.os.Build
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.permissions.impl.action.FakePermissionActions
|
||||
import io.element.android.libraries.permissions.test.FakePermissionStateProvider
|
||||
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState
|
||||
import io.element.android.libraries.troubleshoot.test.FakeNotificationTroubleshootNavigator
|
||||
import io.element.android.libraries.troubleshoot.test.runAndTestState
|
||||
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
|
||||
import io.element.android.services.toolbox.test.strings.FakeStringProvider
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class NotificationTroubleshootCheckPermissionTestTest {
|
||||
@Test
|
||||
fun `test NotificationTroubleshootCheckPermissionTest below TIRAMISU success`() = runTest {
|
||||
val sut = NotificationTroubleshootCheckPermissionTest(
|
||||
permissionStateProvider = FakePermissionStateProvider(),
|
||||
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU - 1),
|
||||
permissionActions = FakePermissionActions(),
|
||||
stringProvider = FakeStringProvider(),
|
||||
)
|
||||
sut.runAndTestState {
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test NotificationTroubleshootCheckPermissionTest TIRAMISU success`() = runTest {
|
||||
val sut = NotificationTroubleshootCheckPermissionTest(
|
||||
permissionStateProvider = FakePermissionStateProvider(),
|
||||
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
|
||||
permissionActions = FakePermissionActions(),
|
||||
stringProvider = FakeStringProvider(),
|
||||
)
|
||||
sut.runAndTestState {
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test NotificationTroubleshootCheckPermissionTest TIRAMISU error`() = runTest {
|
||||
val permissionStateProvider = FakePermissionStateProvider(
|
||||
permissionGranted = false
|
||||
)
|
||||
val actions = FakePermissionActions(
|
||||
openSettingsAction = {
|
||||
permissionStateProvider.setPermissionGranted()
|
||||
}
|
||||
)
|
||||
val sut = NotificationTroubleshootCheckPermissionTest(
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
|
||||
permissionActions = actions,
|
||||
stringProvider = FakeStringProvider(),
|
||||
)
|
||||
sut.runAndTestState {
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(hasQuickFix = true))
|
||||
// Quick fix
|
||||
backgroundScope.launch {
|
||||
sut.quickFix(this, FakeNotificationTroubleshootNavigator())
|
||||
// Run the test again (IRL it will be done thanks to the resuming of the application)
|
||||
sut.run(this)
|
||||
}
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test NotificationTroubleshootCheckPermissionTest error and reset`() = runTest {
|
||||
val permissionStateProvider = FakePermissionStateProvider(
|
||||
permissionGranted = false
|
||||
)
|
||||
val actions = FakePermissionActions(
|
||||
openSettingsAction = {
|
||||
permissionStateProvider.setPermissionGranted()
|
||||
}
|
||||
)
|
||||
val sut = NotificationTroubleshootCheckPermissionTest(
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
|
||||
permissionActions = actions,
|
||||
stringProvider = FakeStringProvider(),
|
||||
)
|
||||
sut.runAndTestState {
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(hasQuickFix = true))
|
||||
sut.reset()
|
||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
24
libraries/permissions/noop/build.gradle.kts
Normal file
24
libraries/permissions/noop/build.gradle.kts
Normal file
@@ -0,0 +1,24 @@
|
||||
import extension.testCommonDependencies
|
||||
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.permissions.noop"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.architecture)
|
||||
api(projects.libraries.permissions.api)
|
||||
|
||||
testCommonDependencies(libs)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.noop
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
|
||||
class NoopPermissionsPresenter(
|
||||
private val isGranted: Boolean = false,
|
||||
) : PermissionsPresenter {
|
||||
@Composable
|
||||
override fun present(): PermissionsState {
|
||||
return PermissionsState(
|
||||
permission = "",
|
||||
permissionGranted = isGranted,
|
||||
shouldShowRationale = false,
|
||||
showDialog = false,
|
||||
permissionAlreadyAsked = false,
|
||||
permissionAlreadyDenied = false,
|
||||
eventSink = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.noop
|
||||
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class NoopPermissionsPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val presenter = NoopPermissionsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.permission).isEmpty()
|
||||
assertThat(initialState.permissionGranted).isFalse()
|
||||
assertThat(initialState.shouldShowRationale).isFalse()
|
||||
assertThat(initialState.permissionAlreadyAsked).isFalse()
|
||||
assertThat(initialState.permissionAlreadyDenied).isFalse()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
}
|
||||
}
|
||||
}
|
||||
20
libraries/permissions/test/build.gradle.kts
Normal file
20
libraries/permissions/test/build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-compose-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.permissions.test"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.architecture)
|
||||
api(projects.libraries.permissions.api)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.test
|
||||
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class FakePermissionStateProvider(
|
||||
private var permissionGranted: Boolean = true,
|
||||
permissionDenied: Boolean = false,
|
||||
permissionAsked: Boolean = false,
|
||||
) : PermissionStateProvider {
|
||||
private val permissionDeniedFlow = MutableStateFlow(permissionDenied)
|
||||
private val permissionAskedFlow = MutableStateFlow(permissionAsked)
|
||||
|
||||
fun setPermissionGranted() {
|
||||
permissionGranted = true
|
||||
}
|
||||
|
||||
override fun isPermissionGranted(permission: String): Boolean = permissionGranted
|
||||
|
||||
override suspend fun setPermissionDenied(permission: String, value: Boolean) {
|
||||
permissionDeniedFlow.value = value
|
||||
}
|
||||
|
||||
override fun isPermissionDenied(permission: String): Flow<Boolean> = permissionDeniedFlow
|
||||
|
||||
override suspend fun setPermissionAsked(permission: String, value: Boolean) {
|
||||
permissionAskedFlow.value = value
|
||||
}
|
||||
|
||||
override fun isPermissionAsked(permission: String): Flow<Boolean> = permissionAskedFlow
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.test
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.aPermissionsState
|
||||
|
||||
class FakePermissionsPresenter(
|
||||
private val initialState: PermissionsState = aPermissionsState(showDialog = false),
|
||||
) : PermissionsPresenter {
|
||||
private fun handleEvent(event: PermissionsEvents) {
|
||||
when (event) {
|
||||
PermissionsEvents.RequestPermissions -> state.value = state.value.copy(showDialog = true, permissionAlreadyAsked = true)
|
||||
PermissionsEvents.CloseDialog -> state.value = state.value.copy(showDialog = false)
|
||||
PermissionsEvents.OpenSystemSettingAndCloseDialog -> state.value = state.value.copy(showDialog = false)
|
||||
}
|
||||
}
|
||||
|
||||
private val state = mutableStateOf(initialState.copy(eventSink = ::handleEvent))
|
||||
|
||||
fun setPermissionGranted() {
|
||||
state.value = state.value.copy(permissionGranted = true)
|
||||
}
|
||||
|
||||
fun setPermissionDenied() {
|
||||
state.value = state.value.copy(permissionGranted = false, permissionAlreadyDenied = true)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun present(): PermissionsState {
|
||||
return state.value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.test
|
||||
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
|
||||
class FakePermissionsPresenterFactory(
|
||||
private val permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
||||
) : PermissionsPresenter.Factory {
|
||||
override fun create(permission: String): PermissionsPresenter {
|
||||
return permissionPresenter
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2023-2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.permissions.test
|
||||
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class InMemoryPermissionsStore(
|
||||
permissionDenied: Boolean = false,
|
||||
permissionAsked: Boolean = false,
|
||||
) : PermissionsStore {
|
||||
private val permissionDeniedFlow = MutableStateFlow(permissionDenied)
|
||||
private val permissionAskedFlow = MutableStateFlow(permissionAsked)
|
||||
|
||||
override suspend fun setPermissionDenied(permission: String, value: Boolean) {
|
||||
permissionDeniedFlow.value = value
|
||||
}
|
||||
|
||||
override fun isPermissionDenied(permission: String): Flow<Boolean> = permissionDeniedFlow
|
||||
|
||||
override suspend fun setPermissionAsked(permission: String, value: Boolean) {
|
||||
permissionAskedFlow.value = value
|
||||
}
|
||||
|
||||
override fun isPermissionAsked(permission: String): Flow<Boolean> = permissionAskedFlow
|
||||
|
||||
override suspend fun resetPermission(permission: String) {
|
||||
setPermissionAsked(permission, false)
|
||||
setPermissionDenied(permission, false)
|
||||
}
|
||||
|
||||
override suspend fun resetStore() = Unit
|
||||
}
|
||||
Reference in New Issue
Block a user