forked from GitHub-Mirror/riotX-android
Start to insert room summaries and listen for changes
This commit is contained in:
parent
b79d23ad24
commit
4904ac894e
Binary file not shown.
@ -28,6 +28,8 @@ dependencies {
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||
|
||||
implementation "org.koin:koin-android:$koin_version"
|
||||
implementation "org.koin:koin-android-scope:$koin_version"
|
||||
implementation "org.koin:koin-android-viewmodel:$koin_version"
|
||||
|
@ -1,13 +1,18 @@
|
||||
package im.vector.riotredesign
|
||||
|
||||
import android.app.Application
|
||||
import im.vector.matrix.android.BuildConfig
|
||||
import im.vector.riotredesign.core.di.AppModule
|
||||
import org.koin.standalone.StandAloneContext.startKoin
|
||||
import timber.log.Timber
|
||||
|
||||
class Riot : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
startKoin(listOf(AppModule(this)))
|
||||
}
|
||||
|
||||
|
@ -4,24 +4,22 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.events.sync.data.SyncResponse
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotActivity
|
||||
import io.realm.RealmChangeListener
|
||||
import io.realm.RealmResults
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import org.koin.android.ext.android.inject
|
||||
import timber.log.Timber
|
||||
|
||||
class HomeActivity : RiotActivity() {
|
||||
|
||||
private val matrix by inject<Matrix>()
|
||||
private val synchronizer = matrix.currentSession?.synchronizer()
|
||||
private val realmHolder = matrix.currentSession?.realmInstanceHolder()
|
||||
private val realmHolder = matrix.currentSession?.realmHolder()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -33,25 +31,25 @@ class HomeActivity : RiotActivity() {
|
||||
synchronizeButton.visibility = View.GONE
|
||||
loadingView.visibility = View.VISIBLE
|
||||
synchronizer?.synchronize(object : MatrixCallback<SyncResponse> {
|
||||
override fun onSuccess(data: SyncResponse?) {
|
||||
override fun onSuccess(data: SyncResponse) {
|
||||
synchronizeButton.visibility = View.VISIBLE
|
||||
loadingView.visibility = View.GONE
|
||||
Timber.v("Sync successful")
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Failure) {
|
||||
synchronizeButton.visibility = View.VISIBLE
|
||||
loadingView.visibility = View.GONE
|
||||
Toast.makeText(this@HomeActivity, failure.toString(), Toast.LENGTH_LONG).show()
|
||||
Timber.e("Sync has failed : %s", failure.toString())
|
||||
}
|
||||
})
|
||||
if (realmHolder != null) {
|
||||
val results = realmHolder.realm.where(EventEntity::class.java).equalTo("chunk.room.roomId", "!UlckfcnwgLKswCmUbe:matrix.org").findAll()
|
||||
results.addChangeListener(RealmChangeListener<RealmResults<EventEntity>> {
|
||||
Toast.makeText(this@HomeActivity, "Room events data changed", Toast.LENGTH_LONG).show()
|
||||
})
|
||||
val results = realmHolder.instance.where(RoomSummaryEntity::class.java).findAll()
|
||||
results.addChangeListener { summaries ->
|
||||
Timber.v("Summaries updated")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -22,8 +22,8 @@ class LoginActivity : RiotActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_login)
|
||||
authenticateButton.setOnClickListener { authenticate() }
|
||||
checkActiveSessions()
|
||||
authenticateButton.setOnClickListener { authenticate() }
|
||||
}
|
||||
|
||||
private fun authenticate() {
|
||||
@ -37,9 +37,8 @@ class LoginActivity : RiotActivity() {
|
||||
.build()
|
||||
|
||||
authenticator.authenticate(homeServerConnectionConfig, login, password, object : MatrixCallback<Session> {
|
||||
override fun onSuccess(data: Session?) {
|
||||
matrix.currentSession = data
|
||||
goToHomeScreen()
|
||||
override fun onSuccess(data: Session) {
|
||||
openSessionAndGoToHome(data)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Failure) {
|
||||
@ -51,12 +50,16 @@ class LoginActivity : RiotActivity() {
|
||||
|
||||
private fun checkActiveSessions() {
|
||||
if (authenticator.hasActiveSessions()) {
|
||||
matrix.currentSession = authenticator.getLastActiveSession()
|
||||
goToHomeScreen()
|
||||
val session = authenticator.getLastActiveSession()
|
||||
session?.let {
|
||||
openSessionAndGoToHome(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun goToHomeScreen() {
|
||||
private fun openSessionAndGoToHome(session: Session) {
|
||||
matrix.currentSession = session
|
||||
session.open()
|
||||
val intent = HomeActivity.newIntent(this)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
|
@ -44,6 +44,7 @@ dependencies {
|
||||
def arrow_version = "0.7.3"
|
||||
def support_version = '28.0.0'
|
||||
def moshi_version = '1.7.0'
|
||||
def lifecycle_version = "1.1.1"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
@ -51,6 +52,10 @@ dependencies {
|
||||
implementation "com.android.support:appcompat-v7:$support_version"
|
||||
implementation "com.android.support:recyclerview-v7:$support_version"
|
||||
|
||||
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
|
||||
kapt "android.arch.lifecycle:compiler:$lifecycle_version"
|
||||
|
||||
|
||||
// Network
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
|
||||
|
@ -4,7 +4,7 @@ import im.vector.matrix.android.api.failure.Failure
|
||||
|
||||
interface MatrixCallback<in T> {
|
||||
|
||||
fun onSuccess(data: T?)
|
||||
fun onSuccess(data: T)
|
||||
|
||||
fun onFailure(failure: Failure)
|
||||
|
||||
|
@ -16,7 +16,7 @@ data class Event(
|
||||
@Json(name = "sender") val sender: String? = null,
|
||||
@Json(name = "state_key") val stateKey: String? = null,
|
||||
@Json(name = "room_id") var roomId: String? = null,
|
||||
@Json(name = "unsigned_data") val unsignedData: UnsignedData? = null
|
||||
@Json(name = "unsigned") val unsignedData: UnsignedData? = null
|
||||
) {
|
||||
|
||||
val contentAsJsonObject: JsonObject? by lazy {
|
||||
|
@ -5,7 +5,7 @@ import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class UnsignedData(
|
||||
@Json(name = "age") val age: Int,
|
||||
@Json(name = "age") val age: Long?,
|
||||
@Json(name = "redacted_because") val redactedEvent: Event? = null,
|
||||
@Json(name = "transaction_id") val transactionId: String
|
||||
@Json(name = "transaction_id") val transactionId: String? = null
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package im.vector.matrix.android.api.rooms
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomNameContent(
|
||||
@Json(name = "name") val name: String
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package im.vector.matrix.android.api.rooms
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class RoomTopicContent(
|
||||
@Json(name = "topic") val topic: String
|
||||
)
|
@ -1,15 +1,20 @@
|
||||
package im.vector.matrix.android.api.session
|
||||
|
||||
import im.vector.matrix.android.internal.database.RealmInstanceHolder
|
||||
import android.support.annotation.MainThread
|
||||
import im.vector.matrix.android.internal.database.SessionRealmHolder
|
||||
import im.vector.matrix.android.internal.events.sync.Synchronizer
|
||||
|
||||
interface Session {
|
||||
|
||||
@MainThread
|
||||
fun open()
|
||||
|
||||
fun synchronizer(): Synchronizer
|
||||
|
||||
// Visible for testing request directly. Will be deleted
|
||||
fun realmInstanceHolder(): RealmInstanceHolder
|
||||
fun realmHolder(): SessionRealmHolder
|
||||
|
||||
@MainThread
|
||||
fun close()
|
||||
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package im.vector.matrix.android.internal.database
|
||||
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
|
||||
class RealmInstanceHolder(realmConfiguration: RealmConfiguration) {
|
||||
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package im.vector.matrix.android.internal.database
|
||||
|
||||
import android.support.annotation.MainThread
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
|
||||
class SessionRealmHolder(private val realmConfiguration: RealmConfiguration
|
||||
) {
|
||||
|
||||
lateinit var instance: Realm
|
||||
|
||||
@MainThread
|
||||
fun open() {
|
||||
instance = Realm.getInstance(realmConfiguration)
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun close() {
|
||||
instance.close()
|
||||
Realm.compactRealm(realmConfiguration)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import com.squareup.moshi.Types
|
||||
import im.vector.matrix.android.api.events.Event
|
||||
import im.vector.matrix.android.api.events.UnsignedData
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
|
||||
@ -12,14 +13,38 @@ object EventMapper {
|
||||
private val type = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)
|
||||
private val adapter = moshi.adapter<Map<String, Any>>(type)
|
||||
|
||||
fun map(event: Event): EventEntity {
|
||||
internal fun map(event: Event): EventEntity {
|
||||
val eventEntity = EventEntity()
|
||||
eventEntity.eventId = event.eventId!!
|
||||
eventEntity.content = adapter.toJson(event.content)
|
||||
eventEntity.prevContent = adapter.toJson(event.prevContent)
|
||||
eventEntity.stateKey = event.stateKey
|
||||
eventEntity.type = event.type
|
||||
eventEntity.sender = event.sender
|
||||
eventEntity.originServerTs = event.originServerTs
|
||||
eventEntity.age = event.unsignedData?.age ?: event.originServerTs
|
||||
return eventEntity
|
||||
}
|
||||
|
||||
internal fun map(eventEntity: EventEntity): Event {
|
||||
return Event(
|
||||
eventEntity.type,
|
||||
eventEntity.eventId,
|
||||
adapter.fromJson(eventEntity.content),
|
||||
adapter.fromJson(eventEntity.prevContent ?: ""),
|
||||
eventEntity.originServerTs,
|
||||
eventEntity.sender,
|
||||
eventEntity.stateKey,
|
||||
null,
|
||||
UnsignedData(eventEntity.age)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun EventEntity.asDomain(): Event {
|
||||
return EventMapper.map(this)
|
||||
}
|
||||
|
||||
fun Event.asEntity(): EventEntity {
|
||||
return EventMapper.map(this)
|
||||
}
|
@ -9,9 +9,14 @@ open class EventEntity(@PrimaryKey var eventId: String = "",
|
||||
var type: String = "",
|
||||
var content: String = "",
|
||||
var prevContent: String? = null,
|
||||
var stateKey: String? = null
|
||||
var stateKey: String? = null,
|
||||
var originServerTs: Long? = null,
|
||||
var sender: String? = null,
|
||||
var age: Long? = 0
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
|
||||
@LinkingObjects("events")
|
||||
val chunk: RealmResults<ChunkEntity>? = null
|
||||
|
||||
|
@ -6,10 +6,10 @@ import io.realm.annotations.Ignore
|
||||
import io.realm.annotations.PrimaryKey
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
open class RoomEntity : RealmObject() {
|
||||
open class RoomEntity(@PrimaryKey var roomId: String = "",
|
||||
var chunks: RealmList<ChunkEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
@PrimaryKey var roomId: String = ""
|
||||
var chunks: RealmList<ChunkEntity> = RealmList()
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
|
||||
@delegate:Ignore var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue ->
|
||||
|
@ -0,0 +1,11 @@
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
// TODO to be completed
|
||||
open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
||||
var displayName: String? = "",
|
||||
var topic: String? = "",
|
||||
var lastMessage: EventEntity? = null
|
||||
) : RealmObject()
|
@ -0,0 +1,20 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import io.realm.Realm
|
||||
|
||||
fun ChunkEntity.Companion.getLastChunkFromRoom(realm: Realm, roomId: String): ChunkEntity? {
|
||||
return realm.where(ChunkEntity::class.java)
|
||||
.equalTo("room.roomId", roomId)
|
||||
.isNull("nextToken")
|
||||
.and()
|
||||
.isNotNull("prevToken")
|
||||
.findAll()
|
||||
.lastOrNull()
|
||||
}
|
||||
|
||||
fun ChunkEntity.Companion.getChunkIncludingEvents(realm: Realm, eventIds: List<String>): ChunkEntity? {
|
||||
return realm.where(ChunkEntity::class.java)
|
||||
.`in`("events.eventId", eventIds.toTypedArray())
|
||||
.findFirst()
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
|
||||
fun EventEntity.Companion.getAllFromRoom(realm: Realm, roomId: String): RealmResults<EventEntity> {
|
||||
return realm.where(EventEntity::class.java)
|
||||
.equalTo("chunk.room.roomId", roomId)
|
||||
.findAll()
|
||||
}
|
||||
|
||||
fun RealmResults<EventEntity>.getLast(type: String? = null): EventEntity? {
|
||||
var query = this.where()
|
||||
if (type != null) {
|
||||
query = query.equalTo("type", type)
|
||||
}
|
||||
return query.findAll().sort("age").lastOrNull()
|
||||
}
|
@ -2,6 +2,7 @@ package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
|
||||
fun RoomEntity.Companion.getForId(realm: Realm, roomId: String): RoomEntity? {
|
||||
return realm.where<RoomEntity>(RoomEntity::class.java)
|
||||
@ -9,10 +10,10 @@ fun RoomEntity.Companion.getForId(realm: Realm, roomId: String): RoomEntity? {
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
fun RoomEntity.Companion.getAll(realm: Realm, membership: RoomEntity.Membership? = null): List<RoomEntity> {
|
||||
fun RoomEntity.Companion.getAllAsync(realm: Realm, membership: RoomEntity.Membership? = null): RealmResults<RoomEntity> {
|
||||
val query = realm.where(RoomEntity::class.java)
|
||||
if (membership != null) {
|
||||
query.equalTo("membership", membership.name)
|
||||
}
|
||||
return query.findAll()
|
||||
return query.findAllAsync()
|
||||
}
|
@ -3,7 +3,6 @@ package im.vector.matrix.android.internal.di
|
||||
import im.vector.matrix.android.api.MatrixOptions
|
||||
import im.vector.matrix.android.api.thread.MainThreadExecutor
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import io.realm.Realm
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
|
@ -1,9 +1,7 @@
|
||||
package im.vector.matrix.android.internal.di
|
||||
|
||||
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
|
||||
import com.squareup.moshi.Moshi
|
||||
import im.vector.matrix.android.internal.network.AccessTokenInterceptor
|
||||
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.koin.dsl.context.ModuleDefinition
|
||||
|
@ -1,11 +1,12 @@
|
||||
package im.vector.matrix.android.internal.di
|
||||
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.database.RealmInstanceHolder
|
||||
import im.vector.matrix.android.internal.database.SessionRealmHolder
|
||||
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.DefaultSession
|
||||
import im.vector.matrix.android.internal.session.RoomSummaryObserver
|
||||
import io.realm.RealmConfiguration
|
||||
import org.koin.dsl.context.ModuleDefinition
|
||||
import org.koin.dsl.module.Module
|
||||
@ -21,7 +22,7 @@ class SessionModule(private val sessionParams: SessionParams) : Module {
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RealmInstanceHolder(get())
|
||||
SessionRealmHolder(get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
@ -31,6 +32,10 @@ class SessionModule(private val sessionParams: SessionParams) : Module {
|
||||
.build()
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomSummaryObserver(get(), get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
val store = MXFileStore(sessionParams.credentials, false, get())
|
||||
val dataHandler = MXDataHandler(store, sessionParams.credentials)
|
||||
|
@ -1,10 +1,12 @@
|
||||
package im.vector.matrix.android.internal.events.sync
|
||||
|
||||
import im.vector.matrix.android.api.events.Event
|
||||
import im.vector.matrix.android.internal.database.mapper.EventMapper
|
||||
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.query.getChunkIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.getForId
|
||||
import im.vector.matrix.android.internal.database.query.getLastChunkFromRoom
|
||||
import im.vector.matrix.android.internal.events.sync.data.InvitedRoomSync
|
||||
import im.vector.matrix.android.internal.events.sync.data.RoomSync
|
||||
import io.realm.Realm
|
||||
@ -39,8 +41,7 @@ class RoomSyncHandler(private val realmConfiguration: RealmConfiguration) {
|
||||
roomId: String,
|
||||
roomSync: RoomSync): RoomEntity {
|
||||
|
||||
val roomEntity = RoomEntity.getForId(realm, roomId)
|
||||
?: RoomEntity().apply { this.roomId = roomId }
|
||||
val roomEntity = RoomEntity.getForId(realm, roomId) ?: RoomEntity(roomId)
|
||||
|
||||
if (roomEntity.membership == RoomEntity.Membership.INVITED) {
|
||||
roomEntity.chunks.deleteAllFromRealm()
|
||||
@ -95,16 +96,16 @@ class RoomSyncHandler(private val realmConfiguration: RealmConfiguration) {
|
||||
isLimited: Boolean = true): ChunkEntity {
|
||||
|
||||
val chunkEntity = if (!isLimited) {
|
||||
realm.where(ChunkEntity::class.java).equalTo("room.roomId", roomId).isNull("nextToken").and().isNotNull("prevToken").findAll().lastOrNull()
|
||||
ChunkEntity.getLastChunkFromRoom(realm, roomId)
|
||||
} else {
|
||||
realm.where(ChunkEntity::class.java).`in`("events.eventId", eventList.map { it.eventId }.toTypedArray()).findFirst()
|
||||
} ?: ChunkEntity()
|
||||
val eventIds = eventList.filter { it.eventId != null }.map { it.eventId!! }
|
||||
ChunkEntity.getChunkIncludingEvents(realm, eventIds)
|
||||
} ?: ChunkEntity().apply { this.prevToken = prevToken }
|
||||
|
||||
chunkEntity.prevToken = prevToken
|
||||
chunkEntity.nextToken = nextToken
|
||||
chunkEntity.isLimited = isLimited
|
||||
eventList.forEach { event ->
|
||||
val eventEntity = EventMapper.map(event).let {
|
||||
val eventEntity = event.asEntity().let {
|
||||
realm.copyToRealmOrUpdate(it)
|
||||
}
|
||||
if (!chunkEntity.events.contains(eventEntity)) {
|
||||
|
@ -2,6 +2,7 @@ package im.vector.matrix.android.internal.events.sync
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.flatMap
|
||||
import arrow.core.leftIfNull
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
@ -42,6 +43,8 @@ class Synchronizer(private val syncAPI: SyncAPI,
|
||||
params["filter"] = filterBody.toJSONString()
|
||||
executeRequest<SyncResponse> {
|
||||
apiCall = syncAPI.sync(params)
|
||||
}.leftIfNull {
|
||||
Failure.Unknown(RuntimeException("Sync response shouln't be null"))
|
||||
}.flatMap {
|
||||
token = it?.nextBatch
|
||||
try {
|
||||
|
@ -32,7 +32,7 @@ class Request<DATA> {
|
||||
} catch (e: Exception) {
|
||||
when (e) {
|
||||
is IOException -> Either.Left(Failure.NetworkConnection)
|
||||
else -> Either.Left(Failure.Unknown(e))
|
||||
else -> Either.Left(Failure.Unknown(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package im.vector.matrix.android.internal.session
|
||||
|
||||
import android.os.Looper
|
||||
import android.support.annotation.MainThread
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.internal.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.database.RealmInstanceHolder
|
||||
import im.vector.matrix.android.internal.database.SessionRealmHolder
|
||||
import im.vector.matrix.android.internal.di.SessionModule
|
||||
import im.vector.matrix.android.internal.events.sync.SyncModule
|
||||
import im.vector.matrix.android.internal.events.sync.Synchronizer
|
||||
@ -12,34 +14,57 @@ import org.koin.standalone.StandAloneContext
|
||||
import org.koin.standalone.getKoin
|
||||
import org.koin.standalone.inject
|
||||
|
||||
class DefaultSession(sessionParams: SessionParams) : Session, KoinComponent {
|
||||
|
||||
private val realmInstanceHolder by inject<RealmInstanceHolder>()
|
||||
private val synchronizer by inject<Synchronizer>()
|
||||
private val scope: Scope
|
||||
|
||||
init {
|
||||
val sessionModule = SessionModule(sessionParams)
|
||||
val syncModule = SyncModule()
|
||||
StandAloneContext.loadKoinModules(listOf(sessionModule, syncModule))
|
||||
scope = getKoin().getOrCreateScope(SCOPE)
|
||||
}
|
||||
|
||||
override fun synchronizer(): Synchronizer {
|
||||
return synchronizer
|
||||
}
|
||||
|
||||
override fun realmInstanceHolder(): RealmInstanceHolder {
|
||||
return realmInstanceHolder
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
realmInstanceHolder.realm.close()
|
||||
scope.close()
|
||||
}
|
||||
class DefaultSession(private val sessionParams: SessionParams) : Session, KoinComponent {
|
||||
|
||||
companion object {
|
||||
const val SCOPE: String = "session"
|
||||
}
|
||||
|
||||
private lateinit var scope: Scope
|
||||
|
||||
private val realmInstanceHolder by inject<SessionRealmHolder>()
|
||||
private val synchronizer by inject<Synchronizer>()
|
||||
private val roomSummaryObserver by inject<RoomSummaryObserver>()
|
||||
|
||||
private var isOpen = false
|
||||
|
||||
@MainThread
|
||||
override fun open() {
|
||||
checkIsMainThread()
|
||||
assert(!isOpen)
|
||||
isOpen = true
|
||||
val sessionModule = SessionModule(sessionParams)
|
||||
val syncModule = SyncModule()
|
||||
StandAloneContext.loadKoinModules(listOf(sessionModule, syncModule))
|
||||
scope = getKoin().getOrCreateScope(SCOPE)
|
||||
realmInstanceHolder.open()
|
||||
roomSummaryObserver.start()
|
||||
}
|
||||
|
||||
override fun synchronizer(): Synchronizer {
|
||||
assert(isOpen)
|
||||
return synchronizer
|
||||
}
|
||||
|
||||
override fun realmHolder(): SessionRealmHolder {
|
||||
assert(isOpen)
|
||||
return realmInstanceHolder
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun close() {
|
||||
checkIsMainThread()
|
||||
assert(isOpen)
|
||||
roomSummaryObserver.dispose()
|
||||
realmInstanceHolder.close()
|
||||
scope.close()
|
||||
isOpen = false
|
||||
}
|
||||
|
||||
private fun checkIsMainThread() {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
throw IllegalStateException("Should be called on main thread")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package im.vector.matrix.android.internal.session
|
||||
|
||||
import im.vector.matrix.android.api.events.EventType
|
||||
import im.vector.matrix.android.api.rooms.RoomNameContent
|
||||
import im.vector.matrix.android.api.rooms.RoomTopicContent
|
||||
import im.vector.matrix.android.internal.database.SessionRealmHolder
|
||||
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.getAllAsync
|
||||
import im.vector.matrix.android.internal.database.query.getAllFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.getLast
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmResults
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
internal class RoomSummaryObserver(private val mainThreadRealm: SessionRealmHolder,
|
||||
private val matrixCoroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val realmConfiguration: RealmConfiguration
|
||||
) {
|
||||
|
||||
private lateinit var roomResults: RealmResults<RoomEntity>
|
||||
private var isStarted = AtomicBoolean(false)
|
||||
|
||||
fun start() {
|
||||
if (isStarted.compareAndSet(false, true)) {
|
||||
roomResults = RoomEntity.getAllAsync(mainThreadRealm.instance)
|
||||
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) = GlobalScope.launch(matrixCoroutineDispatchers.io) {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
val roomEvents = EventEntity.getAllFromRoom(realm, roomId)
|
||||
val lastNameEvent = roomEvents.getLast(EventType.STATE_ROOM_NAME)?.asDomain()
|
||||
val lastTopicEvent = roomEvents.getLast(EventType.STATE_ROOM_TOPIC)?.asDomain()
|
||||
val lastMessageEvent = roomEvents.getLast(EventType.MESSAGE)
|
||||
|
||||
realm.executeTransaction { realmInstance ->
|
||||
val roomSummary = realmInstance.copyToRealmOrUpdate(RoomSummaryEntity(roomId))
|
||||
roomSummary.displayName = lastNameEvent?.content<RoomNameContent>()?.name
|
||||
roomSummary.topic = lastTopicEvent?.content<RoomTopicContent>()?.topic
|
||||
roomSummary.lastMessage = lastMessageEvent
|
||||
}
|
||||
realm.close()
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user