diff --git a/changelog.d/6587.bugfix b/changelog.d/6587.bugfix new file mode 100644 index 00000000000..0273689cfd9 --- /dev/null +++ b/changelog.d/6587.bugfix @@ -0,0 +1 @@ +Check user power level before sharing live location diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt index d86d97e6b05..264b1f0e0be 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingAction.kt @@ -23,5 +23,6 @@ sealed class LocationSharingAction : VectorViewModelAction { data class PinnedLocationSharing(val locationData: LocationData?) : LocationSharingAction() data class LocationTargetChange(val locationData: LocationData) : LocationSharingAction() object ZoomToUserLocation : LocationSharingAction() + object LiveLocationSharingRequested : LocationSharingAction() data class StartLiveLocationSharing(val durationMillis: Long) : LocationSharingAction() } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt index be5f0aed6f1..17e53e63d18 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingFragment.kt @@ -104,6 +104,9 @@ class LocationSharingFragment @Inject constructor( LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError() is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it) is LocationSharingViewEvents.StartLiveLocationService -> handleStartLiveLocationService(it) + LocationSharingViewEvents.ChooseLiveLocationDuration -> handleChooseLiveLocationDuration() + LocationSharingViewEvents.ShowLabsFlagPromotion -> handleShowLabsFlagPromotion() + LocationSharingViewEvents.LiveLocationSharingNotEnoughPermission -> handleLiveLocationSharingNotEnoughPermission() } } } @@ -168,6 +171,14 @@ class LocationSharingFragment @Inject constructor( .show() } + private fun handleLiveLocationSharingNotEnoughPermission() { + MaterialAlertDialogBuilder(requireActivity()) + .setTitle(R.string.live_location_not_enough_permission_dialog_title) + .setMessage(R.string.live_location_not_enough_permission_dialog_description) + .setPositiveButton(R.string.ok, null) + .show() + } + private fun initLocateButton() { views.mapView.locateButton.setOnClickListener { viewModel.handle(LocationSharingAction.ZoomToUserLocation) @@ -201,7 +212,7 @@ class LocationSharingFragment @Inject constructor( viewModel.handle(LocationSharingAction.CurrentUserLocationSharing) } views.shareLocationOptionsPicker.optionUserLive.debouncedClicks { - tryStartLiveLocationSharing() + viewModel.handle(LocationSharingAction.LiveLocationSharingRequested) } } @@ -212,13 +223,13 @@ class LocationSharingFragment @Inject constructor( } } - private fun tryStartLiveLocationSharing() { - if (vectorPreferences.labsEnableLiveLocation()) { - startLiveLocationSharing() - } else { - LiveLocationLabsFlagPromotionBottomSheet.newInstance() - .show(requireActivity().supportFragmentManager, "DISPLAY_LIVE_LOCATION_LABS_FLAG_PROMOTION") - } + private fun handleChooseLiveLocationDuration() { + startLiveLocationSharing() + } + + private fun handleShowLabsFlagPromotion() { + LiveLocationLabsFlagPromotionBottomSheet.newInstance() + .show(requireActivity().supportFragmentManager, "DISPLAY_LIVE_LOCATION_LABS_FLAG_PROMOTION") } private val foregroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently -> diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt index 1116003e414..c9e411c8d74 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewEvents.kt @@ -23,4 +23,7 @@ sealed class LocationSharingViewEvents : VectorViewEvents { object LocationNotAvailableError : LocationSharingViewEvents() data class ZoomToUserLocation(val userLocation: LocationData) : LocationSharingViewEvents() data class StartLiveLocationService(val sessionId: String, val roomId: String, val durationMillis: Long) : LocationSharingViewEvents() + object ChooseLiveLocationDuration : LocationSharingViewEvents() + object ShowLabsFlagPromotion : LocationSharingViewEvents() + object LiveLocationSharingNotEnoughPermission : LocationSharingViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt index b9a2dc830c2..8056b72d57b 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt @@ -26,6 +26,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider import im.vector.app.features.location.domain.usecase.CompareLocationsUseCase +import im.vector.app.features.powerlevel.PowerLevelsFlowFactory +import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.lastOrNull @@ -36,8 +38,10 @@ import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getUser +import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.util.toMatrixItem import timber.log.Timber @@ -52,6 +56,7 @@ class LocationSharingViewModel @AssistedInject constructor( private val locationPinProvider: LocationPinProvider, private val session: Session, private val compareLocationsUseCase: CompareLocationsUseCase, + private val vectorPreferences: VectorPreferences, ) : VectorViewModel(initialState), LocationTracker.Callback { private val room = session.getRoom(initialState.roomId)!! @@ -70,6 +75,21 @@ class LocationSharingViewModel @AssistedInject constructor( setUserItem() updatePin() compareTargetAndUserLocation() + observePowerLevelsForLiveLocationSharing() + } + + private fun observePowerLevelsForLiveLocationSharing() { + PowerLevelsFlowFactory(room).createFlow() + .distinctUntilChanged() + .setOnEach { + val powerLevelsHelper = PowerLevelsHelper(it) + val canShareLiveLocation = EventType.STATE_ROOM_BEACON_INFO + .all { beaconInfoType -> + powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, beaconInfoType) + } + + copy(canShareLiveLocation = canShareLiveLocation) + } } private fun initLocationTracking() { @@ -130,10 +150,21 @@ class LocationSharingViewModel @AssistedInject constructor( is LocationSharingAction.PinnedLocationSharing -> handlePinnedLocationSharingAction(action) is LocationSharingAction.LocationTargetChange -> handleLocationTargetChangeAction(action) LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction() + LocationSharingAction.LiveLocationSharingRequested -> handleLiveLocationSharingRequestedAction() is LocationSharingAction.StartLiveLocationSharing -> handleStartLiveLocationSharingAction(action.durationMillis) } } + private fun handleLiveLocationSharingRequestedAction() = withState { state -> + if (!state.canShareLiveLocation) { + _viewEvents.post(LocationSharingViewEvents.LiveLocationSharingNotEnoughPermission) + } else if (vectorPreferences.labsEnableLiveLocation()) { + _viewEvents.post(LocationSharingViewEvents.ChooseLiveLocationDuration) + } else { + _viewEvents.post(LocationSharingViewEvents.ShowLabsFlagPromotion) + } + } + private fun handleCurrentUserLocationSharingAction() = withState { state -> shareLocation(state.lastKnownUserLocation, isUserLocation = true) } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt index 64f324bc1bb..d5226eacfb9 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewState.kt @@ -34,7 +34,8 @@ data class LocationSharingViewState( val userItem: MatrixItem.UserItem? = null, val areTargetAndUserLocationEqual: Boolean? = null, val lastKnownUserLocation: LocationData? = null, - val locationTargetDrawable: Drawable? = null + val locationTargetDrawable: Drawable? = null, + val canShareLiveLocation: Boolean = false, ) : MavericksState { constructor(locationSharingArgs: LocationSharingArgs) : this( diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 4d7396757cd..841ddc1c35b 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3116,6 +3116,8 @@ Stop sharing Updated %1$s ago + You don’t have permission to share live location + You need to have the right permissions in order to share live location in this room. Share location Show Message bubbles