forked from GitHub-Mirror/riotX-android
Start introducing theme on app + branch toolbar to drawer, still requires refinements
This commit is contained in:
@ -1,15 +1,18 @@
|
||||
package im.vector.matrix.android.api.session.room
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface Room: TimelineHolder {
|
||||
interface Room : TimelineHolder {
|
||||
|
||||
val roomId: String
|
||||
|
||||
val myMembership: MyMembership
|
||||
|
||||
fun getNumberOfJoinedMembers(): Int
|
||||
val roomSummary: LiveData<RoomSummary>
|
||||
|
||||
fun loadRoomMembersIfNeeded(): Cancelable
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomAvatarContent(
|
||||
@Json(name = "url") val avatarUrl: String? = null
|
||||
)
|
@ -2,6 +2,7 @@ package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
data class RoomSummary(
|
||||
val roomId: String,
|
||||
var displayName: String = "",
|
||||
var topic: String = ""
|
||||
val displayName: String = "",
|
||||
val topic: String = "",
|
||||
val avatarUrl: String = ""
|
||||
)
|
@ -10,7 +10,8 @@ object RoomSummaryMapper {
|
||||
return RoomSummary(
|
||||
roomSummaryEntity.roomId,
|
||||
roomSummaryEntity.displayName ?: "",
|
||||
roomSummaryEntity.topic ?: ""
|
||||
roomSummaryEntity.topic ?: "",
|
||||
roomSummaryEntity.avatarUrl ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
@ -18,7 +19,8 @@ object RoomSummaryMapper {
|
||||
return RoomSummaryEntity(
|
||||
roomSummary.roomId,
|
||||
roomSummary.displayName,
|
||||
roomSummary.topic
|
||||
roomSummary.topic,
|
||||
roomSummary.avatarUrl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import io.realm.annotations.PrimaryKey
|
||||
// TODO to be completed
|
||||
open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var displayName: String? = "",
|
||||
var avatarUrl: String? = "",
|
||||
var topic: String? = "",
|
||||
var lastMessage: EventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
|
@ -1,8 +1,5 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
@ -45,13 +42,3 @@ fun RealmQuery<EventEntity>.last(from: Long? = null): EventEntity? {
|
||||
fun RealmList<EventEntity>.fastContains(eventEntity: EventEntity): Boolean {
|
||||
return this.where().equalTo(EventEntityFields.EVENT_ID, eventEntity.eventId).findFirst() != null
|
||||
}
|
||||
|
||||
fun EventEntity.Companion.findAllRoomMembers(realm: Realm, roomId: String): Map<String, RoomMember> {
|
||||
return EventEntity
|
||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||
.sort(EventEntityFields.ORIGIN_SERVER_TS)
|
||||
.findAll()
|
||||
.map { it.asDomain() }
|
||||
.associateBy { it.stateKey!! }
|
||||
.mapValues { it.value.content<RoomMember>()!! }
|
||||
}
|
@ -4,9 +4,10 @@ import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.session.room.DefaultRoomService
|
||||
import im.vector.matrix.android.internal.session.room.RoomAvatarResolver
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomMemberDisplayNameResolver
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import io.realm.RealmConfiguration
|
||||
import org.koin.dsl.context.ModuleDefinition
|
||||
import org.koin.dsl.module.Module
|
||||
@ -37,11 +38,15 @@ class SessionModule(private val sessionParams: SessionParams) : Module {
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomDisplayNameResolver(get(), get(), sessionParams)
|
||||
RoomDisplayNameResolver(get(), get(), sessionParams.credentials)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSummaryUpdater(get(), get(), get())
|
||||
RoomAvatarResolver(get(), sessionParams.credentials)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSummaryUpdater(get(), get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.lifecycle.Transformations
|
||||
import android.arch.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
@ -9,7 +10,9 @@ import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
@ -24,18 +27,25 @@ data class DefaultRoom(
|
||||
override val myMembership: MyMembership
|
||||
) : Room, KoinComponent {
|
||||
|
||||
|
||||
private val loadRoomMembersRequest by inject<LoadRoomMembersRequest>()
|
||||
private val syncTokenStore by inject<SyncTokenStore>()
|
||||
private val monarchy by inject<Monarchy>()
|
||||
private val timelineHolder by inject<TimelineHolder>(parameters = { parametersOf(roomId) })
|
||||
|
||||
override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
|
||||
return timelineHolder.liveTimeline()
|
||||
override val roomSummary: LiveData<RoomSummary> by lazy {
|
||||
val liveData = monarchy
|
||||
.findAllMappedWithChanges(
|
||||
{ realm -> RoomSummaryEntity.where(realm, roomId) },
|
||||
{ from -> from.asDomain() })
|
||||
|
||||
Transformations.map(liveData) {
|
||||
it.first()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNumberOfJoinedMembers(): Int {
|
||||
val roomSummary = monarchy.fetchAllCopiedSync { realm -> RoomSummaryEntity.where(realm, roomId) }.firstOrNull()
|
||||
return roomSummary?.joinedMembersCount ?: 0
|
||||
override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
|
||||
return timelineHolder.liveTimeline()
|
||||
}
|
||||
|
||||
override fun loadRoomMembersIfNeeded(): Cancelable {
|
||||
@ -47,7 +57,6 @@ data class DefaultRoom(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun areAllMembersLoaded(): Boolean {
|
||||
return monarchy
|
||||
.fetchAllCopiedSync { RoomEntity.where(it, roomId) }
|
||||
|
@ -0,0 +1,53 @@
|
||||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomAvatarContent
|
||||
import im.vector.matrix.android.internal.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomMembers
|
||||
|
||||
internal class RoomAvatarResolver(private val monarchy: Monarchy,
|
||||
private val credentials: Credentials) {
|
||||
|
||||
/**
|
||||
* Compute the room avatar url
|
||||
*
|
||||
* @return the room avatar url, can be a fallback to a room member avatar or null
|
||||
*/
|
||||
fun resolve(room: Room): String? {
|
||||
var res: String? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomName = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_AVATAR).last()?.asDomain()
|
||||
res = roomName?.content<RoomAvatarContent>()?.avatarUrl
|
||||
if (!res.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val roomMembers = RoomMembers(realm, room.roomId)
|
||||
val members = roomMembers.getLoaded()
|
||||
if (room.myMembership == MyMembership.INVITED) {
|
||||
if (members.size == 1) {
|
||||
res = members.entries.first().value.avatarUrl
|
||||
} else if (members.size > 1) {
|
||||
val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull()
|
||||
res = firstOtherMember?.avatarUrl
|
||||
}
|
||||
} else {
|
||||
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
|
||||
if (roomMembers.getNumberOfJoinedMembers() == 1 && members.isNotEmpty()) {
|
||||
res = members.entries.first().value.avatarUrl
|
||||
} else if (roomMembers.getNumberOfMembers() == 2 && members.size > 1) {
|
||||
val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull()
|
||||
res = firstOtherMember?.avatarUrl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
internal class RoomSummaryUpdater(private val monarchy: Monarchy,
|
||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||
private val roomAvatarResolver: RoomAvatarResolver,
|
||||
private val context: Context
|
||||
) : Observer<Monarchy.ManagedChangeSet<RoomEntity>> {
|
||||
|
||||
@ -47,23 +48,23 @@ internal class RoomSummaryUpdater(private val monarchy: Monarchy,
|
||||
val rooms = changeSet.realmResults.map { it.asDomain() }
|
||||
val indexesToUpdate = changeSet.orderedCollectionChangeSet.changes + changeSet.orderedCollectionChangeSet.insertions
|
||||
monarchy.writeAsync { realm ->
|
||||
insertRoomList(realm, rooms, indexesToUpdate)
|
||||
updateRoomList(realm, rooms, indexesToUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun insertRoomList(realm: Realm, rooms: List<Room>, indexes: IntArray) {
|
||||
private fun updateRoomList(realm: Realm, rooms: List<Room>, indexes: IntArray) {
|
||||
indexes.forEach {
|
||||
val room = rooms[it]
|
||||
try {
|
||||
insertRoom(realm, room)
|
||||
updateRoom(realm, room)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "An error occured when updating room summaries")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertRoom(realm: Realm, room: Room?) {
|
||||
private fun updateRoom(realm: Realm, room: Room?) {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
@ -74,6 +75,7 @@ internal class RoomSummaryUpdater(private val monarchy: Monarchy,
|
||||
val lastTopicEvent = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_TOPIC).last()?.asDomain()
|
||||
|
||||
roomSummary.displayName = roomDisplayNameResolver.resolve(context, room).toString()
|
||||
roomSummary.avatarUrl = roomAvatarResolver.resolve(room)
|
||||
roomSummary.topic = lastTopicEvent?.content<RoomTopicContent>()?.topic
|
||||
roomSummary.lastMessage = lastMessageEvent
|
||||
}
|
||||
|
@ -8,9 +8,7 @@ import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllRoomMembers
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
@ -63,7 +61,7 @@ internal class LoadRoomMembersRequest(private val roomAPI: RoomAPI,
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||
?: throw IllegalStateException("You shouldn't use this method without a room")
|
||||
|
||||
val roomMembers = EventEntity.findAllRoomMembers(realm, roomId)
|
||||
val roomMembers = RoomMembers(realm, roomId).getLoaded()
|
||||
val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) }
|
||||
|
||||
val chunk = stateEventsChunkHandler.handle(realm, roomId, eventsToInsert)
|
||||
|
@ -25,20 +25,19 @@ import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomAliasesContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomNameContent
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllRoomMembers
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
|
||||
/**
|
||||
* This class computes room display name
|
||||
*/
|
||||
class RoomDisplayNameResolver(private val monarchy: Monarchy,
|
||||
private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver,
|
||||
private val sessionParams: SessionParams
|
||||
internal class RoomDisplayNameResolver(private val monarchy: Monarchy,
|
||||
private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver,
|
||||
private val credentials: Credentials
|
||||
) {
|
||||
|
||||
/**
|
||||
@ -75,9 +74,9 @@ class RoomDisplayNameResolver(private val monarchy: Monarchy,
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val otherRoomMembers = EventEntity
|
||||
.findAllRoomMembers(realm, room.roomId)
|
||||
.filterKeys { it != sessionParams.credentials.userId }
|
||||
val roomMembers = RoomMembers(realm, room.roomId)
|
||||
val otherRoomMembers = roomMembers.getLoaded()
|
||||
.filterKeys { it != credentials.userId }
|
||||
|
||||
if (room.myMembership == MyMembership.INVITED) {
|
||||
//TODO handle invited
|
||||
@ -117,9 +116,9 @@ class RoomDisplayNameResolver(private val monarchy: Monarchy,
|
||||
else -> {
|
||||
val member = memberIds[0]
|
||||
name = context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||
room.getNumberOfJoinedMembers() - 1,
|
||||
roomMembers.getNumberOfJoinedMembers() - 1,
|
||||
roomMemberDisplayNameResolver.resolve(member, otherRoomMembers),
|
||||
room.getNumberOfJoinedMembers() - 1)
|
||||
roomMembers.getNumberOfJoinedMembers() - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
package im.vector.matrix.android.internal.session.room.members
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.Realm
|
||||
|
||||
internal class RoomMembers(private val realm: Realm,
|
||||
private val roomId: String
|
||||
) {
|
||||
|
||||
private val roomSummary: RoomSummaryEntity? by lazy {
|
||||
RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
}
|
||||
|
||||
fun getLoaded(): Map<String, RoomMember> {
|
||||
return EventEntity
|
||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||
.sort(EventEntityFields.ORIGIN_SERVER_TS)
|
||||
.findAll()
|
||||
.map { it.asDomain() }
|
||||
.associateBy { it.stateKey!! }
|
||||
.mapValues { it.value.content<RoomMember>()!! }
|
||||
}
|
||||
|
||||
|
||||
fun getNumberOfJoinedMembers(): Int {
|
||||
return roomSummary?.joinedMembersCount
|
||||
?: getLoaded().filterValues { it.membership == Membership.JOIN }.size
|
||||
}
|
||||
|
||||
fun getNumberOfInvitedMembers(): Int {
|
||||
return roomSummary?.invitedMembersCount
|
||||
?: getLoaded().filterValues { it.membership == Membership.INVITE }.size
|
||||
}
|
||||
|
||||
fun getNumberOfMembers(): Int {
|
||||
return getNumberOfJoinedMembers() + getNumberOfInvitedMembers()
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -63,9 +63,6 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
|
||||
roomEntity.membership = MyMembership.JOINED
|
||||
|
||||
if (roomSync.summary != null) {
|
||||
handleRoomSummary(realm, roomId, roomSync.summary)
|
||||
}
|
||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
||||
val chunkEntity = stateEventsChunkHandler.handle(realm, roomId, roomSync.state.events)
|
||||
if (!roomEntity.chunks.contains(chunkEntity)) {
|
||||
@ -78,6 +75,9 @@ internal class RoomSyncHandler(private val monarchy: Monarchy,
|
||||
roomEntity.chunks.add(chunkEntity)
|
||||
}
|
||||
}
|
||||
if (roomSync.summary != null) {
|
||||
handleRoomSummary(realm, roomId, roomSync.summary)
|
||||
}
|
||||
return roomEntity
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user