Merge pull request #6587 from vector-im/feature/ons/fix_live_location_sharing_permission

Check user power level before sharing live location (PSG-620)
This commit is contained in:
Onuray Sahin 2022-07-20 15:01:32 +03:00 committed by GitHub
commit 7f821f1285
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 9 deletions

1
changelog.d/6587.bugfix Normal file
View File

@ -0,0 +1 @@
Check user power level before sharing live location

View File

@ -23,5 +23,6 @@ sealed class LocationSharingAction : VectorViewModelAction {
data class PinnedLocationSharing(val locationData: LocationData?) : LocationSharingAction() data class PinnedLocationSharing(val locationData: LocationData?) : LocationSharingAction()
data class LocationTargetChange(val locationData: LocationData) : LocationSharingAction() data class LocationTargetChange(val locationData: LocationData) : LocationSharingAction()
object ZoomToUserLocation : LocationSharingAction() object ZoomToUserLocation : LocationSharingAction()
object LiveLocationSharingRequested : LocationSharingAction()
data class StartLiveLocationSharing(val durationMillis: Long) : LocationSharingAction() data class StartLiveLocationSharing(val durationMillis: Long) : LocationSharingAction()
} }

View File

@ -104,6 +104,9 @@ class LocationSharingFragment @Inject constructor(
LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError() LocationSharingViewEvents.LocationNotAvailableError -> handleLocationNotAvailableError()
is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it) is LocationSharingViewEvents.ZoomToUserLocation -> handleZoomToUserLocationEvent(it)
is LocationSharingViewEvents.StartLiveLocationService -> handleStartLiveLocationService(it) is LocationSharingViewEvents.StartLiveLocationService -> handleStartLiveLocationService(it)
LocationSharingViewEvents.ChooseLiveLocationDuration -> handleChooseLiveLocationDuration()
LocationSharingViewEvents.ShowLabsFlagPromotion -> handleShowLabsFlagPromotion()
LocationSharingViewEvents.LiveLocationSharingNotEnoughPermission -> handleLiveLocationSharingNotEnoughPermission()
} }
} }
} }
@ -168,6 +171,14 @@ class LocationSharingFragment @Inject constructor(
.show() .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() { private fun initLocateButton() {
views.mapView.locateButton.setOnClickListener { views.mapView.locateButton.setOnClickListener {
viewModel.handle(LocationSharingAction.ZoomToUserLocation) viewModel.handle(LocationSharingAction.ZoomToUserLocation)
@ -201,7 +212,7 @@ class LocationSharingFragment @Inject constructor(
viewModel.handle(LocationSharingAction.CurrentUserLocationSharing) viewModel.handle(LocationSharingAction.CurrentUserLocationSharing)
} }
views.shareLocationOptionsPicker.optionUserLive.debouncedClicks { views.shareLocationOptionsPicker.optionUserLive.debouncedClicks {
tryStartLiveLocationSharing() viewModel.handle(LocationSharingAction.LiveLocationSharingRequested)
} }
} }
@ -212,13 +223,13 @@ class LocationSharingFragment @Inject constructor(
} }
} }
private fun tryStartLiveLocationSharing() { private fun handleChooseLiveLocationDuration() {
if (vectorPreferences.labsEnableLiveLocation()) { startLiveLocationSharing()
startLiveLocationSharing() }
} else {
LiveLocationLabsFlagPromotionBottomSheet.newInstance() private fun handleShowLabsFlagPromotion() {
.show(requireActivity().supportFragmentManager, "DISPLAY_LIVE_LOCATION_LABS_FLAG_PROMOTION") LiveLocationLabsFlagPromotionBottomSheet.newInstance()
} .show(requireActivity().supportFragmentManager, "DISPLAY_LIVE_LOCATION_LABS_FLAG_PROMOTION")
} }
private val foregroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently -> private val foregroundLocationResultLauncher = registerForPermissionsResult { allGranted, deniedPermanently ->

View File

@ -23,4 +23,7 @@ sealed class LocationSharingViewEvents : VectorViewEvents {
object LocationNotAvailableError : LocationSharingViewEvents() object LocationNotAvailableError : LocationSharingViewEvents()
data class ZoomToUserLocation(val userLocation: LocationData) : LocationSharingViewEvents() data class ZoomToUserLocation(val userLocation: LocationData) : LocationSharingViewEvents()
data class StartLiveLocationService(val sessionId: String, val roomId: String, val durationMillis: Long) : LocationSharingViewEvents() data class StartLiveLocationService(val sessionId: String, val roomId: String, val durationMillis: Long) : LocationSharingViewEvents()
object ChooseLiveLocationDuration : LocationSharingViewEvents()
object ShowLabsFlagPromotion : LocationSharingViewEvents()
object LiveLocationSharingNotEnoughPermission : LocationSharingViewEvents()
} }

View File

@ -26,6 +26,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider 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.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.MutableSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.lastOrNull import kotlinx.coroutines.flow.lastOrNull
@ -36,8 +38,10 @@ import kotlinx.coroutines.flow.sample
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session 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.getRoom
import org.matrix.android.sdk.api.session.getUser 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 org.matrix.android.sdk.api.util.toMatrixItem
import timber.log.Timber import timber.log.Timber
@ -52,6 +56,7 @@ class LocationSharingViewModel @AssistedInject constructor(
private val locationPinProvider: LocationPinProvider, private val locationPinProvider: LocationPinProvider,
private val session: Session, private val session: Session,
private val compareLocationsUseCase: CompareLocationsUseCase, private val compareLocationsUseCase: CompareLocationsUseCase,
private val vectorPreferences: VectorPreferences,
) : VectorViewModel<LocationSharingViewState, LocationSharingAction, LocationSharingViewEvents>(initialState), LocationTracker.Callback { ) : VectorViewModel<LocationSharingViewState, LocationSharingAction, LocationSharingViewEvents>(initialState), LocationTracker.Callback {
private val room = session.getRoom(initialState.roomId)!! private val room = session.getRoom(initialState.roomId)!!
@ -70,6 +75,21 @@ class LocationSharingViewModel @AssistedInject constructor(
setUserItem() setUserItem()
updatePin() updatePin()
compareTargetAndUserLocation() 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() { private fun initLocationTracking() {
@ -130,10 +150,21 @@ class LocationSharingViewModel @AssistedInject constructor(
is LocationSharingAction.PinnedLocationSharing -> handlePinnedLocationSharingAction(action) is LocationSharingAction.PinnedLocationSharing -> handlePinnedLocationSharingAction(action)
is LocationSharingAction.LocationTargetChange -> handleLocationTargetChangeAction(action) is LocationSharingAction.LocationTargetChange -> handleLocationTargetChangeAction(action)
LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction() LocationSharingAction.ZoomToUserLocation -> handleZoomToUserLocationAction()
LocationSharingAction.LiveLocationSharingRequested -> handleLiveLocationSharingRequestedAction()
is LocationSharingAction.StartLiveLocationSharing -> handleStartLiveLocationSharingAction(action.durationMillis) 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 -> private fun handleCurrentUserLocationSharingAction() = withState { state ->
shareLocation(state.lastKnownUserLocation, isUserLocation = true) shareLocation(state.lastKnownUserLocation, isUserLocation = true)
} }

View File

@ -34,7 +34,8 @@ data class LocationSharingViewState(
val userItem: MatrixItem.UserItem? = null, val userItem: MatrixItem.UserItem? = null,
val areTargetAndUserLocationEqual: Boolean? = null, val areTargetAndUserLocationEqual: Boolean? = null,
val lastKnownUserLocation: LocationData? = null, val lastKnownUserLocation: LocationData? = null,
val locationTargetDrawable: Drawable? = null val locationTargetDrawable: Drawable? = null,
val canShareLiveLocation: Boolean = false,
) : MavericksState { ) : MavericksState {
constructor(locationSharingArgs: LocationSharingArgs) : this( constructor(locationSharingArgs: LocationSharingArgs) : this(

View File

@ -3116,6 +3116,8 @@
<!-- TODO remove key --> <!-- TODO remove key -->
<string name="live_location_bottom_sheet_stop_sharing" tools:ignore="UnusedResources">Stop sharing</string> <string name="live_location_bottom_sheet_stop_sharing" tools:ignore="UnusedResources">Stop sharing</string>
<string name="live_location_bottom_sheet_last_updated_at">Updated %1$s ago</string> <string name="live_location_bottom_sheet_last_updated_at">Updated %1$s ago</string>
<string name="live_location_not_enough_permission_dialog_title">You dont have permission to share live location</string>
<string name="live_location_not_enough_permission_dialog_description">You need to have the right permissions in order to share live location in this room.</string>
<string name="live_location_share_location_item_share">Share location</string> <string name="live_location_share_location_item_share">Share location</string>
<string name="message_bubbles">Show Message bubbles</string> <string name="message_bubbles">Show Message bubbles</string>