mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
change(location): ensure permissions are always requested at least once
This commit is contained in:
+3
@@ -14,6 +14,7 @@ import io.element.android.features.location.impl.common.ui.LocationConstraintsDi
|
||||
sealed interface LocationConstraintsCheck {
|
||||
data object Success : LocationConstraintsCheck
|
||||
data object PermissionRationale : LocationConstraintsCheck
|
||||
data object PermissionShouldBeRequested : LocationConstraintsCheck
|
||||
data object PermissionDenied : LocationConstraintsCheck
|
||||
data object LocationServiceDisabled : LocationConstraintsCheck
|
||||
data object NotEnoughPowerLevel : LocationConstraintsCheck
|
||||
@@ -34,6 +35,7 @@ fun checkLocationConstraints(
|
||||
}
|
||||
}
|
||||
permissionsState.shouldShowRationale -> LocationConstraintsCheck.PermissionRationale
|
||||
!permissionsState.permissionsAlreadyRequested -> LocationConstraintsCheck.PermissionShouldBeRequested
|
||||
else -> LocationConstraintsCheck.PermissionDenied
|
||||
}
|
||||
}
|
||||
@@ -41,6 +43,7 @@ fun checkLocationConstraints(
|
||||
fun LocationConstraintsCheck.toDialogState(): LocationConstraintsDialogState {
|
||||
return when (this) {
|
||||
LocationConstraintsCheck.Success -> LocationConstraintsDialogState.None
|
||||
LocationConstraintsCheck.PermissionShouldBeRequested -> LocationConstraintsDialogState.None
|
||||
LocationConstraintsCheck.PermissionRationale -> LocationConstraintsDialogState.PermissionRationale
|
||||
LocationConstraintsCheck.PermissionDenied -> LocationConstraintsDialogState.PermissionDenied
|
||||
LocationConstraintsCheck.LocationServiceDisabled -> LocationConstraintsDialogState.LocationServiceDisabled
|
||||
|
||||
+12
-2
@@ -9,6 +9,10 @@
|
||||
package io.element.android.features.location.impl.common.permissions
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
@@ -32,11 +36,16 @@ class DefaultPermissionsPresenter(
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
override fun present(): PermissionsState {
|
||||
val multiplePermissionsState = rememberMultiplePermissionsState(permissions = permissions)
|
||||
var permissionsRequested by remember { mutableStateOf(false) }
|
||||
val multiplePermissionsState = rememberMultiplePermissionsState(permissions = permissions) {
|
||||
permissionsRequested = true
|
||||
}
|
||||
|
||||
fun handleEvent(event: PermissionsEvents) {
|
||||
when (event) {
|
||||
PermissionsEvents.RequestPermissions -> multiplePermissionsState.launchMultiplePermissionRequest()
|
||||
PermissionsEvents.RequestPermissions -> {
|
||||
multiplePermissionsState.launchMultiplePermissionRequest()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +56,7 @@ class DefaultPermissionsPresenter(
|
||||
else -> PermissionsState.Permissions.NoneGranted
|
||||
},
|
||||
shouldShowRationale = multiplePermissionsState.shouldShowRationale,
|
||||
permissionsAlreadyRequested = permissionsRequested,
|
||||
eventSink = ::handleEvent,
|
||||
)
|
||||
}
|
||||
|
||||
+1
@@ -11,6 +11,7 @@ package io.element.android.features.location.impl.common.permissions
|
||||
data class PermissionsState(
|
||||
val permissions: Permissions,
|
||||
val shouldShowRationale: Boolean,
|
||||
val permissionsAlreadyRequested: Boolean,
|
||||
val eventSink: (PermissionsEvents) -> Unit,
|
||||
) {
|
||||
sealed interface Permissions {
|
||||
|
||||
+46
-18
@@ -88,6 +88,8 @@ class ShareLocationPresenter(
|
||||
var dialogState: ShareLocationState.Dialog by remember {
|
||||
mutableStateOf(ShareLocationState.Dialog.None)
|
||||
}
|
||||
// true when trying to initiate the live location share
|
||||
var pendingLiveLocationShare by remember { mutableStateOf(false) }
|
||||
val startLiveLocationAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
|
||||
val currentUser by client.userProfile.collectAsState()
|
||||
val customMapStyleUrl by produceState(AsyncData.Loading()) {
|
||||
@@ -100,34 +102,55 @@ class ShareLocationPresenter(
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
fun checkLocationConstraints() {
|
||||
// No need to check SendLiveLocationPermissions here
|
||||
val locationConstraints = checkLocationConstraints(permissionsState, locationActions, SendLiveLocationPermissions.GRANTED)
|
||||
val locationConstraints = checkLocationConstraints(
|
||||
permissionsState = permissionsState,
|
||||
locationActions = locationActions,
|
||||
// No need to check SendLiveLocationPermissions here
|
||||
sendLiveLocationPermissions = SendLiveLocationPermissions.GRANTED
|
||||
)
|
||||
if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) {
|
||||
permissionsState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
trackUserPosition = locationConstraints is LocationConstraintsCheck.Success
|
||||
dialogState = ShareLocationState.Dialog.Constraints(locationConstraints.toDialogState())
|
||||
}
|
||||
|
||||
suspend fun computeLiveLocationDialogState(): ShareLocationState.Dialog {
|
||||
val hasAcceptedDisclaimer = liveLocationStore.hasAcceptedLiveLocationDisclaimer()
|
||||
val constraintsResult = checkLocationConstraints(permissionsState, locationActions, sendLiveLocationPermissions)
|
||||
return when {
|
||||
!hasAcceptedDisclaimer -> {
|
||||
ShareLocationState.Dialog.LiveLocationDisclaimer
|
||||
}
|
||||
constraintsResult is LocationConstraintsCheck.Success -> {
|
||||
val durations = LIVE_LOCATION_DURATIONS.map {
|
||||
LiveLocationDuration(duration = it, formatted = durationFormatter.format(it))
|
||||
suspend fun checkLiveLocationConstraints() {
|
||||
val locationConstraints = checkLocationConstraints(
|
||||
permissionsState = permissionsState,
|
||||
locationActions = locationActions,
|
||||
sendLiveLocationPermissions = sendLiveLocationPermissions,
|
||||
)
|
||||
when (locationConstraints) {
|
||||
LocationConstraintsCheck.Success -> {
|
||||
val hasAcceptedDisclaimer = liveLocationStore.hasAcceptedLiveLocationDisclaimer()
|
||||
dialogState = if (!hasAcceptedDisclaimer) {
|
||||
ShareLocationState.Dialog.LiveLocationDisclaimer
|
||||
} else {
|
||||
val durations = LIVE_LOCATION_DURATIONS.map {
|
||||
LiveLocationDuration(duration = it, formatted = durationFormatter.format(it))
|
||||
}
|
||||
ShareLocationState.Dialog.LiveLocationDurations(durations.toImmutableList())
|
||||
}
|
||||
ShareLocationState.Dialog.LiveLocationDurations(durations.toImmutableList())
|
||||
}
|
||||
else -> {
|
||||
ShareLocationState.Dialog.Constraints(constraintsResult.toDialogState())
|
||||
if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) {
|
||||
permissionsState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
dialogState = ShareLocationState.Dialog.Constraints(locationConstraints.toDialogState())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val userLocationState = userLocationStateFactory.create(permissionsState.isAnyGranted)
|
||||
|
||||
LaunchedEffect(permissionsState.permissions) { checkLocationConstraints() }
|
||||
LaunchedEffect(permissionsState) {
|
||||
if (pendingLiveLocationShare) {
|
||||
checkLiveLocationConstraints()
|
||||
} else {
|
||||
checkLocationConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvent(event: ShareLocationEvent) {
|
||||
when (event) {
|
||||
@@ -136,7 +159,10 @@ class ShareLocationPresenter(
|
||||
}
|
||||
ShareLocationEvent.StartTrackingUserLocation -> checkLocationConstraints()
|
||||
ShareLocationEvent.StopTrackingUserLocation -> trackUserPosition = false
|
||||
ShareLocationEvent.DismissDialog -> dialogState = ShareLocationState.Dialog.None
|
||||
ShareLocationEvent.DismissDialog -> {
|
||||
pendingLiveLocationShare = false
|
||||
dialogState = ShareLocationState.Dialog.None
|
||||
}
|
||||
ShareLocationEvent.OpenAppSettings -> {
|
||||
locationActions.openAppSettings()
|
||||
dialogState = ShareLocationState.Dialog.None
|
||||
@@ -146,15 +172,17 @@ class ShareLocationPresenter(
|
||||
dialogState = ShareLocationState.Dialog.None
|
||||
}
|
||||
ShareLocationEvent.InitiateLiveLocationShare -> scope.launch {
|
||||
dialogState = computeLiveLocationDialogState()
|
||||
pendingLiveLocationShare = true
|
||||
checkLiveLocationConstraints()
|
||||
}
|
||||
ShareLocationEvent.AcceptLiveLocationDisclaimer -> scope.launch {
|
||||
liveLocationStore.setAcceptedLiveLocationDisclaimer()
|
||||
.onSuccess {
|
||||
dialogState = computeLiveLocationDialogState()
|
||||
checkLiveLocationConstraints()
|
||||
}
|
||||
}
|
||||
is ShareLocationEvent.StartLiveLocationShare -> scope.launch {
|
||||
pendingLiveLocationShare = false
|
||||
dialogState = ShareLocationState.Dialog.None
|
||||
startLiveLocationAction.runUpdatingState {
|
||||
liveLocationShareManager.startShare(
|
||||
|
||||
+16
-6
@@ -90,10 +90,22 @@ import kotlinx.coroutines.launch
|
||||
value = AsyncData.Success(client.getMapStyleUrl().getOrNull())
|
||||
}
|
||||
|
||||
LaunchedEffect(permissionsState.permissions) {
|
||||
if (permissionsState.isAnyGranted) {
|
||||
dialogState = LocationConstraintsDialogState.None
|
||||
fun checkLocationConstraints() {
|
||||
val locationConstraints = checkLocationConstraints(
|
||||
permissionsState = permissionsState,
|
||||
locationActions = locationActions,
|
||||
// No need to check SendLiveLocationPermissions here
|
||||
sendLiveLocationPermissions = SendLiveLocationPermissions.GRANTED
|
||||
)
|
||||
if (locationConstraints is LocationConstraintsCheck.PermissionShouldBeRequested) {
|
||||
permissionsState.eventSink(PermissionsEvents.RequestPermissions)
|
||||
}
|
||||
isTrackMyLocation = locationConstraints is LocationConstraintsCheck.Success
|
||||
dialogState = locationConstraints.toDialogState()
|
||||
}
|
||||
|
||||
LaunchedEffect(permissionsState) {
|
||||
checkLocationConstraints()
|
||||
}
|
||||
|
||||
fun handleEvent(event: ShowLocationEvent) {
|
||||
@@ -103,9 +115,7 @@ import kotlinx.coroutines.launch
|
||||
}
|
||||
is ShowLocationEvent.TrackMyLocation -> {
|
||||
if (event.enabled) {
|
||||
val locationConstraints = checkLocationConstraints(permissionsState, locationActions, SendLiveLocationPermissions.GRANTED)
|
||||
isTrackMyLocation = locationConstraints is LocationConstraintsCheck.Success
|
||||
dialogState = locationConstraints.toDialogState()
|
||||
checkLocationConstraints()
|
||||
} else {
|
||||
isTrackMyLocation = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user