diff --git a/changelog.d/7852.feature b/changelog.d/7852.feature
new file mode 100644
index 00000000000..85fbd1fc0f6
--- /dev/null
+++ b/changelog.d/7852.feature
@@ -0,0 +1 @@
+Refactored location sharing timeline items to use the mapserver configured by the wellknown file
diff --git a/library/ui-strings/src/main/res/values/donottranslate.xml b/library/ui-strings/src/main/res/values/donottranslate.xml
index bfe751ef5a5..5f20fb24d44 100755
--- a/library/ui-strings/src/main/res/values/donottranslate.xml
+++ b/library/ui-strings/src/main/res/values/donottranslate.xml
@@ -10,6 +10,4 @@
Cut the slack from teams.
-
- © MapTiler © OpenStreetMap contributors
diff --git a/vector-config/src/main/java/im/vector/app/config/Config.kt b/vector-config/src/main/java/im/vector/app/config/Config.kt
index fdc8e9f73b7..77ef9d57eb1 100644
--- a/vector-config/src/main/java/im/vector/app/config/Config.kt
+++ b/vector-config/src/main/java/im/vector/app/config/Config.kt
@@ -41,6 +41,7 @@ object Config {
const val ENABLE_LOCATION_SHARING = true
const val LOCATION_MAP_TILER_KEY = "fU3vlMsMn4Jb6dnEIFsx"
+ const val ENABLE_LOCATION_SHARING_MAPSERVER_FALLBACK = true
/**
* The maximum length of voice messages in milliseconds.
diff --git a/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt b/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt
index caa38d20d96..c77205dc292 100644
--- a/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/ConfigurationModule.kt
@@ -73,6 +73,7 @@ object ConfigurationModule {
@Provides
fun providesLocationSharingConfig() = LocationSharingConfig(
mapTilerKey = Config.LOCATION_MAP_TILER_KEY,
+ isMapTilerFallbackEnabled = Config.ENABLE_LOCATION_SHARING_MAPSERVER_FALLBACK
)
@Provides
diff --git a/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt b/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
index bb1b0fbd7b5..0f65cd67890 100644
--- a/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
+++ b/vector/src/main/java/im/vector/app/core/epoxy/bottomsheet/BottomSheetMessagePreviewItem.kt
@@ -23,7 +23,7 @@ import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
-import com.bumptech.glide.request.RequestOptions
+import com.mapbox.mapboxsdk.maps.MapView
import im.vector.app.R
import im.vector.app.core.epoxy.ClickListener
import im.vector.app.core.epoxy.VectorEpoxyHolder
@@ -36,6 +36,8 @@ import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.timeline.action.LocationUiData
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.INITIAL_MAP_ZOOM_IN_TIMELINE
+import im.vector.app.features.location.zoomToLocation
import im.vector.app.features.media.ImageContentRenderer
import im.vector.lib.core.utils.epoxy.charsequence.EpoxyCharSequence
import org.matrix.android.sdk.api.util.MatrixItem
@@ -98,10 +100,13 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel
- GlideApp.with(holder.staticMapImageView)
- .load(safeLocationUiData.locationUrl)
- .apply(RequestOptions.centerCropTransform())
- .into(holder.staticMapImageView)
+ holder.staticMapView.getMapAsync { mapbox ->
+ mapbox.setStyle(safeLocationUiData.locationUrl)
+ safeLocationUiData.locationData?.let {
+ mapbox.zoomToLocation(it, false, INITIAL_MAP_ZOOM_IN_TIMELINE)
+ }
+ mapbox.uiSettings.setAllGesturesEnabled(false)
+ }
safeLocationUiData.locationPinProvider.create(safeLocationUiData.locationOwnerId) { pinDrawable ->
GlideApp.with(holder.staticMapPinImageView)
@@ -124,7 +129,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel(R.id.bottom_sheet_message_preview_timestamp)
val imagePreview by bind(R.id.bottom_sheet_message_preview_image)
val mapViewContainer by bind(R.id.mapViewContainer)
- val staticMapImageView by bind(R.id.staticMapImageView)
+ val staticMapView by bind(R.id.staticMapView)
val staticMapPinImageView by bind(R.id.staticMapPinImageView)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt
index cb74661eba8..805380849d6 100644
--- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModel.kt
@@ -27,6 +27,7 @@ import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.platform.VectorViewModelAction
import im.vector.app.features.VectorFeatures
+import im.vector.app.features.location.UrlMapProvider
import im.vector.app.features.settings.VectorPreferences
class AttachmentTypeSelectorViewModel @AssistedInject constructor(
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index 8f16121a306..9a584f7759b 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -36,9 +36,11 @@ import im.vector.app.features.analytics.extensions.toAnalyticsType
import im.vector.app.features.analytics.plan.Signup
import im.vector.app.features.analytics.store.AnalyticsStore
import im.vector.app.features.home.room.list.home.release.ReleaseNotesPreferencesStore
+import im.vector.app.features.location.UrlMapProvider
import im.vector.app.features.login.ReAuthHelper
import im.vector.app.features.onboarding.AuthenticationDescription
import im.vector.app.features.raw.wellknown.ElementWellKnown
+import im.vector.app.features.raw.wellknown.WellknownService
import im.vector.app.features.raw.wellknown.getElementWellknown
import im.vector.app.features.raw.wellknown.isSecureBackupRequired
import im.vector.app.features.raw.wellknown.withElementWellKnown
@@ -54,6 +56,7 @@ import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.MatrixPatterns.getServerName
import org.matrix.android.sdk.api.auth.UIABaseAuth
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
import org.matrix.android.sdk.api.auth.UserPasswordAuth
@@ -82,7 +85,7 @@ import kotlin.coroutines.resumeWithException
class HomeActivityViewModel @AssistedInject constructor(
@Assisted private val initialState: HomeActivityViewState,
private val activeSessionHolder: ActiveSessionHolder,
- private val rawService: RawService,
+ private val wellknownService: WellknownService,
private val reAuthHelper: ReAuthHelper,
private val analyticsStore: AnalyticsStore,
private val lightweightSettingsStorage: LightweightSettingsStorage,
@@ -231,7 +234,7 @@ class HomeActivityViewModel @AssistedInject constructor(
.onEach { info ->
val isVerified = info.getOrNull()?.isTrusted() ?: false
if (!isVerified && onceTrusted) {
- rawService.withElementWellKnown(viewModelScope, safeActiveSession.sessionParams) {
+ wellknownService.getElementWellknown(safeActiveSession.sessionParams.userId.getServerName())?.let {
sessionHasBeenUnverified(it)
}
}
@@ -382,7 +385,8 @@ class HomeActivityViewModel @AssistedInject constructor(
Timber.w("## No session to init cross signing or bootstrap")
}
- val elementWellKnown = rawService.getElementWellknown(session.sessionParams)
+ val elementWellKnown = wellknownService.getElementWellknown(session.sessionParams.userId.getServerName())
+
val isSecureBackupRequired = elementWellKnown?.isSecureBackupRequired() ?: false
// In case of account creation, it is already done before
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/LocationUiData.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/LocationUiData.kt
index 073dda626fa..8302ba0d7c8 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/LocationUiData.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/LocationUiData.kt
@@ -17,11 +17,13 @@
package im.vector.app.features.home.room.detail.timeline.action
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
+import im.vector.app.features.location.LocationData
/**
* Data used to display Location data in the message bottom sheet.
*/
data class LocationUiData(
+ val locationData: LocationData?,
val locationUrl: String,
val locationOwnerId: String?,
val locationPinProvider: LocationPinProvider,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
index 5daf82fae6f..d499b2bbd9c 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt
@@ -39,7 +39,6 @@ import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
import im.vector.app.features.home.room.detail.timeline.tools.linkify
import im.vector.app.features.html.SpanUtils
-import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
import im.vector.app.features.location.UrlMapProvider
import im.vector.app.features.location.toLocationData
import im.vector.app.features.media.ImageContentRenderer
@@ -228,13 +227,12 @@ class MessageActionsEpoxyController @Inject constructor(
val locationContent = state.timelineEvent()?.root?.getClearContent().toModel(catchError = true)
?: return null
- val locationUrl = locationContent.toLocationData()
- ?.let { urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, 1200, 800) }
- ?: return null
+
val locationOwnerId = if (locationContent.isSelfLocation()) state.informationData.matrixItem.id else null
return LocationUiData(
- locationUrl = locationUrl,
+ locationData = locationContent.toLocationData(),
+ locationUrl = urlMapProvider.getMapStyleUrl(),
locationOwnerId = locationOwnerId,
locationPinProvider = locationPinProvider,
)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationShareMessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationShareMessageItemFactory.kt
index 493602a291a..8b7d3303235 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationShareMessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/LiveLocationShareMessageItemFactory.kt
@@ -30,7 +30,6 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocation
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationItem_
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem
import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem_
-import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
import im.vector.app.features.location.UrlMapProvider
import im.vector.app.features.location.toLocationData
import org.matrix.android.sdk.api.session.Session
@@ -105,13 +104,12 @@ class LiveLocationShareMessageItemFactory @Inject constructor(
val width = timelineMediaSizeProvider.getMaxSize().first
val height = dimensionConverter.dpToPx(MessageItemFactory.MESSAGE_LOCATION_ITEM_HEIGHT_IN_DP)
- val locationUrl = runningState.lastGeoUri.toLocationData()?.let {
- urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, width, height)
- }
+ val lastLocationData = runningState.lastGeoUri.toLocationData()
return MessageLiveLocationItem_()
.attributes(attributes)
- .locationUrl(locationUrl)
+ .locationData(lastLocationData)
+ .mapStyleUrl(urlMapProvider.getMapStyleUrl())
.mapWidth(width)
.mapHeight(height)
.locationUserId(attributes.informationData.senderId)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
index 42e031a3c47..9f3a0685626 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/MessageItemFactory.kt
@@ -73,7 +73,6 @@ import im.vector.app.features.html.EventHtmlRenderer
import im.vector.app.features.html.PillsPostProcessor
import im.vector.app.features.html.SpanUtils
import im.vector.app.features.html.VectorHtmlCompressor
-import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
import im.vector.app.features.location.UrlMapProvider
import im.vector.app.features.location.toLocationData
import im.vector.app.features.media.ImageContentRenderer
@@ -222,15 +221,12 @@ class MessageItemFactory @Inject constructor(
val width = timelineMediaSizeProvider.getMaxSize().first
val height = dimensionConverter.dpToPx(MESSAGE_LOCATION_ITEM_HEIGHT_IN_DP)
- val locationUrl = locationContent.toLocationData()?.let {
- urlMapProvider.buildStaticMapUrl(it, INITIAL_MAP_ZOOM_IN_TIMELINE, width, height)
- }
-
val locationUserId = if (locationContent.isSelfLocation()) informationData.senderId else null
return MessageLocationItem_()
.attributes(attributes)
- .locationUrl(locationUrl)
+ .locationData(locationContent.toLocationData())
+ .mapStyleUrl(urlMapProvider.getMapStyleUrl())
.mapWidth(width)
.mapHeight(height)
.locationUserId(locationUserId)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/AbsMessageLocationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/AbsMessageLocationItem.kt
index 4903b8c8cf8..c631c99a778 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/AbsMessageLocationItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/AbsMessageLocationItem.kt
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2022 BWI GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,35 +17,34 @@
package im.vector.app.features.home.room.detail.timeline.item
-import android.graphics.drawable.Drawable
import android.widget.ImageView
-import android.widget.TextView
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import com.airbnb.epoxy.EpoxyAttribute
-import com.bumptech.glide.load.DataSource
-import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
-import com.bumptech.glide.request.RequestListener
-import com.bumptech.glide.request.RequestOptions
-import com.bumptech.glide.request.target.Target
+import com.mapbox.mapboxsdk.maps.MapView
import im.vector.app.R
-import im.vector.app.core.glide.GlideApp
import im.vector.app.core.utils.DimensionConverter
import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider
import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout
import im.vector.app.features.home.room.detail.timeline.style.granularRoundedCorners
+import im.vector.app.features.location.INITIAL_MAP_ZOOM_IN_TIMELINE
+import im.vector.app.features.location.LocationData
import im.vector.app.features.location.MapLoadingErrorView
import im.vector.app.features.location.MapLoadingErrorViewState
+import im.vector.app.features.location.zoomToLocation
abstract class AbsMessageLocationItem(
@LayoutRes layoutId: Int = R.layout.item_timeline_event_base
) : AbsMessageItem(layoutId) {
@EpoxyAttribute
- var locationUrl: String? = null
+ var locationData: LocationData? = null
+
+ @EpoxyAttribute
+ var mapStyleUrl: String? = null
@EpoxyAttribute
var locationUserId: String? = null
@@ -64,8 +64,17 @@ abstract class AbsMessageLocationItem(
bindMap(holder)
}
+ override fun onViewAttachedToWindow(holder: H) {
+ super.onViewAttachedToWindow(holder)
+ holder.staticMapView.onStart()
+ }
+
+ override fun onViewDetachedFromWindow(holder: H) {
+ super.onViewDetachedFromWindow(holder)
+ holder.staticMapView.onStop()
+ }
+
private fun bindMap(holder: Holder) {
- val location = locationUrl ?: return
val messageLayout = attributes.informationData.messageLayout
val imageCornerTransformation = if (messageLayout is TimelineMessageLayout.Bubble) {
messageLayout.cornersRadius.granularRoundedCorners()
@@ -73,53 +82,47 @@ abstract class AbsMessageLocationItem(
val dimensionConverter = DimensionConverter(holder.view.resources)
RoundedCorners(dimensionConverter.dpToPx(8))
}
- holder.staticMapImageView.updateLayoutParams {
- width = mapWidth
- height = mapHeight
+
+ holder.staticMapView.apply {
+ updateLayoutParams {
+ width = mapWidth
+ height = mapHeight
+ }
+ addOnDidFailLoadingMapListener {
+ holder.staticMapLoadingErrorView.isVisible = true
+ val mapErrorViewState = MapLoadingErrorViewState(imageCornerTransformation)
+ holder.staticMapLoadingErrorView.render(mapErrorViewState)
+ }
+
+ addOnDidFinishLoadingMapListener {
+ locationPinProvider?.create(locationUserId) { pinDrawable ->
+ holder.staticMapPinImageView.setImageDrawable(pinDrawable)
+ }
+ holder.staticMapLoadingErrorView.isVisible = false
+ }
+
+ clipToOutline = true
+ getMapAsync { mapbox ->
+ mapbox.setStyle(mapStyleUrl)
+ locationData?.let {
+ mapbox.zoomToLocation(it, false, INITIAL_MAP_ZOOM_IN_TIMELINE)
+ }
+ mapbox.uiSettings.setAllGesturesEnabled(false)
+ mapbox.addOnMapClickListener {
+ attributes.itemClickListener?.invoke(holder.staticMapView)
+ true
+ }
+ mapbox.addOnMapLongClickListener {
+ attributes.itemLongClickListener?.onLongClick(holder.staticMapView)
+ true
+ }
+ }
}
- GlideApp.with(holder.staticMapImageView)
- .load(location)
- .apply(RequestOptions.centerCropTransform())
- .placeholder(holder.staticMapImageView.drawable)
- .listener(object : RequestListener {
- override fun onLoadFailed(
- e: GlideException?,
- model: Any?,
- target: Target?,
- isFirstResource: Boolean
- ): Boolean {
- holder.staticMapPinImageView.setImageDrawable(null)
- holder.staticMapLoadingErrorView.isVisible = true
- val mapErrorViewState = MapLoadingErrorViewState(imageCornerTransformation)
- holder.staticMapLoadingErrorView.render(mapErrorViewState)
- holder.staticMapCopyrightTextView.isVisible = false
- return false
- }
-
- override fun onResourceReady(
- resource: Drawable?,
- model: Any?,
- target: Target?,
- dataSource: DataSource?,
- isFirstResource: Boolean
- ): Boolean {
- locationPinProvider?.create(locationUserId) { pinDrawable ->
- // we are not using Glide since it does not display it correctly when there is no user photo
- holder.staticMapPinImageView.setImageDrawable(pinDrawable)
- }
- holder.staticMapLoadingErrorView.isVisible = false
- holder.staticMapCopyrightTextView.isVisible = true
- return false
- }
- })
- .transform(imageCornerTransformation)
- .into(holder.staticMapImageView)
}
abstract class Holder(@IdRes stubId: Int) : AbsMessageItem.Holder(stubId) {
- val staticMapImageView by bind(R.id.staticMapImageView)
+ val staticMapView by bind(R.id.staticMapView)
val staticMapPinImageView by bind(R.id.staticMapPinImageView)
val staticMapLoadingErrorView by bind(R.id.staticMapLoadingError)
- val staticMapCopyrightTextView by bind(R.id.staticMapCopyrightTextView)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingConfig.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingConfig.kt
index 4615564e41d..d19f2dbd584 100644
--- a/vector/src/main/java/im/vector/app/features/location/LocationSharingConfig.kt
+++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingConfig.kt
@@ -18,4 +18,5 @@ package im.vector.app.features.location
data class LocationSharingConfig(
val mapTilerKey: String,
+ val isMapTilerFallbackEnabled: Boolean
)
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 779818b3d6f..2563bef27f1 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
@@ -99,7 +99,7 @@ class LocationSharingFragment :
lifecycleScope.launchWhenCreated {
views.mapView.initialize(
- url = urlMapProvider.getMapUrl(),
+ url = urlMapProvider.getMapStyleUrl(),
locationTargetChangeListener = this@LocationSharingFragment
)
}
diff --git a/vector/src/main/java/im/vector/app/features/location/MapBoxMapExt.kt b/vector/src/main/java/im/vector/app/features/location/MapBoxMapExt.kt
index 8e917c665a9..b183a2e325a 100644
--- a/vector/src/main/java/im/vector/app/features/location/MapBoxMapExt.kt
+++ b/vector/src/main/java/im/vector/app/features/location/MapBoxMapExt.kt
@@ -22,17 +22,24 @@ import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.maps.MapboxMap
-fun MapboxMap?.zoomToLocation(locationData: LocationData, preserveCurrentZoomLevel: Boolean = false) {
- val zoomLevel = if (preserveCurrentZoomLevel && this?.cameraPosition != null) {
- cameraPosition.zoom
+fun MapboxMap?.zoomToLocation(
+ locationData: LocationData,
+ animate: Boolean = true,
+ zoomLevel: Double = INITIAL_MAP_ZOOM_IN_PREVIEW) {
+
+ val cameraPosition = CameraPosition.Builder()
+ .target(LatLng(locationData.latitude, locationData.longitude))
+ .zoom(zoomLevel)
+ .build()
+
+ if(animate) {
+ this?.easeCamera {
+ cameraPosition
+ }
} else {
- INITIAL_MAP_ZOOM_IN_PREVIEW
- }
- this?.easeCamera {
- CameraPosition.Builder()
- .target(LatLng(locationData.latitude, locationData.longitude))
- .zoom(zoomLevel)
- .build()
+ this?.moveCamera {
+ cameraPosition
+ }
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt b/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt
index 3748b1b19e0..3f6ac95b107 100644
--- a/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt
+++ b/vector/src/main/java/im/vector/app/features/location/UrlMapProvider.kt
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2022 New Vector Ltd
+ * Copyright (c) 2022 BWI GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,52 +17,25 @@
package im.vector.app.features.location
-import im.vector.app.features.raw.wellknown.getElementWellknown
-import org.matrix.android.sdk.api.extensions.tryOrNull
-import org.matrix.android.sdk.api.raw.RawService
-import org.matrix.android.sdk.api.session.Session
+import androidx.annotation.VisibleForTesting
+import im.vector.app.features.raw.wellknown.WellknownService
import javax.inject.Inject
+import javax.inject.Singleton
+@Singleton
class UrlMapProvider @Inject constructor(
- private val session: Session,
- private val rawService: RawService,
- locationSharingConfig: LocationSharingConfig,
+ private val wellknownService: WellknownService,
+ private val locationSharingConfig: LocationSharingConfig,
) {
private val keyParam = "?key=${locationSharingConfig.mapTilerKey}"
- private val fallbackMapUrl = buildString {
+ @VisibleForTesting
+ val fallbackMapUrl = buildString {
append(MAP_BASE_URL)
append(keyParam)
}
- suspend fun getMapUrl(): String {
- val upstreamMapUrl = tryOrNull { rawService.getElementWellknown(session.sessionParams) }
- ?.getBestMapTileServerConfig()
- ?.mapStyleUrl
- return upstreamMapUrl ?: fallbackMapUrl
- }
-
- fun buildStaticMapUrl(
- locationData: LocationData,
- zoom: Double,
- width: Int,
- height: Int
- ): String {
- return buildString {
- append(STATIC_MAP_BASE_URL)
- append(locationData.longitude)
- append(",")
- append(locationData.latitude)
- append(",")
- append(zoom)
- append("/")
- append(width)
- append("x")
- append(height)
- append(".png")
- append(keyParam)
- // Since the default copyright font is too small we put a custom one on map
- append("&attribution=false")
- }
+ fun getMapStyleUrl() : String {
+ return wellknownService.getMapStyleUrl() ?: if (locationSharingConfig.isMapTilerFallbackEnabled) fallbackMapUrl else ""
}
}
diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
index 942021dd649..e4dce356740 100644
--- a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewFragment.kt
@@ -129,7 +129,7 @@ class LiveLocationMapViewFragment :
listenMapLoadingError(it)
}
lifecycleScope.launch {
- mapboxMap.setStyle(urlMapProvider.getMapUrl()) { style ->
+ mapboxMap.setStyle(urlMapProvider.getMapStyleUrl()) { style ->
mapStyle = style
this@LiveLocationMapViewFragment.mapboxMap = WeakReference(mapboxMap)
symbolManager = SymbolManager(mapFragment.view as MapView, mapboxMap, style).apply {
@@ -157,7 +157,7 @@ class LiveLocationMapViewFragment :
symbol?.let {
mapboxMap
?.get()
- ?.zoomToLocation(LocationData(it.latLng.latitude, it.latLng.longitude, null), preserveCurrentZoomLevel = false)
+ ?.zoomToLocation(LocationData(it.latLng.latitude, it.latLng.longitude, null))
LiveLocationMapMarkerOptionsDialog(requireContext())
.apply {
@@ -332,7 +332,7 @@ class LiveLocationMapViewFragment :
.find { it.matrixItem.id == userId }
?.locationData
?.let { locationData ->
- mapboxMap?.get()?.zoomToLocation(locationData, preserveCurrentZoomLevel = false)
+ mapboxMap?.get()?.zoomToLocation(locationData, true)
}
}
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 082cee02f06..0330d01e86b 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
@@ -75,7 +75,7 @@ class LocationPreviewFragment :
views.mapView.onCreate(savedInstanceState)
lifecycleScope.launchWhenCreated {
- views.mapView.initialize(urlMapProvider.getMapUrl())
+ views.mapView.initialize(urlMapProvider.getMapStyleUrl())
loadPinDrawable()
}
}
diff --git a/vector/src/main/java/im/vector/app/features/raw/wellknown/WellknownService.kt b/vector/src/main/java/im/vector/app/features/raw/wellknown/WellknownService.kt
new file mode 100644
index 00000000000..9d7571fe02b
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/raw/wellknown/WellknownService.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022 BWI GmbH
+ *
+ * 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.raw.wellknown
+
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.matrix.android.sdk.api.extensions.tryOrNull
+import org.matrix.android.sdk.api.raw.RawService
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class WellknownService @Inject constructor(
+ private val rawService: RawService
+) {
+ private var elementWellKnown : ElementWellKnown? = null
+
+ suspend fun getElementWellknown(domain: String): ElementWellKnown? {
+ elementWellKnown = withContext(Dispatchers.IO) {
+ tryOrNull { rawService.getWellknown(domain) }
+ ?.let { ElementWellKnownMapper.from(it) }
+ }
+ return elementWellKnown
+ }
+
+ fun getMapStyleUrl() : String? {
+ return elementWellKnown?.mapTileServerConfig?.mapStyleUrl
+ }
+}
diff --git a/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml b/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
index b41fda99fbe..872b4f5de5d 100644
--- a/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
+++ b/vector/src/main/res/layout/item_bottom_sheet_message_preview.xml
@@ -120,9 +120,10 @@
tools:alpha="0.3"
tools:visibility="visible">
-
diff --git a/vector/src/main/res/layout/item_timeline_event_location_stub.xml b/vector/src/main/res/layout/item_timeline_event_location_stub.xml
index 8de98b22604..474363b4405 100644
--- a/vector/src/main/res/layout/item_timeline_event_location_stub.xml
+++ b/vector/src/main/res/layout/item_timeline_event_location_stub.xml
@@ -6,12 +6,12 @@
android:layout_height="wrap_content">
-
@@ -24,9 +24,9 @@
android:importantForAccessibility="no"
android:src="@drawable/bg_map_user_pin"
app:layout_constraintBottom_toTopOf="@id/staticMapVerticalCenter"
- app:layout_constraintEnd_toEndOf="@id/staticMapImageView"
- app:layout_constraintStart_toStartOf="@id/staticMapImageView"
- app:layout_constraintTop_toTopOf="@id/staticMapImageView"
+ app:layout_constraintEnd_toEndOf="@id/staticMapView"
+ app:layout_constraintStart_toStartOf="@id/staticMapView"
+ app:layout_constraintTop_toTopOf="@id/staticMapView"
app:layout_constraintVertical_bias="1.0" />
-
-
diff --git a/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt b/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt
index e20d498a37a..960213548f8 100644
--- a/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt
+++ b/vector/src/test/java/im/vector/app/features/attachments/AttachmentTypeSelectorViewModelTest.kt
@@ -57,7 +57,6 @@ internal class AttachmentTypeSelectorViewModelTest {
@Test
fun `given location sharing is enabled, then location sharing option is visible`() {
fakeVectorFeatures.givenLocationSharing(isEnabled = true)
-
createViewModel()
.test()
.assertStates(
@@ -136,7 +135,7 @@ internal class AttachmentTypeSelectorViewModelTest {
return AttachmentTypeSelectorViewModel(
initialState,
vectorFeatures = fakeVectorFeatures,
- vectorPreferences = fakeVectorPreferences.instance,
+ vectorPreferences = fakeVectorPreferences.instance
)
}
}
diff --git a/vector/src/test/java/im/vector/app/features/location/UrlMapProviderTest.kt b/vector/src/test/java/im/vector/app/features/location/UrlMapProviderTest.kt
new file mode 100644
index 00000000000..48c8b1c1e0a
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/location/UrlMapProviderTest.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022 BWI GmbH
+ *
+ * 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 im.vector.app.test.fakes.FakeWellknownService
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.Test
+
+class UrlMapProviderTest {
+
+ @Test
+ fun `given enabled fallback to maptiler API, when map configuration is not set, then the fallback url should be returned`() {
+ val wellknownService = FakeWellknownService()
+ wellknownService.givenMissingMapConfiguration()
+ val urlMapProvider = UrlMapProvider(wellknownService.instance, LocationSharingConfig("", true))
+ urlMapProvider.getMapStyleUrl() shouldBeEqualTo urlMapProvider.fallbackMapUrl
+ }
+
+ @Test
+ fun `given enabled fallback to maptiler API, when map configuration is set, then the configurated url should be returned`() {
+ val wellknownService = FakeWellknownService()
+ wellknownService.givenValidMapConfiguration()
+ val urlMapProvider = UrlMapProvider(wellknownService.instance, LocationSharingConfig("", true))
+ urlMapProvider.getMapStyleUrl() shouldBeEqualTo wellknownService.A_MAPSTYLE_URL
+ }
+
+ @Test
+ fun `given disabled fallback to maptiler API, when map configuration is set, then the configurated url should be returned`() {
+ val wellknownService = FakeWellknownService()
+ wellknownService.givenValidMapConfiguration()
+ val urlMapProvider = UrlMapProvider(wellknownService.instance, LocationSharingConfig("", false))
+ urlMapProvider.getMapStyleUrl() shouldBeEqualTo wellknownService.A_MAPSTYLE_URL
+ }
+
+ @Test
+ fun `given disabled fallback to maptiler API, when map configuration is not set, then empty string should be returned`() {
+ val wellknownService = FakeWellknownService()
+ wellknownService.givenMissingMapConfiguration()
+ val urlMapProvider = UrlMapProvider(wellknownService.instance, LocationSharingConfig("", false))
+ urlMapProvider.getMapStyleUrl() shouldBeEqualTo ""
+ }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeWellknownService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeWellknownService.kt
new file mode 100644
index 00000000000..beed579612c
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeWellknownService.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 BWI GmbH
+ *
+ * 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.test.fakes
+
+import im.vector.app.features.raw.wellknown.WellknownService
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeWellknownService {
+ val A_MAPSTYLE_URL = "https://example.com/style.json"
+
+ val instance = mockk()
+
+ fun givenMissingMapConfiguration() {
+ every { instance.getMapStyleUrl() } returns null
+ }
+
+ fun givenValidMapConfiguration() {
+ every { instance.getMapStyleUrl() } returns A_MAPSTYLE_URL
+ }
+}