mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Add details about events with attachment in the bottomsheet
This commit is contained in:
parent
c502e971a1
commit
edbfc2e2e9
6 changed files with 134 additions and 13 deletions
|
@ -46,6 +46,9 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
|
|||
@EpoxyAttribute
|
||||
lateinit var body: CharSequence
|
||||
|
||||
@EpoxyAttribute
|
||||
var bodyDetails: CharSequence? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var imageContentRenderer: ImageContentRenderer? = null
|
||||
|
||||
|
@ -73,6 +76,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
|
|||
holder.imagePreview.isVisible = data != null
|
||||
holder.body.movementMethod = movementMethod
|
||||
holder.body.text = body
|
||||
holder.bodyDetails.setTextOrHide(bodyDetails)
|
||||
body.findPillsAndProcess(coroutineScope) { it.bind(holder.body) }
|
||||
holder.timestamp.setTextOrHide(time)
|
||||
}
|
||||
|
@ -86,6 +90,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
|
|||
val avatar by bind<ImageView>(R.id.bottom_sheet_message_preview_avatar)
|
||||
val sender by bind<TextView>(R.id.bottom_sheet_message_preview_sender)
|
||||
val body by bind<TextView>(R.id.bottom_sheet_message_preview_body)
|
||||
val bodyDetails by bind<TextView>(R.id.bottom_sheet_message_preview_body_details)
|
||||
val timestamp by bind<TextView>(R.id.bottom_sheet_message_preview_timestamp)
|
||||
val imagePreview by bind<ImageView>(R.id.bottom_sheet_message_preview_image)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.app.core.utils
|
|||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.text.format.Formatter
|
||||
import org.threeten.bp.Duration
|
||||
import java.util.TreeMap
|
||||
|
||||
object TextUtils {
|
||||
|
@ -68,4 +69,15 @@ object TextUtils {
|
|||
Formatter.formatFileSize(context, normalizedSize)
|
||||
}
|
||||
}
|
||||
|
||||
fun formatDuration(duration: Duration): String {
|
||||
val hours = duration.seconds / 3600
|
||||
val minutes = (duration.seconds % 3600) / 60
|
||||
val seconds = duration.seconds % 60
|
||||
return if (hours > 0) {
|
||||
String.format("%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
String.format("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import android.hardware.camera2.CameraManager
|
|||
import androidx.core.content.getSystemService
|
||||
import im.vector.app.core.services.CallService
|
||||
import im.vector.app.core.utils.CountUpTimer
|
||||
import im.vector.app.core.utils.TextUtils.formatDuration
|
||||
import im.vector.app.features.call.CameraEventsHandlerAdapter
|
||||
import im.vector.app.features.call.CameraProxy
|
||||
import im.vector.app.features.call.CameraType
|
||||
|
@ -829,17 +830,6 @@ class WebRtcCall(val mxCall: MxCall,
|
|||
}
|
||||
}
|
||||
|
||||
private fun formatDuration(duration: Duration): String {
|
||||
val hours = duration.seconds / 3600
|
||||
val minutes = (duration.seconds % 3600) / 60
|
||||
val seconds = duration.seconds % 60
|
||||
return if (hours > 0) {
|
||||
String.format("%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
String.format("%02d:%02d", minutes, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
// MxCall.StateListener
|
||||
|
||||
override fun onStateUpdate(call: MxCall) {
|
||||
|
|
|
@ -33,6 +33,7 @@ import im.vector.app.core.resources.StringProvider
|
|||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.app.features.home.room.detail.timeline.format.EventDetailsFormatter
|
||||
import im.vector.app.features.home.room.detail.timeline.image.buildImageContentRendererData
|
||||
import im.vector.app.features.home.room.detail.timeline.item.E2EDecoration
|
||||
import im.vector.app.features.home.room.detail.timeline.tools.createLinkMovementMethod
|
||||
|
@ -53,6 +54,7 @@ class MessageActionsEpoxyController @Inject constructor(
|
|||
private val imageContentRenderer: ImageContentRenderer,
|
||||
private val dimensionConverter: DimensionConverter,
|
||||
private val errorFormatter: ErrorFormatter,
|
||||
private val eventDetailsFormatter: EventDetailsFormatter,
|
||||
private val dateFormatter: VectorDateFormatter
|
||||
) : TypedEpoxyController<MessageActionState>() {
|
||||
|
||||
|
@ -71,6 +73,7 @@ class MessageActionsEpoxyController @Inject constructor(
|
|||
data(state.timelineEvent()?.buildImageContentRendererData(dimensionConverter.dpToPx(66)))
|
||||
userClicked { listener?.didSelectMenuAction(EventSharedAction.OpenUserProfile(state.informationData.senderId)) }
|
||||
body(state.messageBody.linkify(listener))
|
||||
bodyDetails(eventDetailsFormatter.format(state.timelineEvent()?.root))
|
||||
time(formattedDate)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2021 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.format
|
||||
|
||||
import android.content.Context
|
||||
import im.vector.app.core.utils.TextUtils
|
||||
import org.matrix.android.sdk.api.session.events.model.Event
|
||||
import org.matrix.android.sdk.api.session.events.model.isAudioMessage
|
||||
import org.matrix.android.sdk.api.session.events.model.isFileMessage
|
||||
import org.matrix.android.sdk.api.session.events.model.isImageMessage
|
||||
import org.matrix.android.sdk.api.session.events.model.isVideoMessage
|
||||
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent
|
||||
import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent
|
||||
import org.threeten.bp.Duration
|
||||
import javax.inject.Inject
|
||||
|
||||
class EventDetailsFormatter @Inject constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
|
||||
fun format(event: Event?): CharSequence? {
|
||||
event ?: return null
|
||||
|
||||
if (event.isRedacted()) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (event.isEncrypted() && event.mxDecryptionResult == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return when {
|
||||
event.isImageMessage() -> formatForImageMessage(event)
|
||||
event.isVideoMessage() -> formatForVideoMessage(event)
|
||||
event.isAudioMessage() -> formatForAudioMessage(event)
|
||||
event.isFileMessage() -> formatForFileMessage(event)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: "1024 x 720 - 670 kB"
|
||||
*/
|
||||
private fun formatForImageMessage(event: Event): CharSequence? {
|
||||
return event.getClearContent().toModel<MessageImageContent>()?.info
|
||||
?.let { "${it.width} x ${it.height} - ${it.size.asFileSize()}" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: "02:45 - 1024 x 720 - 670 kB"
|
||||
*/
|
||||
private fun formatForVideoMessage(event: Event): CharSequence? {
|
||||
return event.getClearContent().toModel<MessageVideoContent>()?.videoInfo
|
||||
?.let { "${it.duration.asDuration()} - ${it.width} x ${it.height} - ${it.size.asFileSize()}" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: "02:45 - 670 kB"
|
||||
*/
|
||||
private fun formatForAudioMessage(event: Event): CharSequence? {
|
||||
return event.getClearContent().toModel<MessageAudioContent>()?.audioInfo
|
||||
?.let { "${it.duration.asDuration()} - ${it.size.asFileSize()}" }
|
||||
}
|
||||
|
||||
/**
|
||||
* Example: "670 kB - application/pdf"
|
||||
*/
|
||||
private fun formatForFileMessage(event: Event): CharSequence? {
|
||||
return event.getClearContent().toModel<MessageFileContent>()?.info
|
||||
?.let { "${it.size.asFileSize()} - ${it.mimeType}" }
|
||||
}
|
||||
|
||||
private fun Long.asFileSize() = TextUtils.formatFileSize(context, this)
|
||||
private fun Int.asDuration() = TextUtils.formatDuration(Duration.ofMillis(toLong()))
|
||||
}
|
|
@ -76,10 +76,29 @@
|
|||
android:textColor="?riotx_text_secondary"
|
||||
android:textIsSelectable="false"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottom_sheet_message_preview_body_details"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/bottom_sheet_message_preview_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/bottom_sheet_message_preview_image"
|
||||
tools:text="Quis harum id autem cumque consequatur laboriosam aliquam sed. Sint accusamus dignissimos nobis ullam earum debitis aspernatur. Sint accusamus dignissimos nobis ullam earum debitis aspernatur. " />
|
||||
app:layout_goneMarginBottom="4dp"
|
||||
tools:text="Quis harum id autem cumque consequatur laboriosam aliquam sed. Sint accusamus dignissimos nobis ullam earum debitis aspernatur. Sint accusamus dignissimos nobis ullam earum debitis aspernatur." />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bottom_sheet_message_preview_body_details"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_tertiary"
|
||||
android:textIsSelectable="false"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/bottom_sheet_message_preview_body"
|
||||
app:layout_constraintStart_toStartOf="@id/bottom_sheet_message_preview_body"
|
||||
app:layout_constraintTop_toBottomOf="@id/bottom_sheet_message_preview_body"
|
||||
tools:text="1080 x 1024 - 43s - 12kB"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
Loading…
Reference in a new issue