Rework the location code - WIP

This commit is contained in:
Benoit Marty 2022-01-27 22:10:19 +01:00
parent e9b9406bf1
commit 1f53945031
7 changed files with 104 additions and 74 deletions

View File

@ -34,6 +34,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvid
import im.vector.app.features.home.room.detail.timeline.item.BindingOptions
import im.vector.app.features.home.room.detail.timeline.tools.findPillsAndProcess
import im.vector.app.features.location.LocationData
import im.vector.app.features.location.MapState
import im.vector.app.features.location.MapTilerMapView
import im.vector.app.features.media.ImageContentRenderer
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
@ -99,15 +100,25 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
holder.mapView.isVisible = locationData != null
holder.body.isVisible = locationData == null
locationData?.let { location ->
holder.mapView.initialize {
if (holder.view.isAttachedToWindow) {
holder.mapView.zoomToLocation(location.latitude, location.longitude, 15.0)
locationPinProvider?.create(matrixItem.id) { pinDrawable ->
holder.mapView.addPinToMap(matrixItem.id, pinDrawable)
holder.mapView.updatePinLocation(matrixItem.id, location.latitude, location.longitude)
}
}
holder.mapView.initialize()
holder.mapView.render(
MapState(
zoomOnlyOnce = false,
pinLocationData = locationData,
pinId = matrixItem.id,
pinDrawable = null
)
)
locationPinProvider?.create(matrixItem.id) { pinDrawable ->
if (holder.view.isAttachedToWindow) {
holder.mapView.render(
MapState(
zoomOnlyOnce = false,
pinLocationData = locationData,
pinId = matrixItem.id,
pinDrawable = pinDrawable
)
)
}
}
}

View File

@ -24,6 +24,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.onClick
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import im.vector.app.features.location.LocationData
import im.vector.app.features.location.MapState
import im.vector.app.features.location.MapTilerMapView
@EpoxyModelClass(layout = R.layout.item_timeline_event_base)
@ -56,14 +57,25 @@ abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>(
callback?.onMapClicked()
}
holder.mapView.apply {
initialize {
zoomToLocation(location.latitude, location.longitude, INITIAL_ZOOM)
locationPinProvider?.create(locationOwnerId) { pinDrawable ->
addPinToMap(locationOwnerId, pinDrawable)
updatePinLocation(locationOwnerId, location.latitude, location.longitude)
}
holder.mapView.initialize()
holder.mapView.render(
MapState(
zoomOnlyOnce = false,
pinLocationData = location,
pinId = locationOwnerId,
pinDrawable = null
)
)
locationPinProvider?.create(locationOwnerId) { pinDrawable ->
if (holder.view.isAttachedToWindow) {
holder.mapView.render(
MapState(
zoomOnlyOnce = false,
pinLocationData = location,
pinId = locationOwnerId,
pinDrawable = pinDrawable
)
)
}
}
}
@ -78,6 +90,5 @@ abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>(
companion object {
private const val STUB_ID = R.id.messageContentLocationStub
private const val INITIAL_ZOOM = 15.0
}
}

View File

@ -21,6 +21,7 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.mapbox.mapboxsdk.maps.MapView
import im.vector.app.R
@ -52,11 +53,8 @@ class LocationPreviewFragment @Inject constructor(
mapView = WeakReference(views.mapView)
views.mapView.onCreate(savedInstanceState)
views.mapView.initialize {
if (isAdded) {
onMapReady()
}
}
views.mapView.initialize()
loadPinDrawable()
}
override fun onResume() {
@ -112,17 +110,20 @@ class LocationPreviewFragment @Inject constructor(
openLocation(requireActivity(), location.latitude, location.longitude)
}
private fun onMapReady() {
if (!isAdded) return
private fun loadPinDrawable() {
val location = args.initialLocationData ?: return
val userId = args.locationOwnerId
locationPinProvider.create(userId) { pinDrawable ->
views.mapView.apply {
zoomToLocation(location.latitude, location.longitude, INITIAL_MAP_ZOOM)
addPinToMap(userId, pinDrawable)
updatePinLocation(userId, location.latitude, location.longitude)
lifecycleScope.launchWhenResumed {
views.mapView.render(
MapState(
zoomOnlyOnce = true,
pinLocationData = location,
pinId = args.locationOwnerId,
pinDrawable = pinDrawable
)
)
}
}
}

View File

@ -39,8 +39,6 @@ class LocationSharingFragment @Inject constructor(
private val viewModel: LocationSharingViewModel by fragmentViewModel()
private var lastZoomValue: Double = -1.0
// Keep a ref to handle properly the onDestroy callback
private var mapView: WeakReference<MapView>? = null
@ -115,7 +113,7 @@ class LocationSharingFragment @Inject constructor(
}
override fun invalidate() = withState(viewModel) { state ->
views.mapView.render(state)
views.mapView.render(state.toMapState())
}
companion object {

View File

@ -38,3 +38,10 @@ data class LocationSharingViewState(
mode = locationSharingArgs.mode
)
}
fun LocationSharingViewState.toMapState() = MapState(
zoomOnlyOnce = true,
pinLocationData = lastKnownLocation,
pinId = LocationSharingFragment.USER_PIN_NAME,
pinDrawable = pinDrawable
)

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.location
import android.graphics.drawable.Drawable
data class MapState(
val zoomOnlyOnce: Boolean,
val pinLocationData: LocationData? = null,
val pinId: String,
val pinDrawable: Drawable? = null
)

View File

@ -17,7 +17,6 @@
package im.vector.app.features.location
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
@ -29,6 +28,7 @@ import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.mapbox.mapboxsdk.style.layers.Property
import im.vector.app.BuildConfig
import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean
class MapTilerMapView @JvmOverloads constructor(
context: Context,
@ -36,7 +36,7 @@ class MapTilerMapView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : MapView(context, attrs, defStyleAttr) {
private var pendingState: LocationSharingViewState? = null
private var pendingState: MapState? = null
data class MapRefs(
val map: MapboxMap,
@ -44,43 +44,18 @@ class MapTilerMapView @JvmOverloads constructor(
val style: Style
)
private var isInitializing = AtomicBoolean(false)
private var mapRefs: MapRefs? = null
private var initZoomDone = false
// TODO Kept only for the bottom sheet usage
fun initialize(onMapReady: () -> Unit) {
getMapAsync { map ->
map.setStyle(styleUrl) { style ->
mapRefs = MapRefs(
map,
SymbolManager(this, map, style),
style
)
onMapReady()
}
}
}
// TODO Kept only for the bottom sheet usage
fun addPinToMap(pinId: String, image: Drawable) {
mapRefs?.style?.addImage(pinId, image)
}
// TODO Kept only for the bottom sheet usage
fun updatePinLocation(pinId: String, latitude: Double, longitude: Double) {
mapRefs?.symbolManager?.create(
SymbolOptions()
.withLatLng(LatLng(latitude, longitude))
.withIconImage(pinId)
.withIconAnchor(Property.ICON_ANCHOR_BOTTOM)
)
}
/**
* For location fragments
*/
fun initialize() {
Timber.d("## Location: initialize")
Timber.d("## Location: initialize $isInitializing")
if (isInitializing.getAndSet(true)) {
return
}
getMapAsync { map ->
map.setStyle(styleUrl) { style ->
@ -95,20 +70,21 @@ class MapTilerMapView @JvmOverloads constructor(
}
}
fun render(data: LocationSharingViewState) {
fun render(state: MapState) {
val safeMapRefs = mapRefs ?: return Unit.also {
pendingState = data
pendingState = state
}
data.pinDrawable?.let { pinDrawable ->
if (safeMapRefs.style.getImage(LocationSharingFragment.USER_PIN_NAME) == null) {
state.pinDrawable?.let { pinDrawable ->
if (safeMapRefs.style.isFullyLoaded &&
safeMapRefs.style.getImage(LocationSharingFragment.USER_PIN_NAME) == null) {
safeMapRefs.style.addImage(LocationSharingFragment.USER_PIN_NAME, pinDrawable)
}
}
data.lastKnownLocation?.let { locationData ->
if (!initZoomDone) {
zoomToLocation(locationData.latitude, locationData.longitude, INITIAL_MAP_ZOOM)
state.pinLocationData?.let { locationData ->
if (!initZoomDone || !state.zoomOnlyOnce) {
zoomToLocation(locationData.latitude, locationData.longitude)
initZoomDone = true
}
@ -121,11 +97,11 @@ class MapTilerMapView @JvmOverloads constructor(
}
}
fun zoomToLocation(latitude: Double, longitude: Double, zoom: Double) {
private fun zoomToLocation(latitude: Double, longitude: Double) {
Timber.d("## Location: zoomToLocation")
mapRefs?.map?.cameraPosition = CameraPosition.Builder()
.target(LatLng(latitude, longitude))
.zoom(zoom)
.zoom(INITIAL_MAP_ZOOM)
.build()
}