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 753e5116f0..f993676958 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 @@ -25,6 +25,8 @@ import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvid import im.vector.app.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem import im.vector.app.features.home.room.detail.timeline.item.LiveLocationShareSummaryData +import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationInactiveItem +import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationInactiveItem_ import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationItem import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationItem_ import im.vector.app.features.home.room.detail.timeline.item.MessageLiveLocationStartItem @@ -54,8 +56,8 @@ class LiveLocationShareMessageItemFactory @Inject constructor( attributes: AbsMessageItem.Attributes, ): VectorEpoxyModel<*>? { val item = when (val currentState = getViewState(liveLocationShareSummaryData)) { + LiveLocationShareViewState.Inactive -> buildInactiveItem(highlight, attributes) LiveLocationShareViewState.Loading -> buildLoadingItem(highlight, attributes) - LiveLocationShareViewState.Inactive -> buildInactiveItem() is LiveLocationShareViewState.Running -> buildRunningItem(highlight, attributes, currentState) LiveLocationShareViewState.Unkwown -> null } @@ -64,6 +66,21 @@ class LiveLocationShareMessageItemFactory @Inject constructor( return item } + private fun buildInactiveItem( + highlight: Boolean, + attributes: AbsMessageItem.Attributes, + ): MessageLiveLocationInactiveItem { + val width = timelineMediaSizeProvider.getMaxSize().first + val height = dimensionConverter.dpToPx(MessageItemFactory.MESSAGE_LOCATION_ITEM_HEIGHT_IN_DP) + + return MessageLiveLocationInactiveItem_() + .attributes(attributes) + .mapWidth(width) + .mapHeight(height) + .highlighted(highlight) + .leftGuideline(avatarSizeProvider.leftGuideline) + } + private fun buildLoadingItem( highlight: Boolean, attributes: AbsMessageItem.Attributes, @@ -106,11 +123,9 @@ class LiveLocationShareMessageItemFactory @Inject constructor( .vectorDateFormatter(vectorDateFormatter) } - private fun buildInactiveItem() = null - private fun getViewState(liveLocationShareSummaryData: LiveLocationShareSummaryData?): LiveLocationShareViewState { return when { - liveLocationShareSummaryData?.isActive == null -> LiveLocationShareViewState.Unkwown + liveLocationShareSummaryData?.isActive == null -> LiveLocationShareViewState.Unkwown liveLocationShareSummaryData.isActive.not() || isLiveTimedOut(liveLocationShareSummaryData) -> LiveLocationShareViewState.Inactive liveLocationShareSummaryData.isActive && liveLocationShareSummaryData.lastGeoUri.isNullOrEmpty() -> LiveLocationShareViewState.Loading else -> diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/DefaultLiveLocationShareStatusItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/DefaultLiveLocationShareStatusItem.kt new file mode 100644 index 0000000000..e453b01692 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/DefaultLiveLocationShareStatusItem.kt @@ -0,0 +1,80 @@ +/* + * 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.home.room.detail.timeline.item + +import android.content.res.Resources +import android.graphics.drawable.ColorDrawable +import android.widget.ImageView +import androidx.core.view.updateLayoutParams +import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners +import com.bumptech.glide.load.resource.bitmap.RoundedCorners +import im.vector.app.R +import im.vector.app.core.glide.GlideApp +import im.vector.app.core.utils.DimensionConverter +import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout +import im.vector.app.features.home.room.detail.timeline.style.granularRoundedCorners +import im.vector.app.features.themes.ThemeUtils + +/** + * Default implementation of common methods for item representing the status of a live location share. + */ +class DefaultLiveLocationShareStatusItem : LiveLocationShareStatusItem { + + override fun bindMap( + mapImageView: ImageView, + mapWidth: Int, + mapHeight: Int, + messageLayout: TimelineMessageLayout + ) { + val mapCornerTransformation = if (messageLayout is TimelineMessageLayout.Bubble) { + messageLayout.cornersRadius.granularRoundedCorners() + } else { + RoundedCorners(getDefaultLayoutCornerRadiusInDp(mapImageView.resources)) + } + mapImageView.updateLayoutParams { + width = mapWidth + height = mapHeight + } + GlideApp.with(mapImageView) + .load(R.drawable.bg_no_location_map) + .transform(mapCornerTransformation) + .into(mapImageView) + } + + override fun bindBottomBanner(bannerImageView: ImageView, messageLayout: TimelineMessageLayout) { + val imageCornerTransformation = if (messageLayout is TimelineMessageLayout.Bubble) { + GranularRoundedCorners( + 0f, + 0f, + messageLayout.cornersRadius.bottomEndRadius, + messageLayout.cornersRadius.bottomStartRadius + ) + } else { + val bottomCornerRadius = getDefaultLayoutCornerRadiusInDp(bannerImageView.resources).toFloat() + GranularRoundedCorners(0f, 0f, bottomCornerRadius, bottomCornerRadius) + } + GlideApp.with(bannerImageView) + .load(ColorDrawable(ThemeUtils.getColor(bannerImageView.context, R.attr.colorSurface))) + .transform(imageCornerTransformation) + .into(bannerImageView) + } + + private fun getDefaultLayoutCornerRadiusInDp(resources: Resources): Int { + val dimensionConverter = DimensionConverter(resources) + return dimensionConverter.dpToPx(8) + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/LiveLocationShareStatusItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/LiveLocationShareStatusItem.kt new file mode 100644 index 0000000000..2f79f2fc9e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/LiveLocationShareStatusItem.kt @@ -0,0 +1,31 @@ +/* + * 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.home.room.detail.timeline.item + +import android.widget.ImageView +import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout + +interface LiveLocationShareStatusItem { + fun bindMap( + mapImageView: ImageView, + mapWidth: Int, + mapHeight: Int, + messageLayout: TimelineMessageLayout + ) + + fun bindBottomBanner(bannerImageView: ImageView, messageLayout: TimelineMessageLayout) +} 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 new file mode 100644 index 0000000000..bb85316bf1 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationInactiveItem.kt @@ -0,0 +1,52 @@ +/* + * 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.home.room.detail.timeline.item + +import android.widget.ImageView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R + +@EpoxyModelClass(layout = R.layout.item_timeline_event_base) +abstract class MessageLiveLocationInactiveItem : + AbsMessageItem(), + LiveLocationShareStatusItem by DefaultLiveLocationShareStatusItem() { + + @EpoxyAttribute + var mapWidth: Int = 0 + + @EpoxyAttribute + var mapHeight: Int = 0 + + override fun bind(holder: Holder) { + super.bind(holder) + renderSendState(holder.view, null) + bindMap(holder.noLocationMapImageView, mapWidth, mapHeight, attributes.informationData.messageLayout) + bindBottomBanner(holder.bannerImageView, attributes.informationData.messageLayout) + } + + override fun getViewStubId() = STUB_ID + + class Holder : AbsMessageItem.Holder(STUB_ID) { + val bannerImageView by bind(R.id.locationLiveInactiveBanner) + val noLocationMapImageView by bind(R.id.locationLiveInactiveMap) + } + + companion object { + private const val STUB_ID = R.id.messageContentLiveLocationInactiveStub + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationStartItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationStartItem.kt index 390db0ef50..001774b579 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationStartItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageLiveLocationStartItem.kt @@ -16,22 +16,15 @@ package im.vector.app.features.home.room.detail.timeline.item -import android.graphics.drawable.ColorDrawable import android.widget.ImageView -import androidx.core.view.updateLayoutParams import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass -import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners -import com.bumptech.glide.load.resource.bitmap.RoundedCorners import im.vector.app.R -import im.vector.app.core.glide.GlideApp -import im.vector.app.core.utils.DimensionConverter -import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLayout -import im.vector.app.features.home.room.detail.timeline.style.granularRoundedCorners -import im.vector.app.features.themes.ThemeUtils @EpoxyModelClass(layout = R.layout.item_timeline_event_base) -abstract class MessageLiveLocationStartItem : AbsMessageItem() { +abstract class MessageLiveLocationStartItem : + AbsMessageItem(), + LiveLocationShareStatusItem by DefaultLiveLocationShareStatusItem() { @EpoxyAttribute var mapWidth: Int = 0 @@ -42,44 +35,8 @@ abstract class MessageLiveLocationStartItem : AbsMessageItem + +