Show icon to reset map to user location

This commit is contained in:
Maxime Naturel 2022-03-08 11:49:59 +01:00
parent 57fcfeb1c1
commit 40e92842ea
7 changed files with 83 additions and 6 deletions

View File

@ -64,4 +64,7 @@
<!-- Location sharing --> <!-- Location sharing -->
<dimen name="location_sharing_option_default_padding">10dp</dimen> <dimen name="location_sharing_option_default_padding">10dp</dimen>
<dimen name="location_sharing_locate_btn_margin_vertical">16dp</dimen>
<dimen name="location_sharing_locate_btn_margin_horizontal">12dp</dimen>
<dimen name="location_sharing_compass_btn_margin_horizontal">8dp</dimen>
</resources> </resources>

View File

@ -67,10 +67,12 @@ class LocationSharingFragment @Inject constructor(
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
views.mapView.initialize( views.mapView.initialize(
url = urlMapProvider.getMapUrl(), url = urlMapProvider.getMapUrl(),
showLocateBtn = true,
locationTargetChangeListener = this@LocationSharingFragment locationTargetChangeListener = this@LocationSharingFragment
) )
} }
initLocateBtn()
initOptionsPicker() initOptionsPicker()
viewModel.observeViewEvents { viewModel.observeViewEvents {
@ -141,12 +143,18 @@ class LocationSharingFragment @Inject constructor(
.show() .show()
} }
private fun initLocateBtn() {
views.mapView.locateBtn.setOnClickListener {
// TODO retrieve user location and zoom to this location
}
}
private fun initOptionsPicker() { private fun initOptionsPicker() {
// TODO // TODO
// reset map to user location when clicking on reset icon // reset map to user location when clicking on reset icon
// changes in the event sent when this is a pinned location
// changes in the parsing of events when receiving pinned location: since we may present a different UI
// unit tests // unit tests
// need changes in the event sent when this is a pin drop location?
// need changes in the parsing of events when receiving pin drop location?: should it be shown with user avatar or with pin?
// set no option at start // set no option at start
views.shareLocationOptionsPicker.render() views.shareLocationOptionsPicker.render()
views.shareLocationOptionsPicker.optionPinned.debouncedClicks { views.shareLocationOptionsPicker.optionPinned.debouncedClicks {

View File

@ -37,6 +37,9 @@ import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
/**
* Sampling period to compare target location and user location.
*/
private const val TARGET_LOCATION_CHANGE_SAMPLING_PERIOD_IN_MS = 100L private const val TARGET_LOCATION_CHANGE_SAMPLING_PERIOD_IN_MS = 100L
class LocationSharingViewModel @AssistedInject constructor( class LocationSharingViewModel @AssistedInject constructor(
@ -122,7 +125,7 @@ class LocationSharingViewModel @AssistedInject constructor(
} }
private fun handlePinnedLocationSharingAction(action: LocationSharingAction.PinnedLocationSharingAction) { private fun handlePinnedLocationSharingAction(action: LocationSharingAction.PinnedLocationSharingAction) {
// TODO check if we can use the same api than for user location? // TODO confirm how to differentiate the user location and pinned location events?
shareLocation(action.locationData) shareLocation(action.locationData)
} }

View File

@ -18,7 +18,12 @@ package im.vector.app.features.location
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.Gravity
import android.widget.ImageView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.marginBottom
import androidx.core.view.marginTop
import androidx.core.view.updateLayoutParams
import com.mapbox.mapboxsdk.camera.CameraPosition import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapView import com.mapbox.mapboxsdk.maps.MapView
@ -47,16 +52,24 @@ class MapTilerMapView @JvmOverloads constructor(
private val userLocationDrawable by lazy { private val userLocationDrawable by lazy {
ContextCompat.getDrawable(context, R.drawable.ic_location_user) ContextCompat.getDrawable(context, R.drawable.ic_location_user)
} }
val locateBtn by lazy { createLocateBtn() }
private var mapRefs: MapRefs? = null private var mapRefs: MapRefs? = null
private var initZoomDone = false private var initZoomDone = false
/** /**
* For location fragments * For location fragments
*/ */
fun initialize(url: String, locationTargetChangeListener: LocationTargetChangeListener? = null) { fun initialize(
url: String,
showLocateBtn: Boolean = false, // TODO transform into xml attribute
locationTargetChangeListener: LocationTargetChangeListener? = null
) {
Timber.d("## Location: initialize") Timber.d("## Location: initialize")
getMapAsync { map -> getMapAsync { map ->
initMapStyle(map, url) initMapStyle(map, url)
if (showLocateBtn) {
showLocateBtn(map)
}
notifyLocationOfMapCenter(locationTargetChangeListener) notifyLocationOfMapCenter(locationTargetChangeListener)
listenCameraMove(map, locationTargetChangeListener) listenCameraMove(map, locationTargetChangeListener)
} }
@ -86,6 +99,30 @@ class MapTilerMapView @JvmOverloads constructor(
} }
} }
private fun createLocateBtn(): ImageView =
ImageView(context).apply {
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.btn_locate))
contentDescription = context.getString(R.string.a11y_location_share_locate_btn)
layoutParams = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)
updateLayoutParams<MarginLayoutParams> {
val marginHorizontal = context.resources.getDimensionPixelOffset(R.dimen.location_sharing_locate_btn_margin_horizontal)
val marginVertical = context.resources.getDimensionPixelOffset(R.dimen.location_sharing_locate_btn_margin_vertical)
setMargins(marginHorizontal, marginVertical, marginHorizontal, marginVertical)
}
updateLayoutParams<LayoutParams> {
gravity = Gravity.TOP or Gravity.END
}
}
private fun showLocateBtn(map: MapboxMap) {
addView(locateBtn)
locateBtn.post {
val marginTop = locateBtn.height + locateBtn.marginTop + locateBtn.marginBottom
val marginRight = context.resources.getDimensionPixelOffset(R.dimen.location_sharing_compass_btn_margin_horizontal)
map.uiSettings.setCompassMargins(0, marginTop, marginRight, 0)
}
}
fun render(state: MapState) { fun render(state: MapState) {
val safeMapRefs = mapRefs ?: return Unit.also { val safeMapRefs = mapRefs ?: return Unit.also {
pendingState = state pendingState = state
@ -93,7 +130,6 @@ class MapTilerMapView @JvmOverloads constructor(
safeMapRefs.map.uiSettings.setLogoMargins(0, 0, 0, state.logoMarginBottom) safeMapRefs.map.uiSettings.setLogoMargins(0, 0, 0, state.logoMarginBottom)
// TODO add reset to user location button
// TODO check conflict of rendering with preview location in timeline // TODO check conflict of rendering with preview location in timeline
val pinDrawable = state.pinDrawable ?: userLocationDrawable val pinDrawable = state.pinDrawable ?: userLocationDrawable
pinDrawable?.let { drawable -> pinDrawable?.let { drawable ->
@ -110,7 +146,7 @@ class MapTilerMapView @JvmOverloads constructor(
} }
safeMapRefs.symbolManager.deleteAll() safeMapRefs.symbolManager.deleteAll()
if(pinDrawable != null && state.showPin) { if (pinDrawable != null && state.showPin) {
safeMapRefs.symbolManager.create( safeMapRefs.symbolManager.create(
SymbolOptions() SymbolOptions()
.withLatLng(LatLng(locationData.latitude, locationData.longitude)) .withLatLng(LatLng(locationData.latitude, locationData.longitude))

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/palette_white" />
<corners android:radius="4dp" />
</shape>
</item>
<item android:drawable="?selectableItemBackground" />
<item
android:bottom="8dp"
android:drawable="@drawable/ic_locate"
android:left="8dp"
android:right="8dp"
android:top="8dp" />
</layer-list>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="22dp"
android:viewportWidth="22"
android:viewportHeight="22">
<path
android:pathData="M11,7C8.79,7 7,8.79 7,11C7,13.21 8.79,15 11,15C13.21,15 15,13.21 15,11C15,8.79 13.21,7 11,7ZM19.94,10C19.48,5.83 16.17,2.52 12,2.06V1C12,0.45 11.55,0 11,0C10.45,0 10,0.45 10,1V2.06C5.83,2.52 2.52,5.83 2.06,10H1C0.45,10 0,10.45 0,11C0,11.55 0.45,12 1,12H2.06C2.52,16.17 5.83,19.48 10,19.94V21C10,21.55 10.45,22 11,22C11.55,22 12,21.55 12,21V19.94C16.17,19.48 19.48,16.17 19.94,12H21C21.55,12 22,11.55 22,11C22,10.45 21.55,10 21,10H19.94ZM11,18C7.13,18 4,14.87 4,11C4,7.13 7.13,4 11,4C14.87,4 18,7.13 18,11C18,14.87 14.87,18 11,18Z"
android:fillColor="#0DBD8B"/>
</vector>

View File

@ -2930,6 +2930,7 @@
<!-- TODO delete --> <!-- TODO delete -->
<string name="location_share" tools:ignore="UnusedResources">Share location</string> <string name="location_share" tools:ignore="UnusedResources">Share location</string>
<string name="a11y_location_share_pin_on_map">Pin of selected location on map</string> <string name="a11y_location_share_pin_on_map">Pin of selected location on map</string>
<string name="a11y_location_share_locate_btn">Zoom to current location</string>
<string name="location_share_option_user_current">Share my current location</string> <string name="location_share_option_user_current">Share my current location</string>
<string name="a11y_location_share_option_user_current_icon">Share my current location</string> <string name="a11y_location_share_option_user_current_icon">Share my current location</string>
<string name="location_share_option_user_live">Share live location</string> <string name="location_share_option_user_live">Share live location</string>