Rendering the user location pin

This commit is contained in:
Maxime NATUREL 2023-02-16 16:12:28 +01:00
parent d23636900f
commit a4211d8482
6 changed files with 61 additions and 31 deletions

View file

@ -47,7 +47,7 @@ data class LocationSharingViewState(
fun LocationSharingViewState.toMapState() = MapState(
zoomOnlyOnce = true,
userLocationData = lastKnownUserLocation,
pinLocationData = lastKnownUserLocation,
pinId = DEFAULT_PIN_ID,
pinDrawable = null,
// show the map pin only when target location and user location are not equal

View file

@ -21,9 +21,10 @@ import androidx.annotation.Px
data class MapState(
val zoomOnlyOnce: Boolean,
val userLocationData: LocationData? = null,
val pinLocationData: LocationData? = null,
val pinId: String,
val pinDrawable: Drawable? = null,
val showPin: Boolean = true,
@Px val logoMarginBottom: Int = 0
val userLocationData: LocationData? = null,
@Px val logoMarginBottom: Int = 0,
)

View file

@ -38,6 +38,8 @@ import im.vector.app.R
import im.vector.app.core.utils.DimensionConverter
import timber.log.Timber
private const val USER_PIN_ID = "user-pin-id"
class MapTilerMapView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@ -173,13 +175,13 @@ class MapTilerMapView @JvmOverloads constructor(
}
}
state.userLocationData?.let { locationData ->
safeMapRefs.symbolManager.deleteAll()
state.pinLocationData?.let { locationData ->
if (!initZoomDone || !state.zoomOnlyOnce) {
zoomToLocation(locationData)
initZoomDone = true
}
safeMapRefs.symbolManager.deleteAll()
if (pinDrawable != null && state.showPin) {
safeMapRefs.symbolManager.create(
SymbolOptions()
@ -189,6 +191,20 @@ class MapTilerMapView @JvmOverloads constructor(
)
}
}
state.userLocationData?.let { locationData ->
if (!safeMapRefs.style.isFullyLoaded || safeMapRefs.style.getImage(USER_PIN_ID) == null) {
userLocationDrawable?.let { drawable ->
safeMapRefs.style.addImage(USER_PIN_ID, drawable.toBitmap())
}
}
safeMapRefs.symbolManager.create(
SymbolOptions()
.withLatLng(LatLng(locationData.latitude, locationData.longitude))
.withIconImage(USER_PIN_ID)
.withIconAnchor(Property.ICON_ANCHOR_BOTTOM)
)
}
}
fun zoomToLocation(locationData: LocationData) {

View file

@ -37,7 +37,6 @@ import im.vector.app.core.utils.onPermissionDeniedDialog
import im.vector.app.core.utils.openLocation
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.databinding.FragmentLocationPreviewBinding
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import im.vector.app.features.location.DEFAULT_PIN_ID
import im.vector.app.features.location.LocationSharingArgs
import im.vector.app.features.location.MapState
@ -46,8 +45,8 @@ import im.vector.app.features.location.showUserLocationNotAvailableErrorDialog
import java.lang.ref.WeakReference
import javax.inject.Inject
/*
* TODO Move locationPinProvider to a ViewModel
/**
* Screen displaying the expanded map of a static location share.
*/
@AndroidEntryPoint
class LocationPreviewFragment :
@ -55,7 +54,6 @@ class LocationPreviewFragment :
VectorMenuProvider {
@Inject lateinit var urlMapProvider: UrlMapProvider
@Inject lateinit var locationPinProvider: LocationPinProvider
private val args: LocationSharingArgs by args()
@ -81,7 +79,6 @@ class LocationPreviewFragment :
lifecycleScope.launchWhenCreated {
views.mapView.initialize(urlMapProvider.getMapUrl())
loadPinDrawable()
}
observeViewEvents()
@ -151,12 +148,24 @@ class LocationPreviewFragment :
override fun invalidate() = withState(viewModel) { state ->
views.mapPreviewLoadingError.isVisible = state.loadingMapHasFailed
// TODO render pin for user location
if(state.isLoadingUserLocation) {
if (state.isLoadingUserLocation) {
showLoadingDialog()
} else {
dismissLoadingDialog()
}
updateMap(state)
}
private fun updateMap(viewState: LocationPreviewViewState) {
views.mapView.render(
MapState(
zoomOnlyOnce = true,
pinLocationData = viewState.pinLocationData,
pinId = viewState.pinUserId ?: DEFAULT_PIN_ID,
pinDrawable = viewState.pinDrawable,
userLocationData = viewState.lastKnownUserLocation,
)
)
}
override fun getMenuRes() = R.menu.menu_location_preview
@ -176,24 +185,6 @@ class LocationPreviewFragment :
openLocation(requireActivity(), location.latitude, location.longitude)
}
private fun loadPinDrawable() {
val location = args.initialLocationData ?: return
val userId = args.locationOwnerId
locationPinProvider.create(userId) { pinDrawable ->
lifecycleScope.launchWhenResumed {
views.mapView.render(
MapState(
zoomOnlyOnce = true,
userLocationData = location,
pinId = args.locationOwnerId ?: DEFAULT_PIN_ID,
pinDrawable = pinDrawable,
)
)
}
}
}
private fun initLocateButton() {
views.mapView.locateButton.setOnClickListener {
if (checkPermissions(PERMISSIONS_FOR_FOREGROUND_LOCATION_SHARING, requireActivity(), foregroundLocationResultLauncher)) {

View file

@ -23,6 +23,7 @@ import dagger.assisted.AssistedInject
import im.vector.app.core.di.MavericksAssistedViewModelFactory
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.LocationData
import im.vector.app.features.location.LocationTracker
import kotlinx.coroutines.Dispatchers
@ -32,6 +33,7 @@ import kotlinx.coroutines.launch
class LocationPreviewViewModel @AssistedInject constructor(
@Assisted private val initialState: LocationPreviewViewState,
private val locationPinProvider: LocationPinProvider,
private val locationTracker: LocationTracker,
) : VectorViewModel<LocationPreviewViewState, LocationPreviewAction, LocationPreviewViewEvents>(initialState), LocationTracker.Callback {
@ -43,9 +45,18 @@ class LocationPreviewViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory<LocationPreviewViewModel, LocationPreviewViewState> by hiltMavericksViewModelFactory()
init {
initialState.pinUserId?.let { userId ->
initPin(userId)
}
initLocationTracking()
}
private fun initPin(userId: String) {
locationPinProvider.create(userId) { pinDrawable ->
setState { copy(pinDrawable = pinDrawable) }
}
}
private fun initLocationTracking() {
locationTracker.addCallback(this)
locationTracker.locations

View file

@ -16,11 +16,22 @@
package im.vector.app.features.location.preview
import android.graphics.drawable.Drawable
import com.airbnb.mvrx.MavericksState
import im.vector.app.features.location.LocationData
import im.vector.app.features.location.LocationSharingArgs
data class LocationPreviewViewState(
val pinLocationData: LocationData? = null,
val pinUserId: String? = null,
val pinDrawable: Drawable? = null,
val loadingMapHasFailed: Boolean = false,
val isLoadingUserLocation: Boolean = false,
val lastKnownUserLocation: LocationData? = null,
) : MavericksState
) : MavericksState {
constructor(args: LocationSharingArgs): this(
pinLocationData = args.initialLocationData,
pinUserId = args.locationOwnerId,
)
}