Use static map image in timeline.

This commit is contained in:
Onuray Sahin 2022-01-28 18:51:28 +03:00
parent 4026ddb34f
commit 50279e3183
7 changed files with 77 additions and 56 deletions

View file

@ -16,6 +16,7 @@
package im.vector.app.features.home.room.detail.timeline.factory package im.vector.app.features.home.room.detail.timeline.factory
import android.content.res.Resources
import android.text.Spannable import android.text.Spannable
import android.text.SpannableStringBuilder import android.text.SpannableStringBuilder
import android.text.Spanned import android.text.Spanned
@ -127,7 +128,8 @@ class MessageItemFactory @Inject constructor(
private val session: Session, private val session: Session,
private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker, private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker,
private val locationPinProvider: LocationPinProvider, private val locationPinProvider: LocationPinProvider,
private val vectorPreferences: VectorPreferences) { private val vectorPreferences: VectorPreferences,
private val resources: Resources) {
// TODO inject this properly? // TODO inject this properly?
private var roomId: String = "" private var roomId: String = ""
@ -207,11 +209,16 @@ class MessageItemFactory @Inject constructor(
} }
} }
val width = resources.displayMetrics.widthPixels - dimensionConverter.dpToPx(60)
val height = dimensionConverter.dpToPx(200)
return MessageLocationItem_() return MessageLocationItem_()
.attributes(attributes) .attributes(attributes)
.locationData(locationData) .locationData(locationData)
.userId(informationData.senderId) .userId(informationData.senderId)
.locationPinProvider(locationPinProvider) .locationPinProvider(locationPinProvider)
.mapWidth(width)
.mapHeight(height)
.highlighted(highlight) .highlighted(highlight)
.leftGuideline(avatarSizeProvider.leftGuideline) .leftGuideline(avatarSizeProvider.leftGuideline)
.callback(mapCallback) .callback(mapCallback)

View file

@ -17,15 +17,17 @@
package im.vector.app.features.home.room.detail.timeline.item package im.vector.app.features.home.room.detail.timeline.item
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout import android.widget.ImageView
import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass import com.airbnb.epoxy.EpoxyModelClass
import com.bumptech.glide.request.RequestOptions
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.onClick import im.vector.app.core.epoxy.onClick
import im.vector.app.core.glide.GlideApp
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.INITIAL_MAP_ZOOM_IN_TIMELINE
import im.vector.app.features.location.LocationData import im.vector.app.features.location.LocationData
import im.vector.app.features.location.MapState import im.vector.app.features.location.getStaticMapUrl
import im.vector.app.features.location.MapTilerMapView
@EpoxyModelClass(layout = R.layout.item_timeline_event_base) @EpoxyModelClass(layout = R.layout.item_timeline_event_base)
abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>() { abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>() {
@ -46,6 +48,12 @@ abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>(
@EpoxyAttribute @EpoxyAttribute
var locationPinProvider: LocationPinProvider? = null var locationPinProvider: LocationPinProvider? = null
@EpoxyAttribute
var mapWidth: Int = 1200
@EpoxyAttribute
var mapHeight: Int = 800
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
super.bind(holder) super.bind(holder)
renderSendState(holder.mapViewContainer, null) renderSendState(holder.mapViewContainer, null)
@ -53,39 +61,28 @@ abstract class MessageLocationItem : AbsMessageItem<MessageLocationItem.Holder>(
val location = locationData ?: return val location = locationData ?: return
val locationOwnerId = userId ?: return val locationOwnerId = userId ?: return
holder.clickableMapArea.onClick { holder.mapViewContainer.onClick {
callback?.onMapClicked() callback?.onMapClicked()
} }
holder.mapView.initialize() GlideApp.with(holder.staticMapImageView)
holder.mapView.render( .load(getStaticMapUrl(location.latitude, location.longitude, INITIAL_MAP_ZOOM_IN_TIMELINE, mapWidth, mapHeight))
MapState( .apply(RequestOptions.centerCropTransform())
zoomOnlyOnce = false, .into(holder.staticMapImageView)
pinLocationData = location,
pinId = locationOwnerId,
pinDrawable = null
)
)
locationPinProvider?.create(locationOwnerId) { pinDrawable -> locationPinProvider?.create(locationOwnerId) { pinDrawable ->
if (holder.view.isAttachedToWindow) { GlideApp.with(holder.staticMapPinImageView)
holder.mapView.render( .load(pinDrawable)
MapState( .into(holder.staticMapPinImageView)
zoomOnlyOnce = false,
pinLocationData = location,
pinId = locationOwnerId,
pinDrawable = pinDrawable
)
)
}
} }
} }
override fun getViewType() = STUB_ID override fun getViewType() = STUB_ID
class Holder : AbsMessageItem.Holder(STUB_ID) { class Holder : AbsMessageItem.Holder(STUB_ID) {
val mapViewContainer by bind<ConstraintLayout>(R.id.mapViewContainer) val mapViewContainer by bind<FrameLayout>(R.id.mapViewContainer)
val mapView by bind<MapTilerMapView>(R.id.mapView) val staticMapImageView by bind<ImageView>(R.id.staticMapImageView)
val clickableMapArea by bind<FrameLayout>(R.id.clickableMapArea) val staticMapPinImageView by bind<ImageView>(R.id.staticMapPinImageView)
} }
companion object { companion object {

View file

@ -16,6 +16,33 @@
package im.vector.app.features.location package im.vector.app.features.location
const val INITIAL_MAP_ZOOM = 15.0 import im.vector.app.BuildConfig
const val MAP_STYLE_URL = "https://api.maptiler.com/maps/streets/style.json?key=${BuildConfig.mapTilerKey}"
private const val STATIC_MAP_IMAGE_URL = "https://api.maptiler.com/maps/basic/static/"
const val INITIAL_MAP_ZOOM_IN_PREVIEW = 15.0
const val INITIAL_MAP_ZOOM_IN_TIMELINE = 17.0
const val MIN_TIME_TO_UPDATE_LOCATION_MILLIS = 5 * 1_000L // every 5 seconds const val MIN_TIME_TO_UPDATE_LOCATION_MILLIS = 5 * 1_000L // every 5 seconds
const val MIN_DISTANCE_TO_UPDATE_LOCATION_METERS = 10f const val MIN_DISTANCE_TO_UPDATE_LOCATION_METERS = 10f
fun getStaticMapUrl(latitude: Double,
longitude: Double,
zoom: Double,
width: Int,
height: Int): String {
return buildString {
append(STATIC_MAP_IMAGE_URL)
append(longitude)
append(",")
append(latitude)
append(",")
append(zoom)
append("/")
append(width)
append("x")
append(height)
append(".png?key=")
append(BuildConfig.mapTilerKey)
}
}

View file

@ -35,8 +35,7 @@ import javax.inject.Inject
/** /**
* We should consider using SupportMapFragment for a out of the box lifecycle handling * We should consider using SupportMapFragment for a out of the box lifecycle handling
*/ */
class LocationSharingFragment @Inject constructor( class LocationSharingFragment @Inject constructor() : VectorBaseFragment<FragmentLocationSharingBinding>() {
) : VectorBaseFragment<FragmentLocationSharingBinding>() {
private val viewModel: LocationSharingViewModel by fragmentViewModel() private val viewModel: LocationSharingViewModel by fragmentViewModel()

View file

@ -26,7 +26,6 @@ import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.mapbox.mapboxsdk.style.layers.Property import com.mapbox.mapboxsdk.style.layers.Property
import im.vector.app.BuildConfig
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
@ -58,7 +57,7 @@ class MapTilerMapView @JvmOverloads constructor(
} }
getMapAsync { map -> getMapAsync { map ->
map.setStyle(styleUrl) { style -> map.setStyle(MAP_STYLE_URL) { style ->
mapRefs = MapRefs( mapRefs = MapRefs(
map, map,
SymbolManager(this, map, style), SymbolManager(this, map, style),
@ -102,11 +101,7 @@ class MapTilerMapView @JvmOverloads constructor(
Timber.d("## Location: zoomToLocation") Timber.d("## Location: zoomToLocation")
mapRefs?.map?.cameraPosition = CameraPosition.Builder() mapRefs?.map?.cameraPosition = CameraPosition.Builder()
.target(LatLng(latitude, longitude)) .target(LatLng(latitude, longitude))
.zoom(INITIAL_MAP_ZOOM) .zoom(INITIAL_MAP_ZOOM_IN_PREVIEW)
.build() .build()
} }
companion object {
private const val styleUrl = "https://api.maptiler.com/maps/streets/style.json?key=${BuildConfig.mapTilerKey}"
}
} }

View file

@ -6,30 +6,25 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:cardCornerRadius="8dp"> app:cardCornerRadius="8dp">
<androidx.constraintlayout.widget.ConstraintLayout <FrameLayout
android:id="@+id/mapViewContainer" android:id="@+id/mapViewContainer"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<im.vector.app.features.location.MapTilerMapView <ImageView
android:id="@+id/mapView" android:id="@+id/staticMapImageView"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="200dp"
app:layout_constraintBottom_toBottomOf="parent" android:contentDescription="@string/a11y_static_map_image" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mapbox_renderTextureMode="true" />
<FrameLayout <ImageView
android:id="@+id/clickableMapArea" android:id="@+id/staticMapPinImageView"
android:layout_width="0dp" android:layout_width="51dp"
android:layout_height="0dp" android:layout_height="55dp"
app:layout_constraintBottom_toBottomOf="@id/mapView" android:layout_gravity="center"
app:layout_constraintEnd_toEndOf="@id/mapView" android:layout_marginBottom="28dp"
app:layout_constraintStart_toStartOf="@id/mapView" android:importantForAccessibility="no"
app:layout_constraintTop_toTopOf="@id/mapView" /> android:src="@drawable/bg_map_user_pin" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View file

@ -3711,6 +3711,7 @@
<string name="location_activity_title_static_sharing">Share location</string> <string name="location_activity_title_static_sharing">Share location</string>
<string name="location_activity_title_preview">Location</string> <string name="location_activity_title_preview">Location</string>
<string name="a11y_location_share_icon">Share location</string> <string name="a11y_location_share_icon">Share location</string>
<string name="a11y_static_map_image">Map</string>
<string name="location_share">Share location</string> <string name="location_share">Share location</string>
<string name="template_location_not_available_dialog_title">${app_name} could not access your location</string> <string name="template_location_not_available_dialog_title">${app_name} could not access your location</string>
<string name="template_location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string> <string name="template_location_not_available_dialog_content">${app_name} could not access your location. Please try again later.</string>