Merge pull request #5877 from element-hq/feature/bma/fixPermissionSettingNavigation
Fix permission setting navigation
This commit is contained in:
@@ -40,7 +40,7 @@ import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidityEf
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -132,7 +132,7 @@ class ConfigureRoomPresenter(
|
||||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> dataStore.setAvatarUri(uri = null)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import dev.zacsweers.metro.AssistedInject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.noop.NoopPermissionsPresenter
|
||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||
@@ -58,7 +58,7 @@ class NotificationsOptInPresenter(
|
||||
if (notificationsPermissionsState.permissionGranted) {
|
||||
callback.onNotificationsOptInFinished()
|
||||
} else {
|
||||
notificationsPermissionsState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
notificationsPermissionsState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
NotificationsOptInEvents.NotNowClicked -> {
|
||||
|
||||
@@ -18,7 +18,7 @@ import androidx.compose.runtime.setValue
|
||||
import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
|
||||
@Inject
|
||||
@@ -46,7 +46,7 @@ class QrCodeIntroPresenter(
|
||||
canContinue = true
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaSenderFactory
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
|
||||
import io.element.android.libraries.push.api.notifications.conversations.NotificationConversationService
|
||||
@@ -284,7 +284,7 @@ class MessageComposerPresenter(
|
||||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingEvent = event
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
MessageComposerEvent.PickAttachmentSource.VideoFromCamera -> localCoroutineScope.launch {
|
||||
@@ -293,7 +293,7 @@ class MessageComposerPresenter(
|
||||
cameraVideoPicker.launch()
|
||||
} else {
|
||||
pendingEvent = event
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
MessageComposerEvent.PickAttachmentSource.Location -> {
|
||||
|
||||
@@ -33,7 +33,7 @@ import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.mediaupload.api.MediaSenderFactory
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent
|
||||
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
|
||||
@@ -111,7 +111,7 @@ class DefaultVoiceMessageComposerPresenter(
|
||||
}
|
||||
else -> {
|
||||
Timber.i("Voice message permission needed")
|
||||
permissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
permissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,10 +176,10 @@ class DefaultVoiceMessageComposerPresenter(
|
||||
localCoroutineScope.deleteRecording()
|
||||
}
|
||||
VoiceMessageComposerEvent.DismissPermissionsRationale -> {
|
||||
permissionState.eventSink(PermissionsEvents.CloseDialog)
|
||||
permissionState.eventSink(PermissionsEvent.CloseDialog)
|
||||
}
|
||||
VoiceMessageComposerEvent.AcceptPermissionRationale -> {
|
||||
permissionState.eventSink(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
permissionState.eventSink(PermissionsEvent.OpenSystemSettingAndCloseDialog)
|
||||
}
|
||||
is VoiceMessageComposerEvent.LifecycleEvent -> handleLifecycleEvent(event.event)
|
||||
VoiceMessageComposerEvent.DismissSendFailureDialog -> {
|
||||
|
||||
@@ -35,7 +35,7 @@ import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -127,7 +127,7 @@ class EditUserProfilePresenter(
|
||||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> {
|
||||
temporaryUriDeleter.delete(userAvatarUri?.toUri())
|
||||
|
||||
@@ -36,7 +36,7 @@ import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvents
|
||||
import io.element.android.libraries.permissions.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -157,7 +157,7 @@ class RoomDetailsEditPresenter(
|
||||
cameraPhotoPicker.launch()
|
||||
} else {
|
||||
pendingPermissionRequest = true
|
||||
cameraPermissionState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
cameraPermissionState.eventSink(PermissionsEvent.RequestPermissions)
|
||||
}
|
||||
AvatarAction.Remove -> {
|
||||
temporaryUriDeleter.delete(roomAvatarUriEdited?.toUri())
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
package io.element.android.libraries.permissions.api
|
||||
|
||||
sealed interface PermissionsEvents {
|
||||
data object RequestPermissions : PermissionsEvents
|
||||
data object CloseDialog : PermissionsEvents
|
||||
data object OpenSystemSettingAndCloseDialog : PermissionsEvents
|
||||
sealed interface PermissionsEvent {
|
||||
data object RequestPermissions : PermissionsEvent
|
||||
data object CloseDialog : PermissionsEvent
|
||||
data object OpenSystemSettingAndCloseDialog : PermissionsEvent
|
||||
}
|
||||
@@ -17,5 +17,5 @@ data class PermissionsState(
|
||||
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
|
||||
val eventSink: (PermissionsEvent) -> Unit
|
||||
)
|
||||
|
||||
@@ -35,9 +35,9 @@ fun PermissionsView(
|
||||
content = content ?: state.permission.toDialogContent(),
|
||||
submitText = stringResource(id = CommonStrings.action_open_settings),
|
||||
onSubmitClick = {
|
||||
state.eventSink.invoke(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
state.eventSink.invoke(PermissionsEvent.OpenSystemSettingAndCloseDialog)
|
||||
},
|
||||
onDismiss = { state.eventSink.invoke(PermissionsEvents.CloseDialog) },
|
||||
onDismiss = { state.eventSink.invoke(PermissionsEvent.CloseDialog) },
|
||||
icon = icon,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ 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.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
@@ -100,20 +100,20 @@ class DefaultPermissionsPresenter(
|
||||
|
||||
val showDialog = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
fun handleEvent(event: PermissionsEvents) {
|
||||
fun handleEvent(event: PermissionsEvent) {
|
||||
when (event) {
|
||||
PermissionsEvents.CloseDialog -> {
|
||||
PermissionsEvent.CloseDialog -> {
|
||||
showDialog.value = false
|
||||
}
|
||||
PermissionsEvents.RequestPermissions -> {
|
||||
PermissionsEvent.RequestPermissions -> {
|
||||
if (permissionState.status !is PermissionStatus.Granted && isAlreadyDenied) {
|
||||
showDialog.value = true
|
||||
} else {
|
||||
permissionState.launchPermissionRequest()
|
||||
}
|
||||
}
|
||||
PermissionsEvents.OpenSystemSettingAndCloseDialog -> {
|
||||
permissionActions.openSettings()
|
||||
PermissionsEvent.OpenSystemSettingAndCloseDialog -> {
|
||||
permissionActions.openSettings(permission)
|
||||
showDialog.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import dev.zacsweers.metro.AppScope
|
||||
import dev.zacsweers.metro.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.system.openAppSettingsPage
|
||||
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
|
||||
import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
|
||||
@@ -18,7 +20,10 @@ import io.element.android.libraries.di.annotations.ApplicationContext
|
||||
class AndroidPermissionActions(
|
||||
@ApplicationContext private val context: Context
|
||||
) : PermissionActions {
|
||||
override fun openSettings() {
|
||||
context.startNotificationSettingsIntent()
|
||||
override fun openSettings(permission: String) {
|
||||
when (permission) {
|
||||
Manifest.permission.POST_NOTIFICATIONS -> context.startNotificationSettingsIntent()
|
||||
else -> context.openAppSettingsPage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
interface PermissionActions {
|
||||
fun openSettings()
|
||||
fun openSettings(permission: String)
|
||||
}
|
||||
|
||||
@@ -61,6 +61,6 @@ class NotificationTroubleshootCheckPermissionTest(
|
||||
navigator: NotificationTroubleshootNavigator,
|
||||
) {
|
||||
// Do not bother about asking the permission inline, just lead the user to the settings
|
||||
permissionActions.openSettings()
|
||||
permissionActions.openSettings(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,21 +10,23 @@
|
||||
|
||||
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.api.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsStore
|
||||
import io.element.android.libraries.permissions.impl.action.FakePermissionActions
|
||||
import io.element.android.libraries.permissions.impl.action.PermissionActions
|
||||
import io.element.android.libraries.permissions.test.InMemoryPermissionsStore
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
const val A_PERMISSION = "A_PERMISSION"
|
||||
private const val A_PERMISSION = "A_PERMISSION"
|
||||
|
||||
class DefaultPermissionsPresenterTest {
|
||||
@get:Rule
|
||||
@@ -32,24 +34,8 @@ class DefaultPermissionsPresenterTest {
|
||||
|
||||
@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 presenter = createPresenter()
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.permission).isEqualTo(A_PERMISSION)
|
||||
assertThat(initialState.permissionGranted).isTrue()
|
||||
@@ -66,29 +52,22 @@ class DefaultPermissionsPresenterTest {
|
||||
permissionDenied = true,
|
||||
permissionAsked = true
|
||||
)
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = false)
|
||||
),
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
val presenter = createPresenter(
|
||||
permissionsStore = permissionsStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
withDialogState.eventSink.invoke(PermissionsEvents.CloseDialog)
|
||||
withDialogState.eventSink.invoke(PermissionsEvent.CloseDialog)
|
||||
assertThat(awaitItem().showDialog).isFalse()
|
||||
}
|
||||
}
|
||||
@@ -99,59 +78,48 @@ class DefaultPermissionsPresenterTest {
|
||||
permissionDenied = true,
|
||||
permissionAsked = true
|
||||
)
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = false),
|
||||
),
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val permissionActions = FakePermissionActions()
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
permissionActions,
|
||||
val openSettingsAction = lambdaRecorder<String, Unit> { }
|
||||
val permissionActions = FakePermissionActions(
|
||||
openSettingsAction = openSettingsAction,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val presenter = createPresenter(
|
||||
permissionsStore = permissionsStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
permissionActions = permissionActions,
|
||||
)
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
assertThat(permissionActions.openSettingsCalled).isFalse()
|
||||
withDialogState.eventSink.invoke(PermissionsEvents.OpenSystemSettingAndCloseDialog)
|
||||
openSettingsAction.assertions().isNeverCalled()
|
||||
withDialogState.eventSink.invoke(PermissionsEvent.OpenSystemSettingAndCloseDialog)
|
||||
assertThat(awaitItem().showDialog).isFalse()
|
||||
assertThat(permissionActions.openSettingsCalled).isTrue()
|
||||
openSettingsAction.assertions().isCalledOnce().with(value(A_PERMISSION))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - user does not grant permission`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
val permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = permissionState,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val presenter = createPresenter(
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User does not grant permission
|
||||
permissionStateProvider.userGiveAnswer(answer = false, firstTime = true)
|
||||
@@ -166,27 +134,19 @@ class DefaultPermissionsPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - user does not grant permission second time`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = true)
|
||||
val permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = true)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = permissionState,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val presenter = createPresenter(
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User does not grant permission
|
||||
permissionStateProvider.userGiveAnswer(answer = false, firstTime = false)
|
||||
@@ -201,31 +161,24 @@ class DefaultPermissionsPresenterTest {
|
||||
|
||||
@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 permissionsStore = InMemoryPermissionsStore(
|
||||
permissionDenied = true,
|
||||
permissionAsked = true,
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
val permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = false),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = permissionState,
|
||||
)
|
||||
val presenter = createPresenter(
|
||||
permissionsStore = permissionsStore,
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
)
|
||||
presenter.test {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
val withDialogState = awaitItem()
|
||||
assertThat(withDialogState.showDialog).isTrue()
|
||||
assertThat(withDialogState.permissionGranted).isFalse()
|
||||
@@ -236,27 +189,19 @@ class DefaultPermissionsPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - user grants permission`() = runTest {
|
||||
val permissionsStore = InMemoryPermissionsStore()
|
||||
val permissionState = FakePermissionState(
|
||||
A_PERMISSION,
|
||||
PermissionStatus.Denied(shouldShowRationale = false)
|
||||
val permissionState = aFakePermissionState(
|
||||
initialStatus = PermissionStatus.Denied(shouldShowRationale = false)
|
||||
)
|
||||
val permissionStateProvider =
|
||||
FakeComposablePermissionStateProvider(
|
||||
permissionState
|
||||
)
|
||||
val presenter = DefaultPermissionsPresenter(
|
||||
A_PERMISSION,
|
||||
permissionsStore,
|
||||
permissionStateProvider,
|
||||
FakePermissionActions(),
|
||||
val permissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = permissionState,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val presenter = createPresenter(
|
||||
permissionStateProvider = permissionStateProvider,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.showDialog).isFalse()
|
||||
initialState.eventSink.invoke(PermissionsEvents.RequestPermissions)
|
||||
initialState.eventSink.invoke(PermissionsEvent.RequestPermissions)
|
||||
assertThat(permissionState.launchPermissionRequestCalled).isTrue()
|
||||
// User grants permission
|
||||
permissionStateProvider.userGiveAnswer(answer = true, firstTime = true)
|
||||
@@ -269,3 +214,25 @@ class DefaultPermissionsPresenterTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createPresenter(
|
||||
permission: String = A_PERMISSION,
|
||||
permissionsStore: PermissionsStore = InMemoryPermissionsStore(),
|
||||
permissionStateProvider: ComposablePermissionStateProvider = FakeComposablePermissionStateProvider(
|
||||
permissionState = aFakePermissionState(),
|
||||
),
|
||||
permissionActions: PermissionActions = FakePermissionActions(),
|
||||
) = DefaultPermissionsPresenter(
|
||||
permission = permission,
|
||||
permissionsStore = permissionsStore,
|
||||
composablePermissionStateProvider = permissionStateProvider,
|
||||
permissionActions = permissionActions,
|
||||
)
|
||||
|
||||
private fun aFakePermissionState(
|
||||
permission: String = A_PERMISSION,
|
||||
initialStatus: PermissionStatus = PermissionStatus.Granted,
|
||||
) = FakePermissionState(
|
||||
permission = permission,
|
||||
initialStatus = initialStatus,
|
||||
)
|
||||
|
||||
@@ -8,14 +8,12 @@
|
||||
|
||||
package io.element.android.libraries.permissions.impl.action
|
||||
|
||||
class FakePermissionActions(
|
||||
val openSettingsAction: () -> Unit = {}
|
||||
) : PermissionActions {
|
||||
var openSettingsCalled = false
|
||||
private set
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
|
||||
override fun openSettings() {
|
||||
openSettingsAction()
|
||||
openSettingsCalled = true
|
||||
class FakePermissionActions(
|
||||
val openSettingsAction: (String) -> Unit = { lambdaError() }
|
||||
) : PermissionActions {
|
||||
override fun openSettings(permission: String) {
|
||||
openSettingsAction(permission)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ 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.PermissionsEvent
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.aPermissionsState
|
||||
@@ -18,11 +18,11 @@ import io.element.android.libraries.permissions.api.aPermissionsState
|
||||
class FakePermissionsPresenter(
|
||||
private val initialState: PermissionsState = aPermissionsState(showDialog = false),
|
||||
) : PermissionsPresenter {
|
||||
private fun handleEvent(event: PermissionsEvents) {
|
||||
private fun handleEvent(event: PermissionsEvent) {
|
||||
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)
|
||||
PermissionsEvent.RequestPermissions -> state.value = state.value.copy(showDialog = true, permissionAlreadyAsked = true)
|
||||
PermissionsEvent.CloseDialog -> state.value = state.value.copy(showDialog = false)
|
||||
PermissionsEvent.OpenSystemSettingAndCloseDialog -> state.value = state.value.copy(showDialog = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user