Merge pull request #6567 from vector-im/feature/ons/share_location_with_other_apps
Share location with other apps (PSG-242)
This commit is contained in:
commit
9976b3b8ac
1
changelog.d/6567.feature
Normal file
1
changelog.d/6567.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Share location with other apps
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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.live.map
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.PopupWindow
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.databinding.ViewLiveLocationMarkerPopupBinding
|
||||||
|
|
||||||
|
class LocationLiveMapMarkerOptionsDialog(
|
||||||
|
context: Context,
|
||||||
|
) : PopupWindow() {
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onShareLocationClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val views: ViewLiveLocationMarkerPopupBinding
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
contentView = View.inflate(context, R.layout.view_live_location_marker_popup, null)
|
||||||
|
|
||||||
|
views = ViewLiveLocationMarkerPopupBinding.bind(contentView)
|
||||||
|
|
||||||
|
width = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||||
|
inputMethodMode = INPUT_METHOD_NOT_NEEDED
|
||||||
|
isFocusable = true
|
||||||
|
isTouchable = true
|
||||||
|
|
||||||
|
contentView.setOnClickListener {
|
||||||
|
callback?.onShareLocationClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(anchorView: View) {
|
||||||
|
contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
|
||||||
|
// By default the left side of the dialog is aligned with the pin. We need shift it to the left to make it's center aligned with the pin.
|
||||||
|
showAsDropDown(anchorView, -contentView.measuredWidth / 2, 0)
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap
|
|||||||
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
|
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
|
||||||
import com.mapbox.mapboxsdk.maps.Style
|
import com.mapbox.mapboxsdk.maps.Style
|
||||||
import com.mapbox.mapboxsdk.maps.SupportMapFragment
|
import com.mapbox.mapboxsdk.maps.SupportMapFragment
|
||||||
|
import com.mapbox.mapboxsdk.plugins.annotation.Symbol
|
||||||
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
|
||||||
@ -42,6 +43,7 @@ import im.vector.app.core.extensions.addChildFragment
|
|||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.DimensionConverter
|
import im.vector.app.core.utils.DimensionConverter
|
||||||
|
import im.vector.app.core.utils.openLocation
|
||||||
import im.vector.app.databinding.FragmentLocationLiveMapViewBinding
|
import im.vector.app.databinding.FragmentLocationLiveMapViewBinding
|
||||||
import im.vector.app.features.location.UrlMapProvider
|
import im.vector.app.features.location.UrlMapProvider
|
||||||
import im.vector.app.features.location.zoomToBounds
|
import im.vector.app.features.location.zoomToBounds
|
||||||
@ -120,6 +122,10 @@ class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment<Fra
|
|||||||
this@LocationLiveMapViewFragment.mapboxMap = WeakReference(mapboxMap)
|
this@LocationLiveMapViewFragment.mapboxMap = WeakReference(mapboxMap)
|
||||||
symbolManager = SymbolManager(mapFragment.view as MapView, mapboxMap, style).apply {
|
symbolManager = SymbolManager(mapFragment.view as MapView, mapboxMap, style).apply {
|
||||||
iconAllowOverlap = true
|
iconAllowOverlap = true
|
||||||
|
addClickListener {
|
||||||
|
onSymbolClicked(it)
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pendingLiveLocations
|
pendingLiveLocations
|
||||||
.takeUnless { it.isEmpty() }
|
.takeUnless { it.isEmpty() }
|
||||||
@ -129,6 +135,31 @@ class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment<Fra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onSymbolClicked(symbol: Symbol?) {
|
||||||
|
symbol?.let {
|
||||||
|
val screenLocation = mapboxMap?.get()?.projection?.toScreenLocation(it.latLng)
|
||||||
|
views.liveLocationPopupAnchor.apply {
|
||||||
|
x = screenLocation?.x ?: 0f
|
||||||
|
y = (screenLocation?.y ?: 0f) - views.liveLocationPopupAnchor.height
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationLiveMapMarkerOptionsDialog(requireContext())
|
||||||
|
.apply {
|
||||||
|
callback = object : LocationLiveMapMarkerOptionsDialog.Callback {
|
||||||
|
override fun onShareLocationClicked() {
|
||||||
|
shareLocation(symbol)
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.show(views.liveLocationPopupAnchor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shareLocation(symbol: Symbol) {
|
||||||
|
openLocation(requireActivity(), symbol.latLng.latitude, symbol.latLng.longitude)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getOrCreateSupportMapFragment() =
|
private fun getOrCreateSupportMapFragment() =
|
||||||
childFragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG) as? SupportMapFragment
|
childFragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG) as? SupportMapFragment
|
||||||
?: run {
|
?: run {
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<solid android:color="?android:colorBackground" />
|
||||||
|
</shape>
|
@ -6,6 +6,11 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/bg_live_location_users_bottom_sheet">
|
android:background="@drawable/bg_live_location_users_bottom_sheet">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/liveLocationPopupAnchor"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/liveLocationMapFragmentContainer"
|
android:id="@+id/liveLocationMapFragmentContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_live_location_marker_popup"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/shareLocationImageView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_share_external"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="?vctr_content_tertiary" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/TextAppearance.Vector.Caption"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:text="@string/live_location_share_location_item_share"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/shareLocationImageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -3116,6 +3116,7 @@
|
|||||||
<!-- TODO remove key -->
|
<!-- TODO remove key -->
|
||||||
<string name="live_location_bottom_sheet_stop_sharing" tools:ignore="UnusedResources">Stop sharing</string>
|
<string name="live_location_bottom_sheet_stop_sharing" tools:ignore="UnusedResources">Stop sharing</string>
|
||||||
<string name="live_location_bottom_sheet_last_updated_at">Updated %1$s ago</string>
|
<string name="live_location_bottom_sheet_last_updated_at">Updated %1$s ago</string>
|
||||||
|
<string name="live_location_share_location_item_share">Share location</string>
|
||||||
|
|
||||||
<string name="message_bubbles">Show Message bubbles</string>
|
<string name="message_bubbles">Show Message bubbles</string>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user