Timeline: add avatar and displayname (not dynamic...)
This commit is contained in:
parent
560d2a3291
commit
c8b8c08c99
14 changed files with 206 additions and 93 deletions
|
|
@ -12,7 +12,6 @@ import androidx.compose.ui.geometry.Offset
|
|||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil.compose.AsyncImage
|
||||
import io.element.android.x.designsystem.AvatarGradientEnd
|
||||
|
|
@ -27,7 +26,7 @@ fun Avatar(avatarData: AvatarData, modifier: Modifier = Modifier) {
|
|||
if (avatarData.model == null) {
|
||||
InitialsAvatar(
|
||||
modifier = commonModifier,
|
||||
initials = avatarData.initials
|
||||
initials = avatarData.name.first().uppercase()
|
||||
)
|
||||
} else {
|
||||
ImageAvatar(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import androidx.compose.runtime.Stable
|
|||
|
||||
@Stable
|
||||
data class AvatarData(
|
||||
val initials: String = "",
|
||||
val name: String = "",
|
||||
val model: ByteArray? = null,
|
||||
val size: AvatarSize = AvatarSize.MEDIUM
|
||||
) {
|
||||
|
|
@ -14,7 +14,7 @@ data class AvatarData(
|
|||
|
||||
other as AvatarData
|
||||
|
||||
if (initials != other.initials) return false
|
||||
if (name != other.name) return false
|
||||
if (model != null) {
|
||||
if (other.model == null) return false
|
||||
if (!model.contentEquals(other.model)) return false
|
||||
|
|
@ -25,7 +25,7 @@ data class AvatarData(
|
|||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = initials.hashCode()
|
||||
var result = name.hashCode()
|
||||
result = 31 * result + (model?.contentHashCode() ?: 0)
|
||||
result = 31 * result + size.value
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package io.element.android.x.matrix
|
|||
|
||||
import io.element.android.x.core.data.CoroutineDispatchers
|
||||
import io.element.android.x.matrix.core.UserId
|
||||
import io.element.android.x.matrix.media.MediaResolver
|
||||
import io.element.android.x.matrix.media.RustMediaResolver
|
||||
import io.element.android.x.matrix.room.MatrixRoom
|
||||
import io.element.android.x.matrix.room.RoomSummaryDataSource
|
||||
import io.element.android.x.matrix.room.RustRoomSummaryDataSource
|
||||
|
|
@ -64,6 +66,8 @@ class MatrixClient internal constructor(
|
|||
)
|
||||
private var slidingSyncObserverToken: StoppableSpawn? = null
|
||||
|
||||
private val mediaResolver = RustMediaResolver(this)
|
||||
|
||||
init {
|
||||
client.setDelegate(clientDelegate)
|
||||
}
|
||||
|
|
@ -93,6 +97,8 @@ class MatrixClient internal constructor(
|
|||
|
||||
fun roomSummaryDataSource(): RoomSummaryDataSource = roomSummaryDataSource
|
||||
|
||||
fun mediaResolver(): MediaResolver = mediaResolver
|
||||
|
||||
override fun close() {
|
||||
stopSync()
|
||||
roomSummaryDataSource.close()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
package io.element.android.x.matrix.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
@JvmInline
|
||||
value class EventId(val value: String)
|
||||
value class EventId(val value: String) : Serializable
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
package io.element.android.x.matrix.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
@JvmInline
|
||||
value class RoomId(val value: String)
|
||||
value class RoomId(val value: String): Serializable
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
package io.element.android.x.matrix.core
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
@JvmInline
|
||||
value class UserId(val value: String)
|
||||
value class UserId(val value: String): Serializable
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package io.element.android.x.matrix.media
|
||||
|
||||
import io.element.android.x.matrix.MatrixClient
|
||||
import org.matrix.rustcomponents.sdk.mediaSourceFromUrl
|
||||
|
||||
interface MediaResolver {
|
||||
|
||||
sealed interface Kind {
|
||||
data class Thumbnail(val width: Int, val height: Int) : Kind {
|
||||
constructor(size: Int) : this(size, size)
|
||||
}
|
||||
|
||||
object Content : Kind
|
||||
}
|
||||
|
||||
suspend fun resolve(url: String?, kind: Kind): ByteArray?
|
||||
}
|
||||
|
||||
|
||||
internal class RustMediaResolver(private val client: MatrixClient) : MediaResolver {
|
||||
|
||||
override suspend fun resolve(url: String?, kind: MediaResolver.Kind): ByteArray? {
|
||||
if (url.isNullOrEmpty()) return null
|
||||
val mediaSource = mediaSourceFromUrl(url)
|
||||
return when (kind) {
|
||||
is MediaResolver.Kind.Content -> client.loadMediaContentForSource(mediaSource)
|
||||
is MediaResolver.Kind.Thumbnail -> client.loadMediaThumbnailForSource(
|
||||
mediaSource,
|
||||
kind.width.toLong(),
|
||||
kind.height.toLong()
|
||||
)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -2,11 +2,13 @@ package io.element.android.x.matrix.room
|
|||
|
||||
import io.element.android.x.core.data.CoroutineDispatchers
|
||||
import io.element.android.x.matrix.core.RoomId
|
||||
import io.element.android.x.matrix.core.UserId
|
||||
import io.element.android.x.matrix.timeline.MatrixTimeline
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
import org.matrix.rustcomponents.sdk.SlidingSyncRoom
|
||||
import org.matrix.rustcomponents.sdk.UpdateSummary
|
||||
|
|
@ -53,5 +55,18 @@ class MatrixRoom(
|
|||
return room.avatarUrl()
|
||||
}
|
||||
|
||||
suspend fun userDisplayName(userId: String): Result<String?> =
|
||||
withContext(coroutineDispatchers.io) {
|
||||
runCatching {
|
||||
room.memberDisplayName(userId)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun userAvatarUrl(userId: String): Result<String?> =
|
||||
withContext(coroutineDispatchers.io) {
|
||||
runCatching {
|
||||
room.memberAvatarUrl(userId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue