diff --git a/CHANGES.md b/CHANGES.md index d6e107299f..7e386e0194 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,7 @@ Changes in RiotX 0.10.0 (2019-XX-XX) =================================================== Features ✨: - - + - Breadcrumbs: switch from one room to another quickly (#571) Improvements 🙌: - diff --git a/docs/signup.md b/docs/signup.md index 7372ad2204..995f5d50a6 100644 --- a/docs/signup.md +++ b/docs/signup.md @@ -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 { diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt index 1572851d3a..1964d05a1b 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt @@ -38,6 +38,10 @@ class RxSession(private val session: Session) { return session.liveGroupSummaries().asObservable() } + fun liveBreadcrumbs(): Observable> { + return session.liveBreadcrumbs().asObservable() + } + fun liveSyncState(): Observable { return session.syncState().asObservable() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt index c7fedb2627..2dbb580a4f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/RoomService.kt @@ -54,6 +54,18 @@ interface RoomService { */ fun liveRoomSummaries(): LiveData> + /** + * Get a live list of Breadcrumbs + * @return the [LiveData] of [RoomSummary] + */ + fun liveBreadcrumbs(): LiveData> + + /** + * 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 */ diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt index d7ab87a401..1e902f5133 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/CryptoRoomEntityQueries.kt @@ -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.CryptoRoomEntityFields import io.realm.Realm +import io.realm.kotlin.createObject import io.realm.kotlin.where /** * Get or create a room */ internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity { - return getById(realm, roomId) - ?: let { - realm.createObject(CryptoRoomEntity::class.java, roomId) - } + return getById(realm, roomId) ?: realm.createObject(roomId) } /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt index 706815ff76..08bbb8f920 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/DeviceInfoEntityQueries.kt @@ -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.createPrimaryKey import io.realm.Realm +import io.realm.kotlin.createObject import io.realm.kotlin.where /** * Get or create a device info */ internal fun DeviceInfoEntity.Companion.getOrCreate(realm: Realm, userId: String, deviceId: String): DeviceInfoEntity { + val key = DeviceInfoEntity.createPrimaryKey(userId, deviceId) + return realm.where() - .equalTo(DeviceInfoEntityFields.PRIMARY_KEY, DeviceInfoEntity.createPrimaryKey(userId, deviceId)) + .equalTo(DeviceInfoEntityFields.PRIMARY_KEY, key) .findFirst() - ?: let { - realm.createObject(DeviceInfoEntity::class.java, DeviceInfoEntity.createPrimaryKey(userId, deviceId)).apply { - this.deviceId = deviceId - } - } + ?: realm.createObject(key) + .apply { + this.deviceId = deviceId + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt index 8088a14825..b7f75cfead 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/query/UserEntitiesQueries.kt @@ -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.UserEntityFields import io.realm.Realm +import io.realm.kotlin.createObject import io.realm.kotlin.where /** @@ -28,9 +29,7 @@ internal fun UserEntity.Companion.getOrCreate(realm: Realm, userId: String): Use return realm.where() .equalTo(UserEntityFields.USER_ID, userId) .findFirst() - ?: let { - realm.createObject(UserEntity::class.java, userId) - } + ?: realm.createObject(userId) } /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt new file mode 100644 index 0000000000..c396795421 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt @@ -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 = RealmList() +) : RealmObject() { + + companion object +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt index f414325aed..47904380a0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt @@ -38,7 +38,8 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var readMarkerId: String? = null, var hasUnreadMessages: Boolean = false, var tags: RealmList = RealmList(), - var userDrafts: UserDraftsEntity? = null + var userDrafts: UserDraftsEntity? = null, + var breadcrumbsIndex: Int = NOT_IN_BREADCRUMBS ) : RealmObject() { private var membershipStr: String = Membership.NONE.name @@ -59,5 +60,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", versioningStateStr = value.name } - companion object + companion object { + const val NOT_IN_BREADCRUMBS = -1 + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt index 76b355b064..6059d3faf7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt @@ -36,6 +36,7 @@ import io.realm.annotations.RealmModule SyncEntity::class, UserEntity::class, IgnoredUserEntity::class, + BreadcrumbsEntity::class, EventAnnotationsSummaryEntity::class, ReactionAggregatedSummaryEntity::class, EditAggregatedSummaryEntity::class, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/BreadcrumbsEntityQuery.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/BreadcrumbsEntityQuery.kt new file mode 100644 index 0000000000..60ed8aae7c --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/BreadcrumbsEntityQuery.kt @@ -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().findFirst() +} + +internal fun BreadcrumbsEntity.Companion.getOrCreate(realm: Realm): BreadcrumbsEntity { + return get(realm) ?: realm.createObject() +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt index d95dc58574..5f96c12953 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadMarkerEntityQueries.kt @@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.ReadMarkerEntity import im.vector.matrix.android.internal.database.model.ReadMarkerEntityFields import io.realm.Realm import io.realm.RealmQuery +import io.realm.kotlin.createObject import io.realm.kotlin.where internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String): RealmQuery { @@ -28,6 +29,5 @@ internal fun ReadMarkerEntity.Companion.where(realm: Realm, roomId: String): Rea } internal fun ReadMarkerEntity.Companion.getOrCreate(realm: Realm, roomId: String): ReadMarkerEntity { - return where(realm, roomId).findFirst() - ?: realm.createObject(ReadMarkerEntity::class.java, roomId) + return where(realm, roomId).findFirst() ?: realm.createObject(roomId) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt index 6b996d1285..2aa40dd2a1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadReceiptEntityQueries.kt @@ -20,6 +20,7 @@ import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntityFields import io.realm.Realm import io.realm.RealmQuery +import io.realm.kotlin.createObject import io.realm.kotlin.where internal fun ReadReceiptEntity.Companion.where(realm: Realm, roomId: String, userId: String): RealmQuery { @@ -44,10 +45,11 @@ 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, buildPrimaryKey(roomId, userId)).apply { - this.roomId = roomId - this.userId = userId - } + ?: realm.createObject(buildPrimaryKey(roomId, userId)) + .apply { + this.roomId = roomId + this.userId = userId + } } private fun buildPrimaryKey(roomId: String, userId: String) = "${roomId}_$userId" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt index a92d81b54c..79473f3b10 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomSummaryEntityQueries.kt @@ -21,6 +21,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields import io.realm.Realm import io.realm.RealmQuery import io.realm.RealmResults +import io.realm.kotlin.createObject import io.realm.kotlin.where internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery { @@ -32,8 +33,7 @@ internal fun RoomSummaryEntity.Companion.where(realm: Realm, roomId: String? = n } internal fun RoomSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String): RoomSummaryEntity { - return where(realm, roomId).findFirst() - ?: realm.createObject(RoomSummaryEntity::class.java, roomId) + return where(realm, roomId).findFirst() ?: realm.createObject(roomId) } internal fun RoomSummaryEntity.Companion.getDirectRooms(realm: Realm): RealmResults { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index 96cdf29226..793be10880 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -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.UriMoshiAdapter 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.UserAccountDataFallback 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(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST) .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) .registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index 962b7b54d6..be2a588510 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt @@ -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.membership.joining.JoinRoomTask 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.configureWith import io.realm.Realm @@ -43,6 +44,7 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona private val createRoomTask: CreateRoomTask, private val joinRoomTask: JoinRoomTask, private val markAllRoomsReadTask: MarkAllRoomsReadTask, + private val updateBreadcrumbsTask: UpdateBreadcrumbsTask, private val roomFactory: RoomFactory, private val taskExecutor: TaskExecutor) : RoomService { @@ -75,6 +77,25 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona ) } + override fun liveBreadcrumbs(): LiveData> { + 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, callback: MatrixCallback): Cancelable { return joinRoomTask .configureWith(JoinRoomTask.Params(roomId, viaServers)) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt index 56bc005805..9cc3a5a3c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt @@ -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.accountdata.* 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.UpdateUserAccountDataTask 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 savePushRulesTask: SavePushRulesTask, private val saveIgnoredUsersTask: SaveIgnoredUsersTask, + private val saveBreadcrumbsTask: SaveBreadcrumbsTask, private val taskExecutor: TaskExecutor) { suspend fun handle(accountData: UserAccountDataSync?, invites: Map?) { @@ -52,6 +54,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc is UserAccountDataDirectMessages -> handleDirectChatRooms(it) is UserAccountDataPushRules -> handlePushRules(it) is UserAccountDataIgnoredUsers -> handleIgnoredUsers(it) + is UserAccountDataBreadcrumbs -> handleBreadcrumbs(it) is UserAccountDataFallback -> Timber.d("Receive account data of unhandled type ${it.type}") else -> error("Missing code here!") } @@ -130,4 +133,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc .executeBy(taskExecutor) // 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) + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt index 55dbad6099..accc9c900f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt @@ -25,6 +25,7 @@ internal abstract class UserAccountData { companion object { const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list" 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_WIDGETS = "m.widgets" const val TYPE_PUSH_RULES = "m.push_rules" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt new file mode 100644 index 0000000000..cf5ee9c5e1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt @@ -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 = emptyList() +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt index 49fe8caf8e..1fd4162d0a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/AccountDataModule.kt @@ -35,5 +35,11 @@ internal abstract class AccountDataModule { } @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 } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt new file mode 100644 index 0000000000..008dd1d652 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt @@ -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 { + data class Params( + val recentRoomIds: List + ) +} + +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().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 + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt new file mode 100644 index 0000000000..b11072a0bd --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt @@ -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 { + 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) + )) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index 9fa71005ff..4c4f40add5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -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.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.task.Task import javax.inject.Inject @@ -38,6 +39,15 @@ internal interface UpdateUserAccountDataTask : Task 0) + hasUnreadMessage(it.hasUnreadMessages) + hasDraft(it.userDrafts.isNotEmpty()) + itemClickListener( + DebouncedClickListener(View.OnClickListener { _ -> + listener?.onBreadcrumbClicked(it.roomId) + }) + ) + } + } + } + + interface Listener { + fun onBreadcrumbClicked(roomId: String) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt new file mode 100644 index 0000000000..e57a2ddac4 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt @@ -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)) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt new file mode 100644 index 0000000000..074c35af00 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt @@ -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() { + + @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(R.id.breadcrumbsUnreadCounterBadgeView) + val unreadIndentIndicator by bind(R.id.breadcrumbsUnreadIndicator) + val draftIndentIndicator by bind(R.id.breadcrumbsDraftBadge) + val avatarImageView by bind(R.id.breadcrumbsImageView) + val rootView by bind(R.id.breadcrumbsRoot) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt new file mode 100644 index 0000000000..83e9e0fb3f --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt @@ -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(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: BreadcrumbsViewState): BreadcrumbsViewModel + } + + companion object : MvRxViewModelFactory { + + @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) + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewState.kt new file mode 100644 index 0000000000..7cc634c8b0 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewState.kt @@ -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> = Uninitialized +) : MvRxState diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt index eb8118a0c9..431c9e6395 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt @@ -20,17 +20,25 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.widget.Toolbar +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import im.vector.riotx.R +import im.vector.riotx.core.extensions.hideKeyboard import im.vector.riotx.core.extensions.replaceFragment import im.vector.riotx.core.platform.ToolbarConfigurable 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.* class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable { - override fun getLayoutRes(): Int { - return R.layout.activity_room_detail - } + override fun getLayoutRes() = R.layout.activity_room_detail + + private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel + + // Simple filter + private var currentRoomId: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,14 +46,57 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable { if (isFirstCreation()) { val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS) ?: return + currentRoomId = roomDetailArgs.roomId 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) { 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 { private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS" diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedAction.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedAction.kt new file mode 100644 index 0000000000..95dd34ebb8 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedAction.kt @@ -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() +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedActionViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedActionViewModel.kt new file mode 100644 index 0000000000..6f2162bebc --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedActionViewModel.kt @@ -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() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 642bce3319..d0bff31f79 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -143,6 +143,9 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro timeline.addListener(this) timeline.start() setState { copy(timeline = this@RoomDetailViewModel.timeline) } + + // Inform the SDK that the room is displayed + session.onRoomDisplayed(initialState.roomId) } override fun handle(action: RoomDetailAction) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt index 4107bf01b2..6ffe37cb15 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomSummaryController.kt @@ -42,7 +42,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri init { // 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() } diff --git a/vector/src/main/res/layout/activity_home.xml b/vector/src/main/res/layout/activity_home.xml index 0ce124b787..61fb1b5ad4 100644 --- a/vector/src/main/res/layout/activity_home.xml +++ b/vector/src/main/res/layout/activity_home.xml @@ -17,6 +17,7 @@ android:layout_height="match_parent" /> + diff --git a/vector/src/main/res/layout/activity_room_detail.xml b/vector/src/main/res/layout/activity_room_detail.xml index 4d8fc23f24..cc10341d2f 100644 --- a/vector/src/main/res/layout/activity_room_detail.xml +++ b/vector/src/main/res/layout/activity_room_detail.xml @@ -1,14 +1,36 @@ - - + android:layout_height="match_parent" + tools:openDrawer="start"> + + + + + + + + + + + + + + android:id="@+id/roomDetailDrawerContainer" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="start" /> - - - \ No newline at end of file + diff --git a/vector/src/main/res/layout/fragment_breadcrumbs.xml b/vector/src/main/res/layout/fragment_breadcrumbs.xml new file mode 100644 index 0000000000..22cceadc03 --- /dev/null +++ b/vector/src/main/res/layout/fragment_breadcrumbs.xml @@ -0,0 +1,8 @@ + + diff --git a/vector/src/main/res/layout/item_breadcrumbs.xml b/vector/src/main/res/layout/item_breadcrumbs.xml new file mode 100644 index 0000000000..f364ad8211 --- /dev/null +++ b/vector/src/main/res/layout/item_breadcrumbs.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + +