diff --git a/changelog.d/6635.misc b/changelog.d/6635.misc new file mode 100644 index 0000000000..6546659d11 --- /dev/null +++ b/changelog.d/6635.misc @@ -0,0 +1 @@ +[Location Share] - Expanded map state when no more live location shares diff --git a/library/ui-styles/src/main/res/values/stylable_location_live_ended_banner_view.xml b/library/ui-styles/src/main/res/values/stylable_location_live_ended_banner_view.xml new file mode 100644 index 0000000000..81e377d39b --- /dev/null +++ b/library/ui-styles/src/main/res/values/stylable_location_live_ended_banner_view.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationInactiveItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationInactiveItem.kt index bc6e96b0ee..fae8091f06 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationInactiveItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationInactiveItem.kt @@ -42,7 +42,7 @@ abstract class MessageLiveLocationInactiveItem : override fun getViewStubId() = STUB_ID class Holder : AbsMessageItem.Holder(STUB_ID) { - val bannerImageView by bind(R.id.locationLiveInactiveBanner) + val bannerImageView by bind(R.id.locationLiveEndedBannerBackground) val noLocationMapImageView by bind(R.id.locationLiveInactiveMap) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationItem.kt index 84080eaad9..b35b4dff8b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationItem.kt @@ -26,8 +26,8 @@ import im.vector.app.core.resources.toTimestamp import im.vector.app.core.utils.DimensionConverter import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout -import im.vector.app.features.location.live.LocationLiveMessageBannerView import im.vector.app.features.location.live.LocationLiveMessageBannerViewState +import im.vector.app.features.location.live.LocationLiveRunningBannerView import org.threeten.bp.LocalDateTime @EpoxyModelClass @@ -52,9 +52,9 @@ abstract class MessageLiveLocationItem : AbsMessageLocationItem(R.id.locationLiveMessageBanner) + val locationLiveRunningBanner by bind(R.id.locationLiveRunningBanner) } companion object { 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 1f9cb44c91..491386ba64 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 @@ -22,6 +22,7 @@ import android.util.AttributeSet import android.view.Gravity import android.widget.ImageView import androidx.core.content.ContextCompat +import androidx.core.content.res.use import androidx.core.view.marginBottom import androidx.core.view.marginTop import androidx.core.view.updateLayoutParams @@ -60,17 +61,13 @@ class MapTilerMapView @JvmOverloads constructor( private var dimensionConverter: DimensionConverter? = null init { - context.theme.obtainStyledAttributes( + context.obtainStyledAttributes( attrs, R.styleable.MapTilerMapView, 0, 0 - ).run { - try { - setLocateButtonVisibility(this) - } finally { - recycle() - } + ).use { + setLocateButtonVisibility(it) } dimensionConverter = DimensionConverter(resources) } diff --git a/vector/src/main/java/im/vector/app/features/location/live/LocationLiveEndedBannerView.kt b/vector/src/main/java/im/vector/app/features/location/live/LocationLiveEndedBannerView.kt new file mode 100644 index 0000000000..82fa17a625 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/location/live/LocationLiveEndedBannerView.kt @@ -0,0 +1,65 @@ +/* + * 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 + +import android.content.Context +import android.content.res.TypedArray +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.res.use +import androidx.core.view.updateLayoutParams +import im.vector.app.R +import im.vector.app.databinding.ViewLocationLiveEndedBannerBinding + +private const val BACKGROUND_ALPHA = 0.75f + +class LocationLiveEndedBannerView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : ConstraintLayout(context, attrs, defStyleAttr) { + + private val binding = ViewLocationLiveEndedBannerBinding.inflate( + LayoutInflater.from(context), + this + ) + + init { + context.obtainStyledAttributes( + attrs, + R.styleable.LocationLiveEndedBannerView, + 0, + 0 + ).use { + setBackgroundAlpha(it) + setIconMarginStart(it) + } + } + + private fun setBackgroundAlpha(typedArray: TypedArray) { + val withAlpha = typedArray.getBoolean(R.styleable.LocationLiveEndedBannerView_locLiveEndedBkgWithAlpha, false) + binding.locationLiveEndedBannerBackground.alpha = if (withAlpha) BACKGROUND_ALPHA else 1f + } + + private fun setIconMarginStart(typedArray: TypedArray) { + val margin = typedArray.getDimensionPixelOffset(R.styleable.LocationLiveEndedBannerView_locLiveEndedIconMarginStart, 0) + binding.locationLiveEndedBannerIcon.updateLayoutParams { + marginStart = margin + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/location/live/LocationLiveMessageBannerView.kt b/vector/src/main/java/im/vector/app/features/location/live/LocationLiveRunningBannerView.kt similarity index 87% rename from vector/src/main/java/im/vector/app/features/location/live/LocationLiveMessageBannerView.kt rename to vector/src/main/java/im/vector/app/features/location/live/LocationLiveRunningBannerView.kt index 51c7caed3a..4ca8475da1 100644 --- a/vector/src/main/java/im/vector/app/features/location/live/LocationLiveMessageBannerView.kt +++ b/vector/src/main/java/im/vector/app/features/location/live/LocationLiveRunningBannerView.kt @@ -31,34 +31,34 @@ import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners import im.vector.app.R import im.vector.app.core.glide.GlideApp import im.vector.app.core.utils.TextUtils -import im.vector.app.databinding.ViewLocationLiveMessageBannerBinding +import im.vector.app.databinding.ViewLocationLiveRunningBannerBinding import im.vector.app.features.themes.ThemeUtils import org.threeten.bp.Duration private const val REMAINING_TIME_COUNTER_INTERVAL_IN_MS = 1000L -class LocationLiveMessageBannerView @JvmOverloads constructor( +class LocationLiveRunningBannerView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { - private val binding = ViewLocationLiveMessageBannerBinding.inflate( + private val binding = ViewLocationLiveRunningBannerBinding.inflate( LayoutInflater.from(context), this ) val stopButton: Button - get() = binding.locationLiveMessageBannerStop + get() = binding.locationLiveRunningBannerStop private val background: ImageView - get() = binding.locationLiveMessageBannerBackground + get() = binding.locationLiveRunningBannerBackground private val title: TextView - get() = binding.locationLiveMessageBannerTitle + get() = binding.locationLiveRunningBannerTitle private val subTitle: TextView - get() = binding.locationLiveMessageBannerSubTitle + get() = binding.locationLiveRunningBannerSubTitle private var countDownTimer: CountDownTimer? = null @@ -70,7 +70,7 @@ class LocationLiveMessageBannerView @JvmOverloads constructor( GlideApp.with(context) .load(ColorDrawable(ThemeUtils.getColor(context, android.R.attr.colorBackground))) - .placeholder(binding.locationLiveMessageBannerBackground.drawable) + .placeholder(binding.locationLiveRunningBannerBackground.drawable) .transform(GranularRoundedCorners(0f, 0f, viewState.bottomEndCornerRadiusInDp, viewState.bottomStartCornerRadiusInDp)) .into(background) } @@ -109,14 +109,14 @@ class LocationLiveMessageBannerView @JvmOverloads constructor( if (viewState.isStopButtonCenteredVertically) { constraintSet.connect( - R.id.locationLiveMessageBannerStop, + R.id.locationLiveRunningBannerStop, ConstraintSet.BOTTOM, - R.id.locationLiveMessageBannerBackground, + R.id.locationLiveRunningBannerBackground, ConstraintSet.BOTTOM, 0 ) } else { - constraintSet.clear(R.id.locationLiveMessageBannerStop, ConstraintSet.BOTTOM) + constraintSet.clear(R.id.locationLiveRunningBannerStop, ConstraintSet.BOTTOM) } constraintSet.applyTo(parentLayout) 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 index e19580f13b..3aacd70f0e 100644 --- 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 @@ -22,6 +22,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.graphics.drawable.toBitmap +import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState @@ -57,7 +59,6 @@ import javax.inject.Inject /** * Screen showing a map with all the current users sharing their live location in a room. */ - @AndroidEntryPoint class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment() { @@ -110,13 +111,6 @@ class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment - val bottomSheetHeight = BottomSheetBehavior.from(views.bottomSheet).peekHeight - mapboxMap.uiSettings.apply { - // Place copyright above the user list bottom sheet - setLogoMargins(dimensionConverter.dpToPx(8), 0, 0, bottomSheetHeight + dimensionConverter.dpToPx(8)) - setAttributionMargins(dimensionConverter.dpToPx(96), 0, 0, bottomSheetHeight + dimensionConverter.dpToPx(8)) - } - lifecycleScope.launch { mapboxMap.setStyle(urlMapProvider.getMapUrl()) { style -> mapStyle = style @@ -173,9 +167,47 @@ class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment) { + if (userLocations.isEmpty()) { + showEndedLiveBanner() + } else { + showUserList(userLocations) + } + } + + private fun showEndedLiveBanner() { + views.bottomSheet.isGone = true + views.liveLocationMapFragmentEndedBanner.isVisible = true + updateCopyrightMargin(bottomOffset = views.liveLocationMapFragmentEndedBanner.height) + } + + private fun showUserList(userLocations: List) { + val bottomSheetHeight = BottomSheetBehavior.from(views.bottomSheet).peekHeight + updateCopyrightMargin(bottomOffset = bottomSheetHeight) + views.bottomSheet.isVisible = true + views.liveLocationMapFragmentEndedBanner.isGone = true bottomSheetController.setData(userLocations) } + private fun updateCopyrightMargin(bottomOffset: Int) { + getOrCreateSupportMapFragment().getMapAsync { mapboxMap -> + mapboxMap.uiSettings.apply { + // Place copyright above the user list bottom sheet + setLogoMargins( + dimensionConverter.dpToPx(COPYRIGHT_MARGIN_DP), + 0, + 0, + bottomOffset + dimensionConverter.dpToPx(COPYRIGHT_MARGIN_DP) + ) + setAttributionMargins( + dimensionConverter.dpToPx(COPYRIGHT_ATTRIBUTION_MARGIN_DP), + 0, + 0, + bottomOffset + dimensionConverter.dpToPx(COPYRIGHT_MARGIN_DP) + ) + } + } + } + private fun updateMap(userLiveLocations: List) { symbolManager?.let { sManager -> val latLngBoundsBuilder = LatLngBounds.Builder() @@ -278,5 +310,7 @@ class LocationLiveMapViewFragment @Inject constructor() : VectorBaseFragment + android:layout_gravity="center" /> + + diff --git a/vector/src/main/res/layout/item_timeline_event_live_location_inactive_stub.xml b/vector/src/main/res/layout/item_timeline_event_live_location_inactive_stub.xml index ba0ff33230..53b740bb4e 100644 --- a/vector/src/main/res/layout/item_timeline_event_live_location_inactive_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_live_location_inactive_stub.xml @@ -15,16 +15,15 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> - + app:locLiveEndedBkgWithAlpha="true" + app:locLiveEndedIconMarginStart="8dp" /> - - - - - + + + + + + + + diff --git a/vector/src/main/res/layout/view_location_live_message_banner.xml b/vector/src/main/res/layout/view_location_live_running_banner.xml similarity index 71% rename from vector/src/main/res/layout/view_location_live_message_banner.xml rename to vector/src/main/res/layout/view_location_live_running_banner.xml index f13696a5c7..5bf8c8258d 100644 --- a/vector/src/main/res/layout/view_location_live_message_banner.xml +++ b/vector/src/main/res/layout/view_location_live_running_banner.xml @@ -7,7 +7,7 @@ tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">