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 c7a2349afa..e11bfbf16e 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 @@ -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 diff --git a/vector/src/main/java/im/vector/app/features/location/MapState.kt b/vector/src/main/java/im/vector/app/features/location/MapState.kt index c4325291a8..2224317b02 100644 --- a/vector/src/main/java/im/vector/app/features/location/MapState.kt +++ b/vector/src/main/java/im/vector/app/features/location/MapState.kt @@ -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, ) diff --git a/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt b/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt index b001621bf4..106a56cc23 100644 --- a/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt +++ b/vector/src/main/java/im/vector/app/features/location/MapTilerMapView.kt @@ -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) { diff --git a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt index 8be3b063b0..1d816ddc83 100644 --- a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewFragment.kt @@ -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)) { diff --git a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt index 3b4c3cf498..35b49d8644 100644 --- a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt @@ -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(initialState), LocationTracker.Callback { @@ -43,9 +45,18 @@ class LocationPreviewViewModel @AssistedInject constructor( companion object : MavericksViewModelFactory 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 diff --git a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewState.kt b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewState.kt index db37ddb420..15fa911607 100644 --- a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewState.kt @@ -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, + ) +}