commit
e73923dca3
@ -2,7 +2,7 @@ Changes in RiotX 0.10.0 (2019-XX-XX)
|
|||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
Features ✨:
|
Features ✨:
|
||||||
-
|
- Breadcrumbs: switch from one room to another quickly (#571)
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
-
|
-
|
||||||
|
@ -17,7 +17,7 @@ Client request the sign-up flows, once the homeserver is chosen by the user and
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We get the flows with a 401, which also means the the registration is possible on this homeserver.
|
We get the flows with a 401, which also means that the registration is possible on this homeserver.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,10 @@ class RxSession(private val session: Session) {
|
|||||||
return session.liveGroupSummaries().asObservable()
|
return session.liveGroupSummaries().asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun liveBreadcrumbs(): Observable<List<RoomSummary>> {
|
||||||
|
return session.liveBreadcrumbs().asObservable()
|
||||||
|
}
|
||||||
|
|
||||||
fun liveSyncState(): Observable<SyncState> {
|
fun liveSyncState(): Observable<SyncState> {
|
||||||
return session.syncState().asObservable()
|
return session.syncState().asObservable()
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,18 @@ interface RoomService {
|
|||||||
*/
|
*/
|
||||||
fun liveRoomSummaries(): LiveData<List<RoomSummary>>
|
fun liveRoomSummaries(): LiveData<List<RoomSummary>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a live list of Breadcrumbs
|
||||||
|
* @return the [LiveData] of [RoomSummary]
|
||||||
|
*/
|
||||||
|
fun liveBreadcrumbs(): LiveData<List<RoomSummary>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inform the Matrix SDK that a room is displayed.
|
||||||
|
* The SDK will update the breadcrumbs in the user account data
|
||||||
|
*/
|
||||||
|
fun onRoomDisplayed(roomId: String): Cancelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark all rooms as read
|
* Mark all rooms as read
|
||||||
*/
|
*/
|
||||||
|
@ -19,16 +19,14 @@ package im.vector.matrix.android.internal.crypto.store.db.query
|
|||||||
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntity
|
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntity
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntityFields
|
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or create a room
|
* Get or create a room
|
||||||
*/
|
*/
|
||||||
internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity {
|
internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity {
|
||||||
return getById(realm, roomId)
|
return getById(realm, roomId) ?: realm.createObject(roomId)
|
||||||
?: let {
|
|
||||||
realm.createObject(CryptoRoomEntity::class.java, roomId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,18 +20,20 @@ import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntity
|
|||||||
import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityFields
|
import im.vector.matrix.android.internal.crypto.store.db.model.DeviceInfoEntityFields
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.model.createPrimaryKey
|
import im.vector.matrix.android.internal.crypto.store.db.model.createPrimaryKey
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get or create a device info
|
* Get or create a device info
|
||||||
*/
|
*/
|
||||||
internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity {
|
internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity {
|
||||||
|
val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId)
|
||||||
|
|
||||||
return realm.where<DeviceInfoEntity>()
|
return realm.where<DeviceInfoEntity>()
|
||||||
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, DeviceInfoEntity.createPrimaryKey(userId, deviceId))
|
.equalTo(DeviceInfoEntityFields.PRIMARY_KEY, key)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?: let {
|
?: realm.createObject<DeviceInfoEntity>(key)
|
||||||
realm.createObject(DeviceInfoEntity::class.java, DeviceInfoEntity.createPrimaryKey(userId, deviceId)).apply {
|
.apply {
|
||||||
this.deviceId = deviceId
|
this.deviceId = deviceId
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.crypto.store.db.query
|
|||||||
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntity
|
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntity
|
||||||
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields
|
import im.vector.matrix.android.internal.crypto.store.db.model.UserEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,9 +29,7 @@ internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): Use
|
|||||||
return realm.where<UserEntity>()
|
return realm.where<UserEntity>()
|
||||||
.equalTo(UserEntityFields.USER_ID, userId)
|
.equalTo(UserEntityFields.USER_ID, userId)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
?: let {
|
?: realm.createObject(userId)
|
||||||
realm.createObject(UserEntity::class.java, userId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.matrix.android.internal.database.model
|
||||||
|
|
||||||
|
import io.realm.RealmList
|
||||||
|
import io.realm.RealmObject
|
||||||
|
|
||||||
|
internal open class BreadcrumbsEntity(
|
||||||
|
var recentRoomIds: RealmList<String> = RealmList()
|
||||||
|
) : RealmObject() {
|
||||||
|
|
||||||
|
companion object
|
||||||
|
}
|
@ -38,7 +38,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||||||
var readMarkerId: String? = null,
|
var readMarkerId: String? = null,
|
||||||
var hasUnreadMessages: Boolean = false,
|
var hasUnreadMessages: Boolean = false,
|
||||||
var tags: RealmList<RoomTagEntity> = RealmList(),
|
var tags: RealmList<RoomTagEntity> = RealmList(),
|
||||||
var userDrafts: UserDraftsEntity? = null
|
var userDrafts: UserDraftsEntity? = null,
|
||||||
|
var breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS
|
||||||
) : RealmObject() {
|
) : RealmObject() {
|
||||||
|
|
||||||
private var membershipStr: String = Membership.NONE.name
|
private var membershipStr: String = Membership.NONE.name
|
||||||
@ -59,5 +60,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||||||
versioningStateStr = value.name
|
versioningStateStr = value.name
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object
|
companion object {
|
||||||
|
const val NOT_IN_BREADCRUMBS = -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import io.realm.annotations.RealmModule
|
|||||||
SyncEntity::class,
|
SyncEntity::class,
|
||||||
UserEntity::class,
|
UserEntity::class,
|
||||||
IgnoredUserEntity::class,
|
IgnoredUserEntity::class,
|
||||||
|
BreadcrumbsEntity::class,
|
||||||
EventAnnotationsSummaryEntity::class,
|
EventAnnotationsSummaryEntity::class,
|
||||||
ReactionAggregatedSummaryEntity::class,
|
ReactionAggregatedSummaryEntity::class,
|
||||||
EditAggregatedSummaryEntity::class,
|
EditAggregatedSummaryEntity::class,
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.matrix.android.internal.database.query
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
|
internal fun BreadcrumbsEntity.Companion.get(realm: Realm): BreadcrumbsEntity? {
|
||||||
|
return realm.where<BreadcrumbsEntity>().findFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun BreadcrumbsEntity.Companion.getOrCreate(realm: Realm): BreadcrumbsEntity {
|
||||||
|
return get(realm) ?: realm.createObject()
|
||||||
|
}
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.ReadMarkerEntity
|
|||||||
import im.vector.matrix.android.internal.database.model.ReadMarkerEntityFields
|
import im.vector.matrix.android.internal.database.model.ReadMarkerEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<ReadMarkerEntity> {
|
internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<ReadMarkerEntity> {
|
||||||
@ -28,6 +29,5 @@ internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String): Rea
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun ReadMarkerEntity.Companion.getOrCreate(realm: Realm, roomId: String): ReadMarkerEntity {
|
internal fun ReadMarkerEntity.Companion.getOrCreate(realm: Realm, roomId: String): ReadMarkerEntity {
|
||||||
return where(realm, roomId).findFirst()
|
return where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||||
?: realm.createObject(ReadMarkerEntity::class.java, roomId)
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
|||||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntityFields
|
import im.vector.matrix.android.internal.database.model.ReadReceiptEntityFields
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery<ReadReceiptEntity> {
|
internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery<ReadReceiptEntity> {
|
||||||
@ -44,10 +45,11 @@ internal fun ReadReceiptEntity.Companion.createUnmanaged(roomId: String, eventId
|
|||||||
|
|
||||||
internal fun ReadReceiptEntity.Companion.getOrCreate(realm: Realm, roomId: String, userId: String): ReadReceiptEntity {
|
internal fun ReadReceiptEntity.Companion.getOrCreate(realm: Realm, roomId: String, userId: String): ReadReceiptEntity {
|
||||||
return ReadReceiptEntity.where(realm, roomId, userId).findFirst()
|
return ReadReceiptEntity.where(realm, roomId, userId).findFirst()
|
||||||
?: realm.createObject(ReadReceiptEntity::class.java, buildPrimaryKey(roomId, userId)).apply {
|
?: realm.createObject<ReadReceiptEntity>(buildPrimaryKey(roomId, userId))
|
||||||
this.roomId = roomId
|
.apply {
|
||||||
this.userId = userId
|
this.roomId = roomId
|
||||||
}
|
this.userId = userId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildPrimaryKey(roomId: String, userId: String) = "${roomId}_$userId"
|
private fun buildPrimaryKey(roomId: String, userId: String) = "${roomId}_$userId"
|
||||||
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
|||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
import io.realm.RealmResults
|
import io.realm.RealmResults
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
import io.realm.kotlin.where
|
import io.realm.kotlin.where
|
||||||
|
|
||||||
internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<RoomSummaryEntity> {
|
internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<RoomSummaryEntity> {
|
||||||
@ -32,8 +33,7 @@ internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = n
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun RoomSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String): RoomSummaryEntity {
|
internal fun RoomSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String): RoomSummaryEntity {
|
||||||
return where(realm, roomId).findFirst()
|
return where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||||
?: realm.createObject(RoomSummaryEntity::class.java, roomId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm): RealmResults<RoomSummaryEntity> {
|
internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm): RealmResults<RoomSummaryEntity> {
|
||||||
|
@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.room.model.message.*
|
|||||||
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
|
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
|
||||||
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataBreadcrumbs
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataDirectMessages
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataDirectMessages
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataFallback
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataFallback
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers
|
||||||
@ -34,6 +35,7 @@ object MoshiProvider {
|
|||||||
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
||||||
.registerSubtype(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST)
|
.registerSubtype(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST)
|
||||||
.registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES)
|
.registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES)
|
||||||
|
.registerSubtype(UserAccountDataBreadcrumbs::class.java, UserAccountData.TYPE_BREADCRUMBS)
|
||||||
)
|
)
|
||||||
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
|
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
|
||||||
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
||||||
|
@ -33,6 +33,7 @@ import im.vector.matrix.android.internal.database.query.where
|
|||||||
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
|
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
|
||||||
import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask
|
import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask
|
||||||
import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask
|
import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask
|
||||||
|
import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcrumbsTask
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
@ -43,6 +44,7 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
|||||||
private val createRoomTask: CreateRoomTask,
|
private val createRoomTask: CreateRoomTask,
|
||||||
private val joinRoomTask: JoinRoomTask,
|
private val joinRoomTask: JoinRoomTask,
|
||||||
private val markAllRoomsReadTask: MarkAllRoomsReadTask,
|
private val markAllRoomsReadTask: MarkAllRoomsReadTask,
|
||||||
|
private val updateBreadcrumbsTask: UpdateBreadcrumbsTask,
|
||||||
private val roomFactory: RoomFactory,
|
private val roomFactory: RoomFactory,
|
||||||
private val taskExecutor: TaskExecutor) : RoomService {
|
private val taskExecutor: TaskExecutor) : RoomService {
|
||||||
|
|
||||||
@ -75,6 +77,25 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun liveBreadcrumbs(): LiveData<List<RoomSummary>> {
|
||||||
|
return monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm ->
|
||||||
|
RoomSummaryEntity.where(realm)
|
||||||
|
.isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME)
|
||||||
|
.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name)
|
||||||
|
.greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummaryEntity.NOT_IN_BREADCRUMBS)
|
||||||
|
.sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX)
|
||||||
|
},
|
||||||
|
{ roomSummaryMapper.map(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRoomDisplayed(roomId: String): Cancelable {
|
||||||
|
return updateBreadcrumbsTask
|
||||||
|
.configureWith(UpdateBreadcrumbsTask.Params(roomId))
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
override fun joinRoom(roomId: String, viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
override fun joinRoom(roomId: String, viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||||
return joinRoomTask
|
return joinRoomTask
|
||||||
.configureWith(JoinRoomTask.Params(roomId, viaServers)) {
|
.configureWith(JoinRoomTask.Params(roomId, viaServers)) {
|
||||||
|
@ -29,6 +29,7 @@ import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
|||||||
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.*
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.*
|
||||||
import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper
|
import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper
|
||||||
|
import im.vector.matrix.android.internal.session.user.accountdata.SaveBreadcrumbsTask
|
||||||
import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
|
import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
|
||||||
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
|
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
@ -44,6 +45,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
|||||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||||
private val savePushRulesTask: SavePushRulesTask,
|
private val savePushRulesTask: SavePushRulesTask,
|
||||||
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
|
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
|
||||||
|
private val saveBreadcrumbsTask: SaveBreadcrumbsTask,
|
||||||
private val taskExecutor: TaskExecutor) {
|
private val taskExecutor: TaskExecutor) {
|
||||||
|
|
||||||
suspend fun handle(accountData: UserAccountDataSync?, invites: Map<String, InvitedRoomSync>?) {
|
suspend fun handle(accountData: UserAccountDataSync?, invites: Map<String, InvitedRoomSync>?) {
|
||||||
@ -52,6 +54,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
|||||||
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
|
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
|
||||||
is UserAccountDataPushRules -> handlePushRules(it)
|
is UserAccountDataPushRules -> handlePushRules(it)
|
||||||
is UserAccountDataIgnoredUsers -> handleIgnoredUsers(it)
|
is UserAccountDataIgnoredUsers -> handleIgnoredUsers(it)
|
||||||
|
is UserAccountDataBreadcrumbs -> handleBreadcrumbs(it)
|
||||||
is UserAccountDataFallback -> Timber.d("Receive account data of unhandled type ${it.type}")
|
is UserAccountDataFallback -> Timber.d("Receive account data of unhandled type ${it.type}")
|
||||||
else -> error("Missing code here!")
|
else -> error("Missing code here!")
|
||||||
}
|
}
|
||||||
@ -130,4 +133,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
|||||||
.executeBy(taskExecutor)
|
.executeBy(taskExecutor)
|
||||||
// TODO If not initial sync, we should execute a init sync
|
// TODO If not initial sync, we should execute a init sync
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleBreadcrumbs(userAccountDataBreadcrumbs: UserAccountDataBreadcrumbs) {
|
||||||
|
saveBreadcrumbsTask
|
||||||
|
.configureWith(SaveBreadcrumbsTask.Params(userAccountDataBreadcrumbs.content.recentRoomIds))
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ internal abstract class UserAccountData {
|
|||||||
companion object {
|
companion object {
|
||||||
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"
|
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"
|
||||||
const val TYPE_DIRECT_MESSAGES = "m.direct"
|
const val TYPE_DIRECT_MESSAGES = "m.direct"
|
||||||
|
const val TYPE_BREADCRUMBS = "im.vector.setting.breadcrumbs" // Was previously "im.vector.riot.breadcrumb_rooms"
|
||||||
const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls"
|
const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls"
|
||||||
const val TYPE_WIDGETS = "m.widgets"
|
const val TYPE_WIDGETS = "m.widgets"
|
||||||
const val TYPE_PUSH_RULES = "m.push_rules"
|
const val TYPE_PUSH_RULES = "m.push_rules"
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.matrix.android.internal.session.sync.model.accountdata
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class UserAccountDataBreadcrumbs(
|
||||||
|
@Json(name = "type") override val type: String = TYPE_BREADCRUMBS,
|
||||||
|
@Json(name = "content") val content: BreadcrumbsContent
|
||||||
|
) : UserAccountData()
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
internal data class BreadcrumbsContent(
|
||||||
|
@Json(name = "recent_rooms") val recentRoomIds: List<String> = emptyList()
|
||||||
|
)
|
@ -35,5 +35,11 @@ internal abstract class AccountDataModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindUpdateUserAccountDataTask(updateUserAccountDataTask: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask
|
abstract fun bindUpdateUserAccountDataTask(task: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindSaveBreadcrumbsTask(task: DefaultSaveBreadcrumbsTask): SaveBreadcrumbsTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindUpdateBreadcrumsTask(task: DefaultUpdateBreadcrumbsTask): UpdateBreadcrumbsTask
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* 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.matrix.android.internal.session.user.accountdata
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.query.getOrCreate
|
||||||
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||||
|
import io.realm.RealmList
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the Breadcrumbs roomId list in DB, either from the sync, or updated locally
|
||||||
|
*/
|
||||||
|
internal interface SaveBreadcrumbsTask : Task<SaveBreadcrumbsTask.Params, Unit> {
|
||||||
|
data class Params(
|
||||||
|
val recentRoomIds: List<String>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultSaveBreadcrumbsTask @Inject constructor(
|
||||||
|
private val monarchy: Monarchy
|
||||||
|
) : SaveBreadcrumbsTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: SaveBreadcrumbsTask.Params) {
|
||||||
|
monarchy.awaitTransaction { realm ->
|
||||||
|
// Get or create a breadcrumbs entity
|
||||||
|
val entity = BreadcrumbsEntity.getOrCreate(realm)
|
||||||
|
|
||||||
|
// And save the new received list
|
||||||
|
entity.recentRoomIds = RealmList<String>().apply { addAll(params.recentRoomIds) }
|
||||||
|
|
||||||
|
// Update the room summaries
|
||||||
|
// Reset all the indexes...
|
||||||
|
RoomSummaryEntity.where(realm)
|
||||||
|
.greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummaryEntity.NOT_IN_BREADCRUMBS)
|
||||||
|
.findAll()
|
||||||
|
.forEach {
|
||||||
|
it.breadcrumbsIndex = RoomSummaryEntity.NOT_IN_BREADCRUMBS
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and apply new indexes
|
||||||
|
params.recentRoomIds.forEachIndexed { index, roomId ->
|
||||||
|
RoomSummaryEntity.where(realm, roomId)
|
||||||
|
.findFirst()
|
||||||
|
?.breadcrumbsIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.matrix.android.internal.session.user.accountdata
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity
|
||||||
|
import im.vector.matrix.android.internal.database.query.get
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.BreadcrumbsContent
|
||||||
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
import im.vector.matrix.android.internal.util.fetchCopied
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
// Use the same arbitrary value than Riot-Web
|
||||||
|
private const val MAX_BREADCRUMBS_ROOMS_NUMBER = 20
|
||||||
|
|
||||||
|
internal interface UpdateBreadcrumbsTask : Task<UpdateBreadcrumbsTask.Params, Unit> {
|
||||||
|
data class Params(
|
||||||
|
val newTopRoomId: String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultUpdateBreadcrumbsTask @Inject constructor(
|
||||||
|
private val saveBreadcrumbsTask: SaveBreadcrumbsTask,
|
||||||
|
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||||
|
private val monarchy: Monarchy
|
||||||
|
) : UpdateBreadcrumbsTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: UpdateBreadcrumbsTask.Params) {
|
||||||
|
val newBreadcrumbs =
|
||||||
|
// Get the breadcrumbs entity, if any
|
||||||
|
monarchy.fetchCopied { BreadcrumbsEntity.get(it) }
|
||||||
|
?.recentRoomIds
|
||||||
|
?.apply {
|
||||||
|
// Modify the list to add the newTopRoomId first
|
||||||
|
// Ensure the newTopRoomId is not already in the list
|
||||||
|
remove(params.newTopRoomId)
|
||||||
|
// Add the newTopRoomId at first position
|
||||||
|
add(0, params.newTopRoomId)
|
||||||
|
}
|
||||||
|
?.take(MAX_BREADCRUMBS_ROOMS_NUMBER)
|
||||||
|
?: listOf(params.newTopRoomId)
|
||||||
|
|
||||||
|
// Update the DB locally, do not wait for the sync
|
||||||
|
saveBreadcrumbsTask.execute(SaveBreadcrumbsTask.Params(newBreadcrumbs))
|
||||||
|
|
||||||
|
// FIXME It can remove the previous breadcrumbs, if not synced yet
|
||||||
|
// And update account data
|
||||||
|
updateUserAccountDataTask.execute(UpdateUserAccountDataTask.BreadcrumbsParams(
|
||||||
|
breadcrumbsContent = BreadcrumbsContent(newBreadcrumbs)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
|
|||||||
|
|
||||||
import im.vector.matrix.android.internal.di.UserId
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.BreadcrumbsContent
|
||||||
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -38,6 +39,15 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
|
|||||||
return directMessages
|
return directMessages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class BreadcrumbsParams(override val type: String = UserAccountData.TYPE_BREADCRUMBS,
|
||||||
|
private val breadcrumbsContent: BreadcrumbsContent
|
||||||
|
) : Params {
|
||||||
|
|
||||||
|
override fun getData(): Any {
|
||||||
|
return breadcrumbsContent
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultUpdateUserAccountDataTask @Inject constructor(private val accountDataApi: AccountDataAPI,
|
internal class DefaultUpdateUserAccountDataTask @Inject constructor(private val accountDataApi: AccountDataAPI,
|
||||||
|
@ -33,6 +33,7 @@ import im.vector.riotx.features.home.LoadingFragment
|
|||||||
import im.vector.riotx.features.home.createdirect.CreateDirectRoomDirectoryUsersFragment
|
import im.vector.riotx.features.home.createdirect.CreateDirectRoomDirectoryUsersFragment
|
||||||
import im.vector.riotx.features.home.createdirect.CreateDirectRoomKnownUsersFragment
|
import im.vector.riotx.features.home.createdirect.CreateDirectRoomKnownUsersFragment
|
||||||
import im.vector.riotx.features.home.group.GroupListFragment
|
import im.vector.riotx.features.home.group.GroupListFragment
|
||||||
|
import im.vector.riotx.features.home.room.breadcrumbs.BreadcrumbsFragment
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailFragment
|
import im.vector.riotx.features.home.room.detail.RoomDetailFragment
|
||||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||||
import im.vector.riotx.features.login.*
|
import im.vector.riotx.features.login.*
|
||||||
@ -249,4 +250,9 @@ interface FragmentModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(PublicRoomsFragment::class)
|
@FragmentKey(PublicRoomsFragment::class)
|
||||||
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
|
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(BreadcrumbsFragment::class)
|
||||||
|
fun bindBreadcrumbsFragment(fragment: BreadcrumbsFragment): Fragment
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupSharedVie
|
|||||||
import im.vector.riotx.features.crypto.verification.SasVerificationViewModel
|
import im.vector.riotx.features.crypto.verification.SasVerificationViewModel
|
||||||
import im.vector.riotx.features.home.HomeSharedActionViewModel
|
import im.vector.riotx.features.home.HomeSharedActionViewModel
|
||||||
import im.vector.riotx.features.home.createdirect.CreateDirectRoomSharedActionViewModel
|
import im.vector.riotx.features.home.createdirect.CreateDirectRoomSharedActionViewModel
|
||||||
|
import im.vector.riotx.features.home.room.detail.RoomDetailSharedActionViewModel
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
||||||
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
import im.vector.riotx.features.login.LoginSharedActionViewModel
|
import im.vector.riotx.features.login.LoginSharedActionViewModel
|
||||||
@ -118,4 +119,9 @@ interface ViewModelModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(LoginSharedActionViewModel::class)
|
@ViewModelKey(LoginSharedActionViewModel::class)
|
||||||
fun bindLoginSharedActionViewModel(viewModel: LoginSharedActionViewModel): ViewModel
|
fun bindLoginSharedActionViewModel(viewModel: LoginSharedActionViewModel): ViewModel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(RoomDetailSharedActionViewModel::class)
|
||||||
|
fun bindRoomDetailSharedActionViewModel(viewModel: RoomDetailSharedActionViewModel): ViewModel
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
|
|
||||||
|
private const val ANIM_DURATION_IN_MILLIS = 200L
|
||||||
|
|
||||||
|
class BreadcrumbsAnimator : DefaultItemAnimator() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
addDuration = ANIM_DURATION_IN_MILLIS
|
||||||
|
removeDuration = ANIM_DURATION_IN_MILLIS
|
||||||
|
moveDuration = ANIM_DURATION_IN_MILLIS
|
||||||
|
changeDuration = ANIM_DURATION_IN_MILLIS
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import com.airbnb.epoxy.EpoxyController
|
||||||
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class BreadcrumbsController @Inject constructor(
|
||||||
|
private val avatarRenderer: AvatarRenderer
|
||||||
|
) : EpoxyController() {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
|
||||||
|
private var viewState: BreadcrumbsViewState? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
// We are requesting a model build directly as the first build of epoxy is on the main thread.
|
||||||
|
// It avoids to build the whole list of breadcrumbs on the main thread.
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(viewState: BreadcrumbsViewState) {
|
||||||
|
this.viewState = viewState
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildModels() {
|
||||||
|
val safeViewState = viewState ?: return
|
||||||
|
|
||||||
|
// An empty breadcrumbs list can only be temporary because when entering in a room,
|
||||||
|
// this one is added to the breadcrumbs
|
||||||
|
|
||||||
|
safeViewState.asyncBreadcrumbs.invoke()
|
||||||
|
?.forEach {
|
||||||
|
breadcrumbsItem {
|
||||||
|
id(it.roomId)
|
||||||
|
avatarRenderer(avatarRenderer)
|
||||||
|
roomId(it.roomId)
|
||||||
|
roomName(it.displayName)
|
||||||
|
avatarUrl(it.avatarUrl)
|
||||||
|
unreadNotificationCount(it.notificationCount)
|
||||||
|
showHighlighted(it.highlightCount > 0)
|
||||||
|
hasUnreadMessage(it.hasUnreadMessages)
|
||||||
|
hasDraft(it.userDrafts.isNotEmpty())
|
||||||
|
itemClickListener(
|
||||||
|
DebouncedClickListener(View.OnClickListener { _ ->
|
||||||
|
listener?.onBreadcrumbClicked(it.roomId)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onBreadcrumbClicked(roomId: String)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotx.features.home.room.detail.RoomDetailSharedAction
|
||||||
|
import im.vector.riotx.features.home.room.detail.RoomDetailSharedActionViewModel
|
||||||
|
import kotlinx.android.synthetic.main.fragment_breadcrumbs.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class BreadcrumbsFragment @Inject constructor(
|
||||||
|
private val breadcrumbsController: BreadcrumbsController,
|
||||||
|
val breadcrumbsViewModelFactory: BreadcrumbsViewModel.Factory
|
||||||
|
) : VectorBaseFragment(), BreadcrumbsController.Listener {
|
||||||
|
|
||||||
|
private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
|
||||||
|
private val breadcrumbsViewModel: BreadcrumbsViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_breadcrumbs
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setupRecyclerView()
|
||||||
|
sharedActionViewModel = activityViewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
|
||||||
|
|
||||||
|
breadcrumbsViewModel.subscribe { renderState(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
breadcrumbsRecyclerView.adapter = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerView() {
|
||||||
|
val layoutManager = LinearLayoutManager(context)
|
||||||
|
breadcrumbsRecyclerView.layoutManager = layoutManager
|
||||||
|
breadcrumbsRecyclerView.itemAnimator = BreadcrumbsAnimator()
|
||||||
|
breadcrumbsController.listener = this
|
||||||
|
breadcrumbsRecyclerView.setController(breadcrumbsController)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderState(state: BreadcrumbsViewState) {
|
||||||
|
breadcrumbsController.update(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BreadcrumbsController.Listener **************************************************************
|
||||||
|
|
||||||
|
override fun onBreadcrumbClicked(roomId: String) {
|
||||||
|
sharedActionViewModel.post(RoomDetailSharedAction.SwitchToRoom(roomId))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
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.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_breadcrumbs)
|
||||||
|
abstract class BreadcrumbsItem : VectorEpoxyModel<BreadcrumbsItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@EpoxyAttribute lateinit var roomId: String
|
||||||
|
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||||
|
@EpoxyAttribute var avatarUrl: String? = null
|
||||||
|
@EpoxyAttribute var unreadNotificationCount: Int = 0
|
||||||
|
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||||
|
@EpoxyAttribute var hasUnreadMessage: Boolean = false
|
||||||
|
@EpoxyAttribute var hasDraft: Boolean = false
|
||||||
|
@EpoxyAttribute var itemClickListener: View.OnClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.rootView.setOnClickListener(itemClickListener)
|
||||||
|
holder.unreadIndentIndicator.isVisible = hasUnreadMessage
|
||||||
|
avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||||
|
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadNotificationCount, showHighlighted))
|
||||||
|
holder.draftIndentIndicator.isVisible = hasDraft
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.breadcrumbsUnreadCounterBadgeView)
|
||||||
|
val unreadIndentIndicator by bind<View>(R.id.breadcrumbsUnreadIndicator)
|
||||||
|
val draftIndentIndicator by bind<View>(R.id.breadcrumbsDraftBadge)
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.breadcrumbsImageView)
|
||||||
|
val rootView by bind<ViewGroup>(R.id.breadcrumbsRoot)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import com.squareup.inject.assisted.Assisted
|
||||||
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.rx.rx
|
||||||
|
import im.vector.riotx.core.platform.EmptyAction
|
||||||
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
|
class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: BreadcrumbsViewState,
|
||||||
|
private val session: Session)
|
||||||
|
: VectorViewModel<BreadcrumbsViewState, EmptyAction>(initialState) {
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: BreadcrumbsViewState): BreadcrumbsViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<BreadcrumbsViewModel, BreadcrumbsViewState> {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: BreadcrumbsViewState): BreadcrumbsViewModel? {
|
||||||
|
val fragment: BreadcrumbsFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||||
|
return fragment.breadcrumbsViewModelFactory.create(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeBreadcrumbs()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: EmptyAction) {
|
||||||
|
// No op
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
|
private fun observeBreadcrumbs() {
|
||||||
|
session.rx()
|
||||||
|
.liveBreadcrumbs()
|
||||||
|
.observeOn(Schedulers.computation())
|
||||||
|
.execute { asyncBreadcrumbs ->
|
||||||
|
copy(asyncBreadcrumbs = asyncBreadcrumbs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.breadcrumbs
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
data class BreadcrumbsViewState(
|
||||||
|
val asyncBreadcrumbs: Async<List<RoomSummary>> = Uninitialized
|
||||||
|
) : MvRxState
|
@ -20,17 +20,25 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.view.GravityCompat
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
import im.vector.riotx.core.extensions.replaceFragment
|
import im.vector.riotx.core.extensions.replaceFragment
|
||||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotx.core.platform.VectorBaseActivity
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.riotx.features.home.room.breadcrumbs.BreadcrumbsFragment
|
||||||
|
import kotlinx.android.synthetic.main.activity_room_detail.*
|
||||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||||
|
|
||||||
class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
|
class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
override fun getLayoutRes() = R.layout.activity_room_detail
|
||||||
return R.layout.activity_room_detail
|
|
||||||
}
|
private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel
|
||||||
|
|
||||||
|
// Simple filter
|
||||||
|
private var currentRoomId: String? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -38,14 +46,57 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
|
val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
|
||||||
?: return
|
?: return
|
||||||
|
currentRoomId = roomDetailArgs.roomId
|
||||||
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs)
|
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs)
|
||||||
|
replaceFragment(R.id.roomDetailDrawerContainer, BreadcrumbsFragment::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sharedActionViewModel = viewModelProvider.get(RoomDetailSharedActionViewModel::class.java)
|
||||||
|
|
||||||
|
sharedActionViewModel
|
||||||
|
.observe()
|
||||||
|
.subscribe { sharedAction ->
|
||||||
|
when (sharedAction) {
|
||||||
|
is RoomDetailSharedAction.SwitchToRoom -> switchToRoom(sharedAction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disposeOnDestroy()
|
||||||
|
|
||||||
|
drawerLayout.addDrawerListener(drawerListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun switchToRoom(switchToRoom: RoomDetailSharedAction.SwitchToRoom) {
|
||||||
|
drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
// Do not replace the Fragment if it's the same roomId
|
||||||
|
if (currentRoomId != switchToRoom.roomId) {
|
||||||
|
currentRoomId = switchToRoom.roomId
|
||||||
|
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, RoomDetailArgs(switchToRoom.roomId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
drawerLayout.removeDrawerListener(drawerListener)
|
||||||
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun configure(toolbar: Toolbar) {
|
override fun configure(toolbar: Toolbar) {
|
||||||
configureToolbar(toolbar)
|
configureToolbar(toolbar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val drawerListener = object : DrawerLayout.SimpleDrawerListener() {
|
||||||
|
override fun onDrawerStateChanged(newState: Int) {
|
||||||
|
hideKeyboard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
if (drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||||
|
drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
} else {
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
|
private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.detail
|
||||||
|
|
||||||
|
import im.vector.riotx.core.platform.VectorSharedAction
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported navigation actions for [RoomDetailActivity]
|
||||||
|
*/
|
||||||
|
sealed class RoomDetailSharedAction : VectorSharedAction {
|
||||||
|
data class SwitchToRoom(val roomId: String) : RoomDetailSharedAction()
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.room.detail
|
||||||
|
|
||||||
|
import im.vector.riotx.core.platform.VectorSharedActionViewModel
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity shared view model
|
||||||
|
*/
|
||||||
|
class RoomDetailSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<RoomDetailSharedAction>()
|
@ -143,6 +143,9 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
|||||||
timeline.addListener(this)
|
timeline.addListener(this)
|
||||||
timeline.start()
|
timeline.start()
|
||||||
setState { copy(timeline = this@RoomDetailViewModel.timeline) }
|
setState { copy(timeline = this@RoomDetailViewModel.timeline) }
|
||||||
|
|
||||||
|
// Inform the SDK that the room is displayed
|
||||||
|
session.onRoomDisplayed(initialState.roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handle(action: RoomDetailAction) {
|
override fun handle(action: RoomDetailAction) {
|
||||||
|
@ -42,7 +42,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
// We are requesting a model build directly as the first build of epoxy is on the main thread.
|
// We are requesting a model build directly as the first build of epoxy is on the main thread.
|
||||||
// It avoids to build the the whole list of rooms on the main thread.
|
// It avoids to build the whole list of rooms on the main thread.
|
||||||
requestModelBuild()
|
requestModelBuild()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<include layout="@layout/merge_overlay_waiting_view" />
|
<include layout="@layout/merge_overlay_waiting_view" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,36 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/drawerLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
tools:openDrawer="start">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/vector_coordinator_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/roomDetailContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<include layout="@layout/merge_overlay_waiting_view" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/roomDetailContainer"
|
android:id="@+id/roomDetailDrawerContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="start" />
|
||||||
|
|
||||||
<include layout="@layout/merge_overlay_waiting_view" />
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
8
vector/src/main/res/layout/fragment_breadcrumbs.xml
Normal file
8
vector/src/main/res/layout/fragment_breadcrumbs.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.airbnb.epoxy.EpoxyRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/breadcrumbsRecyclerView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
tools:listitem="@layout/item_breadcrumbs" />
|
70
vector/src/main/res/layout/item_breadcrumbs.xml
Normal file
70
vector/src/main/res/layout/item_breadcrumbs.xml
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/breadcrumbsRoot"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/breadcrumbsUnreadIndicator"
|
||||||
|
android:layout_width="4dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="?attr/colorAccent"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/breadcrumbsImageView"
|
||||||
|
android:layout_width="56dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
android:id="@+id/breadcrumbsUnreadCounterBadgeView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="16dp"
|
||||||
|
android:minHeight="16dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="10sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintCircle="@+id/breadcrumbsImageView"
|
||||||
|
app:layout_constraintCircleAngle="45"
|
||||||
|
app:layout_constraintCircleRadius="28dp"
|
||||||
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
|
tools:ignore="MissingConstraints"
|
||||||
|
tools:text="24"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/breadcrumbsDraftBadge"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:background="@drawable/circle"
|
||||||
|
android:padding="3dp"
|
||||||
|
android:src="@drawable/ic_edit"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintCircle="@+id/breadcrumbsImageView"
|
||||||
|
app:layout_constraintCircleAngle="135"
|
||||||
|
app:layout_constraintCircleRadius="28dp"
|
||||||
|
tools:ignore="MissingConstraints"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
x
Reference in New Issue
Block a user