diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationEvents.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationEvents.kt index b725ec6db7..dd4428d0bb 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationEvents.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationEvents.kt @@ -16,7 +16,14 @@ package io.element.android.features.location.impl.show +import io.element.android.features.location.impl.send.SendLocationEvents + sealed interface ShowLocationEvents { object Share : ShowLocationEvents data class TrackMyLocation(val enabled: Boolean) : ShowLocationEvents + object DismissDialog : ShowLocationEvents + + object RequestPermissions : ShowLocationEvents + + object OpenAppSettings : ShowLocationEvents } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt index 3ac5d90bb6..267f9e2dde 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenter.kt @@ -17,6 +17,8 @@ package io.element.android.features.location.impl.show import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -26,13 +28,16 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import io.element.android.features.location.api.Location import io.element.android.features.location.impl.MapDefaults +import io.element.android.features.location.impl.permissions.PermissionsEvents import io.element.android.features.location.impl.permissions.PermissionsPresenter import io.element.android.features.location.impl.permissions.PermissionsState import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.core.meta.BuildMeta class ShowLocationPresenter @AssistedInject constructor( permissionsPresenterFactory: PermissionsPresenter.Factory, - private val actions: LocationActions, + private val locationActions: LocationActions, + private val buildMeta: BuildMeta, @Assisted private val location: Location, @Assisted private val description: String? ) : Presenter { @@ -48,19 +53,47 @@ class ShowLocationPresenter @AssistedInject constructor( override fun present(): ShowLocationState { val permissionsState: PermissionsState = permissionsPresenter.present() var isTrackMyLocation by remember { mutableStateOf(false) } + val appName by remember { derivedStateOf { buildMeta.applicationName } } + var permissionDialog: ShowLocationState.Dialog by remember { + mutableStateOf(ShowLocationState.Dialog.None) + } + + LaunchedEffect(permissionsState.permissions) { + if (permissionsState.isAnyGranted) { + permissionDialog = ShowLocationState.Dialog.None + } + } fun handleEvents(event: ShowLocationEvents) { when (event) { - ShowLocationEvents.Share -> actions.share(location, description) - is ShowLocationEvents.TrackMyLocation -> isTrackMyLocation = event.enabled + ShowLocationEvents.Share -> locationActions.share(location, description) + is ShowLocationEvents.TrackMyLocation -> { + if (event.enabled) { + when { + permissionsState.isAnyGranted -> isTrackMyLocation = true + permissionsState.shouldShowRationale -> permissionDialog = ShowLocationState.Dialog.PermissionRationale + else -> permissionDialog = ShowLocationState.Dialog.PermissionDenied + } + } else { + isTrackMyLocation = false + } + } + ShowLocationEvents.DismissDialog -> permissionDialog = ShowLocationState.Dialog.None + ShowLocationEvents.OpenAppSettings -> { + locationActions.openSettings() + permissionDialog = ShowLocationState.Dialog.None + } + ShowLocationEvents.RequestPermissions -> permissionsState.eventSink(PermissionsEvents.RequestPermissions) } } return ShowLocationState( + permissionDialog = permissionDialog, location = location, description = description, hasLocationPermission = permissionsState.isAnyGranted, isTrackMyLocation = isTrackMyLocation, + appName = appName, eventSink = ::handleEvents, ) } diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt index c567dd3c94..0be6938ef6 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationState.kt @@ -19,9 +19,17 @@ package io.element.android.features.location.impl.show import io.element.android.features.location.api.Location data class ShowLocationState( + val permissionDialog: Dialog, val location: Location, val description: String?, val hasLocationPermission: Boolean, val isTrackMyLocation: Boolean, + val appName: String, val eventSink: (ShowLocationEvents) -> Unit, -) +) { + sealed interface Dialog { + object None : Dialog + object PermissionRationale : Dialog + object PermissionDenied : Dialog + } +} diff --git a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt index 73bb2d37a4..fd1aeb1d27 100644 --- a/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt +++ b/features/location/impl/src/main/kotlin/io/element/android/features/location/impl/show/ShowLocationStateProvider.kt @@ -19,50 +19,64 @@ package io.element.android.features.location.impl.show import androidx.compose.ui.tooling.preview.PreviewParameterProvider import io.element.android.features.location.api.Location +private const val APP_NAME = "ApplicationName" + class ShowLocationStateProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = null, hasLocationPermission = false, isTrackMyLocation = false, + appName = APP_NAME, eventSink = {}, ), ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = null, hasLocationPermission = true, isTrackMyLocation = false, + appName = APP_NAME, eventSink = {}, ), ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = null, hasLocationPermission = true, isTrackMyLocation = true, + appName = APP_NAME, eventSink = {}, ), ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = "My favourite place!", hasLocationPermission = false, isTrackMyLocation = false, + appName = APP_NAME, eventSink = {}, ), ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = "For some reason I decided to to write a small essay that wraps at just two lines!", hasLocationPermission = false, isTrackMyLocation = false, + appName = APP_NAME, eventSink = {}, ), ShowLocationState( + ShowLocationState.Dialog.None, Location(1.23, 2.34, 4f), description = "For some reason I decided to write a small essay in the location description. " + "It is so long that it will wrap onto more than two lines!", hasLocationPermission = false, isTrackMyLocation = false, + appName = APP_NAME, eventSink = {}, ), ) diff --git a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt index 7fff766a9f..633d60b960 100644 --- a/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt +++ b/features/location/impl/src/test/kotlin/io/element/android/features/location/impl/show/ShowLocationPresenterTest.kt @@ -24,6 +24,7 @@ import io.element.android.features.location.api.Location import io.element.android.features.location.impl.permissions.PermissionsPresenter import io.element.android.features.location.impl.permissions.PermissionsPresenterFake import io.element.android.features.location.impl.permissions.PermissionsState +import io.element.android.libraries.matrix.test.core.aBuildMeta import kotlinx.coroutines.delay import kotlinx.coroutines.test.runTest import org.junit.Test @@ -31,13 +32,15 @@ import org.junit.Test class ShowLocationPresenterTest { private val permissionsPresenterFake = PermissionsPresenterFake() - private val actions = FakeLocationActions() + private val fakeLocationActions = FakeLocationActions() + private val fakeBuildMeta = aBuildMeta(applicationName = "app name") private val location = Location(1.23, 4.56, 7.8f) private val presenter = ShowLocationPresenter( permissionsPresenterFactory = object : PermissionsPresenter.Factory { override fun create(permissions: List): PermissionsPresenter = permissionsPresenterFake }, - actions, + fakeLocationActions, + fakeBuildMeta, location, A_DESCRIPTION, ) @@ -93,8 +96,8 @@ class ShowLocationPresenterTest { val initialState = awaitItem() initialState.eventSink(ShowLocationEvents.Share) - Truth.assertThat(actions.sharedLocation).isEqualTo(location) - Truth.assertThat(actions.sharedLabel).isEqualTo(A_DESCRIPTION) + Truth.assertThat(fakeLocationActions.sharedLocation).isEqualTo(location) + Truth.assertThat(fakeLocationActions.sharedLabel).isEqualTo(A_DESCRIPTION) } }