Merge pull request #679 from vector-im/feature/perf_again
Feature/perf again
This commit is contained in:
commit
6ce241163e
|
@ -67,5 +67,5 @@ interface Authenticator {
|
|||
/**
|
||||
* Create a session after a SSO successful login
|
||||
*/
|
||||
fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session
|
||||
fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig, callback: MatrixCallback<Session>): Cancelable
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.internal.auth
|
||||
|
||||
import android.util.Patterns
|
||||
import dagger.Lazy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
|
@ -39,10 +40,9 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
|
||||
private val okHttpClient: Provider<OkHttpClient>,
|
||||
private val okHttpClient: Lazy<OkHttpClient>,
|
||||
private val retrofitFactory: RetrofitFactory,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||
private val sessionParamsStore: SessionParamsStore,
|
||||
|
@ -112,14 +112,27 @@ internal class DefaultAuthenticator @Inject constructor(@Unauthenticated
|
|||
sessionManager.getOrCreateSession(sessionParams)
|
||||
}
|
||||
|
||||
override fun createSessionFromSso(credentials: Credentials, homeServerConnectionConfig: HomeServerConnectionConfig): Session {
|
||||
override fun createSessionFromSso(credentials: Credentials,
|
||||
homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||
callback: MatrixCallback<Session>): Cancelable {
|
||||
val job = GlobalScope.launch(coroutineDispatchers.main) {
|
||||
val sessionOrFailure = runCatching {
|
||||
createSessionFromSso(credentials, homeServerConnectionConfig)
|
||||
}
|
||||
sessionOrFailure.foldToCallback(callback)
|
||||
}
|
||||
return CancelableCoroutine(job)
|
||||
}
|
||||
|
||||
private suspend fun createSessionFromSso(credentials: Credentials,
|
||||
homeServerConnectionConfig: HomeServerConnectionConfig): Session = withContext(coroutineDispatchers.computation) {
|
||||
val sessionParams = SessionParams(credentials, homeServerConnectionConfig)
|
||||
sessionParamsStore.save(sessionParams)
|
||||
return sessionManager.getOrCreateSession(sessionParams)
|
||||
sessionManager.getOrCreateSession(sessionParams)
|
||||
}
|
||||
|
||||
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
|
||||
val retrofit = retrofitFactory.create(okHttpClient.get(), homeServerConnectionConfig.homeServerUri.toString())
|
||||
val retrofit = retrofitFactory.create(okHttpClient, homeServerConnectionConfig.homeServerUri.toString())
|
||||
return retrofit.create(AuthAPI::class.java)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.matrix.android.internal.auth
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
|
||||
internal interface SessionParamsStore {
|
||||
|
@ -27,9 +26,9 @@ internal interface SessionParamsStore {
|
|||
|
||||
fun getAll(): List<SessionParams>
|
||||
|
||||
fun save(sessionParams: SessionParams): Try<Unit>
|
||||
suspend fun save(sessionParams: SessionParams)
|
||||
|
||||
fun delete(userId: String): Try<Unit>
|
||||
suspend fun delete(userId: String)
|
||||
|
||||
fun deleteAll(): Try<Unit>
|
||||
suspend fun deleteAll()
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
package im.vector.matrix.android.internal.auth.db
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.auth.SessionParamsStore
|
||||
import im.vector.matrix.android.internal.database.awaitTransaction
|
||||
import im.vector.matrix.android.internal.di.AuthDatabase
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
|
@ -62,41 +62,29 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
|
|||
return sessionParams
|
||||
}
|
||||
|
||||
override fun save(sessionParams: SessionParams): Try<Unit> {
|
||||
return Try {
|
||||
override suspend fun save(sessionParams: SessionParams) {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
val entity = mapper.map(sessionParams)
|
||||
if (entity != null) {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
realm.executeTransaction {
|
||||
it.insert(entity)
|
||||
}
|
||||
realm.close()
|
||||
it.insert(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun delete(userId: String): Try<Unit> {
|
||||
return Try {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
realm.executeTransaction {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
realm.close()
|
||||
override suspend fun delete(userId: String) {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
}
|
||||
|
||||
override fun deleteAll(): Try<Unit> {
|
||||
return Try {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
realm.executeTransaction {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
realm.close()
|
||||
override suspend fun deleteAll() {
|
||||
awaitTransaction(realmConfiguration) {
|
||||
it.where(SessionParamsEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,14 +20,19 @@ import io.realm.RealmConfiguration
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
|
||||
suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.IO) {
|
||||
suspend fun awaitTransaction(config: RealmConfiguration, transaction: suspend (realm: Realm) -> Unit) = withContext(Dispatchers.Default) {
|
||||
Realm.getInstance(config).use { bgRealm ->
|
||||
bgRealm.beginTransaction()
|
||||
try {
|
||||
val start = System.currentTimeMillis()
|
||||
transaction(bgRealm)
|
||||
if (isActive) {
|
||||
bgRealm.commitTransaction()
|
||||
val end = System.currentTimeMillis()
|
||||
val time = end - start
|
||||
Timber.v("Execute transaction in $time millis")
|
||||
}
|
||||
} finally {
|
||||
if (bgRealm.isInTransaction) {
|
||||
|
|
|
@ -36,7 +36,7 @@ internal class RoomSummaryMapper @Inject constructor(
|
|||
}
|
||||
|
||||
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
|
||||
timelineEventMapper.map(it)
|
||||
timelineEventMapper.map(it, buildReadReceipts = false)
|
||||
}
|
||||
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
|
||||
// TODO use a global event decryptor? attache to session and that listen to new sessionId?
|
||||
|
|
|
@ -16,27 +16,26 @@
|
|||
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.awaitTransaction
|
||||
import im.vector.matrix.android.internal.database.model.FilterEntity
|
||||
import im.vector.matrix.android.internal.session.filter.FilterFactory
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
|
||||
/**
|
||||
* Get the current filter, create one if it does not exist
|
||||
*/
|
||||
internal fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
|
||||
internal suspend fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
|
||||
var filter = realm.where<FilterEntity>().findFirst()
|
||||
if (filter == null) {
|
||||
realm.executeTransaction {
|
||||
realm.createObject<FilterEntity>().apply {
|
||||
filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
|
||||
roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
|
||||
filterId = ""
|
||||
}
|
||||
filter = FilterEntity().apply {
|
||||
filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
|
||||
roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
|
||||
filterId = ""
|
||||
}
|
||||
awaitTransaction(realm.configuration) {
|
||||
it.insert(filter)
|
||||
}
|
||||
filter = realm.where<FilterEntity>().findFirst()!!
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ import io.realm.kotlin.where
|
|||
|
||||
internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery<ReadReceiptEntity> {
|
||||
return realm.where<ReadReceiptEntity>()
|
||||
.equalTo(ReadReceiptEntityFields.ROOM_ID, roomId)
|
||||
.equalTo(ReadReceiptEntityFields.USER_ID, userId)
|
||||
.equalTo(ReadReceiptEntityFields.PRIMARY_KEY, buildPrimaryKey(roomId, userId))
|
||||
}
|
||||
|
||||
internal fun ReadReceiptEntity.Companion.whereUserId(realm: Realm, userId: String): RealmQuery<ReadReceiptEntity> {
|
||||
|
@ -45,8 +44,10 @@ internal fun ReadReceiptEntity.Companion.createUnmanaged(roomId: String, eventId
|
|||
|
||||
internal fun ReadReceiptEntity.Companion.getOrCreate(realm: Realm, roomId: String, userId: String): ReadReceiptEntity {
|
||||
return ReadReceiptEntity.where(realm, roomId, userId).findFirst()
|
||||
?: realm.createObject(ReadReceiptEntity::class.java, "${roomId}_$userId").apply {
|
||||
?: realm.createObject(ReadReceiptEntity::class.java, buildPrimaryKey(roomId, userId)).apply {
|
||||
this.roomId = roomId
|
||||
this.userId = userId
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildPrimaryKey(roomId: String, userId: String) = "${roomId}_$userId"
|
||||
|
|
|
@ -111,7 +111,7 @@ internal fun RealmQuery<TimelineEventEntity>.prev(since: Int? = null, strict: Bo
|
|||
|
||||
internal fun RealmList<TimelineEventEntity>.find(eventId: String): TimelineEventEntity? {
|
||||
return this.where()
|
||||
.equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId)
|
||||
.equalTo(TimelineEventEntityFields.EVENT_ID, eventId)
|
||||
.findFirst()
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ internal object MatrixModule {
|
|||
@MatrixScope
|
||||
fun providesMatrixCoroutineDispatchers(): MatrixCoroutineDispatchers {
|
||||
return MatrixCoroutineDispatchers(io = Dispatchers.IO,
|
||||
computation = Dispatchers.IO,
|
||||
computation = Dispatchers.Default,
|
||||
main = Dispatchers.Main,
|
||||
crypto = createBackgroundHandler("Crypto_Thread").asCoroutineDispatcher(),
|
||||
sync = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
|
||||
|
|
|
@ -17,17 +17,24 @@
|
|||
package im.vector.matrix.android.internal.network
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import dagger.Lazy
|
||||
import okhttp3.Call
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
class RetrofitFactory @Inject constructor(private val moshi: Moshi) {
|
||||
|
||||
fun create(okHttpClient: OkHttpClient, baseUrl: String): Retrofit {
|
||||
fun create(okHttpClient: Lazy<OkHttpClient>, baseUrl: String): Retrofit {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.client(okHttpClient)
|
||||
.callFactory(object : Call.Factory {
|
||||
override fun newCall(request: Request): Call {
|
||||
return okHttpClient.get().newCall(request)
|
||||
}
|
||||
})
|
||||
.addConverterFactory(UnitConverterFactory)
|
||||
.addConverterFactory(MoshiConverterFactory.create(moshi))
|
||||
.build()
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session
|
|||
import android.content.Context
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import dagger.Binds
|
||||
import dagger.Lazy
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.multibindings.IntoSet
|
||||
|
@ -132,7 +133,7 @@ internal abstract class SessionModule {
|
|||
@JvmStatic
|
||||
@Provides
|
||||
@SessionScope
|
||||
fun providesRetrofit(@Authenticated okHttpClient: OkHttpClient,
|
||||
fun providesRetrofit(@Authenticated okHttpClient: Lazy<OkHttpClient>,
|
||||
sessionParams: SessionParams,
|
||||
retrofitFactory: RetrofitFactory): Retrofit {
|
||||
return retrofitFactory
|
||||
|
|
|
@ -16,54 +16,44 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.filter
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
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.getFilter
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.where
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFilterRepository @Inject constructor(
|
||||
@SessionDatabase private val realmConfiguration: RealmConfiguration
|
||||
) : FilterRepository {
|
||||
internal class DefaultFilterRepository @Inject constructor(private val monarchy: Monarchy) : FilterRepository {
|
||||
|
||||
override fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
|
||||
val result: Boolean
|
||||
override suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
val result = if (filter.filterBodyJson != filterBody.toJSONString()) {
|
||||
// Filter has changed, store it and reset the filter Id
|
||||
monarchy.awaitTransaction {
|
||||
// We manage only one filter for now
|
||||
val filterBodyJson = filterBody.toJSONString()
|
||||
val roomEventFilterJson = roomEventFilter.toJSONString()
|
||||
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
val filterEntity = FilterEntity.getFilter(it)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
if (filter.filterBodyJson != filterBody.toJSONString()) {
|
||||
// Filter has changed, store it and reset the filter Id
|
||||
realm.executeTransaction {
|
||||
// We manage only one filter for now
|
||||
val filterBodyJson = filterBody.toJSONString()
|
||||
val roomEventFilterJson = roomEventFilter.toJSONString()
|
||||
|
||||
val filterEntity = FilterEntity.getFilter(it)
|
||||
|
||||
filterEntity.filterBodyJson = filterBodyJson
|
||||
filterEntity.roomEventFilterJson = roomEventFilterJson
|
||||
// Reset filterId
|
||||
filterEntity.filterId = ""
|
||||
filterEntity.filterBodyJson = filterBodyJson
|
||||
filterEntity.roomEventFilterJson = roomEventFilterJson
|
||||
// Reset filterId
|
||||
filterEntity.filterId = ""
|
||||
}
|
||||
true
|
||||
} else {
|
||||
filter.filterId.isBlank()
|
||||
}
|
||||
result = true
|
||||
} else {
|
||||
result = filter.filterId.isBlank()
|
||||
result
|
||||
}
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun storeFilterId(filterBody: FilterBody, filterId: String) {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
realm.executeTransaction {
|
||||
override suspend fun storeFilterId(filterBody: FilterBody, filterId: String) {
|
||||
monarchy.awaitTransaction {
|
||||
// We manage only one filter for now
|
||||
val filterBodyJson = filterBody.toJSONString()
|
||||
|
||||
|
@ -73,39 +63,24 @@ internal class DefaultFilterRepository @Inject constructor(
|
|||
?.findFirst()
|
||||
?.filterId = filterId
|
||||
}
|
||||
|
||||
realm.close()
|
||||
}
|
||||
|
||||
override fun getFilter(): String {
|
||||
val result: String
|
||||
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
result = if (filter.filterId.isBlank()) {
|
||||
// Use the Json format
|
||||
filter.filterBodyJson
|
||||
} else {
|
||||
// Use FilterId
|
||||
filter.filterId
|
||||
override suspend fun getFilter(): String {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
val filter = FilterEntity.getFilter(it)
|
||||
if (filter.filterId.isBlank()) {
|
||||
// Use the Json format
|
||||
filter.filterBodyJson
|
||||
} else {
|
||||
// Use FilterId
|
||||
filter.filterId
|
||||
}
|
||||
}
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getRoomFilter(): String {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
val result = filter.roomEventFilterJson
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
override suspend fun getRoomFilter(): String {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
FilterEntity.getFilter(it).roomEventFilterJson
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,36 +21,13 @@ import im.vector.matrix.android.internal.task.TaskExecutor
|
|||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFilterService @Inject constructor(private val filterRepository: FilterRepository,
|
||||
private val saveFilterTask: SaveFilterTask,
|
||||
internal class DefaultFilterService @Inject constructor(private val saveFilterTask: SaveFilterTask,
|
||||
private val taskExecutor: TaskExecutor) : FilterService {
|
||||
|
||||
// TODO Pass a list of support events instead
|
||||
override fun setFilter(filterPreset: FilterService.FilterPreset) {
|
||||
val filterBody = when (filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotFilterBody()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultFilterBody()
|
||||
}
|
||||
}
|
||||
|
||||
val roomFilter = when (filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotRoomFilter()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultRoomFilter()
|
||||
}
|
||||
}
|
||||
|
||||
val updated = filterRepository.storeFilter(filterBody, roomFilter)
|
||||
|
||||
if (updated) {
|
||||
saveFilterTask
|
||||
.configureWith(SaveFilterTask.Params(filterBody))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
saveFilterTask
|
||||
.configureWith(SaveFilterTask.Params(filterPreset))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,18 +16,19 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.filter
|
||||
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Save a filter to the server
|
||||
* Save a filter, in db and if any changes, upload to the server
|
||||
*/
|
||||
internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
|
||||
|
||||
data class Params(
|
||||
val filter: FilterBody
|
||||
val filterPreset: FilterService.FilterPreset
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -37,10 +38,29 @@ internal class DefaultSaveFilterTask @Inject constructor(@UserId private val use
|
|||
) : SaveFilterTask {
|
||||
|
||||
override suspend fun execute(params: SaveFilterTask.Params) {
|
||||
val filterResponse = executeRequest<FilterResponse> {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(userId, params.filter)
|
||||
val filterBody = when (params.filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotFilterBody()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultFilterBody()
|
||||
}
|
||||
}
|
||||
val roomFilter = when (params.filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotRoomFilter()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultRoomFilter()
|
||||
}
|
||||
}
|
||||
val updated = filterRepository.storeFilter(filterBody, roomFilter)
|
||||
if (updated) {
|
||||
val filterResponse = executeRequest<FilterResponse> {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(userId, filterBody)
|
||||
}
|
||||
filterRepository.storeFilterId(filterBody, filterResponse.filterId)
|
||||
}
|
||||
filterRepository.storeFilterId(params.filter, filterResponse.filterId)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,20 +21,20 @@ internal interface FilterRepository {
|
|||
/**
|
||||
* Return true if the filterBody has changed, or need to be sent to the server
|
||||
*/
|
||||
fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
|
||||
suspend fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
|
||||
|
||||
/**
|
||||
* Set the filterId of this filter
|
||||
*/
|
||||
fun storeFilterId(filterBody: FilterBody, filterId: String)
|
||||
suspend fun storeFilterId(filterBody: FilterBody, filterId: String)
|
||||
|
||||
/**
|
||||
* Return filter json or filter id
|
||||
*/
|
||||
fun getFilter(): String
|
||||
suspend fun getFilter(): String
|
||||
|
||||
/**
|
||||
* Return the room filter
|
||||
*/
|
||||
fun getRoomFilter(): String
|
||||
suspend fun getRoomFilter(): String
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ 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
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
||||
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.prev
|
||||
|
@ -41,8 +41,8 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
|
|||
fun resolve(roomId: String): String? {
|
||||
var res: String? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain()
|
||||
res = roomName?.content.toModel<RoomAvatarContent>()?.avatarUrl
|
||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()
|
||||
res = ContentMapper.map(roomName?.content).toModel<RoomAvatarContent>()?.avatarUrl
|
||||
if (!res.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
@ -60,6 +60,6 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
|
|||
}
|
||||
|
||||
private fun EventEntity?.toRoomMember(): RoomMember? {
|
||||
return this?.asDomain()?.content?.toModel<RoomMember>()
|
||||
return ContentMapper.map(this?.content).toModel<RoomMember>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ 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.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomTopicContent
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.mapper.ContentMapper
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
|
@ -65,8 +65,10 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
|||
roomId: String,
|
||||
membership: Membership? = null,
|
||||
roomSummary: RoomSyncSummary? = null,
|
||||
unreadNotifications: RoomSyncUnreadNotifications? = null) {
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||
unreadNotifications: RoomSyncUnreadNotifications? = null,
|
||||
updateMembers: Boolean = false) {
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
|
||||
if (roomSummary != null) {
|
||||
if (roomSummary.heroes.isNotEmpty()) {
|
||||
|
@ -88,24 +90,27 @@ internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId
|
|||
}
|
||||
|
||||
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, filterTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()
|
||||
|
||||
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
|
||||
// avoid this call if we are sure there are unread events
|
||||
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
|
||||
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
.queryRoomMembersEvent()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, userId)
|
||||
.findAll()
|
||||
.asSequence()
|
||||
.map { it.stateKey }
|
||||
// avoid this call if we are sure there are unread events
|
||||
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
|
||||
|
||||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||
|
||||
if (updateMembers) {
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
.queryRoomMembersEvent()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, userId)
|
||||
.findAll()
|
||||
.asSequence()
|
||||
.map { it.stateKey }
|
||||
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP
|
|||
it.updateSenderData()
|
||||
}
|
||||
roomEntity.areAllMembersLoaded = true
|
||||
roomSummaryUpdater.update(realm, roomId)
|
||||
roomSummaryUpdater.update(realm, roomId, updateMembers = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ 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
|
||||
import im.vector.matrix.android.api.session.room.model.*
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
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.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
|
@ -56,20 +56,20 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||
var name: CharSequence? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst()
|
||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_NAME).prev()?.asDomain()
|
||||
name = roomName?.content.toModel<RoomNameContent>()?.name
|
||||
val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_NAME).prev()
|
||||
name = ContentMapper.map(roomName?.content).toModel<RoomNameContent>()?.name
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val canonicalAlias = EventEntity.where(realm, roomId, EventType.STATE_CANONICAL_ALIAS).prev()?.asDomain()
|
||||
name = canonicalAlias?.content.toModel<RoomCanonicalAliasContent>()?.canonicalAlias
|
||||
val canonicalAlias = EventEntity.where(realm, roomId, EventType.STATE_CANONICAL_ALIAS).prev()
|
||||
name = ContentMapper.map(canonicalAlias?.content).toModel<RoomCanonicalAliasContent>()?.canonicalAlias
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
||||
val aliases = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()?.asDomain()
|
||||
name = aliases?.content.toModel<RoomAliasesContent>()?.aliases?.firstOrNull()
|
||||
val aliases = EventEntity.where(realm, roomId, EventType.STATE_ROOM_ALIASES).prev()
|
||||
name = ContentMapper.map(aliases?.content).toModel<RoomAliasesContent>()?.aliases?.firstOrNull()
|
||||
if (!name.isNullOrEmpty()) {
|
||||
return@doWithRealm
|
||||
}
|
||||
|
@ -132,6 +132,6 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||
}
|
||||
|
||||
private fun EventEntity?.toRoomMember(): RoomMember? {
|
||||
return this?.asDomain()?.content?.toModel<RoomMember>()
|
||||
return ContentMapper.map(this?.content).toModel<RoomMember>()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
}
|
||||
|
||||
suspend fun handle(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean, reporter: DefaultInitialSyncProgressService? = null) {
|
||||
Timber.v("Execute transaction from $this")
|
||||
monarchy.awaitTransaction { realm ->
|
||||
handleRoomSync(realm, HandlingStrategy.JOINED(roomsSyncResponse.join), isInitialSync, reporter)
|
||||
handleRoomSync(realm, HandlingStrategy.INVITED(roomsSyncResponse.invite), isInitialSync, reporter)
|
||||
|
@ -133,6 +134,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
roomEntity.membership = Membership.JOIN
|
||||
|
||||
// State event
|
||||
|
||||
if (roomSync.state != null && roomSync.state.events.isNotEmpty()) {
|
||||
val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt()
|
||||
?: Int.MIN_VALUE
|
||||
|
@ -146,7 +148,6 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) {
|
||||
val chunkEntity = handleTimelineEvents(
|
||||
realm,
|
||||
|
@ -157,14 +158,19 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
}
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications)
|
||||
val hasRoomMember = roomSync.state?.events?.firstOrNull {
|
||||
it.type == EventType.STATE_ROOM_MEMBER
|
||||
} != null || roomSync.timeline?.events?.firstOrNull {
|
||||
it.type == EventType.STATE_ROOM_MEMBER
|
||||
} != null
|
||||
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications, updateMembers = hasRoomMember)
|
||||
return roomEntity
|
||||
}
|
||||
|
||||
private fun handleInvitedRoom(realm: Realm,
|
||||
roomId: String,
|
||||
roomSync:
|
||||
InvitedRoomSync): RoomEntity {
|
||||
roomSync: InvitedRoomSync): RoomEntity {
|
||||
Timber.v("Handle invited sync for room $roomId")
|
||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||
roomEntity.membership = Membership.INVITE
|
||||
|
@ -172,7 +178,10 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events)
|
||||
roomEntity.addOrUpdate(chunkEntity)
|
||||
}
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.INVITE)
|
||||
val hasRoomMember = roomSync.inviteState?.events?.firstOrNull {
|
||||
it.type == EventType.STATE_ROOM_MEMBER
|
||||
} != null
|
||||
roomSummaryUpdater.update(realm, roomId, Membership.INVITE, updateMembers = hasRoomMember)
|
||||
return roomEntity
|
||||
}
|
||||
|
||||
|
|
|
@ -16,27 +16,24 @@
|
|||
|
||||
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 im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SyncTokenStore @Inject constructor(@SessionDatabase private val realmConfiguration: RealmConfiguration) {
|
||||
internal class SyncTokenStore @Inject constructor(private val monarchy: Monarchy) {
|
||||
|
||||
fun getLastToken(): String? {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
val token = realm.where(SyncEntity::class.java).findFirst()?.nextBatch
|
||||
realm.close()
|
||||
return token
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use {
|
||||
it.where(SyncEntity::class.java).findFirst()?.nextBatch
|
||||
}
|
||||
}
|
||||
|
||||
fun saveToken(token: String?) {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
realm.executeTransaction {
|
||||
suspend fun saveToken(token: String?) {
|
||||
monarchy.awaitTransaction {
|
||||
val sync = SyncEntity(token)
|
||||
it.insertOrUpdate(sync)
|
||||
}
|
||||
realm.close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@ dependencies {
|
|||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
implementation "com.airbnb.android:epoxy-paging:$epoxy_version"
|
||||
implementation 'com.airbnb.android:mvrx:1.1.0'
|
||||
implementation 'com.airbnb.android:mvrx:1.3.0'
|
||||
|
||||
// Work
|
||||
implementation "androidx.work:work-runtime-ktx:2.3.0-alpha01"
|
||||
|
|
|
@ -26,6 +26,7 @@ import im.vector.matrix.rx.rx
|
|||
import im.vector.riotx.features.home.HomeRoomListDataSource
|
||||
import im.vector.riotx.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.riotx.features.home.group.SelectedGroupDataSource
|
||||
import im.vector.riotx.features.home.room.list.ChronologicalRoomComparator
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
@ -43,7 +44,8 @@ import javax.inject.Singleton
|
|||
class AppStateHandler @Inject constructor(
|
||||
private val sessionDataSource: ActiveSessionDataSource,
|
||||
private val homeRoomListDataSource: HomeRoomListDataSource,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource) : LifecycleObserver {
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource,
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator) : LifecycleObserver {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
|
@ -64,31 +66,24 @@ class AppStateHandler @Inject constructor(
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.switchMap {
|
||||
it.orNull()?.rx()?.liveRoomSummaries()
|
||||
?: Observable.just(emptyList())
|
||||
?: Observable.just(emptyList())
|
||||
}
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
selectedGroupDataSource.observe(),
|
||||
BiFunction { rooms, selectedGroupOption ->
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
val filteredDirectRooms = rooms
|
||||
.filter { it.isDirect }
|
||||
.filter {
|
||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
true
|
||||
} else {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
val filteredGroupRooms = rooms
|
||||
.filter { !it.isDirect }
|
||||
.filter {
|
||||
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|
||||
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||
}
|
||||
filteredDirectRooms + filteredGroupRooms
|
||||
val filteredRooms = rooms.filter {
|
||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
true
|
||||
} else if (it.isDirect) {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
} else {
|
||||
selectedGroup.roomIds.contains(it.roomId)
|
||||
}
|
||||
}
|
||||
filteredRooms.sortedWith(chronologicalRoomComparator)
|
||||
}
|
||||
)
|
||||
.subscribe {
|
||||
|
|
|
@ -21,31 +21,31 @@ import androidx.fragment.app.Fragment
|
|||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
|
||||
fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment) {
|
||||
supportFragmentManager.inTransaction { add(frameId, fragment) }
|
||||
supportFragmentManager.commitTransactionNow { add(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransactionNow {
|
||||
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
supportFragmentManager.inTransaction { replace(frameId, fragment, tag) }
|
||||
supportFragmentManager.commitTransactionNow { replace(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransactionNow {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
supportFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||
supportFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,61 +21,61 @@ import androidx.fragment.app.Fragment
|
|||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
|
||||
fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment) {
|
||||
parentFragmentManager.inTransaction { add(frameId, fragment) }
|
||||
parentFragmentManager.commitTransactionNow { add(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
parentFragmentManager.inTransaction {
|
||||
parentFragmentManager.commitTransactionNow {
|
||||
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment) {
|
||||
parentFragmentManager.inTransaction { replace(frameId, fragment) }
|
||||
parentFragmentManager.commitTransactionNow { replace(frameId, fragment) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
parentFragmentManager.inTransaction {
|
||||
parentFragmentManager.commitTransactionNow {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
parentFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||
parentFragmentManager.commitTransaction { replace(frameId, fragment, tag).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
parentFragmentManager.inTransaction {
|
||||
parentFragmentManager.commitTransaction {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment) {
|
||||
childFragmentManager.inTransaction { add(frameId, fragment) }
|
||||
fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
childFragmentManager.commitTransactionNow { add(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
childFragmentManager.inTransaction {
|
||||
childFragmentManager.commitTransactionNow {
|
||||
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment) {
|
||||
childFragmentManager.inTransaction { replace(frameId, fragment) }
|
||||
fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
childFragmentManager.commitTransactionNow { replace(frameId, fragment, tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
childFragmentManager.inTransaction {
|
||||
childFragmentManager.commitTransactionNow {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
|
||||
}
|
||||
}
|
||||
|
||||
fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
|
||||
childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||
childFragmentManager.commitTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||
}
|
||||
|
||||
fun <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
|
||||
childFragmentManager.inTransaction {
|
||||
childFragmentManager.commitTransaction {
|
||||
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ package im.vector.riotx.core.extensions
|
|||
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
|
||||
inline fun androidx.fragment.app.FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
|
||||
inline fun androidx.fragment.app.FragmentManager.commitTransactionNow(func: FragmentTransaction.() -> FragmentTransaction) {
|
||||
beginTransaction().func().commitNow()
|
||||
}
|
||||
|
||||
inline fun androidx.fragment.app.FragmentManager.commitTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
|
||||
beginTransaction().func().commit()
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.annotation.*
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -34,7 +35,6 @@ import androidx.lifecycle.ViewModelProviders
|
|||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import butterknife.Unbinder
|
||||
import com.airbnb.mvrx.BaseMvRxActivity
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.bumptech.glide.util.Util
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
@ -59,7 +59,7 @@ import io.reactivex.disposables.Disposable
|
|||
import timber.log.Timber
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
|
||||
abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
|
||||
/* ==========================================================================================
|
||||
* UI
|
||||
* ========================================================================================== */
|
||||
|
|
|
@ -25,24 +25,22 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.MvRxView
|
||||
import com.airbnb.mvrx.MvRxViewModelStore
|
||||
import com.airbnb.mvrx.MvRxViewId
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import im.vector.riotx.core.di.DaggerScreenComponent
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.utils.DimensionConverter
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Add MvRx capabilities to bottomsheetdialog (like BaseMvRxFragment)
|
||||
*/
|
||||
abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MvRxView {
|
||||
|
||||
override val mvrxViewModelStore by lazy { MvRxViewModelStore(viewModelStore) }
|
||||
private lateinit var mvrxPersistedViewId: String
|
||||
private val mvrxViewIdProperty = MvRxViewId()
|
||||
final override val mvrxViewId: String by mvrxViewIdProperty
|
||||
private lateinit var screenComponent: ScreenComponent
|
||||
final override val mvrxViewId: String by lazy { mvrxPersistedViewId }
|
||||
|
||||
/* ==========================================================================================
|
||||
* View model
|
||||
|
@ -78,10 +76,7 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
protected open fun injectWith(screenComponent: ScreenComponent) = Unit
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
mvrxViewModelStore.restoreViewModels(this, savedInstanceState)
|
||||
mvrxPersistedViewId = savedInstanceState?.getString(PERSISTED_VIEW_ID_KEY)
|
||||
?: this::class.java.simpleName + "_" + UUID.randomUUID().toString()
|
||||
|
||||
mvrxViewIdProperty.restoreFrom(savedInstanceState)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
|
@ -98,8 +93,7 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
mvrxViewModelStore.saveViewModels(outState)
|
||||
outState.putString(PERSISTED_VIEW_ID_KEY, mvrxViewId)
|
||||
mvrxViewIdProperty.saveTo(outState)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
@ -121,5 +115,3 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment()
|
|||
arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
|
||||
}
|
||||
}
|
||||
|
||||
private const val PERSISTED_VIEW_ID_KEY = "mvrx:bottomsheet_persisted_view_id"
|
||||
|
|
|
@ -114,11 +114,12 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
super.onDestroyView()
|
||||
mUnBinder?.unbind()
|
||||
mUnBinder = null
|
||||
uiDisposables.clear()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
uiDisposables.dispose()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun injector(): ScreenComponent {
|
||||
|
@ -181,7 +182,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
|
|||
|
||||
private val uiDisposables = CompositeDisposable()
|
||||
|
||||
protected fun Disposable.disposeOnDestroy(): Disposable {
|
||||
protected fun Disposable.disposeOnDestroyView(): Disposable {
|
||||
uiDisposables.add(this)
|
||||
return this
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.widget.ImageView
|
|||
import android.widget.LinearLayout
|
||||
import androidx.core.view.isVisible
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.glide.GlideApp
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.room.detail.timeline.item.ReadReceiptData
|
||||
import kotlinx.android.synthetic.main.view_read_receipts.view.*
|
||||
|
@ -105,4 +106,11 @@ class ReadReceiptsView @JvmOverloads constructor(
|
|||
isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
receiptAvatars.forEach {
|
||||
GlideApp.with(context.applicationContext).clear(it)
|
||||
}
|
||||
isVisible = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,14 +34,14 @@ interface MutableDataSource<T> : DataSource<T> {
|
|||
*/
|
||||
open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableDataSource<T> {
|
||||
|
||||
private val storeRelay = createRelay()
|
||||
private val behaviorRelay = createRelay()
|
||||
|
||||
override fun observe(): Observable<T> {
|
||||
return storeRelay.hide().observeOn(Schedulers.computation())
|
||||
return behaviorRelay.hide().observeOn(Schedulers.computation())
|
||||
}
|
||||
|
||||
override fun post(value: T) {
|
||||
storeRelay.accept(value)
|
||||
behaviorRelay.accept(value)
|
||||
}
|
||||
|
||||
private fun createRelay(): BehaviorRelay<T> {
|
||||
|
@ -58,13 +58,13 @@ open class BehaviorDataSource<T>(private val defaultValue: T? = null) : MutableD
|
|||
*/
|
||||
open class PublishDataSource<T> : MutableDataSource<T> {
|
||||
|
||||
private val storeRelay = PublishRelay.create<T>()
|
||||
private val publishRelay = PublishRelay.create<T>()
|
||||
|
||||
override fun observe(): Observable<T> {
|
||||
return storeRelay.hide()
|
||||
return publishRelay.hide()
|
||||
}
|
||||
|
||||
override fun post(value: T) {
|
||||
storeRelay.accept(value)
|
||||
publishRelay.accept(value)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTr
|
|||
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.inTransaction
|
||||
import im.vector.riotx.core.extensions.commitTransaction
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.platform.SimpleFragmentActivity
|
||||
import im.vector.riotx.core.platform.WaitingViewData
|
||||
|
@ -102,20 +102,20 @@ class SASVerificationActivity : SimpleFragmentActivity() {
|
|||
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT,
|
||||
IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> {
|
||||
supportActionBar?.setTitle(R.string.sas_incoming_request_title)
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationIncomingFragment::class.java, null)
|
||||
}
|
||||
}
|
||||
IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION,
|
||||
IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
|
||||
}
|
||||
}
|
||||
IncomingSasVerificationTransaction.UxState.VERIFIED -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
|
||||
}
|
||||
|
@ -133,20 +133,20 @@ class SASVerificationActivity : SimpleFragmentActivity() {
|
|||
OutgoingSasVerificationRequest.UxState.UNKNOWN,
|
||||
OutgoingSasVerificationRequest.UxState.WAIT_FOR_START,
|
||||
OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationStartFragment::class.java, null)
|
||||
}
|
||||
}
|
||||
OutgoingSasVerificationRequest.UxState.SHOW_SAS,
|
||||
OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
|
||||
}
|
||||
}
|
||||
OutgoingSasVerificationRequest.UxState.VERIFIED -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
|
||||
}
|
||||
|
@ -172,13 +172,13 @@ class SASVerificationActivity : SimpleFragmentActivity() {
|
|||
finish()
|
||||
}
|
||||
SasVerificationViewModel.NAVIGATE_SAS_DISPLAY -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
|
||||
}
|
||||
}
|
||||
SasVerificationViewModel.NAVIGATE_SUCCESS -> {
|
||||
supportFragmentManager.inTransaction {
|
||||
supportFragmentManager.commitTransaction {
|
||||
setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
|
||||
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
package im.vector.riotx.features.home
|
||||
|
||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
|
||||
sealed class HomeDetailAction : VectorViewModelAction {
|
||||
data class SwitchDisplayMode(val displayMode: RoomListFragment.DisplayMode) : HomeDetailAction()
|
||||
data class SwitchDisplayMode(val displayMode: RoomListDisplayMode) : HomeDetailAction()
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.home
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.core.view.forEachIndexed
|
||||
import androidx.lifecycle.Observer
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -28,7 +29,7 @@ import im.vector.matrix.android.api.session.Session
|
|||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.addChildFragmentToBackstack
|
||||
import im.vector.riotx.core.extensions.commitTransactionNow
|
||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.core.ui.views.KeysBackupBanner
|
||||
|
@ -59,9 +60,8 @@ class HomeDetailFragment @Inject constructor(
|
|||
return R.layout.fragment_home_detail
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
|
||||
setupBottomNavigationView()
|
||||
|
@ -133,10 +133,10 @@ class HomeDetailFragment @Inject constructor(
|
|||
private fun setupBottomNavigationView() {
|
||||
bottomNavigationView.setOnNavigationItemSelectedListener {
|
||||
val displayMode = when (it.itemId) {
|
||||
R.id.bottom_action_home -> RoomListFragment.DisplayMode.HOME
|
||||
R.id.bottom_action_people -> RoomListFragment.DisplayMode.PEOPLE
|
||||
R.id.bottom_action_rooms -> RoomListFragment.DisplayMode.ROOMS
|
||||
else -> RoomListFragment.DisplayMode.HOME
|
||||
R.id.bottom_action_home -> RoomListDisplayMode.HOME
|
||||
R.id.bottom_action_people -> RoomListDisplayMode.PEOPLE
|
||||
R.id.bottom_action_rooms -> RoomListDisplayMode.ROOMS
|
||||
else -> RoomListDisplayMode.HOME
|
||||
}
|
||||
viewModel.handle(HomeDetailAction.SwitchDisplayMode(displayMode))
|
||||
true
|
||||
|
@ -152,25 +152,32 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun switchDisplayMode(displayMode: RoomListFragment.DisplayMode) {
|
||||
private fun switchDisplayMode(displayMode: RoomListDisplayMode) {
|
||||
groupToolbarTitleView.setText(displayMode.titleRes)
|
||||
updateSelectedFragment(displayMode)
|
||||
// Update the navigation view (for when we restore the tabs)
|
||||
bottomNavigationView.selectedItemId = when (displayMode) {
|
||||
RoomListFragment.DisplayMode.PEOPLE -> R.id.bottom_action_people
|
||||
RoomListFragment.DisplayMode.ROOMS -> R.id.bottom_action_rooms
|
||||
RoomListDisplayMode.PEOPLE -> R.id.bottom_action_people
|
||||
RoomListDisplayMode.ROOMS -> R.id.bottom_action_rooms
|
||||
else -> R.id.bottom_action_home
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectedFragment(displayMode: RoomListFragment.DisplayMode) {
|
||||
private fun updateSelectedFragment(displayMode: RoomListDisplayMode) {
|
||||
val fragmentTag = "FRAGMENT_TAG_${displayMode.name}"
|
||||
val fragment = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||
if (fragment == null) {
|
||||
val params = RoomListParams(displayMode)
|
||||
addChildFragmentToBackstack(R.id.roomListContainer, RoomListFragment::class.java, params, fragmentTag)
|
||||
} else {
|
||||
addChildFragmentToBackstack(R.id.roomListContainer, fragment, fragmentTag)
|
||||
val fragmentToShow = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||
childFragmentManager.commitTransactionNow {
|
||||
childFragmentManager.fragments
|
||||
.filter { it != fragmentToShow }
|
||||
.forEach {
|
||||
hide(it)
|
||||
}
|
||||
if (fragmentToShow == null) {
|
||||
val params = RoomListParams(displayMode)
|
||||
add(R.id.roomListContainer, RoomListFragment::class.java, params.toMvRxBundle(), fragmentTag)
|
||||
} else {
|
||||
show(fragmentToShow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,14 +17,17 @@
|
|||
package im.vector.riotx.features.home
|
||||
|
||||
import arrow.core.Option
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.sync.SyncState
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
|
||||
data class HomeDetailViewState(
|
||||
val groupSummary: Option<GroupSummary> = Option.empty(),
|
||||
val displayMode: RoomListFragment.DisplayMode = RoomListFragment.DisplayMode.HOME,
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val displayMode: RoomListDisplayMode = RoomListDisplayMode.HOME,
|
||||
val notificationCountCatchup: Int = 0,
|
||||
val notificationHighlightCatchup: Boolean = false,
|
||||
val notificationCountPeople: Int = 0,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.riotx.features.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.observeK
|
||||
|
@ -33,8 +34,8 @@ class HomeDrawerFragment @Inject constructor(
|
|||
|
||||
override fun getLayoutResId() = R.layout.fragment_home_drawer
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2019 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.riotx.features.home
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import im.vector.riotx.R
|
||||
|
||||
enum class RoomListDisplayMode(@StringRes val titleRes: Int) {
|
||||
HOME(R.string.bottom_action_home),
|
||||
PEOPLE(R.string.bottom_action_people_x),
|
||||
ROOMS(R.string.bottom_action_rooms),
|
||||
FILTERED(/* Not used */ 0),
|
||||
SHARE(/* Not used */ 0)
|
||||
}
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.home.createdirect
|
|||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
|
@ -40,8 +41,8 @@ class CreateDirectRoomDirectoryUsersFragment @Inject constructor(
|
|||
|
||||
private lateinit var sharedActionViewModel: CreateDirectRoomSharedActionViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(CreateDirectRoomSharedActionViewModel::class.java)
|
||||
setupRecyclerView()
|
||||
setupSearchByMatrixIdView()
|
||||
|
@ -61,7 +62,7 @@ class CreateDirectRoomDirectoryUsersFragment @Inject constructor(
|
|||
.subscribe {
|
||||
viewModel.handle(CreateDirectRoomAction.SearchDirectoryUsers(it.toString()))
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
createDirectRoomSearchById.requestFocus()
|
||||
val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
||||
imm?.showSoftInput(createDirectRoomSearchById, InputMethodManager.SHOW_IMPLICIT)
|
||||
|
|
|
@ -21,6 +21,7 @@ package im.vector.riotx.features.home.createdirect
|
|||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ScrollView
|
||||
import androidx.core.view.size
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -50,8 +51,8 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor(
|
|||
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
|
||||
private lateinit var sharedActionViewModel: CreateDirectRoomSharedActionViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(CreateDirectRoomSharedActionViewModel::class.java)
|
||||
vectorBaseActivity.setSupportActionBar(createDirectRoomToolbar)
|
||||
setupRecyclerView()
|
||||
|
@ -113,7 +114,7 @@ class CreateDirectRoomKnownUsersFragment @Inject constructor(
|
|||
}
|
||||
viewModel.handle(action)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
|
||||
createDirectRoomFilter.setupAsSearch()
|
||||
createDirectRoomFilter.requestFocus()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.riotx.features.home.group
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
|
@ -40,8 +41,8 @@ class GroupListFragment @Inject constructor(
|
|||
|
||||
override fun getLayoutResId() = R.layout.fragment_group_list
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
groupController.callback = this
|
||||
stateView.contentView = groupListEpoxyRecyclerView
|
||||
|
|
|
@ -42,10 +42,10 @@ sealed class RoomDetailAction : VectorViewModelAction {
|
|||
object AcceptInvite : RoomDetailAction()
|
||||
object RejectInvite : RoomDetailAction()
|
||||
|
||||
data class EnterEditMode(val eventId: String, val draft: String) : RoomDetailAction()
|
||||
data class EnterQuoteMode(val eventId: String, val draft: String) : RoomDetailAction()
|
||||
data class EnterReplyMode(val eventId: String, val draft: String) : RoomDetailAction()
|
||||
data class ExitSpecialMode(val draft: String) : RoomDetailAction()
|
||||
data class EnterEditMode(val eventId: String, val text: String) : RoomDetailAction()
|
||||
data class EnterQuoteMode(val eventId: String, val text: String) : RoomDetailAction()
|
||||
data class EnterReplyMode(val eventId: String, val text: String) : RoomDetailAction()
|
||||
data class ExitSpecialMode(val text: String) : RoomDetailAction()
|
||||
|
||||
data class ResendMessage(val eventId: String) : RoomDetailAction()
|
||||
data class RemoveFailedEcho(val eventId: String) : RoomDetailAction()
|
||||
|
|
|
@ -203,15 +203,14 @@ class RoomDetailFragment @Inject constructor(
|
|||
|
||||
private var lockSendButton = false
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
|
||||
attachmentsHelper = AttachmentsHelper.create(this, this).register()
|
||||
keyboardStateUtils = KeyboardStateUtils(requireActivity())
|
||||
setupToolbar(roomToolbar)
|
||||
setupRecyclerView()
|
||||
setupComposer()
|
||||
setupAttachmentButton()
|
||||
setupInviteView()
|
||||
setupNotificationView()
|
||||
setupJumpToReadMarkerView()
|
||||
|
@ -229,7 +228,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
.subscribe {
|
||||
handleActions(it)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
|
||||
roomDetailViewModel.navigateToEvent.observeEvent(this) {
|
||||
val scrollPosition = timelineEventController.searchPositionOfEvent(it)
|
||||
|
@ -274,7 +273,10 @@ class RoomDetailFragment @Inject constructor(
|
|||
roomDetailViewModel.requestLiveData.observeEvent(this) {
|
||||
displayRoomDetailActionResult(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
when (val sharedData = roomDetailArgs.sharedData) {
|
||||
is SharedData.Text -> roomDetailViewModel.handle(RoomDetailAction.SendMessage(sharedData.text, false))
|
||||
|
@ -284,6 +286,11 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
recyclerView.adapter = null
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
debouncer.cancelAll()
|
||||
super.onDestroy()
|
||||
|
@ -470,6 +477,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
recyclerView.adapter = timelineEventController.adapter
|
||||
|
||||
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
if (recyclerView.scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
|
@ -490,6 +498,7 @@ class RoomDetailFragment @Inject constructor(
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
timelineEventController.callback = this
|
||||
|
||||
if (vectorPreferences.swipeToReplyIsEnabled()) {
|
||||
|
@ -592,21 +601,29 @@ class RoomDetailFragment @Inject constructor(
|
|||
})
|
||||
.build()
|
||||
|
||||
composerLayout.sendButton.setOnClickListener {
|
||||
if (lockSendButton) {
|
||||
Timber.w("Send button is locked")
|
||||
return@setOnClickListener
|
||||
}
|
||||
val textMessage = composerLayout.composerEditText.text.toString()
|
||||
if (textMessage.isNotBlank()) {
|
||||
lockSendButton = true
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMessage(textMessage, vectorPreferences.isMarkdownEnabled()))
|
||||
}
|
||||
}
|
||||
composerLayout.composerRelatedMessageCloseButton.setOnClickListener {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ExitSpecialMode(composerLayout.composerEditText.text.toString()))
|
||||
}
|
||||
composerLayout.callback = object : TextComposerView.Callback {
|
||||
override fun onAddAttachment() {
|
||||
if (!::attachmentTypeSelector.isInitialized) {
|
||||
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this@RoomDetailFragment)
|
||||
}
|
||||
attachmentTypeSelector.show(composerLayout.attachmentButton, keyboardStateUtils.isKeyboardShowing)
|
||||
}
|
||||
|
||||
override fun onSendMessage(text: String) {
|
||||
if (lockSendButton) {
|
||||
Timber.w("Send button is locked")
|
||||
return
|
||||
}
|
||||
if (text.isNotBlank()) {
|
||||
lockSendButton = true
|
||||
roomDetailViewModel.handle(RoomDetailAction.SendMessage(text, vectorPreferences.isMarkdownEnabled()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCloseRelatedMessage() {
|
||||
roomDetailViewModel.handle(RoomDetailAction.ExitSpecialMode(composerLayout.text.toString()))
|
||||
}
|
||||
|
||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||
// We need WRITE_EXTERNAL permission
|
||||
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this@RoomDetailFragment, PERMISSION_REQUEST_CODE_INCOMING_URI)) {
|
||||
|
@ -629,15 +646,6 @@ class RoomDetailFragment @Inject constructor(
|
|||
return isHandled
|
||||
}
|
||||
|
||||
private fun setupAttachmentButton() {
|
||||
composerLayout.attachmentButton.setOnClickListener {
|
||||
if (!::attachmentTypeSelector.isInitialized) {
|
||||
attachmentTypeSelector = AttachmentTypeSelectorView(vectorBaseActivity, vectorBaseActivity.layoutInflater, this)
|
||||
}
|
||||
attachmentTypeSelector.show(composerLayout.attachmentButton, keyboardStateUtils.isKeyboardShowing)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupInviteView() {
|
||||
inviteView.callback = this
|
||||
}
|
||||
|
@ -1112,13 +1120,13 @@ class RoomDetailFragment @Inject constructor(
|
|||
roomDetailViewModel.handle(RoomDetailAction.UpdateQuickReactAction(action.eventId, action.clickedOn, action.add))
|
||||
}
|
||||
is EventSharedAction.Edit -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterEditMode(action.eventId, composerLayout.composerEditText.text.toString()))
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterEditMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.Quote -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterQuoteMode(action.eventId, composerLayout.composerEditText.text.toString()))
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterQuoteMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.Reply -> {
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(action.eventId, composerLayout.composerEditText.text.toString()))
|
||||
roomDetailViewModel.handle(RoomDetailAction.EnterReplyMode(action.eventId, composerLayout.text.toString()))
|
||||
}
|
||||
is EventSharedAction.CopyPermalink -> {
|
||||
val permalink = PermalinkFactory.createPermalink(roomDetailArgs.roomId, action.eventId)
|
||||
|
|
|
@ -521,9 +521,10 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||
}
|
||||
|
||||
private fun handleEditAction(action: RoomDetailAction.EnterEditMode) {
|
||||
saveCurrentDraft(action.draft)
|
||||
saveCurrentDraft(action.text)
|
||||
|
||||
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
|
||||
setState { copy(sendMode = SendMode.EDIT(timelineEvent, action.text)) }
|
||||
timelineEvent.root.eventId?.let {
|
||||
room.saveDraft(UserDraft.EDIT(it, timelineEvent.getTextEditableContent() ?: ""))
|
||||
}
|
||||
|
@ -531,16 +532,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||
}
|
||||
|
||||
private fun handleQuoteAction(action: RoomDetailAction.EnterQuoteMode) {
|
||||
saveCurrentDraft(action.draft)
|
||||
saveCurrentDraft(action.text)
|
||||
|
||||
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
|
||||
setState { copy(sendMode = SendMode.QUOTE(timelineEvent, action.text)) }
|
||||
withState { state ->
|
||||
// Save a new draft and keep the previously entered text, if it was not an edit
|
||||
timelineEvent.root.eventId?.let {
|
||||
if (state.sendMode is SendMode.EDIT) {
|
||||
room.saveDraft(UserDraft.QUOTE(it, ""))
|
||||
} else {
|
||||
room.saveDraft(UserDraft.QUOTE(it, action.draft))
|
||||
room.saveDraft(UserDraft.QUOTE(it, action.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -548,16 +550,17 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||
}
|
||||
|
||||
private fun handleReplyAction(action: RoomDetailAction.EnterReplyMode) {
|
||||
saveCurrentDraft(action.draft)
|
||||
saveCurrentDraft(action.text)
|
||||
|
||||
room.getTimeLineEvent(action.eventId)?.let { timelineEvent ->
|
||||
setState { copy(sendMode = SendMode.REPLY(timelineEvent, action.text)) }
|
||||
withState { state ->
|
||||
// Save a new draft and keep the previously entered text, if it was not an edit
|
||||
timelineEvent.root.eventId?.let {
|
||||
if (state.sendMode is SendMode.EDIT) {
|
||||
room.saveDraft(UserDraft.REPLY(it, ""))
|
||||
} else {
|
||||
room.saveDraft(UserDraft.REPLY(it, action.draft))
|
||||
room.saveDraft(UserDraft.REPLY(it, action.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -579,13 +582,14 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||
}
|
||||
|
||||
private fun handleExitSpecialMode(action: RoomDetailAction.ExitSpecialMode) {
|
||||
setState { copy(sendMode = SendMode.REGULAR(action.text)) }
|
||||
withState { state ->
|
||||
// For edit, just delete the current draft
|
||||
if (state.sendMode is SendMode.EDIT) {
|
||||
room.deleteDraft()
|
||||
} else {
|
||||
// Save a new draft and keep the previously entered text
|
||||
room.saveDraft(UserDraft.REGULAR(action.draft))
|
||||
room.saveDraft(UserDraft.REGULAR(action.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.home.room.detail.composer
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.text.Editable
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageButton
|
||||
|
@ -31,6 +32,7 @@ import androidx.transition.TransitionManager
|
|||
import butterknife.BindView
|
||||
import butterknife.ButterKnife
|
||||
import im.vector.riotx.R
|
||||
import kotlinx.android.synthetic.main.merge_composer_layout.view.*
|
||||
|
||||
/**
|
||||
* Encapsulate the timeline composer UX.
|
||||
|
@ -39,7 +41,11 @@ import im.vector.riotx.R
|
|||
class TextComposerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
interface Callback : ComposerEditText.Callback
|
||||
interface Callback : ComposerEditText.Callback {
|
||||
fun onCloseRelatedMessage()
|
||||
fun onSendMessage(text: String)
|
||||
fun onAddAttachment()
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
|
@ -62,15 +68,31 @@ class TextComposerView @JvmOverloads constructor(context: Context, attrs: Attrib
|
|||
|
||||
private val animationDuration = 100L
|
||||
|
||||
val text: Editable?
|
||||
get() = composerEditText.text
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.merge_composer_layout, this)
|
||||
ButterKnife.bind(this)
|
||||
collapse(false)
|
||||
composerEditText.callback = object : Callback, ComposerEditText.Callback {
|
||||
composerEditText.callback = object : ComposerEditText.Callback {
|
||||
override fun onRichContentSelected(contentUri: Uri): Boolean {
|
||||
return callback?.onRichContentSelected(contentUri) ?: false
|
||||
}
|
||||
}
|
||||
composerRelatedMessageCloseButton.setOnClickListener {
|
||||
collapse()
|
||||
callback?.onCloseRelatedMessage()
|
||||
}
|
||||
|
||||
sendButton.setOnClickListener {
|
||||
val textMessage = text?.toString() ?: ""
|
||||
callback?.onSendMessage(textMessage)
|
||||
}
|
||||
|
||||
attachmentButton.setOnClickListener {
|
||||
callback?.onAddAttachment()
|
||||
}
|
||||
}
|
||||
|
||||
fun collapse(animate: Boolean = true, transitionComplete: (() -> Unit)? = null) {
|
||||
|
|
|
@ -139,6 +139,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
|||
|
||||
override fun unbind(holder: H) {
|
||||
holder.readMarkerView.unbind()
|
||||
holder.readReceiptsView.unbind()
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import androidx.core.view.isVisible
|
|||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.glide.GlideApp
|
||||
import im.vector.riotx.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder
|
||||
import im.vector.riotx.features.media.ImageContentRenderer
|
||||
|
||||
|
@ -60,6 +61,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
|||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
GlideApp.with(holder.view.context.applicationContext).clear(holder.imageView)
|
||||
contentUploadStateTrackerBinder.unbind(attributes.informationData.eventId)
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.riotx.R
|
|||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.replaceFragment
|
||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
import im.vector.riotx.features.home.room.list.RoomListParams
|
||||
import kotlinx.android.synthetic.main.activity_filtered_rooms.*
|
||||
|
@ -47,7 +48,7 @@ class FilteredRoomsActivity : VectorBaseActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
configureToolbar(filteredRoomsToolbar)
|
||||
if (isFirstCreation()) {
|
||||
val params = RoomListParams(RoomListFragment.DisplayMode.FILTERED)
|
||||
val params = RoomListParams(RoomListDisplayMode.FILTERED)
|
||||
replaceFragment(R.id.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG)
|
||||
}
|
||||
filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
|
|
|
@ -18,21 +18,22 @@ package im.vector.riotx.features.home.room.list
|
|||
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import io.reactivex.functions.Predicate
|
||||
|
||||
class RoomListDisplayModeFilter(private val displayMode: RoomListFragment.DisplayMode) : Predicate<RoomSummary> {
|
||||
class RoomListDisplayModeFilter(private val displayMode: RoomListDisplayMode) : Predicate<RoomSummary> {
|
||||
|
||||
override fun test(roomSummary: RoomSummary): Boolean {
|
||||
if (roomSummary.membership.isLeft()) {
|
||||
return false
|
||||
}
|
||||
return when (displayMode) {
|
||||
RoomListFragment.DisplayMode.HOME ->
|
||||
RoomListDisplayMode.HOME ->
|
||||
roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE || roomSummary.userDrafts.isNotEmpty()
|
||||
RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListFragment.DisplayMode.FILTERED -> roomSummary.membership == Membership.JOIN
|
||||
RoomListFragment.DisplayMode.SHARE -> roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.FILTERED -> roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.SHARE -> roomSummary.membership == Membership.JOIN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import android.os.Bundle
|
|||
import android.os.Parcelable
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.StringRes
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
|
@ -38,8 +38,10 @@ import im.vector.riotx.core.error.ErrorFormatter
|
|||
import im.vector.riotx.core.platform.OnBackPressed
|
||||
import im.vector.riotx.core.platform.StateView
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||
import im.vector.riotx.features.home.room.list.widget.FabMenuView
|
||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
|
@ -51,7 +53,7 @@ import javax.inject.Inject
|
|||
|
||||
@Parcelize
|
||||
data class RoomListParams(
|
||||
val displayMode: RoomListFragment.DisplayMode,
|
||||
val displayMode: RoomListDisplayMode,
|
||||
val sharedData: SharedData? = null
|
||||
) : Parcelable
|
||||
|
||||
|
@ -63,14 +65,6 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
|
||||
|
||||
enum class DisplayMode(@StringRes val titleRes: Int) {
|
||||
HOME(R.string.bottom_action_home),
|
||||
PEOPLE(R.string.bottom_action_people_x),
|
||||
ROOMS(R.string.bottom_action_rooms),
|
||||
FILTERED(/* Not used */ 0),
|
||||
SHARE(/* Not used */ 0)
|
||||
}
|
||||
|
||||
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||
private val roomListParams: RoomListParams by args()
|
||||
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
||||
|
@ -97,13 +91,13 @@ class RoomListFragment @Inject constructor(
|
|||
super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupCreateRoomButton()
|
||||
setupRecyclerView()
|
||||
roomListViewModel.subscribe { renderState(it) }
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
|
||||
roomListViewModel.subscribe { renderState(it) }
|
||||
roomListViewModel.viewEvents
|
||||
.observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
@ -113,18 +107,23 @@ class RoomListFragment @Inject constructor(
|
|||
is RoomListViewEvents.Failure -> showError(it)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
|
||||
createChatFabMenu.listener = this
|
||||
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
.subscribe { handleQuickActions(it) }
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
roomListView.adapter = null
|
||||
}
|
||||
|
||||
private fun openSelectedRoom(event: RoomListViewEvents.SelectRoom) {
|
||||
if (roomListParams.displayMode == DisplayMode.SHARE) {
|
||||
if (roomListParams.displayMode == RoomListDisplayMode.SHARE) {
|
||||
val sharedData = roomListParams.sharedData ?: return
|
||||
navigator.openRoomForSharing(requireActivity(), event.roomId, sharedData)
|
||||
} else {
|
||||
|
@ -141,9 +140,9 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
private fun setupCreateRoomButton() {
|
||||
when (roomListParams.displayMode) {
|
||||
DisplayMode.HOME -> createChatFabMenu.isVisible = true
|
||||
DisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
|
||||
DisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
|
||||
RoomListDisplayMode.HOME -> createChatFabMenu.isVisible = true
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
|
||||
else -> Unit // No button in this mode
|
||||
}
|
||||
|
||||
|
@ -155,7 +154,7 @@ class RoomListFragment @Inject constructor(
|
|||
}
|
||||
|
||||
// Hide FAB when list is scrolling
|
||||
roomListEpoxyRecyclerView.addOnScrollListener(
|
||||
roomListView.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
createChatFabMenu.removeCallbacks(showFabRunnable)
|
||||
|
@ -167,9 +166,9 @@ class RoomListFragment @Inject constructor(
|
|||
RecyclerView.SCROLL_STATE_DRAGGING,
|
||||
RecyclerView.SCROLL_STATE_SETTLING -> {
|
||||
when (roomListParams.displayMode) {
|
||||
DisplayMode.HOME -> createChatFabMenu.hide()
|
||||
DisplayMode.PEOPLE -> createChatRoomButton.hide()
|
||||
DisplayMode.ROOMS -> createGroupRoomButton.hide()
|
||||
RoomListDisplayMode.HOME -> createChatFabMenu.hide()
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide()
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
@ -180,7 +179,7 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
fun filterRoomsWith(filter: String) {
|
||||
// Scroll the list to top
|
||||
roomListEpoxyRecyclerView.scrollToPosition(0)
|
||||
roomListView.scrollToPosition(0)
|
||||
|
||||
roomListViewModel.handle(RoomListAction.FilterWith(filter))
|
||||
}
|
||||
|
@ -196,20 +195,20 @@ class RoomListFragment @Inject constructor(
|
|||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||
roomListEpoxyRecyclerView.layoutManager = layoutManager
|
||||
roomListEpoxyRecyclerView.itemAnimator = RoomListAnimator()
|
||||
roomListView.layoutManager = layoutManager
|
||||
roomListView.itemAnimator = RoomListAnimator()
|
||||
roomController.listener = this
|
||||
roomController.addModelBuildListener { it.dispatchTo(stateRestorer) }
|
||||
stateView.contentView = roomListEpoxyRecyclerView
|
||||
roomListEpoxyRecyclerView.setController(roomController)
|
||||
roomListView.adapter = roomController.adapter
|
||||
stateView.contentView = roomListView
|
||||
}
|
||||
|
||||
private val showFabRunnable = Runnable {
|
||||
if (isAdded) {
|
||||
when (roomListParams.displayMode) {
|
||||
DisplayMode.HOME -> createChatFabMenu.show()
|
||||
DisplayMode.PEOPLE -> createChatRoomButton.show()
|
||||
DisplayMode.ROOMS -> createGroupRoomButton.show()
|
||||
RoomListDisplayMode.HOME -> createChatFabMenu.show()
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.show()
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
@ -255,9 +254,9 @@ class RoomListFragment @Inject constructor(
|
|||
|
||||
// Mark all as read menu
|
||||
when (roomListParams.displayMode) {
|
||||
DisplayMode.HOME,
|
||||
DisplayMode.PEOPLE,
|
||||
DisplayMode.ROOMS -> {
|
||||
RoomListDisplayMode.HOME,
|
||||
RoomListDisplayMode.PEOPLE,
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
val newValue = state.hasUnread
|
||||
if (hasUnreadRooms != newValue) {
|
||||
hasUnreadRooms = newValue
|
||||
|
@ -285,7 +284,7 @@ class RoomListFragment @Inject constructor(
|
|||
}
|
||||
.isNullOrEmpty()
|
||||
val emptyState = when (roomListParams.displayMode) {
|
||||
DisplayMode.HOME -> {
|
||||
RoomListDisplayMode.HOME -> {
|
||||
if (hasNoRoom) {
|
||||
StateView.State.Empty(
|
||||
getString(R.string.room_list_catchup_welcome_title),
|
||||
|
@ -299,13 +298,13 @@ class RoomListFragment @Inject constructor(
|
|||
getString(R.string.room_list_catchup_empty_body))
|
||||
}
|
||||
}
|
||||
DisplayMode.PEOPLE ->
|
||||
RoomListDisplayMode.PEOPLE ->
|
||||
StateView.State.Empty(
|
||||
getString(R.string.room_list_people_empty_title),
|
||||
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_chat),
|
||||
getString(R.string.room_list_people_empty_body)
|
||||
)
|
||||
DisplayMode.ROOMS ->
|
||||
RoomListDisplayMode.ROOMS ->
|
||||
StateView.State.Empty(
|
||||
getString(R.string.room_list_rooms_empty_title),
|
||||
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_group),
|
||||
|
|
|
@ -33,9 +33,7 @@ import javax.inject.Inject
|
|||
|
||||
class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
||||
private val session: Session,
|
||||
private val roomSummariesSource: DataSource<List<RoomSummary>>,
|
||||
private val alphabeticalRoomComparator: AlphabeticalRoomComparator,
|
||||
private val chronologicalRoomComparator: ChronologicalRoomComparator)
|
||||
private val roomSummariesSource: DataSource<List<RoomSummary>>)
|
||||
: VectorViewModel<RoomListViewState, RoomListAction>(initialState) {
|
||||
|
||||
interface Factory {
|
||||
|
@ -96,9 +94,6 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
roomSummariesSource
|
||||
.observe()
|
||||
.observeOn(Schedulers.computation())
|
||||
.map {
|
||||
it.sortedWith(chronologicalRoomComparator)
|
||||
}
|
||||
.execute { asyncRooms ->
|
||||
copy(asyncRooms = asyncRooms)
|
||||
}
|
||||
|
@ -210,10 +205,11 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
}
|
||||
|
||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||
// Set up init size on directChats and groupRooms as they are the biggest ones
|
||||
val invites = ArrayList<RoomSummary>()
|
||||
val favourites = ArrayList<RoomSummary>()
|
||||
val directChats = ArrayList<RoomSummary>()
|
||||
val groupRooms = ArrayList<RoomSummary>()
|
||||
val directChats = ArrayList<RoomSummary>(rooms.size)
|
||||
val groupRooms = ArrayList<RoomSummary>(rooms.size)
|
||||
val lowPriorities = ArrayList<RoomSummary>()
|
||||
val serverNotices = ArrayList<RoomSummary>()
|
||||
|
||||
|
@ -231,21 +227,13 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
|||
}
|
||||
}
|
||||
|
||||
val roomComparator = when (displayMode) {
|
||||
RoomListFragment.DisplayMode.HOME -> chronologicalRoomComparator
|
||||
RoomListFragment.DisplayMode.PEOPLE -> chronologicalRoomComparator
|
||||
RoomListFragment.DisplayMode.ROOMS -> chronologicalRoomComparator
|
||||
RoomListFragment.DisplayMode.FILTERED -> chronologicalRoomComparator
|
||||
RoomListFragment.DisplayMode.SHARE -> chronologicalRoomComparator
|
||||
}
|
||||
|
||||
return RoomSummaries().apply {
|
||||
put(RoomCategory.INVITE, invites.sortedWith(roomComparator))
|
||||
put(RoomCategory.FAVOURITE, favourites.sortedWith(roomComparator))
|
||||
put(RoomCategory.DIRECT, directChats.sortedWith(roomComparator))
|
||||
put(RoomCategory.GROUP, groupRooms.sortedWith(roomComparator))
|
||||
put(RoomCategory.LOW_PRIORITY, lowPriorities.sortedWith(roomComparator))
|
||||
put(RoomCategory.SERVER_NOTICE, serverNotices.sortedWith(roomComparator))
|
||||
put(RoomCategory.INVITE, invites)
|
||||
put(RoomCategory.FAVOURITE, favourites)
|
||||
put(RoomCategory.DIRECT, directChats)
|
||||
put(RoomCategory.GROUP, groupRooms)
|
||||
put(RoomCategory.LOW_PRIORITY, lowPriorities)
|
||||
put(RoomCategory.SERVER_NOTICE, serverNotices)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,22 +18,21 @@ package im.vector.riotx.features.home.room.list
|
|||
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.riotx.features.home.HomeRoomListDataSource
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import im.vector.riotx.features.share.ShareRoomListDataSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
|
||||
private val homeRoomListDataSource: Provider<HomeRoomListDataSource>,
|
||||
private val shareRoomListDataSource: Provider<ShareRoomListDataSource>,
|
||||
private val alphabeticalRoomComparator: Provider<AlphabeticalRoomComparator>,
|
||||
private val chronologicalRoomComparator: Provider<ChronologicalRoomComparator>) : RoomListViewModel.Factory {
|
||||
private val shareRoomListDataSource: Provider<ShareRoomListDataSource>)
|
||||
: RoomListViewModel.Factory {
|
||||
|
||||
override fun create(initialState: RoomListViewState): RoomListViewModel {
|
||||
return RoomListViewModel(
|
||||
initialState,
|
||||
session.get(),
|
||||
if (initialState.displayMode == RoomListFragment.DisplayMode.SHARE) shareRoomListDataSource.get() else homeRoomListDataSource.get(),
|
||||
alphabeticalRoomComparator.get(),
|
||||
chronologicalRoomComparator.get())
|
||||
if (initialState.displayMode == RoomListDisplayMode.SHARE) shareRoomListDataSource.get() else homeRoomListDataSource.get()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,10 @@ import com.airbnb.mvrx.Uninitialized
|
|||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
|
||||
data class RoomListViewState(
|
||||
val displayMode: RoomListFragment.DisplayMode,
|
||||
val displayMode: RoomListDisplayMode,
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val roomFilter: String = "",
|
||||
val asyncFilteredRooms: Async<RoomSummaries> = Uninitialized,
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.riotx.R
|
|||
import im.vector.riotx.core.epoxy.helpFooterItem
|
||||
import im.vector.riotx.core.epoxy.noResultItem
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||
import im.vector.riotx.features.home.room.filtered.FilteredRoomFooterItem
|
||||
import im.vector.riotx.features.home.room.filtered.filteredRoomFooterItem
|
||||
|
@ -58,8 +59,8 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
|||
override fun buildModels() {
|
||||
val nonNullViewState = viewState ?: return
|
||||
when (nonNullViewState.displayMode) {
|
||||
RoomListFragment.DisplayMode.FILTERED,
|
||||
RoomListFragment.DisplayMode.SHARE -> {
|
||||
RoomListDisplayMode.FILTERED,
|
||||
RoomListDisplayMode.SHARE -> {
|
||||
buildFilteredRooms(nonNullViewState)
|
||||
}
|
||||
else -> {
|
||||
|
@ -106,7 +107,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
|||
viewState.rejectingErrorRoomsIds)
|
||||
|
||||
when {
|
||||
viewState.displayMode == RoomListFragment.DisplayMode.FILTERED -> addFilterFooter(viewState)
|
||||
viewState.displayMode == RoomListDisplayMode.FILTERED -> addFilterFooter(viewState)
|
||||
filteredSummaries.isEmpty() -> addEmptyFooter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ class LoginFragment @Inject constructor() : VectorBaseFragment() {
|
|||
viewModel.handle(LoginAction.UpdateHomeServer(homeServerField.text.toString()))
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
|
||||
homeServerField.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
|
@ -107,7 +107,7 @@ class LoginFragment @Inject constructor() : VectorBaseFragment() {
|
|||
}
|
||||
)
|
||||
.subscribeBy { authenticateButton.isEnabled = it }
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
authenticateButton.setOnClickListener { authenticate() }
|
||||
|
||||
authenticateButtonSso.setOnClickListener { openSso() }
|
||||
|
|
|
@ -116,7 +116,6 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
|||
private fun onSessionCreated(session: Session) {
|
||||
activeSessionHolder.setActiveSession(session)
|
||||
session.configureAndStart(pushRuleTriggerListener, sessionListener)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
asyncLoginAction = Success(Unit)
|
||||
|
@ -131,9 +130,15 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
|||
// Should not happen
|
||||
Timber.w("homeServerConnectionConfig is null")
|
||||
} else {
|
||||
val session = authenticator.createSessionFromSso(action.credentials, homeServerConnectionConfigFinal)
|
||||
authenticator.createSessionFromSso(action.credentials, homeServerConnectionConfigFinal, object : MatrixCallback<Session> {
|
||||
override fun onSuccess(data: Session) {
|
||||
onSessionCreated(data)
|
||||
}
|
||||
|
||||
onSessionCreated(session)
|
||||
override fun onFailure(failure: Throwable) = setState {
|
||||
copy(asyncLoginAction = Fail(failure))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +154,7 @@ class LoginViewModel @AssistedInject constructor(@Assisted initialState: LoginVi
|
|||
|
||||
// Do not retry if we already have flows for this config -> causes infinite focus loop
|
||||
if (newConfig?.homeServerUri?.toString() == homeServerConnectionConfig?.homeServerUri?.toString()
|
||||
&& state.asyncHomeServerLoginFlowRequest is Success) return@withState
|
||||
&& state.asyncHomeServerLoginFlowRequest is Success) return@withState
|
||||
|
||||
currentTask?.cancel()
|
||||
homeServerConnectionConfig = newConfig
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.riotx.features.reactions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
|
@ -27,8 +28,8 @@ class EmojiChooserFragment @Inject constructor() : VectorBaseFragment() {
|
|||
|
||||
private lateinit var viewModel: EmojiChooserViewModel
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel = activityViewModelProvider.get(EmojiChooserViewModel::class.java)
|
||||
viewModel.initWithContext(context!!)
|
||||
(view as? RecyclerView)?.let {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package im.vector.riotx.features.reactions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -37,9 +38,8 @@ class EmojiSearchResultFragment @Inject constructor(
|
|||
|
||||
var sharedViewModel: EmojiChooserViewModel? = null
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedViewModel = activityViewModelProvider.get(EmojiChooserViewModel::class.java)
|
||||
|
||||
epoxyController.listener = object : ReactionClickListener {
|
||||
|
|
|
@ -67,7 +67,7 @@ class PublicRoomsFragment @Inject constructor(
|
|||
.subscribeBy {
|
||||
viewModel.handle(RoomDirectoryAction.FilterWith(it.toString()))
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
.disposeOnDestroyView()
|
||||
|
||||
publicRoomsCreateNewRoom.setOnClickListener {
|
||||
sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoom)
|
||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.riotx.features.roomdirectory.createroom
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
|
@ -39,8 +40,8 @@ class CreateRoomFragment @Inject constructor(private val createRoomController: C
|
|||
|
||||
override fun getMenuRes() = R.menu.vector_room_creation
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
vectorBaseActivity.setSupportActionBar(createRoomToolbar)
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||
setupRecyclerView()
|
||||
|
|
|
@ -55,6 +55,9 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
|||
it.setDisplayShowHomeEnabled(true)
|
||||
it.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
||||
override fun getMenuRes() = R.menu.menu_directory_server_picker
|
||||
|
@ -69,12 +72,6 @@ class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerVie
|
|||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomDirectorySharedActionViewModel::class.java)
|
||||
setupRecyclerView()
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
|
||||
|
|
|
@ -45,16 +45,11 @@ class RoomPreviewNoPreviewFragment @Inject constructor(
|
|||
private val roomPreviewViewModel: RoomPreviewViewModel by fragmentViewModel()
|
||||
private val roomPreviewData: RoomPreviewData by args()
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
setupToolbar(roomPreviewNoPreviewToolbar)
|
||||
}
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_room_preview_no_preview
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
setupToolbar(roomPreviewNoPreviewToolbar)
|
||||
// Toolbar
|
||||
avatarRenderer.render(roomPreviewData.avatarUrl, roomPreviewData.roomId, roomPreviewData.roomName, roomPreviewNoPreviewToolbarAvatar)
|
||||
roomPreviewNoPreviewToolbarTitle.text = roomPreviewData.roomName
|
||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.riotx.core.extensions.replaceFragment
|
|||
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||
import im.vector.riotx.features.attachments.AttachmentsHelper
|
||||
import im.vector.riotx.features.home.LoadingFragment
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
import im.vector.riotx.features.home.room.list.RoomListParams
|
||||
import im.vector.riotx.features.login.LoginActivity
|
||||
|
@ -97,7 +98,7 @@ class IncomingShareActivity :
|
|||
}
|
||||
|
||||
override fun onContentAttachmentsReady(attachments: List<ContentAttachmentData>) {
|
||||
val roomListParams = RoomListParams(RoomListFragment.DisplayMode.SHARE, sharedData = SharedData.Attachments(attachments))
|
||||
val roomListParams = RoomListParams(RoomListDisplayMode.SHARE, sharedData = SharedData.Attachments(attachments))
|
||||
replaceFragment(R.id.shareRoomListFragmentContainer, RoomListFragment::class.java, roomListParams)
|
||||
}
|
||||
|
||||
|
@ -116,7 +117,7 @@ class IncomingShareActivity :
|
|||
return if (sharedText.isNullOrEmpty()) {
|
||||
false
|
||||
} else {
|
||||
val roomListParams = RoomListParams(RoomListFragment.DisplayMode.SHARE, sharedData = SharedData.Text(sharedText))
|
||||
val roomListParams = RoomListParams(RoomListDisplayMode.SHARE, sharedData = SharedData.Text(sharedText))
|
||||
replaceFragment(R.id.shareRoomListFragmentContainer, RoomListFragment::class.java, roomListParams)
|
||||
true
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package im.vector.riotx.features.ui
|
|||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -26,21 +26,21 @@ import javax.inject.Inject
|
|||
*/
|
||||
class SharedPreferencesUiStateRepository @Inject constructor(private val sharedPreferences: SharedPreferences) : UiStateRepository {
|
||||
|
||||
override fun getDisplayMode(): RoomListFragment.DisplayMode {
|
||||
override fun getDisplayMode(): RoomListDisplayMode {
|
||||
return when (sharedPreferences.getInt(KEY_DISPLAY_MODE, VALUE_DISPLAY_MODE_CATCHUP)) {
|
||||
VALUE_DISPLAY_MODE_PEOPLE -> RoomListFragment.DisplayMode.PEOPLE
|
||||
VALUE_DISPLAY_MODE_ROOMS -> RoomListFragment.DisplayMode.ROOMS
|
||||
else -> RoomListFragment.DisplayMode.HOME
|
||||
VALUE_DISPLAY_MODE_PEOPLE -> RoomListDisplayMode.PEOPLE
|
||||
VALUE_DISPLAY_MODE_ROOMS -> RoomListDisplayMode.ROOMS
|
||||
else -> RoomListDisplayMode.HOME
|
||||
}
|
||||
}
|
||||
|
||||
override fun storeDisplayMode(displayMode: RoomListFragment.DisplayMode) {
|
||||
override fun storeDisplayMode(displayMode: RoomListDisplayMode) {
|
||||
sharedPreferences.edit {
|
||||
putInt(KEY_DISPLAY_MODE,
|
||||
when (displayMode) {
|
||||
RoomListFragment.DisplayMode.PEOPLE -> VALUE_DISPLAY_MODE_PEOPLE
|
||||
RoomListFragment.DisplayMode.ROOMS -> VALUE_DISPLAY_MODE_ROOMS
|
||||
else -> VALUE_DISPLAY_MODE_CATCHUP
|
||||
RoomListDisplayMode.PEOPLE -> VALUE_DISPLAY_MODE_PEOPLE
|
||||
RoomListDisplayMode.ROOMS -> VALUE_DISPLAY_MODE_ROOMS
|
||||
else -> VALUE_DISPLAY_MODE_CATCHUP
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
|
||||
package im.vector.riotx.features.ui
|
||||
|
||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||
import im.vector.riotx.features.home.RoomListDisplayMode
|
||||
|
||||
/**
|
||||
* This interface is used to persist UI state across application restart
|
||||
*/
|
||||
interface UiStateRepository {
|
||||
|
||||
fun getDisplayMode(): RoomListFragment.DisplayMode
|
||||
fun getDisplayMode(): RoomListDisplayMode
|
||||
|
||||
fun storeDisplayMode(displayMode: RoomListFragment.DisplayMode)
|
||||
fun storeDisplayMode(displayMode: RoomListDisplayMode)
|
||||
}
|
||||
|
|
|
@ -90,10 +90,8 @@
|
|||
|
||||
<ImageButton
|
||||
android:id="@+id/composer_related_message_close"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_close_round"
|
||||
android:tint="@color/riotx_notice"
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
android:layout_height="match_parent"
|
||||
android:background="?riotx_header_panel_background">
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/roomListEpoxyRecyclerView"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/roomListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:overScrollMode="always" />
|
||||
|
@ -30,7 +30,7 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:accessibilityTraversalBefore="@+id/roomListEpoxyRecyclerView"
|
||||
android:accessibilityTraversalBefore="@+id/roomListView"
|
||||
android:contentDescription="@string/a11y_create_direct_message"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_fab_add_chat"
|
||||
|
@ -47,7 +47,7 @@
|
|||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:accessibilityTraversalBefore="@+id/roomListEpoxyRecyclerView"
|
||||
android:accessibilityTraversalBefore="@+id/roomListView"
|
||||
android:contentDescription="@string/a11y_create_room"
|
||||
android:src="@drawable/ic_fab_add_room"
|
||||
android:visibility="gone"
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:accessibilityTraversalBefore="@+id/roomListEpoxyRecyclerView"
|
||||
android:accessibilityTraversalBefore="@+id/roomListView"
|
||||
android:contentDescription="@string/a11y_create_room"
|
||||
android:src="@drawable/ic_fab_add_room"
|
||||
app:backgroundTint="#FFFFFF"
|
||||
|
|
Loading…
Reference in New Issue