mirror of
https://github.com/element-hq/element-android
synced 2024-11-26 03:15:40 +03:00
First attempt to handle room name + make app listen to room summaries instead of rooms
This commit is contained in:
parent
279241974a
commit
f747d268c9
40 changed files with 568 additions and 144 deletions
|
@ -3,6 +3,7 @@ package im.vector.riotredesign
|
|||
import android.app.Application
|
||||
import im.vector.matrix.android.BuildConfig
|
||||
import im.vector.riotredesign.core.di.AppModule
|
||||
import org.koin.log.EmptyLogger
|
||||
import org.koin.standalone.StandAloneContext.startKoin
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -13,7 +14,7 @@ class Riot : Application() {
|
|||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
startKoin(listOf(AppModule(this)))
|
||||
startKoin(listOf(AppModule(this)), logger = EmptyLogger())
|
||||
}
|
||||
|
||||
}
|
|
@ -5,11 +5,11 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
|||
|
||||
class EventDiffUtilCallback : DiffUtil.ItemCallback<EnrichedEvent>() {
|
||||
override fun areItemsTheSame(p0: EnrichedEvent, p1: EnrichedEvent): Boolean {
|
||||
return p0.core.eventId == p1.core.eventId
|
||||
return p0.root.eventId == p1.root.eventId
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(p0: EnrichedEvent, p1: EnrichedEvent): Boolean {
|
||||
return p0.core == p1.core
|
||||
return p0.root == p1.root
|
||||
&& p0.getMetaEvents()
|
||||
.zip(p1.getMetaEvents()) { a, b ->
|
||||
a.eventId == b.eventId
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
|
||||
class RoomController(private val callback: Callback? = null) : TypedEpoxyController<List<Room>>() {
|
||||
|
||||
override fun buildModels(data: List<Room>?) {
|
||||
data?.forEach {
|
||||
RoomItem(it.roomId, listener = { callback?.onRoomSelected(it) })
|
||||
.id(it.roomId)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onRoomSelected(room: Room)
|
||||
}
|
||||
|
||||
}
|
|
@ -55,9 +55,10 @@ class RoomDetailFragment : RiotFragment(), TimelineEventAdapter.Callback {
|
|||
layoutManager.stackFromEnd = true
|
||||
timelineAdapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
if (layoutManager.findFirstVisibleItemPosition() == 0) {
|
||||
/*if (layoutManager.findFirstVisibleItemPosition() == 0) {
|
||||
layoutManager.scrollToPosition(0)
|
||||
}
|
||||
*/
|
||||
}
|
||||
})
|
||||
recyclerView.layoutManager = layoutManager
|
||||
|
|
|
@ -5,7 +5,7 @@ import im.vector.riotredesign.R
|
|||
import im.vector.riotredesign.core.epoxy.KotlinModel
|
||||
|
||||
data class RoomItem(
|
||||
val title: String,
|
||||
val title: CharSequence,
|
||||
val listener: (() -> Unit)? = null
|
||||
) : KotlinModel(R.layout.item_room) {
|
||||
|
||||
|
|
|
@ -2,19 +2,18 @@ package im.vector.riotredesign.features.home
|
|||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.os.Bundle
|
||||
import android.support.v7.widget.LinearLayoutManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class RoomListFragment : RiotFragment(), RoomController.Callback {
|
||||
class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -26,7 +25,7 @@ class RoomListFragment : RiotFragment(), RoomController.Callback {
|
|||
|
||||
private val matrix by inject<Matrix>()
|
||||
private val currentSession = matrix.currentSession!!
|
||||
private val roomController = RoomController(this)
|
||||
private lateinit var roomController: RoomSummaryController
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_room_list, container, false)
|
||||
|
@ -34,15 +33,16 @@ class RoomListFragment : RiotFragment(), RoomController.Callback {
|
|||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
roomController = RoomSummaryController(this)
|
||||
epoxyRecyclerView.setController(roomController)
|
||||
currentSession.liveRooms().observe(this, Observer<List<Room>> { renderRooms(it) })
|
||||
currentSession.liveRoomSummaries().observe(this, Observer<List<RoomSummary>> { renderRooms(it) })
|
||||
}
|
||||
|
||||
private fun renderRooms(rooms: List<Room>?) {
|
||||
private fun renderRooms(rooms: List<RoomSummary>?) {
|
||||
roomController.setData(rooms)
|
||||
}
|
||||
|
||||
override fun onRoomSelected(room: Room) {
|
||||
override fun onRoomSelected(room: RoomSummary) {
|
||||
val detailFragment = RoomDetailFragment.newInstance(room.roomId)
|
||||
addFragmentToBackstack(detailFragment, R.id.homeFragmentContainer)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package im.vector.riotredesign.features.home
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
class RoomSummaryController(private val callback: Callback? = null
|
||||
) : TypedEpoxyController<List<RoomSummary>>() {
|
||||
|
||||
override fun buildModels(data: List<RoomSummary>?) {
|
||||
data?.forEach {
|
||||
RoomItem(it.displayName, listener = { callback?.onRoomSelected(it) })
|
||||
.id(it.roomId)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onRoomSelected(room: RoomSummary)
|
||||
}
|
||||
|
||||
}
|
|
@ -38,10 +38,10 @@ class TimelineEventAdapter(private val callback: Callback? = null)
|
|||
val titleView = view.findViewById<TextView>(R.id.titleView)!!
|
||||
|
||||
fun bind(event: EnrichedEvent?) {
|
||||
if (event == null || event.core.type != EventType.MESSAGE) {
|
||||
if (event == null) {
|
||||
titleView.text = null
|
||||
} else {
|
||||
val messageContent = event.core.content<MessageContent>()
|
||||
} else if (event.root.type == EventType.MESSAGE) {
|
||||
val messageContent = event.root.content<MessageContent>()
|
||||
val roomMember = event.getMetaEvents(EventType.STATE_ROOM_MEMBER).firstOrNull()?.content<RoomMember>()
|
||||
if (messageContent == null || roomMember == null) {
|
||||
titleView.text = null
|
||||
|
@ -49,6 +49,8 @@ class TimelineEventAdapter(private val callback: Callback? = null)
|
|||
val text = "${roomMember.displayName} : ${messageContent.body}"
|
||||
titleView.text = text
|
||||
}
|
||||
} else {
|
||||
titleView.text = event.root.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ package im.vector.matrix.android.api.session
|
|||
|
||||
import android.support.annotation.MainThread
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.internal.database.SessionRealmHolder
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
|
||||
interface Session : RoomService {
|
||||
|
||||
val sessionParams: SessionParams
|
||||
|
||||
@MainThread
|
||||
fun open()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package im.vector.matrix.android.api.session.events.model
|
||||
|
||||
data class EnrichedEvent(val core: Event) {
|
||||
data class EnrichedEvent(val root: Event) {
|
||||
|
||||
private val metaEventsByType = HashMap<String, ArrayList<Event>>()
|
||||
|
||||
|
|
|
@ -3,11 +3,16 @@ package im.vector.matrix.android.api.session.room
|
|||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
|
||||
interface Room {
|
||||
|
||||
val roomId: String
|
||||
|
||||
val myMembership: MyMembership
|
||||
|
||||
fun liveTimeline(): LiveData<PagedList<EnrichedEvent>>
|
||||
|
||||
fun getNumberOfJoinedMembers(): Int
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package im.vector.matrix.android.api.session.room
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
interface RoomService {
|
||||
|
||||
|
@ -10,4 +11,7 @@ interface RoomService {
|
|||
|
||||
fun liveRooms(): LiveData<List<Room>>
|
||||
|
||||
fun liveRoomSummaries(): LiveData<List<RoomSummary>>
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
enum class MyMembership {
|
||||
JOINED,
|
||||
LEFT,
|
||||
INVITED,
|
||||
NONE
|
||||
}
|
|
@ -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 RoomAliasesContent(
|
||||
@Json(name = "aliases") val aliases: List<String> = emptyList()
|
||||
)
|
|
@ -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 RoomCanonicalAliasContent(
|
||||
@Json(name = "alias") val canonicalAlias: String? = null
|
||||
)
|
|
@ -12,4 +12,4 @@ data class RoomMember(
|
|||
@Json(name = "is_direct") val isDirect: Boolean = false,
|
||||
@Json(name = "third_party_invite") val thirdPartyInvite: Invite? = null,
|
||||
@Json(name = "unsigned") val unsignedData: UnsignedData? = null
|
||||
)
|
||||
)
|
|
@ -5,5 +5,5 @@ import com.squareup.moshi.JsonClass
|
|||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomNameContent(
|
||||
@Json(name = "name") val name: String
|
||||
@Json(name = "name") val name: String? = null
|
||||
)
|
|
@ -0,0 +1,7 @@
|
|||
package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
data class RoomSummary(
|
||||
val roomId: String,
|
||||
var displayName: String = "",
|
||||
var topic: String = ""
|
||||
)
|
|
@ -0,0 +1,21 @@
|
|||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.session.room.DefaultRoom
|
||||
|
||||
|
||||
object RoomMapper {
|
||||
|
||||
|
||||
internal fun map(roomEntity: RoomEntity): Room {
|
||||
return DefaultRoom(
|
||||
roomEntity.roomId,
|
||||
roomEntity.membership
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomEntity.asDomain(): Room {
|
||||
return RoomMapper.map(this)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
|
||||
|
||||
object RoomSummaryMapper {
|
||||
|
||||
internal fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||
return RoomSummary(
|
||||
roomSummaryEntity.roomId,
|
||||
roomSummaryEntity.displayName ?: "",
|
||||
roomSummaryEntity.topic ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun RoomSummaryEntity.asDomain(): RoomSummary {
|
||||
return RoomSummaryMapper.map(this)
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Ignore
|
||||
|
@ -10,19 +11,12 @@ open class RoomEntity(@PrimaryKey var roomId: String = "",
|
|||
var chunks: RealmList<ChunkEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
private var membershipStr: String = MyMembership.NONE.name
|
||||
|
||||
@delegate:Ignore var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue ->
|
||||
@delegate:Ignore var membership: MyMembership by Delegates.observable(MyMembership.valueOf(membershipStr)) { _, _, newValue ->
|
||||
membershipStr = newValue.name
|
||||
}
|
||||
|
||||
companion object;
|
||||
|
||||
enum class Membership {
|
||||
JOINED,
|
||||
LEFT,
|
||||
INVITED,
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
|
@ -7,5 +8,12 @@ import io.realm.annotations.PrimaryKey
|
|||
open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var displayName: String? = "",
|
||||
var topic: String? = "",
|
||||
var lastMessage: EventEntity? = null
|
||||
) : RealmObject()
|
||||
var lastMessage: EventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
var joinedMembersCount: Int? = 0,
|
||||
var invitedMembersCount: Int? = 0
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
||||
}
|
|
@ -1,26 +1,43 @@
|
|||
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.EventEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.Sort
|
||||
|
||||
fun EventEntity.Companion.where(realm: Realm, roomId: String, type: String? = null): RealmQuery<EventEntity> {
|
||||
var query = realm.where(EventEntity::class.java)
|
||||
val query = realm.where(EventEntity::class.java)
|
||||
.equalTo("chunk.room.roomId", roomId)
|
||||
if (type != null) {
|
||||
query = query.equalTo("type", type)
|
||||
query.equalTo("type", type)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
fun EventEntity.Companion.stateEvents(realm: Realm, roomId: String): RealmQuery<EventEntity> {
|
||||
return realm.where(EventEntity::class.java)
|
||||
.equalTo("chunk.room.roomId", roomId)
|
||||
.isNotNull("stateKey")
|
||||
}
|
||||
|
||||
fun RealmQuery<EventEntity>.last(from: Long? = null): EventEntity? {
|
||||
var query = this
|
||||
if (from != null) {
|
||||
query = query.lessThanOrEqualTo("originServerTs", from)
|
||||
this.lessThanOrEqualTo("originServerTs", from)
|
||||
}
|
||||
return query
|
||||
return this
|
||||
.sort("originServerTs", Sort.DESCENDING)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
fun EventEntity.Companion.findAllRoomMembers(realm: Realm, roomId: String): Map<String, RoomMember> {
|
||||
return EventEntity
|
||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||
.sort("originServerTs")
|
||||
.findAll()
|
||||
.map { it.asDomain() }
|
||||
.associateBy { it.stateKey!! }
|
||||
.mapValues { it.value.content<RoomMember>()!! }
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
|
@ -8,7 +9,7 @@ fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<RoomEnt
|
|||
return realm.where<RoomEntity>(RoomEntity::class.java).equalTo("roomId", roomId)
|
||||
}
|
||||
|
||||
fun RoomEntity.Companion.where(realm: Realm, membership: RoomEntity.Membership? = null): RealmQuery<RoomEntity> {
|
||||
fun RoomEntity.Companion.where(realm: Realm, membership: MyMembership? = null): RealmQuery<RoomEntity> {
|
||||
val query = realm.where(RoomEntity::class.java)
|
||||
if (membership != null) {
|
||||
query.equalTo("membership", membership.name)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
|
||||
fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<RoomSummaryEntity> {
|
||||
val query = realm.where(RoomSummaryEntity::class.java)
|
||||
if (roomId != null) {
|
||||
query.equalTo("roomId", roomId)
|
||||
}
|
||||
return query
|
||||
}
|
|
@ -25,7 +25,9 @@ class NetworkModule : Module {
|
|||
|
||||
single {
|
||||
val logger = HttpLoggingInterceptor.Logger { message -> Timber.v(message) }
|
||||
HttpLoggingInterceptor(logger).apply { level = HttpLoggingInterceptor.Level.BASIC }
|
||||
val interceptor = HttpLoggingInterceptor(logger)
|
||||
interceptor.level = HttpLoggingInterceptor.Level.BASIC
|
||||
interceptor
|
||||
}
|
||||
|
||||
single {
|
||||
|
|
|
@ -6,9 +6,10 @@ import android.support.annotation.MainThread
|
|||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.session.room.RoomModule
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryObserver
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.sync.SyncModule
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||
import org.koin.core.scope.Scope
|
||||
|
@ -18,7 +19,7 @@ import org.koin.standalone.getKoin
|
|||
import org.koin.standalone.inject
|
||||
|
||||
|
||||
class DefaultSession(private val sessionParams: SessionParams) : Session, KoinComponent, RoomService {
|
||||
class DefaultSession(override val sessionParams: SessionParams) : Session, KoinComponent, RoomService {
|
||||
|
||||
companion object {
|
||||
const val SCOPE: String = "session"
|
||||
|
@ -26,7 +27,7 @@ class DefaultSession(private val sessionParams: SessionParams) : Session, KoinCo
|
|||
|
||||
private lateinit var scope: Scope
|
||||
|
||||
private val roomSummaryObserver by inject<RoomSummaryObserver>()
|
||||
private val roomSummaryObserver by inject<RoomSummaryUpdater>()
|
||||
private val roomService by inject<RoomService>()
|
||||
private val syncThread by inject<SyncThread>()
|
||||
private var isOpen = false
|
||||
|
@ -70,6 +71,10 @@ class DefaultSession(private val sessionParams: SessionParams) : Session, KoinCo
|
|||
return roomService.liveRooms()
|
||||
}
|
||||
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
return roomService.liveRoomSummaries()
|
||||
}
|
||||
|
||||
// Private methods *****************************************************************************
|
||||
|
||||
private fun checkIsMainThread() {
|
||||
|
|
|
@ -7,7 +7,9 @@ import im.vector.matrix.android.internal.legacy.MXDataHandler
|
|||
import im.vector.matrix.android.internal.legacy.MXSession
|
||||
import im.vector.matrix.android.internal.legacy.data.store.MXFileStore
|
||||
import im.vector.matrix.android.internal.session.room.DefaultRoomService
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryObserver
|
||||
import im.vector.matrix.android.internal.session.room.RoomDisplayNameResolver
|
||||
import im.vector.matrix.android.internal.session.room.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
|
||||
|
@ -34,7 +36,15 @@ class SessionModule(private val sessionParams: SessionParams) : Module {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSummaryObserver(get())
|
||||
RoomMemberDisplayNameResolver()
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomDisplayNameResolver(get(), get(), sessionParams)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSummaryUpdater(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package im.vector.matrix.android.api.session.events.interceptor
|
||||
package im.vector.matrix.android.internal.session.events.interceptor
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.interceptor.EnrichedEventInterceptor
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
|
@ -11,15 +12,15 @@ import im.vector.matrix.android.internal.database.query.where
|
|||
class MessageEventInterceptor(val monarchy: Monarchy) : EnrichedEventInterceptor {
|
||||
|
||||
override fun canEnrich(event: EnrichedEvent): Boolean {
|
||||
return event.core.type == EventType.MESSAGE
|
||||
return event.root.type == EventType.MESSAGE
|
||||
}
|
||||
|
||||
override fun enrich(roomId: String, event: EnrichedEvent) {
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomMember = EventEntity
|
||||
.where(realm, roomId, EventType.STATE_ROOM_MEMBER)
|
||||
.equalTo("stateKey", event.core.sender)
|
||||
.last(from = event.core.originServerTs)
|
||||
.equalTo("stateKey", event.root.sender)
|
||||
.last(from = event.root.originServerTs)
|
||||
?.asDomain()
|
||||
event.enrichWith(roomMember)
|
||||
}
|
|
@ -5,12 +5,14 @@ import android.arch.paging.LivePagedListBuilder
|
|||
import android.arch.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.interceptor.EnrichedEventInterceptor
|
||||
import im.vector.matrix.android.api.session.events.interceptor.MessageEventInterceptor
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationRequest
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
|
||||
import io.realm.Sort
|
||||
|
@ -19,7 +21,8 @@ import org.koin.standalone.inject
|
|||
import java.util.concurrent.Executors
|
||||
|
||||
data class DefaultRoom(
|
||||
override val roomId: String
|
||||
override val roomId: String,
|
||||
override val myMembership: MyMembership
|
||||
) : Room, KoinComponent {
|
||||
|
||||
private val paginationRequest by inject<PaginationRequest>()
|
||||
|
@ -63,4 +66,10 @@ data class DefaultRoom(
|
|||
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
||||
}
|
||||
|
||||
override fun getNumberOfJoinedMembers(): Int {
|
||||
val roomSummary = monarchy.fetchAllCopiedSync { realm -> RoomSummaryEntity.where(realm, roomId) }.firstOrNull()
|
||||
return roomSummary?.joinedMembersCount ?: 0
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -4,7 +4,10 @@ import android.arch.lifecycle.LiveData
|
|||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
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
|
||||
|
||||
class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
||||
|
@ -12,7 +15,7 @@ class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
|||
override fun getAllRooms(): List<Room> {
|
||||
var rooms: List<Room> = emptyList()
|
||||
monarchy.doWithRealm { realm ->
|
||||
rooms = RoomEntity.where(realm).findAll().map { DefaultRoom(it.roomId) }
|
||||
rooms = RoomEntity.where(realm).findAll().map { it.asDomain() }
|
||||
}
|
||||
return rooms
|
||||
}
|
||||
|
@ -20,7 +23,7 @@ class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
|||
override fun getRoom(roomId: String): Room? {
|
||||
var room: Room? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
room = RoomEntity.where(realm, roomId).findFirst()?.let { DefaultRoom(it.roomId) }
|
||||
room = RoomEntity.where(realm, roomId).findFirst()?.let { it.asDomain() }
|
||||
}
|
||||
return room
|
||||
}
|
||||
|
@ -28,8 +31,16 @@ class DefaultRoomService(private val monarchy: Monarchy) : RoomService {
|
|||
override fun liveRooms(): LiveData<List<Room>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm -> RoomEntity.where(realm) },
|
||||
{ DefaultRoom(it.roomId) }
|
||||
{ it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun liveRoomSummaries(): LiveData<List<RoomSummary>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm -> RoomSummaryEntity.where(realm) },
|
||||
{ it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2018 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.matrix.android.internal.session.room
|
||||
|
||||
import android.content.Context
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
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.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.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
|
||||
) {
|
||||
|
||||
/**
|
||||
* Compute the room display name
|
||||
*
|
||||
* @param context
|
||||
* @param room: the room to resolve the name of.
|
||||
* @return the room display name
|
||||
*/
|
||||
fun resolve(context: Context, room: Room): CharSequence {
|
||||
// this algorithm is the one defined in
|
||||
// https://github.com/matrix-org/matrix-js-sdk/blob/develop/lib/models/room.js#L617
|
||||
// calculateRoomName(room, userId)
|
||||
|
||||
// For Lazy Loaded room, see algorithm here:
|
||||
// https://docs.google.com/document/d/11i14UI1cUz-OJ0knD5BFu7fmT6Fo327zvMYqfSAR7xs/edit#heading=h.qif6pkqyjgzn
|
||||
var name: CharSequence? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomName = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_NAME).last()?.asDomain()
|
||||
name = roomName?.content<RoomNameContent>()?.name
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val canonicalAlias = EventEntity.where(realm, room.roomId, EventType.STATE_CANONICAL_ALIAS).last()?.asDomain()
|
||||
name = canonicalAlias?.content<RoomCanonicalAliasContent>()?.canonicalAlias
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val aliases = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_ALIASES).last()?.asDomain()
|
||||
name = aliases?.content<RoomAliasesContent>()?.aliases?.firstOrNull()
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val otherRoomMembers = EventEntity
|
||||
.findAllRoomMembers(realm, room.roomId)
|
||||
.filterKeys { it != sessionParams.credentials.userId }
|
||||
|
||||
if (room.myMembership == MyMembership.INVITED) {
|
||||
//TODO handle invited
|
||||
/*
|
||||
if (currentUser != null
|
||||
&& !othersActiveMembers.isEmpty()
|
||||
&& !TextUtils.isEmpty(currentUser!!.mSender)) {
|
||||
// extract who invited us to the room
|
||||
name = context.getString(R.string.room_displayname_invite_from, roomState.resolve(currentUser!!.mSender))
|
||||
} else {
|
||||
name = context.getString(R.string.room_displayname_room_invite)
|
||||
}
|
||||
*/
|
||||
name = context.getString(R.string.room_displayname_room_invite)
|
||||
} else {
|
||||
|
||||
val roomSummary = RoomSummaryEntity.where(realm, room.roomId).findFirst()
|
||||
val memberIds = if (roomSummary?.heroes?.isNotEmpty() == true) {
|
||||
roomSummary.heroes
|
||||
} else {
|
||||
otherRoomMembers.keys.toList()
|
||||
}
|
||||
|
||||
val nbOfOtherMembers = memberIds.size
|
||||
|
||||
when (nbOfOtherMembers) {
|
||||
0 -> name = context.getString(R.string.room_displayname_empty_room)
|
||||
1 -> name = roomMemberDisplayNameResolver.resolve(memberIds[0], otherRoomMembers)
|
||||
2 -> {
|
||||
val member1 = memberIds[0]
|
||||
val member2 = memberIds[1]
|
||||
name = context.getString(R.string.room_displayname_two_members,
|
||||
roomMemberDisplayNameResolver.resolve(member1, otherRoomMembers),
|
||||
roomMemberDisplayNameResolver.resolve(member2, otherRoomMembers)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
val member = memberIds[0]
|
||||
name = context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
|
||||
room.getNumberOfJoinedMembers() - 1,
|
||||
roomMemberDisplayNameResolver.resolve(member, otherRoomMembers),
|
||||
room.getNumberOfJoinedMembers() - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return@doWithRealm
|
||||
}
|
||||
return name ?: room.roomId
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
|
||||
class RoomMemberDisplayNameResolver {
|
||||
|
||||
fun resolve(userId: String, members: Map<String, RoomMember>): String? {
|
||||
var displayName: String? = null
|
||||
val currentMember = members[userId]
|
||||
// Get the user display name from the member list of the room
|
||||
// Do not consider null display name
|
||||
if (currentMember != null && !currentMember.displayName.isNullOrEmpty()) {
|
||||
val hasNameCollision = members
|
||||
.filterValues { it != currentMember && it.displayName == currentMember.displayName }
|
||||
.isNotEmpty()
|
||||
displayName = if (hasNameCollision) {
|
||||
"${currentMember.displayName} ( $userId )"
|
||||
} else {
|
||||
currentMember.displayName
|
||||
}
|
||||
}
|
||||
// TODO handle invited users
|
||||
/*else if (null != member && TextUtils.equals(member!!.membership, RoomMember.MEMBERSHIP_INVITE)) {
|
||||
val user = (mDataHandler as MXDataHandler).getUser(userId)
|
||||
if (null != user) {
|
||||
displayName = user!!.displayname
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (displayName == null) {
|
||||
// By default, use the user ID
|
||||
displayName = userId
|
||||
}
|
||||
return displayName
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
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.model.RoomNameContent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
|
||||
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.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.RealmResults
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
internal class RoomSummaryObserver(private val monarchy: Monarchy) {
|
||||
|
||||
private lateinit var roomResults: RealmResults<RoomEntity>
|
||||
private var isStarted = AtomicBoolean(false)
|
||||
|
||||
fun start() {
|
||||
if (isStarted.compareAndSet(false, true)) {
|
||||
monarchy.doWithRealm {
|
||||
roomResults = RoomEntity.where(it).findAllAsync()
|
||||
roomResults.addChangeListener { rooms, changeSet ->
|
||||
manageRoomResults(rooms, changeSet.changes)
|
||||
manageRoomResults(rooms, changeSet.insertions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
if (isStarted.compareAndSet(true, false)) {
|
||||
roomResults.removeAllChangeListeners()
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE
|
||||
|
||||
private fun manageRoomResults(rooms: RealmResults<RoomEntity>, indexes: IntArray) {
|
||||
indexes.forEach {
|
||||
val room = rooms[it]
|
||||
if (room != null) {
|
||||
manageRoom(room.roomId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun manageRoom(roomId: String) {
|
||||
monarchy.writeAsync { realm ->
|
||||
val lastNameEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_NAME).last()?.asDomain()
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).last()?.asDomain()
|
||||
val lastMessageEvent = EventEntity.where(realm, roomId, EventType.MESSAGE).last()
|
||||
|
||||
val roomSummary = realm.copyToRealmOrUpdate(RoomSummaryEntity(roomId))
|
||||
roomSummary.displayName = lastNameEvent?.content<RoomNameContent>()?.name
|
||||
roomSummary.topic = lastTopicEvent?.content<RoomTopicContent>()?.topic
|
||||
roomSummary.lastMessage = lastMessageEvent
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import android.arch.lifecycle.Observer
|
||||
import android.content.Context
|
||||
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.RoomTopicContent
|
||||
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.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.last
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.RealmResults
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
internal class RoomSummaryUpdater(private val monarchy: Monarchy,
|
||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||
private val context: Context
|
||||
) : Observer<Monarchy.ManagedChangeSet<RoomEntity>> {
|
||||
|
||||
private var isStarted = AtomicBoolean(false)
|
||||
private val liveResults = monarchy.findAllManagedWithChanges { RoomEntity.where(it) }
|
||||
|
||||
fun start() {
|
||||
if (isStarted.compareAndSet(false, true)) {
|
||||
liveResults.observeForever(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
if (isStarted.compareAndSet(true, false)) {
|
||||
liveResults.removeObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE
|
||||
|
||||
override fun onChanged(changeSet: Monarchy.ManagedChangeSet<RoomEntity>?) {
|
||||
if (changeSet == null) {
|
||||
return
|
||||
}
|
||||
manageRoomResults(changeSet.realmResults, changeSet.orderedCollectionChangeSet.changes)
|
||||
manageRoomResults(changeSet.realmResults, changeSet.orderedCollectionChangeSet.insertions)
|
||||
}
|
||||
|
||||
|
||||
private fun manageRoomResults(rooms: RealmResults<RoomEntity>, indexes: IntArray) {
|
||||
indexes.forEach {
|
||||
val room = rooms[it]?.asDomain()
|
||||
try {
|
||||
manageRoom(room)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, "An error occured when updating room summaries")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun manageRoom(room: Room?) {
|
||||
if (room == null) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
monarchy.writeAsync { realm ->
|
||||
val roomSummary = RoomSummaryEntity.where(realm, room.roomId).findFirst()
|
||||
?: RoomSummaryEntity(room.roomId)
|
||||
|
||||
val lastMessageEvent = EventEntity.where(realm, room.roomId, EventType.MESSAGE).last()
|
||||
val lastTopicEvent = EventEntity.where(realm, room.roomId, EventType.STATE_ROOM_TOPIC).last()?.asDomain()
|
||||
|
||||
roomSummary.displayName = roomDisplayNameResolver.resolve(context, room).toString()
|
||||
roomSummary.topic = lastTopicEvent?.content<RoomTopicContent>()?.topic
|
||||
roomSummary.lastMessage = lastMessageEvent
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -28,10 +28,10 @@ class TimelineBoundaryCallback(private val paginationRequest: PaginationRequest,
|
|||
override fun onItemAtEndLoaded(itemAtEnd: EnrichedEvent) {
|
||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) {
|
||||
monarchy.doWithRealm { realm ->
|
||||
if (itemAtEnd.core.eventId == null) {
|
||||
if (itemAtEnd.root.eventId == null) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtEnd.core.eventId)).firstOrNull()
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtEnd.root.eventId)).firstOrNull()
|
||||
paginationRequest.execute(roomId, chunkEntity?.prevToken, PaginationDirection.BACKWARDS, callback = createCallback(it))
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,10 @@ class TimelineBoundaryCallback(private val paginationRequest: PaginationRequest,
|
|||
override fun onItemAtFrontLoaded(itemAtFront: EnrichedEvent) {
|
||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.BEFORE) {
|
||||
monarchy.doWithRealm { realm ->
|
||||
if (itemAtFront.core.eventId == null) {
|
||||
if (itemAtFront.root.eventId == null) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtFront.core.eventId)).firstOrNull()
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtFront.root.eventId)).firstOrNull()
|
||||
paginationRequest.execute(roomId, chunkEntity?.nextToken, PaginationDirection.FORWARDS, callback = createCallback(it))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,14 +2,17 @@ package im.vector.matrix.android.internal.session.sync
|
|||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
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.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSync
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||
import io.realm.Realm
|
||||
|
||||
|
||||
|
@ -41,11 +44,16 @@ class RoomSyncHandler(private val monarchy: Monarchy) {
|
|||
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: RoomEntity(roomId)
|
||||
|
||||
if (roomEntity.membership == RoomEntity.Membership.INVITED) {
|
||||
if (roomEntity.membership == MyMembership.INVITED) {
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
}
|
||||
|
||||
roomEntity.membership = RoomEntity.Membership.JOINED
|
||||
|
||||
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)) {
|
||||
|
@ -67,7 +75,7 @@ class RoomSyncHandler(private val monarchy: Monarchy) {
|
|||
InvitedRoomSync): RoomEntity {
|
||||
val roomEntity = RoomEntity()
|
||||
roomEntity.roomId = roomId
|
||||
roomEntity.membership = RoomEntity.Membership.INVITED
|
||||
roomEntity.membership = MyMembership.INVITED
|
||||
if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) {
|
||||
val chunkEntity = handleListOfEvent(realm, roomId, roomSync.inviteState.events)
|
||||
if (!roomEntity.chunks.contains(chunkEntity)) {
|
||||
|
@ -82,10 +90,30 @@ class RoomSyncHandler(private val monarchy: Monarchy) {
|
|||
roomSync: RoomSync): RoomEntity {
|
||||
return RoomEntity().apply {
|
||||
this.roomId = roomId
|
||||
this.membership = RoomEntity.Membership.LEFT
|
||||
this.membership = MyMembership.LEFT
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRoomSummary(realm: Realm,
|
||||
roomId: String,
|
||||
roomSummary: RoomSyncSummary) {
|
||||
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
?: RoomSummaryEntity(roomId)
|
||||
|
||||
if (roomSummary.heroes.isNotEmpty()) {
|
||||
roomSummaryEntity.heroes.clear()
|
||||
roomSummaryEntity.heroes.addAll(roomSummary.heroes)
|
||||
}
|
||||
if (roomSummary.invitedMembersCount != null) {
|
||||
roomSummaryEntity.invitedMembersCount = roomSummary.invitedMembersCount
|
||||
}
|
||||
if (roomSummary.joinedMembersCount != null) {
|
||||
roomSummaryEntity.joinedMembersCount = roomSummary.joinedMembersCount
|
||||
}
|
||||
realm.insertOrUpdate(roomSummaryEntity)
|
||||
}
|
||||
|
||||
private fun handleListOfEvent(realm: Realm,
|
||||
roomId: String,
|
||||
eventList: List<Event>,
|
||||
|
|
|
@ -44,6 +44,12 @@ data class RoomSync(
|
|||
/**
|
||||
* The notification counts for the room.
|
||||
*/
|
||||
@Json(name = "unread_notifications") val unreadNotifications: RoomSyncUnreadNotifications? = null
|
||||
@Json(name = "unread_notifications") val unreadNotifications: RoomSyncUnreadNotifications? = null,
|
||||
|
||||
/**
|
||||
* The room summary
|
||||
*/
|
||||
@Json(name = "summary") val summary: RoomSyncSummary? = null
|
||||
|
||||
|
||||
)
|
|
@ -0,0 +1,32 @@
|
|||
package im.vector.matrix.android.internal.session.sync.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomSyncSummary(
|
||||
|
||||
/**
|
||||
* Present only if the room has no m.room.name or m.room.canonical_alias.
|
||||
*
|
||||
*
|
||||
* Lists the mxids of the first 5 members in the room who are currently joined or invited (ordered by stream ordering as seen on the server,
|
||||
* to avoid it jumping around if/when topological order changes). As the heroes’ membership status changes, the list changes appropriately
|
||||
* (sending the whole new list in the next /sync response). This list always excludes the current logged in user. If there are no joined or
|
||||
* invited users, it lists the parted and banned ones instead. Servers can choose to send more or less than 5 members if they must, but 5
|
||||
* seems like a good enough number for most naming purposes. Clients should use all the provided members to name the room, but may truncate
|
||||
* the list if helpful for UX
|
||||
*/
|
||||
@Json(name = "m.heroes") val heroes: List<String> = emptyList(),
|
||||
|
||||
/**
|
||||
* The number of m.room.members in state 'joined' (including the syncing user) (can be null)
|
||||
*/
|
||||
@Json(name = "m.joined_member_count") val joinedMembersCount: Int? = null,
|
||||
|
||||
/**
|
||||
* The number of m.room.members in state 'invited' (can be null)
|
||||
*/
|
||||
@Json(name = "m.invited_member_count") val invitedMembersCount: Int? = null
|
||||
)
|
|
@ -84,4 +84,18 @@
|
|||
<string name="reply_to_an_audio_file">sent an audio file.</string>
|
||||
<string name="reply_to_a_file">sent a file.</string>
|
||||
|
||||
<!-- Room display name -->
|
||||
<string name="room_displayname_invite_from">Invite from %s</string>
|
||||
<string name="room_displayname_room_invite">Room Invite</string>
|
||||
|
||||
<!-- The 2 parameters will be members' name -->
|
||||
<string name="room_displayname_two_members">%1$s and %2$s</string>
|
||||
|
||||
<plurals name="room_displayname_three_and_more_members">
|
||||
<item quantity="one">%1$s and 1 other</item>
|
||||
<item quantity="other">%1$s and %2$d others</item>
|
||||
</plurals>
|
||||
|
||||
<string name="room_displayname_empty_room">Empty room</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue