diff --git a/changelog.d/6012.wip b/changelog.d/6012.wip
new file mode 100644
index 0000000000..9c67d562fe
--- /dev/null
+++ b/changelog.d/6012.wip
@@ -0,0 +1 @@
+Live location sharing: navigation from timeline to map screen
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index 20b7c4908a..fc78ce90a3 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -343,6 +343,7 @@
+
diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
index dfbd2eba97..61c4fe2174 100644
--- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
+++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt
@@ -36,9 +36,10 @@ fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit):
fun Fragment.addFragment(
frameId: Int,
fragment: Fragment,
+ tag: String? = null,
allowStateLoss: Boolean = false
) {
- parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment) }
+ parentFragmentManager.commitTransaction(allowStateLoss) { add(frameId, fragment, tag) }
}
fun Fragment.addFragment(
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index 635b00c05d..736722946f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -221,6 +221,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconInfoContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
import org.matrix.android.sdk.api.session.room.model.message.MessageImageInfoContent
@@ -647,6 +648,13 @@ class TimelineFragment @Inject constructor(
)
}
+ private fun navigateToLocationLiveMap() {
+ navigator.openLocationLiveMap(
+ context = requireContext(),
+ roomId = timelineArgs.roomId
+ )
+ }
+
private fun handleChangeLocationIndicator(event: RoomDetailViewEvents.ChangeLocationIndicator) {
views.locationLiveStatusIndicator.isVisible = event.isVisible
}
@@ -2015,6 +2023,9 @@ class TimelineFragment @Inject constructor(
is MessageLocationContent -> {
handleShowLocationPreview(messageContent, informationData.senderId)
}
+ is MessageBeaconInfoContent -> {
+ navigateToLocationLiveMap()
+ }
else -> {
val handled = onThreadSummaryClicked(informationData.eventId, isRootThreadEvent)
if (!handled) {
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 479a742369..912702aaed 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
@@ -75,7 +75,8 @@ class LiveLocationShareMessageItemFactory @Inject constructor(
val height = dimensionConverter.dpToPx(MessageItemFactory.MESSAGE_LOCATION_ITEM_HEIGHT_IN_DP)
return MessageLiveLocationInactiveItem_()
- .attributes(attributes)
+ // disable the click on this state item
+ .attributes(attributes.copy(itemClickListener = null))
.mapWidth(width)
.mapHeight(height)
.highlighted(highlight)
@@ -90,7 +91,8 @@ class LiveLocationShareMessageItemFactory @Inject constructor(
val height = dimensionConverter.dpToPx(MessageItemFactory.MESSAGE_LOCATION_ITEM_HEIGHT_IN_DP)
return MessageLiveLocationStartItem_()
- .attributes(attributes)
+ // disable the click on this state item
+ .attributes(attributes.copy(itemClickListener = null))
.mapWidth(width)
.mapHeight(height)
.highlighted(highlight)
diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewActivity.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewActivity.kt
new file mode 100644
index 0000000000..c0f07dba57
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewActivity.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.content.Intent
+import android.os.Parcelable
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.VectorBaseActivity
+import im.vector.app.databinding.ActivityLocationSharingBinding
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class LocationLiveMapViewArgs(
+ val roomId: String
+) : Parcelable
+
+@AndroidEntryPoint
+class LocationLiveMapViewActivity : VectorBaseActivity() {
+
+ override fun getBinding() = ActivityLocationSharingBinding.inflate(layoutInflater)
+
+ override fun initUiAndData() {
+ val mapViewArgs: LocationLiveMapViewArgs? = intent?.extras?.getParcelable(EXTRA_LOCATION_LIVE_MAP_VIEW_ARGS)
+ if (mapViewArgs == null) {
+ finish()
+ return
+ }
+ setupToolbar(views.toolbar)
+ .setTitle(getString(R.string.location_activity_title_preview))
+ .allowBack()
+
+ if (isFirstCreation()) {
+ addFragment(
+ views.fragmentContainer,
+ LocationLiveMapViewFragment::class.java,
+ mapViewArgs
+ )
+ }
+ }
+
+ companion object {
+
+ private const val EXTRA_LOCATION_LIVE_MAP_VIEW_ARGS = "EXTRA_LOCATION_LIVE_MAP_VIEW_ARGS"
+
+ fun getIntent(context: Context, locationLiveMapViewArgs: LocationLiveMapViewArgs): Intent {
+ return Intent(context, LocationLiveMapViewActivity::class.java).apply {
+ putExtra(EXTRA_LOCATION_LIVE_MAP_VIEW_ARGS, locationLiveMapViewArgs)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewFragment.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewFragment.kt
new file mode 100644
index 0000000000..32b87727d8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewFragment.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
+import com.airbnb.mvrx.args
+import com.mapbox.mapboxsdk.maps.MapboxMapOptions
+import com.mapbox.mapboxsdk.maps.SupportMapFragment
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.extensions.addChildFragment
+import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.databinding.FragmentSimpleContainerBinding
+import im.vector.app.features.location.UrlMapProvider
+import javax.inject.Inject
+
+/**
+ * Screen showing a map with all the current users sharing their live location in room.
+ */
+@AndroidEntryPoint
+class LocationLiveMapViewFragment : VectorBaseFragment() {
+
+ @Inject
+ lateinit var urlMapProvider: UrlMapProvider
+
+ private val args: LocationLiveMapViewArgs by args()
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSimpleContainerBinding {
+ return FragmentSimpleContainerBinding.inflate(layoutInflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupMap()
+ }
+
+ private fun setupMap() {
+ val mapFragment = getOrCreateSupportMapFragment()
+
+ mapFragment.getMapAsync { mapBoxMap ->
+ lifecycleScope.launchWhenCreated {
+ mapBoxMap.setStyle(urlMapProvider.getMapUrl())
+ }
+ }
+ }
+
+ private fun getOrCreateSupportMapFragment() =
+ childFragmentManager.findFragmentByTag(MAP_FRAGMENT_TAG) as? SupportMapFragment
+ ?: run {
+ val options = MapboxMapOptions.createFromAttributes(requireContext(), null)
+ SupportMapFragment.newInstance(options)
+ .also { addChildFragment(R.id.fragmentContainer, it, tag = MAP_FRAGMENT_TAG) }
+ }
+
+ companion object {
+ private const val MAP_FRAGMENT_TAG = "im.vector.app.features.location.live.map"
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
index 0f921ab80a..a051266688 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt
@@ -68,6 +68,8 @@ import im.vector.app.features.location.LocationData
import im.vector.app.features.location.LocationSharingActivity
import im.vector.app.features.location.LocationSharingArgs
import im.vector.app.features.location.LocationSharingMode
+import im.vector.app.features.location.live.map.LocationLiveMapViewActivity
+import im.vector.app.features.location.live.map.LocationLiveMapViewArgs
import im.vector.app.features.login.LoginActivity
import im.vector.app.features.login.LoginConfig
import im.vector.app.features.matrixto.MatrixToBottomSheet
@@ -592,6 +594,14 @@ class DefaultNavigator @Inject constructor(
context.startActivity(intent)
}
+ override fun openLocationLiveMap(context: Context, roomId: String) {
+ val intent = LocationLiveMapViewActivity.getIntent(
+ context = context,
+ locationLiveMapViewArgs = LocationLiveMapViewArgs(roomId = roomId)
+ )
+ context.startActivity(intent)
+ }
+
private fun startActivity(context: Context, intent: Intent, buildTask: Boolean) {
if (buildTask) {
val stackBuilder = TaskStackBuilder.create(context)
diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
index 075b41daf3..d4ef2b8099 100644
--- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
+++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt
@@ -172,6 +172,8 @@ interface Navigator {
initialLocationData: LocationData?,
locationOwnerId: String?)
+ fun openLocationLiveMap(context: Context, roomId: String)
+
fun openThread(context: Context, threadTimelineArgs: ThreadTimelineArgs, eventIdToNavigate: String? = null)
fun openThreadList(context: Context, threadTimelineArgs: ThreadTimelineArgs)
diff --git a/vector/src/main/res/layout/fragment_simple_container.xml b/vector/src/main/res/layout/fragment_simple_container.xml
new file mode 100644
index 0000000000..fb9e6d38c5
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_simple_container.xml
@@ -0,0 +1,5 @@
+
+