mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Show inactive message item when a live is inactive
This commit is contained in:
parent
a37edb591b
commit
c10b2a405c
8 changed files with 203 additions and 61 deletions
|
@ -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 ->
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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<MessageLiveLocationInactiveItem.Holder>(),
|
||||
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<ImageView>(R.id.locationLiveInactiveBanner)
|
||||
val noLocationMapImageView by bind<ImageView>(R.id.locationLiveInactiveMap)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STUB_ID = R.id.messageContentLiveLocationInactiveStub
|
||||
}
|
||||
}
|
|
@ -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<MessageLiveLocationStartItem.Holder>() {
|
||||
abstract class MessageLiveLocationStartItem :
|
||||
AbsMessageItem<MessageLiveLocationStartItem.Holder>(),
|
||||
LiveLocationShareStatusItem by DefaultLiveLocationShareStatusItem() {
|
||||
|
||||
@EpoxyAttribute
|
||||
var mapWidth: Int = 0
|
||||
|
@ -42,44 +35,8 @@ abstract class MessageLiveLocationStartItem : AbsMessageItem<MessageLiveLocation
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
renderSendState(holder.view, null)
|
||||
bindMap(holder)
|
||||
bindBottomBanner(holder)
|
||||
}
|
||||
|
||||
private fun bindMap(holder: Holder) {
|
||||
val messageLayout = attributes.informationData.messageLayout
|
||||
val mapCornerTransformation = if (messageLayout is TimelineMessageLayout.Bubble) {
|
||||
messageLayout.cornersRadius.granularRoundedCorners()
|
||||
} else {
|
||||
RoundedCorners(getDefaultLayoutCornerRadiusInDp(holder))
|
||||
}
|
||||
holder.noLocationMapImageView.updateLayoutParams {
|
||||
width = mapWidth
|
||||
height = mapHeight
|
||||
}
|
||||
GlideApp.with(holder.noLocationMapImageView)
|
||||
.load(R.drawable.bg_no_location_map)
|
||||
.transform(mapCornerTransformation)
|
||||
.into(holder.noLocationMapImageView)
|
||||
}
|
||||
|
||||
private fun bindBottomBanner(holder: Holder) {
|
||||
val messageLayout = attributes.informationData.messageLayout
|
||||
val imageCornerTransformation = if (messageLayout is TimelineMessageLayout.Bubble) {
|
||||
GranularRoundedCorners(0f, 0f, messageLayout.cornersRadius.bottomEndRadius, messageLayout.cornersRadius.bottomStartRadius)
|
||||
} else {
|
||||
val bottomCornerRadius = getDefaultLayoutCornerRadiusInDp(holder).toFloat()
|
||||
GranularRoundedCorners(0f, 0f, bottomCornerRadius, bottomCornerRadius)
|
||||
}
|
||||
GlideApp.with(holder.bannerImageView)
|
||||
.load(ColorDrawable(ThemeUtils.getColor(holder.bannerImageView.context, R.attr.colorSurface)))
|
||||
.transform(imageCornerTransformation)
|
||||
.into(holder.bannerImageView)
|
||||
}
|
||||
|
||||
private fun getDefaultLayoutCornerRadiusInDp(holder: Holder): Int {
|
||||
val dimensionConverter = DimensionConverter(holder.view.resources)
|
||||
return dimensionConverter.dpToPx(8)
|
||||
bindMap(holder.noLocationMapImageView, mapWidth, mapHeight, attributes.informationData.messageLayout)
|
||||
bindBottomBanner(holder.bannerImageView, attributes.informationData.messageLayout)
|
||||
}
|
||||
|
||||
override fun getViewStubId() = STUB_ID
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@color/element_background_light"
|
||||
android:src="?colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="@id/locationLiveInactiveMap"
|
||||
app:layout_constraintEnd_toEndOf="@id/locationLiveInactiveMap"
|
||||
app:layout_constraintStart_toStartOf="@id/locationLiveInactiveMap"
|
||||
|
@ -30,7 +30,6 @@
|
|||
android:id="@+id/locationLiveInactiveIcon"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="65dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@drawable/ic_attachment_location_white"
|
||||
app:layout_constraintBottom_toTopOf="@id/locationLiveInactiveVerticalCenter"
|
||||
app:layout_constraintEnd_toEndOf="@id/locationLiveInactiveMap"
|
||||
|
@ -40,9 +39,10 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/locationLiveInactiveBannerIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/circle"
|
||||
android:backgroundTint="?vctr_content_quaternary"
|
||||
android:padding="3dp"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@color/element_background_light"
|
||||
android:src="?colorSurface"
|
||||
app:layout_constraintBottom_toBottomOf="@id/locationLiveStartMap"
|
||||
app:layout_constraintEnd_toEndOf="@id/locationLiveStartMap"
|
||||
app:layout_constraintStart_toStartOf="@id/locationLiveStartMap"
|
||||
|
@ -28,9 +28,10 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/locationLiveStartIcon"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:background="@drawable/circle"
|
||||
android:backgroundTint="?vctr_content_quaternary"
|
||||
android:padding="3dp"
|
||||
|
|
|
@ -65,6 +65,12 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout="@layout/item_timeline_event_live_location_start_stub" />
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/messageContentLiveLocationInactiveStub"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout="@layout/item_timeline_event_live_location_inactive_stub" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue