Merge pull request #512 from vector-im/feature/fga/improve_timeline_file_rendering
Timeline file item iteration
This commit is contained in:
@@ -18,12 +18,12 @@ package io.element.android.features.messages.impl.timeline.components.event
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Attachment
|
||||
import androidx.compose.material.icons.outlined.Attachment
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -35,6 +35,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContentProvider
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
@@ -49,7 +50,6 @@ fun TimelineItemFileView(
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -64,12 +64,18 @@ fun TimelineItemFileView(
|
||||
modifier = Modifier.size(16.dp).rotate(-45f),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = content.body,
|
||||
modifier = Modifier.padding(horizontal = 8.dp),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Column(modifier = Modifier.padding(horizontal = 8.dp),) {
|
||||
Text(
|
||||
text = content.body,
|
||||
maxLines = 2,
|
||||
fontSize = 16.sp,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = content.fileExtensionAndSize,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
|
||||
import io.element.android.features.messages.impl.timeline.util.FileSizeFormatter
|
||||
import io.element.android.features.messages.impl.timeline.util.toHtmlDocument
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
|
||||
@@ -34,7 +35,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||
import javax.inject.Inject
|
||||
|
||||
class TimelineItemContentMessageFactory @Inject constructor() {
|
||||
class TimelineItemContentMessageFactory @Inject constructor(
|
||||
private val fileSizeFormatter: FileSizeFormatter
|
||||
) {
|
||||
|
||||
fun create(content: MessageContent): TimelineItemEventContent {
|
||||
return when (val messageType = content.type) {
|
||||
@@ -74,7 +77,9 @@ class TimelineItemContentMessageFactory @Inject constructor() {
|
||||
thumbnailSource = messageType.info?.thumbnailSource,
|
||||
fileSource = messageType.source,
|
||||
mimeType = messageType.info?.mimetype,
|
||||
size = messageType.info?.size,
|
||||
formattedFileSize = messageType.info?.size?.let {
|
||||
fileSizeFormatter.format(it)
|
||||
},
|
||||
)
|
||||
is NoticeMessageType -> TimelineItemNoticeContent(
|
||||
body = messageType.body,
|
||||
|
||||
@@ -22,8 +22,17 @@ data class TimelineItemFileContent(
|
||||
val body: String,
|
||||
val fileSource: MediaSource,
|
||||
val thumbnailSource: MediaSource?,
|
||||
val size: Long?,
|
||||
val formattedFileSize: String?,
|
||||
val mimeType: String?,
|
||||
) : TimelineItemEventContent {
|
||||
override val type: String = "TimelineItemFileContent"
|
||||
|
||||
private val fileExtension = body.substringAfterLast('.', "").uppercase()
|
||||
val fileExtensionAndSize = buildString {
|
||||
append(fileExtension)
|
||||
if (formattedFileSize != null) {
|
||||
append(' ')
|
||||
append("($formattedFileSize)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ open class TimelineItemFileContentProvider : PreviewParameterProvider<TimelineIt
|
||||
get() = sequenceOf(
|
||||
aTimelineItemFileContent("A file.pdf"),
|
||||
aTimelineItemFileContent("A bigger name file.pdf"),
|
||||
aTimelineItemFileContent("An even bigger file name which doesn't fit.pdf"),
|
||||
aTimelineItemFileContent("An even bigger bigger bigger bigger bigger bigger bigger file name which doesn't fit .pdf"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,5 +34,5 @@ fun aTimelineItemFileContent(fileName: String) = TimelineItemFileContent(
|
||||
thumbnailSource = MediaSource(url = ""),
|
||||
fileSource = MediaSource(url = ""),
|
||||
mimeType = MimeTypes.OctetStream,
|
||||
size = 100
|
||||
formattedFileSize = "100kB"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.features.messages.impl.timeline.util
|
||||
|
||||
import android.content.Context
|
||||
import android.text.format.Formatter
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
|
||||
interface FileSizeFormatter {
|
||||
/**
|
||||
* Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.
|
||||
*/
|
||||
fun format(fileSize: Long): String
|
||||
}
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class AndroidFileSizeFormatter @Inject constructor(@ApplicationContext private val context: Context) : FileSizeFormatter {
|
||||
override fun format(fileSize: Long): String {
|
||||
return Formatter.formatShortFileSize(context, fileSize)
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import io.element.android.features.messages.impl.timeline.factories.event.Timeli
|
||||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemDaySeparatorFactory
|
||||
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
|
||||
import io.element.android.features.messages.impl.timeline.groups.TimelineItemGrouper
|
||||
import io.element.android.features.messages.timeline.FakeFileSizeFormatter
|
||||
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
||||
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||
@@ -42,7 +43,7 @@ internal fun aTimelineItemsFactory(): TimelineItemsFactory {
|
||||
dispatchers = testCoroutineDispatchers(),
|
||||
eventItemFactory = TimelineItemEventFactory(
|
||||
TimelineItemContentFactory(
|
||||
messageFactory = TimelineItemContentMessageFactory(),
|
||||
messageFactory = TimelineItemContentMessageFactory(FakeFileSizeFormatter()),
|
||||
redactedMessageFactory = TimelineItemContentRedactedFactory(),
|
||||
stickerFactory = TimelineItemContentStickerFactory(),
|
||||
utdFactory = TimelineItemContentUTDFactory(),
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.features.messages.timeline
|
||||
|
||||
import io.element.android.features.messages.impl.timeline.util.FileSizeFormatter
|
||||
|
||||
class FakeFileSizeFormatter : FileSizeFormatter {
|
||||
override fun format(fileSize: Long): String {
|
||||
return "$fileSize Bytes"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user