Add permission request flow to ShowLocation feature too.

TODO:
- Presenter Tests
- Add Dialogs in View
This commit is contained in:
Marco Romano
2023-07-25 16:47:25 +02:00
committed by Benoit Marty
parent c1a00e15ee
commit 675dd4b109
5 changed files with 73 additions and 8 deletions

View File

@@ -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
}

View File

@@ -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<ShowLocationState> {
@@ -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,
)
}

View File

@@ -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
}
}

View File

@@ -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<ShowLocationState> {
override val values: Sequence<ShowLocationState>
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 = {},
),
)

View File

@@ -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<String>): 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)
}
}