diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 6737f4faf1..08fe557f7c 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -64,4 +64,7 @@ 10dp + 16dp + 12dp + 8dp 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 fb86033065..dc28c2dba9 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 @@ -67,10 +67,12 @@ class LocationSharingFragment @Inject constructor( lifecycleScope.launchWhenCreated { views.mapView.initialize( url = urlMapProvider.getMapUrl(), + showLocateBtn = true, locationTargetChangeListener = this@LocationSharingFragment ) } + initLocateBtn() initOptionsPicker() viewModel.observeViewEvents { @@ -141,12 +143,18 @@ class LocationSharingFragment @Inject constructor( .show() } + private fun initLocateBtn() { + views.mapView.locateBtn.setOnClickListener { + // TODO retrieve user location and zoom to this location + } + } + private fun initOptionsPicker() { // TODO // 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 - // 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 views.shareLocationOptionsPicker.render() views.shareLocationOptionsPicker.optionPinned.debouncedClicks { diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt index b721adb93f..5ad762adff 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingViewModel.kt @@ -37,6 +37,9 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session 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 class LocationSharingViewModel @AssistedInject constructor( @@ -122,7 +125,7 @@ class LocationSharingViewModel @AssistedInject constructor( } 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) } 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 903b88423a..1c6a20aadf 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 @@ -18,7 +18,12 @@ package im.vector.app.features.location import android.content.Context import android.util.AttributeSet +import android.view.Gravity +import android.widget.ImageView 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.geometry.LatLng import com.mapbox.mapboxsdk.maps.MapView @@ -47,16 +52,24 @@ class MapTilerMapView @JvmOverloads constructor( private val userLocationDrawable by lazy { ContextCompat.getDrawable(context, R.drawable.ic_location_user) } + val locateBtn by lazy { createLocateBtn() } private var mapRefs: MapRefs? = null private var initZoomDone = false /** * 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") getMapAsync { map -> initMapStyle(map, url) + if (showLocateBtn) { + showLocateBtn(map) + } notifyLocationOfMapCenter(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 { + 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 { + 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) { val safeMapRefs = mapRefs ?: return Unit.also { pendingState = state @@ -93,7 +130,6 @@ class MapTilerMapView @JvmOverloads constructor( 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 val pinDrawable = state.pinDrawable ?: userLocationDrawable pinDrawable?.let { drawable -> @@ -110,7 +146,7 @@ class MapTilerMapView @JvmOverloads constructor( } safeMapRefs.symbolManager.deleteAll() - if(pinDrawable != null && state.showPin) { + if (pinDrawable != null && state.showPin) { safeMapRefs.symbolManager.create( SymbolOptions() .withLatLng(LatLng(locationData.latitude, locationData.longitude)) diff --git a/vector/src/main/res/drawable/btn_locate.xml b/vector/src/main/res/drawable/btn_locate.xml new file mode 100644 index 0000000000..583b3a97ea --- /dev/null +++ b/vector/src/main/res/drawable/btn_locate.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/vector/src/main/res/drawable/ic_locate.xml b/vector/src/main/res/drawable/ic_locate.xml new file mode 100644 index 0000000000..784665fcdd --- /dev/null +++ b/vector/src/main/res/drawable/ic_locate.xml @@ -0,0 +1,9 @@ + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 62f6c37428..bbb2bc7740 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2930,6 +2930,7 @@ Share location Pin of selected location on map + Zoom to current location Share my current location Share my current location Share live location