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/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index c68a35f4e5..6d42c83ac2 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -64,6 +64,7 @@ import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.threads.list.views.ThreadListFragment import im.vector.app.features.location.LocationPreviewFragment import im.vector.app.features.location.LocationSharingFragment +import im.vector.app.features.location.live.map.LocationLiveMapViewFragment import im.vector.app.features.login.LoginCaptchaFragment import im.vector.app.features.login.LoginFragment import im.vector.app.features.login.LoginGenericTextInputFormFragment @@ -993,4 +994,9 @@ interface FragmentModule { @IntoMap @FragmentKey(LocationPreviewFragment::class) fun bindLocationPreviewFragment(fragment: LocationPreviewFragment): Fragment + + @Binds + @IntoMap + @FragmentKey(LocationLiveMapViewFragment::class) + fun bindLocationLiveMapViewFragment(fragment: LocationLiveMapViewFragment): Fragment } 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 2bb620623c..bf7c506d79 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,10 @@ class TimelineFragment @Inject constructor( is MessageLocationContent -> { handleShowLocationPreview(messageContent, informationData.senderId) } + is MessageBeaconInfoContent -> { + // TODO navigate only from running live location message: possible after merge of associated PR + navigateToLocationLiveMap() + } else -> { val handled = onThreadSummaryClicked(informationData.eventId, isRootThreadEvent) if (!handled) { 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..cb54e93f97 --- /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.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) + // TODO check what should be the title and create String resource + .setTitle("Live") + .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..7e17712556 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/location/live/map/LocationLiveMapViewFragment.kt @@ -0,0 +1,99 @@ +/* + * 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.MapView +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentLocationPreviewBinding +import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider +import im.vector.app.features.location.UrlMapProvider +import java.lang.ref.WeakReference +import javax.inject.Inject + +/** + * Screen showing a map with all the current users sharing their live location in room. + */ +class LocationLiveMapViewFragment @Inject constructor( + private val urlMapProvider: UrlMapProvider, + private val locationPinProvider: LocationPinProvider +) : VectorBaseFragment() { + + // TODO use a SupportMapFragment with FragmentManager + // TODO align design with Figma + + private val args: LocationLiveMapViewArgs by args() + + // Keep a ref to handle properly the onDestroy callback + private var mapView: WeakReference? = null + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentLocationPreviewBinding { + return FragmentLocationPreviewBinding.inflate(layoutInflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mapView = WeakReference(views.mapView) + views.mapView.onCreate(savedInstanceState) + + lifecycleScope.launchWhenCreated { + views.mapView.initialize(urlMapProvider.getMapUrl()) + } + } + + override fun onResume() { + super.onResume() + views.mapView.onResume() + } + + override fun onPause() { + views.mapView.onPause() + super.onPause() + } + + override fun onLowMemory() { + views.mapView.onLowMemory() + super.onLowMemory() + } + + override fun onStart() { + super.onStart() + views.mapView.onStart() + } + + override fun onStop() { + views.mapView.onStop() + super.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + views.mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + mapView?.get()?.onDestroy() + mapView?.clear() + super.onDestroy() + } +} 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 7cc42ec57f..1ec4011289 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 @@ -591,6 +593,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)