Merge pull request #1504 from vector-im/feature/improve_perf

Feature/improve perf
This commit is contained in:
ganfra 2020-06-25 17:00:56 +02:00 committed by GitHub
commit f8452429a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
144 changed files with 811 additions and 442 deletions

View file

@ -1,6 +1,9 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<option name="RIGHT_MARGIN" value="160" />
<AndroidXmlCodeStyleSettings>
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>

View file

@ -43,6 +43,7 @@ import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.api.session.terms.TermsService
import im.vector.matrix.android.api.session.typing.TypingUsersTracker
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.api.session.widgets.WidgetService
@ -146,6 +147,11 @@ interface Session :
*/
fun contentUploadProgressTracker(): ContentUploadStateTracker
/**
* Returns the TypingUsersTracker associated with the session
*/
fun typingUsersTracker(): TypingUsersTracker
/**
* Returns the cryptoService associated with the session
*/

View file

@ -17,8 +17,8 @@ package im.vector.matrix.android.api.session.room.model
data class EventAnnotationsSummary(
var eventId: String,
var reactionsSummary: List<ReactionAggregatedSummary>,
var editSummary: EditAggregatedSummary?,
var pollResponseSummary: PollResponseAggregatedSummary?,
var reactionsSummary: List<ReactionAggregatedSummary> = emptyList(),
var editSummary: EditAggregatedSummary? = null,
var pollResponseSummary: PollResponseAggregatedSummary? = null,
var referencesAggregatedSummary: ReferencesAggregatedSummary? = null
)

View file

@ -48,7 +48,6 @@ data class RoomSummary constructor(
val isEncrypted: Boolean,
val encryptionEventTs: Long?,
val inviterId: String? = null,
val typingRoomMemberIds: List<String> = emptyList(),
val breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
) {

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2020 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.api.session.typing
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.session.room.sender.SenderInfo
/**
* Responsible for tracking typing users from each room.
* It's ephemeral data and it's only saved in memory.
*/
interface TypingUsersTracker {
/**
* Returns the sender information of all currently typing users in a room, excluding yourself.
*/
fun getTypingUsers(roomId: String): List<SenderInfo>
/**
* Returns a LiveData of the sender information of all currently typing users in a room, excluding yourself.
*/
fun getTypingUsersLive(roomId: String): LiveData<List<SenderInfo>>
}

View file

@ -84,6 +84,7 @@ import im.vector.matrix.android.internal.database.model.EventEntityFields
import im.vector.matrix.android.internal.database.query.whereType
import im.vector.matrix.android.internal.di.DeviceId
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.session.SessionScope
@ -168,7 +169,7 @@ internal class DefaultCryptoService @Inject constructor(
private val setDeviceNameTask: SetDeviceNameTask,
private val uploadKeysTask: UploadKeysTask,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val taskExecutor: TaskExecutor,
private val cryptoCoroutineScope: CoroutineScope,

View file

@ -21,7 +21,8 @@ import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityF
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.createBackgroundHandler
@ -42,7 +43,7 @@ internal class ShieldTrustUpdater @Inject constructor(
private val taskExecutor: TaskExecutor,
@SessionDatabase private val sessionRealmConfiguration: RealmConfiguration,
private val roomSummaryUpdater: RoomSummaryUpdater
) {
): SessionLifecycleObserver {
companion object {
private val BACKGROUND_HANDLER = createBackgroundHandler("SHIELD_CRYPTO_DB_THREAD")
@ -53,7 +54,7 @@ internal class ShieldTrustUpdater @Inject constructor(
private val isStarted = AtomicBoolean()
fun start() {
override fun onStart() {
if (isStarted.compareAndSet(false, true)) {
eventBus.register(this)
BACKGROUND_HANDLER.post {
@ -62,7 +63,7 @@ internal class ShieldTrustUpdater @Inject constructor(
}
}
fun stop() {
override fun onStop() {
if (isStarted.compareAndSet(true, false)) {
eventBus.unregister(this)
BACKGROUND_HANDLER.post {

View file

@ -17,6 +17,7 @@
package im.vector.matrix.android.internal.database
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.util.createBackgroundHandler
import io.realm.OrderedRealmCollectionChangeListener
import io.realm.Realm
@ -29,12 +30,7 @@ import kotlinx.coroutines.cancelChildren
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
internal interface LiveEntityObserver {
fun start()
fun dispose()
fun cancelProcess()
fun isStarted(): Boolean
}
internal interface LiveEntityObserver: SessionLifecycleObserver
internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val realmConfiguration: RealmConfiguration)
: LiveEntityObserver, OrderedRealmCollectionChangeListener<RealmResults<T>> {
@ -49,7 +45,7 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val r
private val backgroundRealm = AtomicReference<Realm>()
private lateinit var results: AtomicReference<RealmResults<T>>
override fun start() {
override fun onStart() {
if (isStarted.compareAndSet(false, true)) {
BACKGROUND_HANDLER.post {
val realm = Realm.getInstance(realmConfiguration)
@ -61,7 +57,7 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val r
}
}
override fun dispose() {
override fun onStop() {
if (isStarted.compareAndSet(true, false)) {
BACKGROUND_HANDLER.post {
results.getAndSet(null).removeAllChangeListeners()
@ -73,11 +69,7 @@ internal abstract class RealmLiveEntityObserver<T : RealmObject>(protected val r
}
}
override fun cancelProcess() {
override fun onClearCache() {
observerScope.coroutineContext.cancelChildren()
}
override fun isStarted(): Boolean {
return isStarted.get()
}
}

View file

@ -54,7 +54,6 @@ internal class RoomSummaryMapper @Inject constructor(private val timelineEventMa
aliases = roomSummaryEntity.aliases.toList(),
isEncrypted = roomSummaryEntity.isEncrypted,
encryptionEventTs = roomSummaryEntity.encryptionEventTs,
typingRoomMemberIds = roomSummaryEntity.typingUserIds.toList(),
breadcrumbsIndex = roomSummaryEntity.breadcrumbsIndex,
roomEncryptionTrustLevel = roomSummaryEntity.roomEncryptionTrustLevel,
inviterId = roomSummaryEntity.inviterId

View file

@ -49,7 +49,6 @@ internal open class RoomSummaryEntity(
var flatAliases: String = "",
var isEncrypted: Boolean = false,
var encryptionEventTs: Long? = 0,
var typingUserIds: RealmList<String> = RealmList(),
var roomEncryptionTrustLevelStr: String? = null,
var inviterId: String? = null
) : RealmObject() {

View file

@ -15,15 +15,15 @@
*/
package im.vector.matrix.android.internal.database.query
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.events.model.LocalEcho
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.ReadMarkerEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import io.realm.Realm
import io.realm.RealmConfiguration
internal fun isEventRead(monarchy: Monarchy,
internal fun isEventRead(realmConfiguration: RealmConfiguration,
userId: String?,
roomId: String?,
eventId: String?): Boolean {
@ -35,14 +35,14 @@ internal fun isEventRead(monarchy: Monarchy,
}
var isEventRead = false
monarchy.doWithRealm { realm ->
val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@doWithRealm
Realm.getInstance(realmConfiguration).use { realm ->
val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use
val eventToCheck = liveChunk.timelineEvents.find(eventId)
isEventRead = if (eventToCheck == null || eventToCheck.root?.sender == userId) {
true
} else {
val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst()
?: return@doWithRealm
?: return@use
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex
?: Int.MIN_VALUE
val eventToCheckIndex = eventToCheck.displayIndex
@ -54,13 +54,13 @@ internal fun isEventRead(monarchy: Monarchy,
return isEventRead
}
internal fun isReadMarkerMoreRecent(monarchy: Monarchy,
internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration,
roomId: String?,
eventId: String?): Boolean {
if (roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
return false
}
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
return Realm.getInstance(realmConfiguration).use { realm ->
val eventToCheck = TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst()
val eventToCheckChunk = eventToCheck?.chunk?.firstOrNull()
val readMarker = ReadMarkerEntity.where(realm, roomId).findFirst() ?: return false

View file

@ -46,12 +46,11 @@ import im.vector.matrix.android.api.session.signout.SignOutService
import im.vector.matrix.android.api.session.sync.FilterService
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.api.session.terms.TermsService
import im.vector.matrix.android.api.session.typing.TypingUsersTracker
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.api.session.widgets.WidgetService
import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.crypto.crosssigning.ShieldTrustUpdater
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.identity.DefaultIdentityService
@ -59,9 +58,9 @@ import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecr
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
import im.vector.matrix.android.internal.session.sync.job.SyncThread
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
import im.vector.matrix.android.internal.session.widgets.WidgetDependenciesHolder
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import im.vector.matrix.android.internal.util.createUIHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
@ -78,7 +77,7 @@ internal class DefaultSession @Inject constructor(
private val eventBus: EventBus,
@SessionId
override val sessionId: String,
private val liveEntityObservers: Set<@JvmSuppressWildcards LiveEntityObserver>,
private val lifecycleObservers: Set<@JvmSuppressWildcards SessionLifecycleObserver>,
private val sessionListeners: SessionListeners,
private val roomService: Lazy<RoomService>,
private val roomDirectoryService: Lazy<RoomDirectoryService>,
@ -100,6 +99,7 @@ internal class DefaultSession @Inject constructor(
private val syncTokenStore: SyncTokenStore,
private val sessionParamsStore: SessionParamsStore,
private val contentUploadProgressTracker: ContentUploadStateTracker,
private val typingUsersTracker: TypingUsersTracker,
private val initialSyncProgressService: Lazy<InitialSyncProgressService>,
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>,
private val accountDataService: Lazy<AccountDataService>,
@ -110,8 +110,6 @@ internal class DefaultSession @Inject constructor(
private val defaultIdentityService: DefaultIdentityService,
private val integrationManagerService: IntegrationManagerService,
private val taskExecutor: TaskExecutor,
private val widgetDependenciesHolder: WidgetDependenciesHolder,
private val shieldTrustUpdater: ShieldTrustUpdater,
private val callSignalingService: Lazy<CallSignalingService>)
: Session,
RoomService by roomService.get(),
@ -138,6 +136,8 @@ internal class DefaultSession @Inject constructor(
private var syncThread: SyncThread? = null
private val uiHandler = createUIHandler()
override val isOpenable: Boolean
get() = sessionParamsStore.get(sessionId)?.isTokenValid ?: false
@ -145,12 +145,11 @@ internal class DefaultSession @Inject constructor(
override fun open() {
assert(!isOpen)
isOpen = true
liveEntityObservers.forEach { it.start() }
uiHandler.post {
lifecycleObservers.forEach { it.onStart() }
}
eventBus.register(this)
timelineEventDecryptor.start()
shieldTrustUpdater.start()
defaultIdentityService.start()
widgetDependenciesHolder.start()
}
override fun requireBackgroundSync() {
@ -188,16 +187,12 @@ internal class DefaultSession @Inject constructor(
assert(isOpen)
stopSync()
timelineEventDecryptor.destroy()
liveEntityObservers.forEach { it.dispose() }
uiHandler.post {
lifecycleObservers.forEach { it.onStop() }
}
cryptoService.get().close()
isOpen = false
eventBus.unregister(this)
shieldTrustUpdater.stop()
taskExecutor.executorScope.launch(coroutineDispatchers.main) {
// This has to be done on main thread
defaultIdentityService.stop()
widgetDependenciesHolder.stop()
}
}
override fun getSyncStateLive(): LiveData<SyncState> {
@ -217,7 +212,9 @@ internal class DefaultSession @Inject constructor(
override fun clearCache(callback: MatrixCallback<Unit>) {
stopSync()
stopAnyBackgroundSync()
liveEntityObservers.forEach { it.cancelProcess() }
uiHandler.post {
lifecycleObservers.forEach { it.onClearCache() }
}
cacheService.get().clearCache(callback)
workManagerProvider.cancelAllWorks()
}
@ -239,6 +236,8 @@ internal class DefaultSession @Inject constructor(
override fun contentUploadProgressTracker() = contentUploadProgressTracker
override fun typingUsersTracker() = typingUsersTracker
override fun cryptoService(): CryptoService = cryptoService.get()
override fun identityService() = defaultIdentityService

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020 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
import androidx.annotation.MainThread
/**
* This defines methods associated with some lifecycle events of a session.
* A list of SessionLifecycle will be injected into [DefaultSession]
*/
internal interface SessionLifecycleObserver {
/*
Called when the session is opened
*/
@MainThread
fun onStart() {
// noop
}
/*
Called when the session is cleared
*/
@MainThread
fun onClearCache() {
// noop
}
/*
Called when the session is closed
*/
@MainThread
fun onStop() {
// noop
}
}

View file

@ -36,9 +36,10 @@ import im.vector.matrix.android.api.session.accountdata.AccountDataService
import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesService
import im.vector.matrix.android.api.session.securestorage.SecureStorageService
import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService
import im.vector.matrix.android.api.session.typing.TypingUsersTracker
import im.vector.matrix.android.internal.crypto.crosssigning.ShieldTrustUpdater
import im.vector.matrix.android.internal.crypto.secrets.DefaultSharedSecretStorageService
import im.vector.matrix.android.internal.crypto.verification.VerificationMessageLiveObserver
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory
import im.vector.matrix.android.internal.di.Authenticated
import im.vector.matrix.android.internal.di.DeviceId
@ -62,12 +63,16 @@ import im.vector.matrix.android.internal.network.token.HomeserverAccessTokenProv
import im.vector.matrix.android.internal.session.call.CallEventObserver
import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater
import im.vector.matrix.android.internal.session.homeserver.DefaultHomeServerCapabilitiesService
import im.vector.matrix.android.internal.session.identity.DefaultIdentityService
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater
import im.vector.matrix.android.internal.session.room.create.RoomCreateEventLiveObserver
import im.vector.matrix.android.internal.session.room.prune.EventsPruner
import im.vector.matrix.android.internal.session.room.tombstone.RoomTombstoneEventLiveObserver
import im.vector.matrix.android.internal.session.securestorage.DefaultSecureStorageService
import im.vector.matrix.android.internal.session.typing.DefaultTypingUsersTracker
import im.vector.matrix.android.internal.session.user.accountdata.DefaultAccountDataService
import im.vector.matrix.android.internal.session.widgets.DefaultWidgetURLFormatter
import im.vector.matrix.android.internal.util.md5
import io.realm.RealmConfiguration
import okhttp3.OkHttpClient
@ -164,9 +169,9 @@ internal abstract class SessionModule {
@JvmStatic
@Provides
@SessionDatabase
@SessionScope
fun providesMonarchy(@SessionDatabase
realmConfiguration: RealmConfiguration): Monarchy {
fun providesMonarchy(@SessionDatabase realmConfiguration: RealmConfiguration): Monarchy {
return Monarchy.Builder()
.setRealmConfiguration(realmConfiguration)
.build()
@ -234,31 +239,47 @@ internal abstract class SessionModule {
@Binds
@IntoSet
abstract fun bindGroupSummaryUpdater(updater: GroupSummaryUpdater): LiveEntityObserver
abstract fun bindGroupSummaryUpdater(updater: GroupSummaryUpdater): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindEventsPruner(pruner: EventsPruner): LiveEntityObserver
abstract fun bindEventsPruner(pruner: EventsPruner): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindEventRelationsAggregationUpdater(updater: EventRelationsAggregationUpdater): LiveEntityObserver
abstract fun bindEventRelationsAggregationUpdater(updater: EventRelationsAggregationUpdater): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindCallEventObserver(observer: CallEventObserver): LiveEntityObserver
abstract fun bindRoomTombstoneEventLiveObserver(observer: RoomTombstoneEventLiveObserver): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindRoomTombstoneEventLiveObserver(observer: RoomTombstoneEventLiveObserver): LiveEntityObserver
abstract fun bindRoomCreateEventLiveObserver(observer: RoomCreateEventLiveObserver): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindRoomCreateEventLiveObserver(observer: RoomCreateEventLiveObserver): LiveEntityObserver
abstract fun bindVerificationMessageLiveObserver(observer: VerificationMessageLiveObserver): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindVerificationMessageLiveObserver(observer: VerificationMessageLiveObserver): LiveEntityObserver
abstract fun bindCallEventObserver(observer: CallEventObserver): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindIntegrationManager(observer: IntegrationManager): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindWidgetUrlFormatter(observer: DefaultWidgetURLFormatter): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindShieldTrustUpdated(observer: ShieldTrustUpdater): SessionLifecycleObserver
@Binds
@IntoSet
abstract fun bindIdentityService(observer: DefaultIdentityService): SessionLifecycleObserver
@Binds
abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService
@ -274,4 +295,7 @@ internal abstract class SessionModule {
@Binds
abstract fun bindSharedSecretStorageService(service: DefaultSharedSecretStorageService): SharedSecretStorageService
@Binds
abstract fun bindTypingUsersTracker(tracker: DefaultTypingUsersTracker): TypingUsersTracker
}

View file

@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.crypto.MXCryptoError
import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
@ -37,7 +38,7 @@ internal interface CallEventsObserverTask : Task<CallEventsObserverTask.Params,
}
internal class DefaultCallEventsObserverTask @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val cryptoService: CryptoService,
private val callService: DefaultCallSignalingService) : CallEventsObserverTask {

View file

@ -21,12 +21,13 @@ import im.vector.matrix.android.internal.database.model.FilterEntity
import im.vector.matrix.android.internal.database.model.FilterEntityFields
import im.vector.matrix.android.internal.database.query.get
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
import io.realm.kotlin.where
import javax.inject.Inject
internal class DefaultFilterRepository @Inject constructor(private val monarchy: Monarchy) : FilterRepository {
internal class DefaultFilterRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : FilterRepository {
override suspend fun storeFilter(filter: Filter, roomEventFilter: RoomEventFilter): Boolean {
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->

View file

@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.group.model.GroupRooms
import im.vector.matrix.android.internal.session.group.model.GroupSummaryResponse
@ -36,7 +37,7 @@ internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
internal class DefaultGetGroupDataTask @Inject constructor(
private val groupAPI: GroupAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus
) : GetGroupDataTask {

View file

@ -26,13 +26,14 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.model.GroupSummaryEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.query.process
import im.vector.matrix.android.internal.util.fetchCopyMap
import io.realm.Realm
import io.realm.RealmQuery
import javax.inject.Inject
internal class DefaultGroupService @Inject constructor(private val monarchy: Monarchy) : GroupService {
internal class DefaultGroupService @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : GroupService {
override fun getGroup(groupId: String): Group? {
return null

View file

@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.database.awaitTransaction
import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
@ -37,7 +38,7 @@ private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
internal class GroupSummaryUpdater @Inject constructor(
private val workManagerProvider: WorkManagerProvider,
@SessionId private val sessionId: String,
private val monarchy: Monarchy)
@SessionDatabase private val monarchy: Monarchy)
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
override val query = Monarchy.Query { GroupEntity.where(it) }

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.auth.version.Versions
import im.vector.matrix.android.internal.auth.version.isLoginAndRegistrationSupportedBySdk
import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManagerConfigExtractor
@ -38,7 +39,7 @@ internal interface GetHomeServerCapabilitiesTask : Task<Unit, Unit>
internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
private val capabilitiesAPI: CapabilitiesAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus,
private val getWellknownTask: GetWellknownTask,
private val configExtractor: IntegrationManagerConfigExtractor,

View file

@ -22,10 +22,11 @@ import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesSer
import im.vector.matrix.android.internal.database.mapper.HomeServerCapabilitiesMapper
import im.vector.matrix.android.internal.database.model.HomeServerCapabilitiesEntity
import im.vector.matrix.android.internal.database.query.get
import im.vector.matrix.android.internal.di.SessionDatabase
import io.realm.Realm
import javax.inject.Inject
internal class DefaultHomeServerCapabilitiesService @Inject constructor(private val monarchy: Monarchy) : HomeServerCapabilitiesService {
internal class DefaultHomeServerCapabilitiesService @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : HomeServerCapabilitiesService {
override fun getHomeServerCapabilities(): HomeServerCapabilities {
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->

View file

@ -39,6 +39,7 @@ import im.vector.matrix.android.internal.di.AuthenticatedIdentity
import im.vector.matrix.android.internal.di.Unauthenticated
import im.vector.matrix.android.internal.extensions.observeNotNull
import im.vector.matrix.android.internal.network.RetrofitFactory
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.identity.data.IdentityStore
import im.vector.matrix.android.internal.session.openid.GetOpenIdTokenTask
@ -82,14 +83,14 @@ internal class DefaultIdentityService @Inject constructor(
private val homeServerCapabilitiesService: HomeServerCapabilitiesService,
private val sessionParams: SessionParams,
private val taskExecutor: TaskExecutor
) : IdentityService {
) : IdentityService, SessionLifecycleObserver {
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
private val listeners = mutableSetOf<IdentityServiceListener>()
fun start() {
override fun onStart() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
// Observe the account data change
accountDataDataSource
@ -114,7 +115,7 @@ internal class DefaultIdentityService @Inject constructor(
}
}
fun stop() {
override fun onStop() {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}

View file

@ -30,7 +30,9 @@ import im.vector.matrix.android.api.session.widgets.model.WidgetType
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.NoOpCancellable
import im.vector.matrix.android.internal.database.model.WellknownIntegrationManagerConfigEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.extensions.observeNotNull
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
@ -58,10 +60,11 @@ import javax.inject.Inject
@SessionScope
internal class IntegrationManager @Inject constructor(matrixConfiguration: MatrixConfiguration,
private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val accountDataDataSource: AccountDataDataSource,
private val widgetFactory: WidgetFactory) {
private val widgetFactory: WidgetFactory)
: SessionLifecycleObserver {
private val currentConfigs = ArrayList<IntegrationManagerConfig>()
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
@ -80,7 +83,7 @@ internal class IntegrationManager @Inject constructor(matrixConfiguration: Matri
currentConfigs.add(defaultConfig)
}
fun start() {
override fun onStart() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
observeWellknownConfig()
accountDataDataSource
@ -108,7 +111,7 @@ internal class IntegrationManager @Inject constructor(matrixConfiguration: Matri
}
}
fun stop() {
override fun onStop() {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}

View file

@ -28,6 +28,7 @@ import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
import im.vector.matrix.android.internal.database.model.PushRulesEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask
@ -47,7 +48,7 @@ internal class DefaultPushRuleService @Inject constructor(
private val updatePushRuleActionsTask: UpdatePushRuleActionsTask,
private val removePushRuleTask: RemovePushRuleTask,
private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy
@SessionDatabase private val monarchy: Monarchy
) : PushRuleService {
private var listeners = mutableSetOf<PushRuleService.PushRuleListener>()

View file

@ -26,13 +26,14 @@ import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import io.realm.kotlin.where
import javax.inject.Inject
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
private val getProfileInfoTask: GetProfileInfoTask,
private val setDisplayNameTask: SetDisplayNameTask) : ProfileService {

View file

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.profile
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
@ -27,7 +28,7 @@ import javax.inject.Inject
internal abstract class RefreshUserThreePidsTask : Task<Unit, Unit>
internal class DefaultRefreshUserThreePidsTask @Inject constructor(private val profileAPI: ProfileAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus) : RefreshUserThreePidsTask() {
override suspend fun execute(params: Unit) {

View file

@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.pushers.PusherState
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.util.awaitTransaction
import im.vector.matrix.android.internal.worker.SessionWorkerParams
@ -45,7 +46,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
) : SessionWorkerParams
@Inject lateinit var pushersAPI: PushersAPI
@Inject lateinit var monarchy: Monarchy
@Inject @SessionDatabase lateinit var monarchy: Monarchy
@Inject lateinit var eventBus: EventBus
override suspend fun doWork(): Result {

View file

@ -25,6 +25,7 @@ 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.PusherEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.task.TaskExecutor
@ -37,7 +38,7 @@ import javax.inject.Inject
internal class DefaultPushersService @Inject constructor(
private val workManagerProvider: WorkManagerProvider,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
@SessionId private val sessionId: String,
private val getPusherTask: GetPushersTask,
private val removePusherTask: RemovePusherTask,

View file

@ -19,6 +19,7 @@ import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.pushers.PusherState
import im.vector.matrix.android.internal.database.mapper.toEntity
import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
@ -29,7 +30,7 @@ internal interface GetPushersTask : Task<Unit, Unit>
internal class DefaultGetPushersTask @Inject constructor(
private val pushersAPI: PushersAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus
) : GetPushersTask {

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.pushers.PusherState
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
@ -35,7 +36,7 @@ internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
internal class DefaultRemovePusherTask @Inject constructor(
private val pushersAPI: PushersAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus
) : RemovePusherTask {

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.pushrules.RuleSetKey
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
import im.vector.matrix.android.internal.database.model.PushRulesEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import javax.inject.Inject
@ -32,7 +33,7 @@ internal interface SavePushRulesTask : Task<SavePushRulesTask.Params, Unit> {
data class Params(val pushRules: GetPushRulesResponse)
}
internal class DefaultSavePushRulesTask @Inject constructor(private val monarchy: Monarchy) : SavePushRulesTask {
internal class DefaultSavePushRulesTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : SavePushRulesTask {
override suspend fun execute(params: SavePushRulesTask.Params) {
monarchy.awaitTransaction { realm ->

View file

@ -17,8 +17,6 @@
package im.vector.matrix.android.internal.session.room
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.events.model.EventType
@ -38,21 +36,16 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.session.room.typing.TypingService
import im.vector.matrix.android.api.session.room.uploads.UploadsService
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.room.state.SendStateTask
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import java.security.InvalidParameterException
import javax.inject.Inject
internal class DefaultRoom @Inject constructor(override val roomId: String,
private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper,
private val roomSummaryDataSource: RoomSummaryDataSource,
private val timelineService: TimelineService,
private val sendService: SendService,
private val draftService: DraftService,
@ -85,20 +78,11 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
RoomPushRuleService by roomPushRuleService {
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
{ roomSummaryMapper.map(it) }
)
return Transformations.map(liveData) { results ->
results.firstOrNull().toOptional()
}
return roomSummaryDataSource.getRoomSummaryLive(roomId)
}
override fun roomSummary(): RoomSummary? {
return monarchy.fetchAllMappedSync(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
{ roomSummaryMapper.map(it) }
).firstOrNull()
return roomSummaryDataSource.getRoomSummary(roomId)
}
override fun isEncrypted(): Boolean {

View file

@ -17,43 +17,32 @@
package im.vector.matrix.android.internal.session.room
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
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.RoomSummaryQueryParams
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.VersioningState
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
import im.vector.matrix.android.internal.database.query.findByAlias
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.query.process
import im.vector.matrix.android.internal.session.room.alias.GetRoomIdByAliasTask
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask
import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource
import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcrumbsTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.fetchCopyMap
import io.realm.Realm
import io.realm.RealmQuery
import javax.inject.Inject
internal class DefaultRoomService @Inject constructor(
private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper,
private val createRoomTask: CreateRoomTask,
private val joinRoomTask: JoinRoomTask,
private val markAllRoomsReadTask: MarkAllRoomsReadTask,
private val updateBreadcrumbsTask: UpdateBreadcrumbsTask,
private val roomIdByAliasTask: GetRoomIdByAliasTask,
private val roomGetter: RoomGetter,
private val roomSummaryDataSource: RoomSummaryDataSource,
private val taskExecutor: TaskExecutor
) : RoomService {
@ -74,61 +63,23 @@ internal class DefaultRoomService @Inject constructor(
}
override fun getRoomSummary(roomIdOrAlias: String): RoomSummary? {
return monarchy
.fetchCopyMap({
if (roomIdOrAlias.startsWith("!")) {
// It's a roomId
RoomSummaryEntity.where(it, roomId = roomIdOrAlias).findFirst()
} else {
// Assume it's a room alias
RoomSummaryEntity.findByAlias(it, roomIdOrAlias)
}
}, { entity, _ ->
roomSummaryMapper.map(entity)
})
return roomSummaryDataSource.getRoomSummary(roomIdOrAlias)
}
override fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
return monarchy.fetchAllMappedSync(
{ roomSummariesQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
return roomSummaryDataSource.getRoomSummaries(queryParams)
}
override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
return monarchy.findAllMappedWithChanges(
{ roomSummariesQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
val query = RoomSummaryEntity.where(realm)
query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
query.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name)
return query
return roomSummaryDataSource.getRoomSummariesLive(queryParams)
}
override fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
return monarchy.fetchAllMappedSync(
{ breadcrumbsQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
return roomSummaryDataSource.getBreadcrumbs(queryParams)
}
override fun getBreadcrumbsLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
return monarchy.findAllMappedWithChanges(
{ breadcrumbsQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
private fun breadcrumbsQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
return roomSummariesQuery(realm, queryParams)
.greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummary.NOT_IN_BREADCRUMBS)
.sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX)
return roomSummaryDataSource.getBreadcrumbsLive(queryParams)
}
override fun onRoomDisplayed(roomId: String): Cancelable {

View file

@ -47,6 +47,7 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.create
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
@ -92,7 +93,7 @@ private fun VerificationState?.toState(newState: VerificationState): Verificatio
* Called by EventRelationAggregationUpdater, when new events that can affect relations are inserted in base.
*/
internal class DefaultEventRelationsAggregationTask @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val cryptoService: CryptoService) : EventRelationsAggregationTask {
// OPT OUT serer aggregation until API mature enough

View file

@ -16,7 +16,6 @@
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.events.model.toModel
import im.vector.matrix.android.api.session.room.model.RoomAvatarContent
@ -26,33 +25,32 @@ import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityF
import im.vector.matrix.android.internal.database.query.getOrNull
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import io.realm.Realm
import javax.inject.Inject
internal class RoomAvatarResolver @Inject constructor(private val monarchy: Monarchy,
@UserId private val userId: String) {
internal class RoomAvatarResolver @Inject constructor(@UserId private val userId: String) {
/**
* Compute the room avatar url
* @param realm: the current instance of realm
* @param roomId the roomId of the room to resolve avatar
* @return the room avatar url, can be a fallback to a room member avatar or null
*/
fun resolve(roomId: String): String? {
var res: String? = null
monarchy.doWithRealm { realm ->
val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_AVATAR, stateKey = "")?.root
res = ContentMapper.map(roomName?.content).toModel<RoomAvatarContent>()?.avatarUrl
if (!res.isNullOrEmpty()) {
return@doWithRealm
}
val roomMembers = RoomMemberHelper(realm, roomId)
val members = roomMembers.queryActiveRoomMembersEvent().findAll()
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
if (members.size == 1) {
res = members.firstOrNull()?.avatarUrl
} else if (members.size == 2) {
val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst()
res = firstOtherMember?.avatarUrl
}
fun resolve(realm: Realm, roomId: String): String? {
var res: String?
val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_AVATAR, stateKey = "")?.root
res = ContentMapper.map(roomName?.content).toModel<RoomAvatarContent>()?.avatarUrl
if (!res.isNullOrEmpty()) {
return res
}
val roomMembers = RoomMemberHelper(realm, roomId)
val members = roomMembers.queryActiveRoomMembersEvent().findAll()
// detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat)
if (members.size == 1) {
res = members.firstOrNull()?.avatarUrl
} else if (members.size == 2) {
val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst()
res = firstOtherMember?.avatarUrl
}
return res
}

View file

@ -16,10 +16,8 @@
package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.crypto.CryptoService
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.room.call.DefaultRoomCallService
import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService
@ -31,6 +29,7 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReporting
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
import im.vector.matrix.android.internal.session.room.state.DefaultStateService
import im.vector.matrix.android.internal.session.room.state.SendStateTask
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource
import im.vector.matrix.android.internal.session.room.tags.DefaultTagsService
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
import im.vector.matrix.android.internal.session.room.typing.DefaultTypingService
@ -43,9 +42,8 @@ internal interface RoomFactory {
}
@SessionScope
internal class DefaultRoomFactory @Inject constructor(private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper,
private val cryptoService: CryptoService,
internal class DefaultRoomFactory @Inject constructor(private val cryptoService: CryptoService,
private val roomSummaryDataSource: RoomSummaryDataSource,
private val timelineServiceFactory: DefaultTimelineService.Factory,
private val sendServiceFactory: DefaultSendService.Factory,
private val draftServiceFactory: DefaultDraftService.Factory,
@ -66,8 +64,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
override fun create(roomId: String): Room {
return DefaultRoom(
roomId = roomId,
monarchy = monarchy,
roomSummaryMapper = roomSummaryMapper,
roomSummaryDataSource = roomSummaryDataSource,
timelineService = timelineServiceFactory.create(roomId),
sendService = sendServiceFactory.create(roomId),
draftService = draftServiceFactory.create(roomId),

View file

@ -23,6 +23,7 @@ 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.model.RoomSummaryEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import io.realm.Realm
@ -36,7 +37,7 @@ internal interface RoomGetter {
@SessionScope
internal class DefaultRoomGetter @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val roomFactory: RoomFactory
) : RoomGetter {

View file

@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.query.findByAlias
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task
@ -35,7 +36,7 @@ internal interface GetRoomIdByAliasTask : Task<GetRoomIdByAliasTask.Params, Opti
}
internal class DefaultGetRoomIdByAliasTask @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val roomAPI: RoomAPI,
private val eventBus: EventBus
) : GetRoomIdByAliasTask {

View file

@ -45,7 +45,7 @@ internal interface CreateRoomTask : Task<CreateRoomParams, String>
internal class DefaultCreateRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val readMarkersTask: SetReadMarkersTask,

View file

@ -26,13 +26,14 @@ import im.vector.matrix.android.internal.database.model.DraftEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.UserDraftsEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
import io.realm.kotlin.createObject
import timber.log.Timber
import javax.inject.Inject
class DraftRepository @Inject constructor(private val monarchy: Monarchy) {
class DraftRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
suspend fun saveDraft(roomId: String, userDraft: UserDraft) {
monarchy.awaitTransaction {

View file

@ -29,6 +29,7 @@ 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.RoomMemberSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityFields
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.query.process
import im.vector.matrix.android.internal.session.room.membership.admin.MembershipAdminTask
@ -43,7 +44,7 @@ import io.realm.RealmQuery
internal class DefaultMembershipService @AssistedInject constructor(
@Assisted private val roomId: String,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val inviteTask: InviteTask,

View file

@ -25,9 +25,10 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.copyToRealmOrIgnore
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
@ -46,7 +47,7 @@ internal interface LoadRoomMembersTask : Task<LoadRoomMembersTask.Params, Unit>
internal class DefaultLoadRoomMembersTask @Inject constructor(
private val roomAPI: RoomAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val syncTokenStore: SyncTokenStore,
private val roomSummaryUpdater: RoomSummaryUpdater,
private val roomMemberEventHandler: RoomMemberEventHandler,

View file

@ -17,7 +17,6 @@
package im.vector.matrix.android.internal.session.room.membership
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.events.model.toModel
@ -34,94 +33,91 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.query.getOrNull
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.UserId
import io.realm.Realm
import javax.inject.Inject
/**
* This class computes room display name
*/
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
private val monarchy: Monarchy,
@UserId private val userId: String
) {
/**
* Compute the room display name
*
* @param realm: the current instance of realm
* @param roomId: the roomId to resolve the name of.
* @return the room display name
*/
fun resolve(roomId: String): CharSequence {
fun resolve(realm: Realm, roomId: String): 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 roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()
val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root
name = ContentMapper.map(roomName?.content).toModel<RoomNameContent>()?.name
if (!name.isNullOrEmpty()) {
return@doWithRealm
var name: CharSequence?
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()
val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root
name = ContentMapper.map(roomName?.content).toModel<RoomNameContent>()?.name
if (!name.isNullOrEmpty()) {
return name
}
val canonicalAlias = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root
name = ContentMapper.map(canonicalAlias?.content).toModel<RoomCanonicalAliasContent>()?.canonicalAlias
if (!name.isNullOrEmpty()) {
return name
}
val aliases = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ALIASES, stateKey = "")?.root
name = ContentMapper.map(aliases?.content).toModel<RoomAliasesContent>()?.aliases?.firstOrNull()
if (!name.isNullOrEmpty()) {
return name
}
val roomMembers = RoomMemberHelper(realm, roomId)
val activeMembers = roomMembers.queryActiveRoomMembersEvent().findAll()
if (roomEntity?.membership == Membership.INVITE) {
val inviteMeEvent = roomMembers.getLastStateEvent(userId)
val inviterId = inviteMeEvent?.sender
name = if (inviterId != null) {
activeMembers.where()
.equalTo(RoomMemberSummaryEntityFields.USER_ID, inviterId)
.findFirst()
?.displayName
} else {
context.getString(R.string.room_displayname_room_invite)
}
val canonicalAlias = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root
name = ContentMapper.map(canonicalAlias?.content).toModel<RoomCanonicalAliasContent>()?.canonicalAlias
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
val aliases = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ALIASES, stateKey = "")?.root
name = ContentMapper.map(aliases?.content).toModel<RoomAliasesContent>()?.aliases?.firstOrNull()
if (!name.isNullOrEmpty()) {
return@doWithRealm
}
val roomMembers = RoomMemberHelper(realm, roomId)
val activeMembers = roomMembers.queryActiveRoomMembersEvent().findAll()
if (roomEntity?.membership == Membership.INVITE) {
val inviteMeEvent = roomMembers.getLastStateEvent(userId)
val inviterId = inviteMeEvent?.sender
name = if (inviterId != null) {
activeMembers.where()
.equalTo(RoomMemberSummaryEntityFields.USER_ID, inviterId)
.findFirst()
?.displayName
} else {
context.getString(R.string.room_displayname_room_invite)
}
} else if (roomEntity?.membership == Membership.JOIN) {
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
val otherMembersSubset: List<RoomMemberSummaryEntity> = if (roomSummary?.heroes?.isNotEmpty() == true) {
roomSummary.heroes.mapNotNull { userId ->
roomMembers.getLastRoomMember(userId)?.takeIf {
it.membership == Membership.INVITE || it.membership == Membership.JOIN
}
} else if (roomEntity?.membership == Membership.JOIN) {
val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst()
val otherMembersSubset: List<RoomMemberSummaryEntity> = if (roomSummary?.heroes?.isNotEmpty() == true) {
roomSummary.heroes.mapNotNull { userId ->
roomMembers.getLastRoomMember(userId)?.takeIf {
it.membership == Membership.INVITE || it.membership == Membership.JOIN
}
} else {
activeMembers.where()
.notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
.limit(3)
.findAll()
.createSnapshot()
}
val otherMembersCount = otherMembersSubset.count()
name = when (otherMembersCount) {
0 -> context.getString(R.string.room_displayname_empty_room)
1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
2 -> context.getString(R.string.room_displayname_two_members,
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
resolveRoomMemberName(otherMembersSubset[1], roomMembers)
)
else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
roomMembers.getNumberOfJoinedMembers() - 1,
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
roomMembers.getNumberOfJoinedMembers() - 1)
}
} else {
activeMembers.where()
.notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId)
.limit(3)
.findAll()
.createSnapshot()
}
val otherMembersCount = otherMembersSubset.count()
name = when (otherMembersCount) {
0 -> context.getString(R.string.room_displayname_empty_room)
1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers)
2 -> context.getString(R.string.room_displayname_two_members,
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
resolveRoomMemberName(otherMembersSubset[1], roomMembers)
)
else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members,
roomMembers.getNumberOfJoinedMembers() - 1,
resolveRoomMemberName(otherMembersSubset[0], roomMembers),
roomMembers.getNumberOfJoinedMembers() - 1)
}
return@doWithRealm
}
return name ?: roomId
}

View file

@ -28,12 +28,13 @@ import im.vector.matrix.android.api.session.room.notification.RoomPushRuleServic
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.database.model.PushRuleEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
internal class DefaultRoomPushRuleService @AssistedInject constructor(@Assisted private val roomId: String,
private val setRoomNotificationStateTask: SetRoomNotificationStateTask,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor)
: RoomPushRuleService {

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.pushrules.RuleScope
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
import im.vector.matrix.android.internal.database.model.PushRuleEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask
import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask
import im.vector.matrix.android.internal.task.Task
@ -34,7 +35,7 @@ internal interface SetRoomNotificationStateTask : Task<SetRoomNotificationStateT
)
}
internal class DefaultSetRoomNotificationStateTask @Inject constructor(private val monarchy: Monarchy,
internal class DefaultSetRoomNotificationStateTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val removePushRuleTask: RemovePushRuleTask,
private val addPushRuleTask: AddPushRuleTask)
: SetRoomNotificationStateTask {

View file

@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.findWithSenderMembershipEvent
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
@ -40,7 +41,7 @@ internal interface PruneEventTask : Task<PruneEventTask.Params, Unit> {
)
}
internal class DefaultPruneEventTask @Inject constructor(private val monarchy: Monarchy) : PruneEventTask {
internal class DefaultPruneEventTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : PruneEventTask {
override suspend fun execute(params: PruneEventTask.Params) {
monarchy.awaitTransaction { realm ->

View file

@ -32,13 +32,14 @@ import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity
import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
internal class DefaultReadService @AssistedInject constructor(
@Assisted private val roomId: String,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor,
private val setReadMarkersTask: SetReadMarkersTask,
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper,
@ -82,7 +83,7 @@ internal class DefaultReadService @AssistedInject constructor(
}
override fun isEventRead(eventId: String): Boolean {
return isEventRead(monarchy, userId, roomId, eventId)
return isEventRead(monarchy.realmConfiguration, userId, roomId, eventId)
}
override fun getReadMarkerLive(): LiveData<Optional<String>> {

View file

@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.isReadMarkerMoreRecent
import im.vector.matrix.android.internal.database.query.latestEvent
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
@ -53,7 +54,7 @@ private const val READ_RECEIPT = "m.read"
internal class DefaultSetReadMarkersTask @Inject constructor(
private val roomAPI: RoomAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val roomFullyReadHandler: RoomFullyReadHandler,
private val readReceiptHandler: ReadReceiptHandler,
@UserId private val userId: String,
@ -74,7 +75,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(
} else {
params.readReceiptEventId
}
if (fullyReadEventId != null && !isReadMarkerMoreRecent(monarchy, params.roomId, fullyReadEventId)) {
if (fullyReadEventId != null && !isReadMarkerMoreRecent(monarchy.realmConfiguration, params.roomId, fullyReadEventId)) {
if (LocalEcho.isLocalEchoId(fullyReadEventId)) {
Timber.w("Can't set read marker for local event $fullyReadEventId")
} else {
@ -82,7 +83,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(
}
}
if (readReceiptEventId != null
&& !isEventRead(monarchy, userId, params.roomId, readReceiptEventId)) {
&& !isEventRead(monarchy.realmConfiguration, userId, params.roomId, readReceiptEventId)) {
if (LocalEcho.isLocalEchoId(readReceiptEventId)) {
Timber.w("Can't set read receipt for local event $readReceiptEventId")
} else {

View file

@ -37,6 +37,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
@ -58,7 +59,7 @@ internal class DefaultRelationService @AssistedInject constructor(
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
private val fetchEditHistoryTask: FetchEditHistoryTask,
private val timelineEventMapper: TimelineEventMapper,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val taskExecutor: TaskExecutor)
: RelationService {

View file

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryE
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.task.Task
import io.realm.Realm
@ -39,7 +40,7 @@ internal interface FindReactionEventForUndoTask : Task<FindReactionEventForUndoT
}
internal class DefaultFindReactionEventForUndoTask @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
@UserId private val userId: String) : FindReactionEventForUndoTask {
override suspend fun execute(params: FindReactionEventForUndoTask.Params): FindReactionEventForUndoTask.Result {

View file

@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryE
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.model.ReactionAggregatedSummaryEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.task.Task
import io.realm.Realm
@ -40,7 +41,7 @@ internal interface UpdateQuickReactionTask : Task<UpdateQuickReactionTask.Params
)
}
internal class DefaultUpdateQuickReactionTask @Inject constructor(private val monarchy: Monarchy,
internal class DefaultUpdateQuickReactionTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
@UserId private val userId: String) : UpdateQuickReactionTask {
override suspend fun execute(params: UpdateQuickReactionTask.Params): UpdateQuickReactionTask.Result {

View file

@ -33,7 +33,8 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline
import im.vector.matrix.android.internal.util.awaitTransaction
@ -42,7 +43,7 @@ import org.greenrobot.eventbus.EventBus
import timber.log.Timber
import javax.inject.Inject
internal class LocalEchoRepository @Inject constructor(private val monarchy: Monarchy,
internal class LocalEchoRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val roomSummaryUpdater: RoomSummaryUpdater,
private val eventBus: EventBus,
private val timelineEventMapper: TimelineEventMapper) {

View file

@ -24,10 +24,11 @@ import im.vector.matrix.android.internal.crypto.MXEventDecryptionResult
import im.vector.matrix.android.internal.database.mapper.ContentMapper
import im.vector.matrix.android.internal.database.model.EventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import timber.log.Timber
import javax.inject.Inject
internal class LocalEchoUpdater @Inject constructor(private val monarchy: Monarchy) {
internal class LocalEchoUpdater @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
fun updateSendState(eventId: String, sendState: SendState) {
Timber.v("Update local state of $eventId to ${sendState.name}")

View file

@ -26,13 +26,14 @@ import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.query.process
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.kotlin.where
import javax.inject.Inject
internal class StateEventDataSource @Inject constructor(private val monarchy: Monarchy) {
internal class StateEventDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
fun getStateEvent(roomId: String, eventType: String, stateKey: QueryStringValue): Event? {
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2020 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.summary
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.model.VersioningState
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
import im.vector.matrix.android.internal.database.query.findByAlias
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.query.process
import im.vector.matrix.android.internal.util.fetchCopyMap
import io.realm.Realm
import io.realm.RealmQuery
import javax.inject.Inject
internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper) {
fun getRoomSummary(roomIdOrAlias: String): RoomSummary? {
return monarchy
.fetchCopyMap({
if (roomIdOrAlias.startsWith("!")) {
// It's a roomId
RoomSummaryEntity.where(it, roomId = roomIdOrAlias).findFirst()
} else {
// Assume it's a room alias
RoomSummaryEntity.findByAlias(it, roomIdOrAlias)
}
}, { entity, _ ->
roomSummaryMapper.map(entity)
})
}
fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },
{ roomSummaryMapper.map(it) }
)
return Transformations.map(liveData) { results ->
results.firstOrNull().toOptional()
}
}
fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
return monarchy.fetchAllMappedSync(
{ roomSummariesQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
return monarchy.findAllMappedWithChanges(
{ roomSummariesQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List<RoomSummary> {
return monarchy.fetchAllMappedSync(
{ breadcrumbsQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
fun getBreadcrumbsLive(queryParams: RoomSummaryQueryParams): LiveData<List<RoomSummary>> {
return monarchy.findAllMappedWithChanges(
{ breadcrumbsQuery(it, queryParams) },
{ roomSummaryMapper.map(it) }
)
}
private fun breadcrumbsQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
return roomSummariesQuery(realm, queryParams)
.greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummary.NOT_IN_BREADCRUMBS)
.sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX)
}
private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery<RoomSummaryEntity> {
val query = RoomSummaryEntity.where(realm)
query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName)
query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias)
query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships)
query.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name)
return query
}
}

View file

@ -14,9 +14,8 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.room
package im.vector.matrix.android.internal.session.room.summary
import com.zhuinden.monarchy.Monarchy
import dagger.Lazy
import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel
import im.vector.matrix.android.api.session.events.model.EventType
@ -40,10 +39,10 @@ import im.vector.matrix.android.internal.database.query.isEventRead
import im.vector.matrix.android.internal.database.query.latestEvent
import im.vector.matrix.android.internal.database.query.whereType
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.room.RoomAvatarResolver
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecryptor
import im.vector.matrix.android.internal.session.sync.RoomSyncHandler
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications
import io.realm.Realm
@ -56,8 +55,7 @@ internal class RoomSummaryUpdater @Inject constructor(
private val roomDisplayNameResolver: RoomDisplayNameResolver,
private val roomAvatarResolver: RoomAvatarResolver,
private val timelineEventDecryptor: Lazy<TimelineEventDecryptor>,
private val eventBus: EventBus,
private val monarchy: Monarchy) {
private val eventBus: EventBus) {
companion object {
// TODO: maybe allow user of SDK to give that list
@ -85,7 +83,6 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummary: RoomSyncSummary? = null,
unreadNotifications: RoomSyncUnreadNotifications? = null,
updateMembers: Boolean = false,
ephemeralResult: RoomSyncHandler.EphemeralResult? = null,
inviterId: String? = null) {
val roomSummaryEntity = RoomSummaryEntity.getOrCreate(realm, roomId)
if (roomSummary != null) {
@ -121,24 +118,22 @@ internal class RoomSummaryUpdater @Inject constructor(
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
// avoid this call if we are sure there are unread events
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
|| !isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId)
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(realm, roomId).toString()
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId)
roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel<RoomTopicContent>()?.topic
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
roomSummaryEntity.canonicalAlias = ContentMapper.map(lastCanonicalAliasEvent?.content).toModel<RoomCanonicalAliasContent>()
?.canonicalAlias
val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel<RoomAliasesContent>()?.aliases
.orEmpty()
.orEmpty()
roomSummaryEntity.aliases.clear()
roomSummaryEntity.aliases.addAll(roomAliases)
roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|")
roomSummaryEntity.isEncrypted = encryptionEvent != null
roomSummaryEntity.encryptionEventTs = encryptionEvent?.originServerTs
roomSummaryEntity.typingUserIds.clear()
roomSummaryEntity.typingUserIds.addAll(ephemeralResult?.typingUserIds.orEmpty())
if (roomSummaryEntity.membership == Membership.INVITE && inviterId != null) {
roomSummaryEntity.inviterId = inviterId

View file

@ -341,6 +341,7 @@ internal class DefaultTimeline(
listeners.forEach {
it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId))
}
Timber.v("On local echo created: $onLocalEchoCreated")
inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent)
postSnapshot()
}
@ -790,11 +791,7 @@ internal class DefaultTimeline(
private fun List<TimelineEvent>.filterEventsWithSettings(): List<TimelineEvent> {
return filter {
val filterType = if (settings.filterTypes) {
settings.allowedTypes.contains(it.root.type)
} else {
true
}
val filterType = !settings.filterTypes || settings.allowedTypes.contains(it.root.type)
if (!filterType) return@filter false
val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) {
@ -805,7 +802,7 @@ internal class DefaultTimeline(
}
if (!filterEdits) return@filter false
val filterRedacted = settings.filterRedacted && it.root.isRedacted()
val filterRedacted = !settings.filterRedacted || it.root.isRedacted()
filterRedacted
}

View file

@ -31,12 +31,13 @@ import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapp
import im.vector.matrix.android.internal.database.mapper.TimelineEventMapper
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.util.fetchCopyMap
import org.greenrobot.eventbus.EventBus
internal class DefaultTimelineService @AssistedInject constructor(@Assisted private val roomId: String,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus,
private val taskExecutor: TaskExecutor,
private val contextOfEventTask: GetContextOfEventTask,

View file

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.room.timeline
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.query.findIncludingEvent
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.filter.FilterRepository
import im.vector.matrix.android.internal.session.room.RoomAPI
@ -38,7 +39,7 @@ internal interface FetchNextTokenAndPaginateTask : Task<FetchNextTokenAndPaginat
internal class DefaultFetchNextTokenAndPaginateTask @Inject constructor(
private val roomAPI: RoomAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val filterRepository: FilterRepository,
private val paginationTask: PaginationTask,
private val eventBus: EventBus

View file

@ -39,7 +39,8 @@ import im.vector.matrix.android.internal.database.query.findLastForwardChunkOfRo
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.latestEvent
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.Realm
import timber.log.Timber
@ -48,7 +49,7 @@ import javax.inject.Inject
/**
* Insert Chunk in DB, and eventually merge with existing chunk event
*/
internal class TokenChunkEventPersistor @Inject constructor(private val monarchy: Monarchy) {
internal class TokenChunkEventPersistor @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
/**
* <pre>

View file

@ -30,6 +30,7 @@ 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.query.TimelineEventFilter
import im.vector.matrix.android.internal.database.query.whereType
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.filter.FilterFactory
import im.vector.matrix.android.internal.session.room.RoomAPI
@ -54,7 +55,7 @@ internal interface GetUploadsTask : Task<GetUploadsTask.Params, GetUploadsResult
internal class DefaultGetUploadsTask @Inject constructor(
private val roomAPI: RoomAPI,
private val tokenStore: SyncTokenStore,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val eventBus: EventBus)
: GetUploadsTask {

View file

@ -46,7 +46,7 @@ import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.mapWithProgress
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater
import im.vector.matrix.android.internal.session.room.membership.RoomMemberEventHandler
import im.vector.matrix.android.internal.session.room.read.FullyReadContent
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline
@ -69,6 +69,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
private val roomFullyReadHandler: RoomFullyReadHandler,
private val cryptoService: DefaultCryptoService,
private val roomMemberEventHandler: RoomMemberEventHandler,
private val roomTypingUsersHandler: RoomTypingUsersHandler,
@UserId private val userId: String,
private val eventBus: EventBus) {
@ -170,14 +171,15 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle
it.type == EventType.STATE_ROOM_MEMBER
} != null
roomTypingUsersHandler.handle(realm, roomId, ephemeralResult)
roomSummaryUpdater.update(
realm,
roomId,
Membership.JOIN,
roomSync.summary,
roomSync.unreadNotifications,
updateMembers = hasRoomMember,
ephemeralResult = ephemeralResult)
updateMembers = hasRoomMember
)
return roomEntity
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020 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.sync
import im.vector.matrix.android.api.session.room.sender.SenderInfo
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.session.typing.DefaultTypingUsersTracker
import io.realm.Realm
import javax.inject.Inject
internal class RoomTypingUsersHandler @Inject constructor(@UserId private val userId: String,
private val typingUsersTracker: DefaultTypingUsersTracker) {
fun handle(realm: Realm, roomId: String, ephemeralResult: RoomSyncHandler.EphemeralResult?) {
val roomMemberHelper = RoomMemberHelper(realm, roomId)
val typingIds = ephemeralResult?.typingUserIds?.filter { it != userId } ?: emptyList()
val senderInfo = typingIds.map { userId ->
val roomMemberSummaryEntity = roomMemberHelper.getLastRoomMember(userId)
SenderInfo(
userId = userId,
displayName = roomMemberSummaryEntity?.displayName,
isUniqueDisplayName = roomMemberHelper.isUniqueDisplayName(roomMemberSummaryEntity?.displayName),
avatarUrl = roomMemberSummaryEntity?.avatarUrl
)
}
typingUsersTracker.setTypingUsersFromRoom(roomId, senderInfo)
}
}

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.R
import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.pushrules.RuleScope
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask
import im.vector.matrix.android.internal.session.reportSubtask
@ -31,7 +32,7 @@ import timber.log.Timber
import javax.inject.Inject
import kotlin.system.measureTimeMillis
internal class SyncResponseHandler @Inject constructor(private val monarchy: Monarchy,
internal class SyncResponseHandler @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val roomSyncHandler: RoomSyncHandler,
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
private val groupSyncHandler: GroupSyncHandler,
@ -68,7 +69,6 @@ internal class SyncResponseHandler @Inject constructor(private val monarchy: Mon
}.also {
Timber.v("Finish handling toDevice in $it ms")
}
// Start one big transaction
monarchy.awaitTransaction { realm ->
measureTimeMillis {
@ -103,7 +103,6 @@ internal class SyncResponseHandler @Inject constructor(private val monarchy: Mon
}
tokenStore.saveToken(realm, syncResponse.nextBatch)
}
// Everything else we need to do outside the transaction
syncResponse.rooms?.also {
checkPushRules(it, isInitialSync)

View file

@ -18,10 +18,11 @@ package im.vector.matrix.android.internal.session.sync
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.SyncEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import io.realm.Realm
import javax.inject.Inject
internal class SyncTokenStore @Inject constructor(private val monarchy: Monarchy) {
internal class SyncTokenStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
fun getLastToken(): String? {
return Realm.getInstance(monarchy.realmConfiguration).use {

View file

@ -38,6 +38,7 @@ import im.vector.matrix.android.internal.database.query.getDirectRooms
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
@ -56,7 +57,7 @@ import timber.log.Timber
import javax.inject.Inject
internal class UserAccountDataSyncHandler @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
@UserId private val userId: String,
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask) {

View file

@ -24,6 +24,7 @@ import im.vector.matrix.android.api.failure.isTokenError
import im.vector.matrix.android.api.session.sync.SyncState
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
import im.vector.matrix.android.internal.session.sync.SyncTask
import im.vector.matrix.android.internal.session.typing.DefaultTypingUsersTracker
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
import im.vector.matrix.android.internal.util.Debouncer
import im.vector.matrix.android.internal.util.createUIHandler
@ -44,6 +45,7 @@ private const val RETRY_WAIT_TIME_MS = 10_000L
private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L
internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
private val typingUsersTracker: DefaultTypingUsersTracker,
private val networkConnectivityChecker: NetworkConnectivityChecker,
private val backgroundDetectionObserver: BackgroundDetectionObserver)
: Thread(), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener {
@ -196,7 +198,14 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
private fun updateStateTo(newState: SyncState) {
Timber.v("Update state from $state to $newState")
if (newState == state) {
return
}
state = newState
// We clear typing users if the sync is not running
if (newState !is SyncState.Running) {
typingUsersTracker.clear()
}
debouncer.debounce("post_state", Runnable {
liveState.value = newState
}, 150)

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2020 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.typing
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import im.vector.matrix.android.api.session.room.sender.SenderInfo
import im.vector.matrix.android.api.session.typing.TypingUsersTracker
import im.vector.matrix.android.internal.session.SessionScope
import javax.inject.Inject
@SessionScope
internal class DefaultTypingUsersTracker @Inject constructor() : TypingUsersTracker {
private val typingUsers = mutableMapOf<String, List<SenderInfo>>()
private val typingUsersLiveData = mutableMapOf<String, MutableLiveData<List<SenderInfo>>>()
/**
* Set all currently typing users for a room (excluding yourself)
*/
fun setTypingUsersFromRoom(roomId: String, senderInfoList: List<SenderInfo>) {
val hasNewValue = typingUsers[roomId] != senderInfoList
if (hasNewValue) {
typingUsers[roomId] = senderInfoList
typingUsersLiveData[roomId]?.postValue(senderInfoList)
}
}
/**
* Can be called when there is no sync so you don't get stuck with ephemeral data
*/
fun clear() {
val roomIds = typingUsers.keys
roomIds.forEach {
setTypingUsersFromRoom(it, emptyList())
}
}
override fun getTypingUsers(roomId: String): List<SenderInfo> {
return typingUsers[roomId] ?: emptyList()
}
override fun getTypingUsersLive(roomId: String): LiveData<List<SenderInfo>> {
return typingUsersLiveData.getOrPut(roomId) {
MutableLiveData(getTypingUsers(roomId))
}
}
}

View file

@ -31,10 +31,11 @@ import im.vector.matrix.android.internal.database.model.IgnoredUserEntityFields
import im.vector.matrix.android.internal.database.model.UserEntity
import im.vector.matrix.android.internal.database.model.UserEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.fetchCopied
import javax.inject.Inject
internal class UserDataSource @Inject constructor(private val monarchy: Monarchy) {
internal class UserDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory<UserEntity> by lazy {
monarchy.createDataSourceFactory { realm ->

View file

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.user
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.UserEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import javax.inject.Inject
@ -25,7 +26,7 @@ internal interface UserStore {
suspend fun createOrUpdate(userId: String, displayName: String? = null, avatarUrl: String? = null)
}
internal class RealmUserStore @Inject constructor(private val monarchy: Monarchy) : UserStore {
internal class RealmUserStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : UserStore {
override suspend fun createOrUpdate(userId: String, displayName: String?, avatarUrl: String?) {
monarchy.awaitTransaction {

View file

@ -24,12 +24,13 @@ import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.AccountDataMapper
import im.vector.matrix.android.internal.database.model.UserAccountDataEntity
import im.vector.matrix.android.internal.database.model.UserAccountDataEntityFields
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
import io.realm.Realm
import io.realm.RealmQuery
import javax.inject.Inject
internal class AccountDataDataSource @Inject constructor(private val monarchy: Monarchy,
internal class AccountDataDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val accountDataMapper: AccountDataMapper) {
fun getAccountDataEvent(type: String): UserAccountDataEvent? {

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.accountdata.AccountDataService
import im.vector.matrix.android.api.session.events.model.Content
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.sync.UserAccountDataSyncHandler
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataEvent
import im.vector.matrix.android.internal.task.TaskExecutor
@ -30,7 +31,7 @@ import im.vector.matrix.android.internal.task.configureWith
import javax.inject.Inject
internal class DefaultAccountDataService @Inject constructor(
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
private val accountDataDataSource: AccountDataDataSource,

View file

@ -22,6 +22,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
import im.vector.matrix.android.internal.database.query.getOrCreate
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import io.realm.RealmList
@ -37,7 +38,7 @@ internal interface SaveBreadcrumbsTask : Task<SaveBreadcrumbsTask.Params, Unit>
}
internal class DefaultSaveBreadcrumbsTask @Inject constructor(
private val monarchy: Monarchy
@SessionDatabase private val monarchy: Monarchy
) : SaveBreadcrumbsTask {
override suspend fun execute(params: SaveBreadcrumbsTask.Params) {

View file

@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import javax.inject.Inject
@ -30,7 +31,7 @@ internal interface SaveIgnoredUsersTask : Task<SaveIgnoredUsersTask.Params, Unit
)
}
internal class DefaultSaveIgnoredUsersTask @Inject constructor(private val monarchy: Monarchy) : SaveIgnoredUsersTask {
internal class DefaultSaveIgnoredUsersTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : SaveIgnoredUsersTask {
override suspend fun execute(params: SaveIgnoredUsersTask.Params) {
monarchy.awaitTransaction { realm ->

View file

@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity
import im.vector.matrix.android.internal.database.query.get
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.session.sync.model.accountdata.BreadcrumbsContent
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.fetchCopied
@ -36,7 +37,7 @@ internal interface UpdateBreadcrumbsTask : Task<UpdateBreadcrumbsTask.Params, Un
internal class DefaultUpdateBreadcrumbsTask @Inject constructor(
private val saveBreadcrumbsTask: SaveBreadcrumbsTask,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val monarchy: Monarchy
@SessionDatabase private val monarchy: Monarchy
) : UpdateBreadcrumbsTask {
override suspend fun execute(params: UpdateBreadcrumbsTask.Params) {

View file

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.sync.model.accountdata.IgnoredUsersContent
@ -36,7 +37,7 @@ internal interface UpdateIgnoredUserIdsTask : Task<UpdateIgnoredUserIdsTask.Para
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(
private val accountDataApi: AccountDataAPI,
private val monarchy: Monarchy,
@SessionDatabase private val monarchy: Monarchy,
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
@UserId private val userId: String,
private val eventBus: EventBus

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.database.awaitNotEmptyResult
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields
import im.vector.matrix.android.internal.database.query.whereStateKey
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
@ -39,7 +40,7 @@ internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, Unit> {
)
}
internal class DefaultCreateWidgetTask @Inject constructor(private val monarchy: Monarchy,
internal class DefaultCreateWidgetTask @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
private val roomAPI: RoomAPI,
@UserId private val userId: String,
private val eventBus: EventBus) : CreateWidgetTask {

View file

@ -20,6 +20,7 @@ import im.vector.matrix.android.api.MatrixConfiguration
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerConfig
import im.vector.matrix.android.api.session.integrationmanager.IntegrationManagerService
import im.vector.matrix.android.api.session.widgets.WidgetURLFormatter
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
import im.vector.matrix.android.internal.session.widgets.token.GetScalarTokenTask
@ -30,17 +31,17 @@ import javax.inject.Inject
internal class DefaultWidgetURLFormatter @Inject constructor(private val integrationManager: IntegrationManager,
private val getScalarTokenTask: GetScalarTokenTask,
private val matrixConfiguration: MatrixConfiguration
) : IntegrationManagerService.Listener, WidgetURLFormatter {
) : IntegrationManagerService.Listener, WidgetURLFormatter, SessionLifecycleObserver {
private lateinit var currentConfig: IntegrationManagerConfig
private var whiteListedUrls: List<String> = emptyList()
fun start() {
override fun onStart() {
setupWithConfiguration()
integrationManager.addListener(this)
}
fun stop() {
override fun onStop() {
integrationManager.removeListener(this)
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (c) 2020 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.widgets
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
import javax.inject.Inject
internal class WidgetDependenciesHolder @Inject constructor(private val integrationManager: IntegrationManager,
private val widgetManager: WidgetManager,
private val widgetURLFormatter: DefaultWidgetURLFormatter) {
fun start() {
integrationManager.start()
widgetManager.start()
widgetURLFormatter.start()
}
fun stop() {
widgetURLFormatter.stop()
widgetManager.stop()
integrationManager.stop()
}
}

View file

@ -34,6 +34,7 @@ import im.vector.matrix.android.api.session.widgets.WidgetManagementFailure
import im.vector.matrix.android.api.session.widgets.model.Widget
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.SessionLifecycleObserver
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
import im.vector.matrix.android.internal.session.room.state.StateEventDataSource
@ -54,17 +55,19 @@ internal class WidgetManager @Inject constructor(private val integrationManager:
private val taskExecutor: TaskExecutor,
private val createWidgetTask: CreateWidgetTask,
private val widgetFactory: WidgetFactory,
@UserId private val userId: String) : IntegrationManagerService.Listener {
@UserId private val userId: String)
: IntegrationManagerService.Listener, SessionLifecycleObserver {
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
fun start() {
override fun onStart() {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
integrationManager.addListener(this)
}
fun stop() {
override fun onStop() {
integrationManager.removeListener(this)
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
}

View file

@ -19,11 +19,12 @@ package im.vector.matrix.android.internal.session.widgets.token
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.ScalarTokenEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.util.awaitTransaction
import im.vector.matrix.android.internal.util.fetchCopyMap
import javax.inject.Inject
internal class ScalarTokenStore @Inject constructor(private val monarchy: Monarchy) {
internal class ScalarTokenStore @Inject constructor(@SessionDatabase private val monarchy: Monarchy) {
fun getToken(apiUrl: String): String? {
return monarchy.fetchCopyMap({ realm ->

View file

@ -29,6 +29,7 @@ abstract class DividerItem : VectorEpoxyModel<DividerItem.Holder>() {
@EpoxyAttribute var color: Int = -1
override fun bind(holder: Holder) {
super.bind(holder)
if (color != -1) {
holder.view.setBackgroundColor(color)
}

View file

@ -33,6 +33,7 @@ abstract class ErrorWithRetryItem : VectorEpoxyModel<ErrorWithRetryItem.Holder>(
var listener: (() -> Unit)? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.textView.text = text
holder.buttonView.isVisible = listener != null
holder.buttonView.setOnClickListener { listener?.invoke() }

View file

@ -28,6 +28,7 @@ abstract class HelpFooterItem : VectorEpoxyModel<HelpFooterItem.Holder>() {
var text: String? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.textView.text = text
}

View file

@ -28,6 +28,7 @@ abstract class NoResultItem : VectorEpoxyModel<NoResultItem.Holder>() {
var text: String? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.textView.text = text
}

View file

@ -16,6 +16,10 @@
package im.vector.riotx.core.epoxy
import androidx.annotation.CallSuper
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import com.airbnb.epoxy.EpoxyModelWithHolder
import com.airbnb.epoxy.VisibilityState
import kotlinx.coroutines.CoroutineScope
@ -26,13 +30,24 @@ import kotlinx.coroutines.cancelChildren
/**
* EpoxyModelWithHolder which can listen to visibility state change
*/
abstract class VectorEpoxyModel<H : VectorEpoxyHolder> : EpoxyModelWithHolder<H>() {
abstract class VectorEpoxyModel<H : VectorEpoxyHolder> : EpoxyModelWithHolder<H>(), LifecycleOwner {
protected val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
override fun getLifecycle() = lifecycleRegistry
private var onModelVisibilityStateChangedListener: OnVisibilityStateChangedListener? = null
@CallSuper
override fun bind(holder: H) {
super.bind(holder)
lifecycleRegistry.currentState = Lifecycle.State.STARTED
}
@CallSuper
override fun unbind(holder: H) {
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
coroutineScope.coroutineContext.cancelChildren()
super.unbind(holder)
}

View file

@ -58,6 +58,7 @@ abstract class BottomSheetActionItem : VectorEpoxyModel<BottomSheetActionItem.Ho
lateinit var listener: View.OnClickListener
override fun bind(holder: Holder) {
super.bind(holder)
holder.view.setOnClickListener {
listener.onClick(it)
}

View file

@ -49,6 +49,7 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
var userClicked: (() -> Unit)? = null
override fun bind(holder: Holder) {
super.bind(holder)
avatarRenderer.render(matrixItem, holder.avatar)
holder.avatar.setOnClickListener { userClicked?.invoke() }
holder.sender.setTextOrHide(matrixItem.displayName)

View file

@ -41,6 +41,7 @@ abstract class BottomSheetQuickReactionsItem : VectorEpoxyModel<BottomSheetQuick
var listener: Listener? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.textViews.forEachIndexed { index, textView ->
textView.typeface = fontProvider.typeface ?: Typeface.DEFAULT
textView.text = texts[index]

View file

@ -49,6 +49,7 @@ abstract class BottomSheetRoomPreviewItem : VectorEpoxyModel<BottomSheetRoomPrev
@EpoxyAttribute var favoriteClickListener: ClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
avatarRenderer.render(matrixItem, holder.avatar)
holder.avatar.onClick(settingsClickListener)
holder.roomName.setTextOrHide(matrixItem.displayName)

View file

@ -41,6 +41,7 @@ abstract class BottomSheetSendStateItem : VectorEpoxyModel<BottomSheetSendStateI
var drawableStart: Int = 0
override fun bind(holder: Holder) {
super.bind(holder)
holder.progress.isVisible = showProgress
holder.text.setCompoundDrawablesWithIntrinsicBounds(drawableStart, 0, 0, 0)
holder.text.text = text

View file

@ -40,6 +40,7 @@ abstract class ProfileMatrixItem : VectorEpoxyModel<ProfileMatrixItem.Holder>()
@EpoxyAttribute var clickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
val bestName = matrixItem.getBestName()
val matrixId = matrixItem.id.takeIf { it != bestName }
holder.view.setOnClickListener(clickListener)

View file

@ -47,6 +47,7 @@ abstract class GenericButtonItem : VectorEpoxyModel<GenericButtonItem.Holder>()
var iconRes: Int? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.button.text = text
val textColor = textColor ?: ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_primary)
holder.button.setTextColor(textColor)

View file

@ -52,6 +52,7 @@ abstract class GenericFooterItem : VectorEpoxyModel<GenericFooterItem.Holder>()
var textColor: Int? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.text.setTextOrHide(text)
when (style) {
GenericItem.STYLE.BIG_TEXT -> holder.text.textSize = 18f

View file

@ -74,6 +74,7 @@ abstract class GenericItem : VectorEpoxyModel<GenericItem.Holder>() {
var itemClickAction: Action? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.titleText.setTextOrHide(title)
if (titleIconResourceId != -1) {

View file

@ -33,6 +33,7 @@ abstract class GenericItemHeader : VectorEpoxyModel<GenericItemHeader.Holder>()
var text: String? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.text.setTextOrHide(text)
}

View file

@ -57,6 +57,7 @@ abstract class GenericItemWithValue : VectorEpoxyModel<GenericItemWithValue.Hold
var itemClickAction: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.titleText.setTextOrHide(title)
if (titleIconResourceId != -1) {

View file

@ -13,7 +13,5 @@ abstract class GenericLoaderItem : VectorEpoxyModel<GenericLoaderItem.Holder>()
// Maybe/Later add some style configuration, SMALL/BIG ?
override fun bind(holder: Holder) {}
class Holder : VectorEpoxyHolder()
}

View file

@ -33,6 +33,7 @@ abstract class AttachmentPreviewItem<H : AttachmentPreviewItem.Holder> : VectorE
abstract val attachment: ContentAttachmentData
override fun bind(holder: H) {
super.bind(holder)
if (attachment.type == ContentAttachmentData.Type.VIDEO || attachment.type == ContentAttachmentData.Type.IMAGE) {
Glide.with(holder.view.context)
.asBitmap()

View file

@ -37,6 +37,7 @@ abstract class AutocompleteMatrixItem : VectorEpoxyModel<AutocompleteMatrixItem.
@EpoxyAttribute var clickListener: View.OnClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.view.setOnClickListener(clickListener)
holder.nameView.text = matrixItem.getBestName()
holder.subNameView.setTextOrHide(subName)

Some files were not shown because too many files have changed in this diff Show more