From cec08a20e5619b0d3b5ba333c3018b125a8a9b58 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 12:13:45 +0100 Subject: [PATCH 01/12] Handle breadcrumbs from account data --- .../java/im/vector/matrix/rx/RxSession.kt | 4 ++ .../android/api/session/room/RoomService.kt | 6 +++ .../database/model/BreadcrumbsEntity.kt | 25 ++++++++++ .../database/model/SessionRealmModule.kt | 1 + .../android/internal/di/MoshiProvider.kt | 2 + .../session/room/DefaultRoomService.kt | 14 ++++++ .../sync/UserAccountDataSyncHandler.kt | 9 ++++ .../sync/model/accountdata/UserAccountData.kt | 1 + .../accountdata/UserAccountDataBreadcrumbs.kt | 34 ++++++++++++++ .../user/accountdata/AccountDataModule.kt | 3 ++ .../user/accountdata/SaveBreadcrumbsTask.kt | 46 +++++++++++++++++++ 11 files changed, 145 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt 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..9b0bae9e08 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,12 @@ interface RoomService { */ fun liveRoomSummaries(): LiveData> + /** + * Get a live list of Breadcrumbs + * @return the [LiveData] of [RoomSummary] + */ + fun liveBreadcrumbs(): LiveData> + /** * Mark all rooms as read */ 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..e430c194c5 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt @@ -0,0 +1,25 @@ +/* + * 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 roomIds: RealmList = RealmList()) : RealmObject() { + + companion object +} 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/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..9863d12ee5 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 @@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.room.model.VersioningState import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper +import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields @@ -36,6 +37,7 @@ import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.Realm +import io.realm.RealmList import javax.inject.Inject internal class DefaultRoomService @Inject constructor(private val monarchy: Monarchy, @@ -75,6 +77,18 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona ) } + override fun liveBreadcrumbs(): LiveData> { + return monarchy.findAllMappedWithChanges( + { realm -> + // TODO Improve this query, it's not live when breadcrumbs changes + realm.where(RoomSummaryEntity::class.java) + .`in`(RoomSummaryEntityFields.ROOM_ID, + (realm.where(BreadcrumbsEntity::class.java).findFirst()?.roomIds ?: RealmList()).toTypedArray()) + }, + { roomSummaryMapper.map(it) } + ) + } + 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..0436afd05f 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.roomIds)) + .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..c12ab126b9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt @@ -0,0 +1,34 @@ +/* + * 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 = "rooms") val roomIds: List = emptyList(), + + // We also have "recent_rooms", I do not know what to do with that list + @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..5889ab4847 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 @@ -36,4 +36,7 @@ internal abstract class AccountDataModule { @Binds abstract fun bindUpdateUserAccountDataTask(updateUserAccountDataTask: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask + + @Binds + abstract fun bindSaveBreadcrumbsTask(saveBreadcrumbsTask: DefaultSaveBreadcrumbsTask): SaveBreadcrumbsTask } 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..7cabb2772e --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt @@ -0,0 +1,46 @@ +/* + * 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.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 + */ +internal interface SaveBreadcrumbsTask : Task { + data class Params( + val roomIds: 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 = realm.where(BreadcrumbsEntity::class.java).findFirst() + ?: realm.createObject(BreadcrumbsEntity::class.java) + + // And save the new received list + entity.roomIds = RealmList().apply { addAll(params.roomIds) } + } + } +} From 7c561ae622fe231693f9d3b609bd3a52262cff07 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 14:51:12 +0100 Subject: [PATCH 02/12] Breadcrumbs simple UI --- .../im/vector/riotx/core/di/FragmentModule.kt | 6 ++ .../vector/riotx/core/di/ViewModelModule.kt | 6 ++ .../room/breadcrumbs/BreadcrumbsAnimator.kt | 31 ++++++++ .../room/breadcrumbs/BreadcrumbsController.kt | 70 ++++++++++++++++++ .../room/breadcrumbs/BreadcrumbsFragment.kt | 71 +++++++++++++++++++ .../home/room/breadcrumbs/BreadcrumbsItem.kt | 53 ++++++++++++++ .../room/breadcrumbs/BreadcrumbsViewModel.kt | 66 +++++++++++++++++ .../room/breadcrumbs/BreadcrumbsViewState.kt | 26 +++++++ .../home/room/detail/RoomDetailActivity.kt | 55 +++++++++++++- .../room/detail/RoomDetailSharedAction.kt | 26 +++++++ .../detail/RoomDetailSharedActionViewModel.kt | 24 +++++++ vector/src/main/res/layout/activity_home.xml | 1 + .../main/res/layout/activity_room_detail.xml | 38 +++++++--- .../main/res/layout/fragment_breadcrumbs.xml | 7 ++ .../src/main/res/layout/item_breadcrumbs.xml | 22 ++++++ 15 files changed, 491 insertions(+), 11 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsAnimator.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewModel.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsViewState.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedAction.kt create mode 100644 vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailSharedActionViewModel.kt create mode 100644 vector/src/main/res/layout/fragment_breadcrumbs.xml create mode 100644 vector/src/main/res/layout/item_breadcrumbs.xml diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt index 208246aa68..1a7a07bee2 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt @@ -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.CreateDirectRoomKnownUsersFragment 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.list.RoomListFragment import im.vector.riotx.features.login.* @@ -249,4 +250,9 @@ interface FragmentModule { @IntoMap @FragmentKey(PublicRoomsFragment::class) fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment + + @Binds + @IntoMap + @FragmentKey(BreadcrumbsFragment::class) + fun bindBreadcrumbsFragment(fragment: BreadcrumbsFragment): Fragment } diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt index 0876701504..4b136c557b 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt @@ -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.home.HomeSharedActionViewModel 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.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.riotx.features.login.LoginSharedActionViewModel @@ -118,4 +119,9 @@ interface ViewModelModule { @IntoMap @ViewModelKey(LoginSharedActionViewModel::class) fun bindLoginSharedActionViewModel(viewModel: LoginSharedActionViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(RoomDetailSharedActionViewModel::class) + fun bindRoomDetailSharedActionViewModel(viewModel: RoomDetailSharedActionViewModel): ViewModel } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsAnimator.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsAnimator.kt new file mode 100644 index 0000000000..2e849dfe38 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsAnimator.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.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 + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt new file mode 100644 index 0000000000..eb97b91cbe --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.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.view.View +import com.airbnb.epoxy.EpoxyController +import im.vector.matrix.android.api.session.room.model.RoomSummary +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 the whole list of rooms on the main thread. + requestModelBuild() + } + + fun update(viewState: BreadcrumbsViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val nonNullViewState = viewState ?: return + + // TODO Display a loading, or an empty state + + nonNullViewState.asyncRooms.invoke() + ?.forEach { + breadcrumbsItem { + id(it.roomId) + avatarRenderer(avatarRenderer) + roomId(it.roomId) + roomName(it.displayName) + avatarUrl(it.avatarUrl) + itemClickListener( + DebouncedClickListener(View.OnClickListener { _ -> + listener?.onRoomClicked(it) + }) + ) + } + } + } + + interface Listener { + fun onRoomClicked(room: RoomSummary) + } +} 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..036208ec6a --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsFragment.kt @@ -0,0 +1,71 @@ +/* + * 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.matrix.android.api.session.room.model.RoomSummary +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 onRoomClicked(room: RoomSummary) { + sharedActionViewModel.post(RoomDetailSharedAction.OpenRoom(room.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..d8d1acb6d3 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsItem.kt @@ -0,0 +1,53 @@ +/* + * 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 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 + +@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 + // TODO @EpoxyAttribute var unreadNotificationCount: Int = 0 + // TODO @EpoxyAttribute var hasUnreadMessage: Boolean = false + // TODO @EpoxyAttribute var showHighlighted: Boolean = false + @EpoxyAttribute var itemClickListener: View.OnClickListener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.rootView.setOnClickListener(itemClickListener) + avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) + } + + class Holder : VectorEpoxyHolder() { + // TODO val unreadCounterBadgeView by bind(R.id.roomUnreadCounterBadgeView) + // TODO val unreadIndentIndicator by bind(R.id.roomUnreadIndicator) + 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..4b462a05a6 --- /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 { asyncRooms -> + copy(asyncRooms = asyncRooms) + } + } +} 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..cb00db4c9f --- /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 asyncRooms: 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..bdc3b59eff 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,55 @@ 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.OpenRoom -> { + drawerLayout.closeDrawer(GravityCompat.START) + // Do not replace the Fragment if it's the same roomId + if (currentRoomId != sharedAction.roomId) { + currentRoomId = sharedAction.roomId + replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, RoomDetailArgs(sharedAction.roomId)) + } + } + } + } + .disposeOnDestroy() + + drawerLayout.addDrawerListener(drawerListener) + } + + 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..6a88bb1f13 --- /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 OpenRoom(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/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..14fda5e9c6 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: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..780a1a5cb2 --- /dev/null +++ b/vector/src/main/res/layout/fragment_breadcrumbs.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file 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..0f8b535b7b --- /dev/null +++ b/vector/src/main/res/layout/item_breadcrumbs.xml @@ -0,0 +1,22 @@ + + + + + + From 4ff12605e911c40ba785d46ea1379a78e51adf75 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 16:06:47 +0100 Subject: [PATCH 03/12] Breadcrumbs: notify viewed rooms --- .../android/api/session/room/RoomService.kt | 6 ++ .../database/model/BreadcrumbsEntity.kt | 4 +- .../session/room/DefaultRoomService.kt | 10 ++- .../sync/UserAccountDataSyncHandler.kt | 2 +- .../accountdata/UserAccountDataBreadcrumbs.kt | 3 - .../user/accountdata/AccountDataModule.kt | 3 + .../user/accountdata/SaveBreadcrumbsTask.kt | 10 +-- .../user/accountdata/UpdateBreadcrumbsTask.kt | 68 +++++++++++++++++++ .../accountdata/UpdateUserAccountDataTask.kt | 10 +++ .../home/room/detail/RoomDetailViewModel.kt | 3 + 10 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt 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 9b0bae9e08..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 @@ -60,6 +60,12 @@ interface RoomService { */ 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/database/model/BreadcrumbsEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/BreadcrumbsEntity.kt index e430c194c5..c396795421 100644 --- 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 @@ -19,7 +19,9 @@ package im.vector.matrix.android.internal.database.model import io.realm.RealmList import io.realm.RealmObject -internal open class BreadcrumbsEntity(var roomIds: RealmList = RealmList()) : 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/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index 9863d12ee5..268d625622 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 @@ -34,6 +34,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 @@ -45,6 +46,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 { @@ -83,12 +85,18 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona // TODO Improve this query, it's not live when breadcrumbs changes realm.where(RoomSummaryEntity::class.java) .`in`(RoomSummaryEntityFields.ROOM_ID, - (realm.where(BreadcrumbsEntity::class.java).findFirst()?.roomIds ?: RealmList()).toTypedArray()) + (realm.where(BreadcrumbsEntity::class.java).findFirst()?.recentRoomIds ?: RealmList()).toTypedArray()) }, { 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 0436afd05f..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 @@ -136,7 +136,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc private fun handleBreadcrumbs(userAccountDataBreadcrumbs: UserAccountDataBreadcrumbs) { saveBreadcrumbsTask - .configureWith(SaveBreadcrumbsTask.Params(userAccountDataBreadcrumbs.content.roomIds)) + .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/UserAccountDataBreadcrumbs.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataBreadcrumbs.kt index c12ab126b9..cf5ee9c5e1 100644 --- 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 @@ -27,8 +27,5 @@ internal data class UserAccountDataBreadcrumbs( @JsonClass(generateAdapter = true) internal data class BreadcrumbsContent( - @Json(name = "rooms") val roomIds: List = emptyList(), - - // We also have "recent_rooms", I do not know what to do with that list @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 5889ab4847..37b63dcd07 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 @@ -39,4 +39,7 @@ internal abstract class AccountDataModule { @Binds abstract fun bindSaveBreadcrumbsTask(saveBreadcrumbsTask: DefaultSaveBreadcrumbsTask): SaveBreadcrumbsTask + + @Binds + abstract fun bindUpdateBreadcrumsTask(saveBreadcrumbsTask: 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 index 7cabb2772e..97cfba0549 100644 --- 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 @@ -23,15 +23,17 @@ import io.realm.RealmList import javax.inject.Inject /** - * Save the Breadcrumbs roomId list in DB + * Save the Breadcrumbs roomId list in DB, either from the sync, or updated locally */ internal interface SaveBreadcrumbsTask : Task { data class Params( - val roomIds: List + val recentRoomIds: List ) } -internal class DefaultSaveBreadcrumbsTask @Inject constructor(private val monarchy: Monarchy) : SaveBreadcrumbsTask { +internal class DefaultSaveBreadcrumbsTask @Inject constructor( + private val monarchy: Monarchy +) : SaveBreadcrumbsTask { override suspend fun execute(params: SaveBreadcrumbsTask.Params) { monarchy.awaitTransaction { realm -> @@ -40,7 +42,7 @@ internal class DefaultSaveBreadcrumbsTask @Inject constructor(private val monarc ?: realm.createObject(BreadcrumbsEntity::class.java) // And save the new received list - entity.roomIds = RealmList().apply { addAll(params.roomIds) } + entity.recentRoomIds = RealmList().apply { addAll(params.recentRoomIds) } } } } 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..0f2f5f9a3d --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateBreadcrumbsTask.kt @@ -0,0 +1,68 @@ +/* + * 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.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 + +internal interface UpdateBreadcrumbsTask : Task { + data class Params( + // Last seen roomId + val roomId: 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) { + // Get the current breadcrumbs in DB + val bc = monarchy.fetchCopied { realm -> + // Get the breadcrumbs entity, if any + realm.where(BreadcrumbsEntity::class.java).findFirst() + + } + + // Modify the list to add the roomId first + val newRecentRoomIds = if (bc != null) { + // Ensure the roomId is not already in the list + bc.recentRoomIds.remove(params.roomId) + // Add the room at first position + bc.recentRoomIds.add(0, params.roomId) + bc.recentRoomIds.toList() + } else { + listOf(params.roomId) + } + + // Update the DB locally, do not wait for the sync + saveBreadcrumbsTask.execute(SaveBreadcrumbsTask.Params(newRecentRoomIds)) + + // And update account data + updateUserAccountDataTask.execute(UpdateUserAccountDataTask.BreadcrumbsParams( + breadcrumbsContent = BreadcrumbsContent( + newRecentRoomIds + ) + )) + } +} 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 Date: Thu, 5 Dec 2019 17:43:23 +0100 Subject: [PATCH 04/12] Breadcrumbs: limit number to 20 --- .../session/user/accountdata/UpdateBreadcrumbsTask.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 index 0f2f5f9a3d..faf0325220 100644 --- 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 @@ -23,6 +23,9 @@ import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.fetchCopied import javax.inject.Inject +// Use same arbitrary value than Riot-Web +private const val MAX_BREADCRUMBS_ROOMS_NUMBER = 20 + internal interface UpdateBreadcrumbsTask : Task { data class Params( // Last seen roomId @@ -50,7 +53,7 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor( bc.recentRoomIds.remove(params.roomId) // Add the room at first position bc.recentRoomIds.add(0, params.roomId) - bc.recentRoomIds.toList() + bc.recentRoomIds.take(MAX_BREADCRUMBS_ROOMS_NUMBER) } else { listOf(params.roomId) } From 5373d9aa21493f7745b706264eff5177e52211a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 17:49:45 +0100 Subject: [PATCH 05/12] Breadcrumbs: fix layout issue --- vector/src/main/res/layout/activity_room_detail.xml | 2 +- vector/src/main/res/layout/fragment_breadcrumbs.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/src/main/res/layout/activity_room_detail.xml b/vector/src/main/res/layout/activity_room_detail.xml index 14fda5e9c6..cc10341d2f 100644 --- a/vector/src/main/res/layout/activity_room_detail.xml +++ b/vector/src/main/res/layout/activity_room_detail.xml @@ -29,7 +29,7 @@ diff --git a/vector/src/main/res/layout/fragment_breadcrumbs.xml b/vector/src/main/res/layout/fragment_breadcrumbs.xml index 780a1a5cb2..c17b35fdee 100644 --- a/vector/src/main/res/layout/fragment_breadcrumbs.xml +++ b/vector/src/main/res/layout/fragment_breadcrumbs.xml @@ -2,6 +2,7 @@ \ No newline at end of file From 60169d53d72094ba00a5e97d07b05f7169790495 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 20:28:07 +0100 Subject: [PATCH 06/12] Breadcrumbs: add some visual attributes --- .../room/breadcrumbs/BreadcrumbsController.kt | 4 ++ .../home/room/breadcrumbs/BreadcrumbsItem.kt | 17 +++++-- .../src/main/res/layout/item_breadcrumbs.xml | 50 ++++++++++++++++++- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt index eb97b91cbe..ea359ee2f7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt @@ -55,6 +55,10 @@ class BreadcrumbsController @Inject constructor( 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?.onRoomClicked(it) 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 index d8d1acb6d3..074c35af00 100644 --- 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 @@ -19,12 +19,14 @@ 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() { @@ -33,20 +35,25 @@ abstract class BreadcrumbsItem : VectorEpoxyModel() { @EpoxyAttribute lateinit var roomId: String @EpoxyAttribute lateinit var roomName: CharSequence @EpoxyAttribute var avatarUrl: String? = null - // TODO @EpoxyAttribute var unreadNotificationCount: Int = 0 - // TODO @EpoxyAttribute var hasUnreadMessage: Boolean = false - // TODO @EpoxyAttribute var showHighlighted: Boolean = false + @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() { - // TODO val unreadCounterBadgeView by bind(R.id.roomUnreadCounterBadgeView) - // TODO val unreadIndentIndicator by bind(R.id.roomUnreadIndicator) + 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/res/layout/item_breadcrumbs.xml b/vector/src/main/res/layout/item_breadcrumbs.xml index 0f8b535b7b..4d9616ab1b 100644 --- a/vector/src/main/res/layout/item_breadcrumbs.xml +++ b/vector/src/main/res/layout/item_breadcrumbs.xml @@ -1,5 +1,6 @@ - + + - + + + + + From 849e7c613c621aa6869481769b2eabbbd16214cb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 21:27:56 +0100 Subject: [PATCH 07/12] Breadcrumbs: live update in correct order --- .../database/model/RoomSummaryEntity.kt | 7 +++++-- .../session/room/DefaultRoomService.kt | 11 +++++------ .../user/accountdata/SaveBreadcrumbsTask.kt | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) 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/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index 268d625622..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 @@ -26,7 +26,6 @@ import im.vector.matrix.android.api.session.room.model.VersioningState import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper -import im.vector.matrix.android.internal.database.model.BreadcrumbsEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields @@ -38,7 +37,6 @@ import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcru import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.Realm -import io.realm.RealmList import javax.inject.Inject internal class DefaultRoomService @Inject constructor(private val monarchy: Monarchy, @@ -82,10 +80,11 @@ internal class DefaultRoomService @Inject constructor(private val monarchy: Mona override fun liveBreadcrumbs(): LiveData> { return monarchy.findAllMappedWithChanges( { realm -> - // TODO Improve this query, it's not live when breadcrumbs changes - realm.where(RoomSummaryEntity::class.java) - .`in`(RoomSummaryEntityFields.ROOM_ID, - (realm.where(BreadcrumbsEntity::class.java).findFirst()?.recentRoomIds ?: RealmList()).toTypedArray()) + 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) } ) 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 index 97cfba0549..be694290c3 100644 --- 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 @@ -17,6 +17,9 @@ 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.where import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.RealmList @@ -43,6 +46,22 @@ internal class DefaultSaveBreadcrumbsTask @Inject constructor( // 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 + } } } } From 65333e603196c19352db33995d22b5ec8c21b12a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 21:49:01 +0100 Subject: [PATCH 08/12] Cleanup some Realm queries --- .../store/db/query/CryptoRoomEntityQueries.kt | 6 ++-- .../store/db/query/DeviceInfoEntityQueries.kt | 14 +++++---- .../store/db/query/UserEntitiesQueries.kt | 5 ++-- .../database/query/BreadcrumbsEntityQuery.kt | 30 +++++++++++++++++++ .../database/query/ReadMarkerEntityQueries.kt | 4 +-- .../query/ReadReceiptEntityQueries.kt | 10 ++++--- .../query/RoomSummaryEntityQueries.kt | 4 +-- .../user/accountdata/SaveBreadcrumbsTask.kt | 4 +-- .../user/accountdata/UpdateBreadcrumbsTask.kt | 5 ++-- 9 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/BreadcrumbsEntityQuery.kt 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/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/session/user/accountdata/SaveBreadcrumbsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveBreadcrumbsTask.kt index be694290c3..008dd1d652 100644 --- 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 @@ -19,6 +19,7 @@ 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 @@ -41,8 +42,7 @@ internal class DefaultSaveBreadcrumbsTask @Inject constructor( override suspend fun execute(params: SaveBreadcrumbsTask.Params) { monarchy.awaitTransaction { realm -> // Get or create a breadcrumbs entity - val entity = realm.where(BreadcrumbsEntity::class.java).findFirst() - ?: realm.createObject(BreadcrumbsEntity::class.java) + val entity = BreadcrumbsEntity.getOrCreate(realm) // And save the new received list entity.recentRoomIds = RealmList().apply { addAll(params.recentRoomIds) } 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 index faf0325220..e2fbf67301 100644 --- 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 @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.user.accountdata import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.internal.database.model.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 @@ -43,8 +44,7 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor( // Get the current breadcrumbs in DB val bc = monarchy.fetchCopied { realm -> // Get the breadcrumbs entity, if any - realm.where(BreadcrumbsEntity::class.java).findFirst() - + BreadcrumbsEntity.get(realm) } // Modify the list to add the roomId first @@ -55,6 +55,7 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor( bc.recentRoomIds.add(0, params.roomId) bc.recentRoomIds.take(MAX_BREADCRUMBS_ROOMS_NUMBER) } else { + // FIXME It can remove the previous breadcrumbs, if not synced yet listOf(params.roomId) } From 0768bd5c884cf6df7cecfdda5a37eb3e7eaeecb0 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 22:05:37 +0100 Subject: [PATCH 09/12] Breadcrumbs: nicer algorithm --- .../user/accountdata/UpdateBreadcrumbsTask.kt | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) 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 index e2fbf67301..bde4d138af 100644 --- 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 @@ -24,13 +24,12 @@ import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.fetchCopied import javax.inject.Inject -// Use same arbitrary value than Riot-Web +// Use the same arbitrary value than Riot-Web private const val MAX_BREADCRUMBS_ROOMS_NUMBER = 20 internal interface UpdateBreadcrumbsTask : Task { data class Params( - // Last seen roomId - val roomId: String + val newTopRoomId: String ) } @@ -41,32 +40,27 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor( ) : UpdateBreadcrumbsTask { override suspend fun execute(params: UpdateBreadcrumbsTask.Params) { - // Get the current breadcrumbs in DB - val bc = monarchy.fetchCopied { realm -> - // Get the breadcrumbs entity, if any - BreadcrumbsEntity.get(realm) - } - - // Modify the list to add the roomId first - val newRecentRoomIds = if (bc != null) { - // Ensure the roomId is not already in the list - bc.recentRoomIds.remove(params.roomId) - // Add the room at first position - bc.recentRoomIds.add(0, params.roomId) - bc.recentRoomIds.take(MAX_BREADCRUMBS_ROOMS_NUMBER) - } else { - // FIXME It can remove the previous breadcrumbs, if not synced yet - listOf(params.roomId) - } + 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 roomId is not already in the list + remove(params.newTopRoomId) + // Add the room 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(newRecentRoomIds)) + 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( - newRecentRoomIds - ) + breadcrumbsContent = BreadcrumbsContent(newBreadcrumbs) )) } } From aef76241a39b1d27c7de6c8069d00dba552bcd86 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 22:09:55 +0100 Subject: [PATCH 10/12] Breadcrumbs: changes --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 553091bd67..d6f6801257 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 🙌: - From 9a4d8f87f66f2955d4279925968553c69b52368d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 5 Dec 2019 22:38:49 +0100 Subject: [PATCH 11/12] Breadcrumbs: auto-review --- docs/signup.md | 2 +- .../user/accountdata/AccountDataModule.kt | 6 +++--- .../user/accountdata/UpdateBreadcrumbsTask.kt | 4 ++-- .../room/breadcrumbs/BreadcrumbsController.kt | 14 +++++++------- .../room/breadcrumbs/BreadcrumbsFragment.kt | 5 ++--- .../room/breadcrumbs/BreadcrumbsViewModel.kt | 4 ++-- .../room/breadcrumbs/BreadcrumbsViewState.kt | 2 +- .../home/room/detail/RoomDetailActivity.kt | 18 ++++++++++-------- .../home/room/detail/RoomDetailSharedAction.kt | 2 +- .../home/room/list/RoomSummaryController.kt | 2 +- .../main/res/layout/fragment_breadcrumbs.xml | 2 +- 11 files changed, 31 insertions(+), 30 deletions(-) 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/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 37b63dcd07..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,11 +35,11 @@ internal abstract class AccountDataModule { } @Binds - abstract fun bindUpdateUserAccountDataTask(updateUserAccountDataTask: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask + abstract fun bindUpdateUserAccountDataTask(task: DefaultUpdateUserAccountDataTask): UpdateUserAccountDataTask @Binds - abstract fun bindSaveBreadcrumbsTask(saveBreadcrumbsTask: DefaultSaveBreadcrumbsTask): SaveBreadcrumbsTask + abstract fun bindSaveBreadcrumbsTask(task: DefaultSaveBreadcrumbsTask): SaveBreadcrumbsTask @Binds - abstract fun bindUpdateBreadcrumsTask(saveBreadcrumbsTask: DefaultUpdateBreadcrumbsTask): UpdateBreadcrumbsTask + abstract fun bindUpdateBreadcrumsTask(task: DefaultUpdateBreadcrumbsTask): UpdateBreadcrumbsTask } 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 index bde4d138af..b11072a0bd 100644 --- 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 @@ -46,9 +46,9 @@ internal class DefaultUpdateBreadcrumbsTask @Inject constructor( ?.recentRoomIds ?.apply { // Modify the list to add the newTopRoomId first - // Ensure the roomId is not already in the list + // Ensure the newTopRoomId is not already in the list remove(params.newTopRoomId) - // Add the room at first position + // Add the newTopRoomId at first position add(0, params.newTopRoomId) } ?.take(MAX_BREADCRUMBS_ROOMS_NUMBER) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt index ea359ee2f7..3e400b37ea 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/breadcrumbs/BreadcrumbsController.kt @@ -18,7 +18,6 @@ package im.vector.riotx.features.home.room.breadcrumbs import android.view.View import com.airbnb.epoxy.EpoxyController -import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.riotx.core.utils.DebouncedClickListener import im.vector.riotx.features.home.AvatarRenderer import javax.inject.Inject @@ -33,7 +32,7 @@ class BreadcrumbsController @Inject constructor( 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 breadcrumbs on the main thread. requestModelBuild() } @@ -43,11 +42,12 @@ class BreadcrumbsController @Inject constructor( } override fun buildModels() { - val nonNullViewState = viewState ?: return + val safeViewState = viewState ?: return - // TODO Display a loading, or an empty state + // An empty breadcrumbs list can only be temporary because when entering in a room, + // this one is added to the breadcrumbs - nonNullViewState.asyncRooms.invoke() + safeViewState.asyncBreadcrumbs.invoke() ?.forEach { breadcrumbsItem { id(it.roomId) @@ -61,7 +61,7 @@ class BreadcrumbsController @Inject constructor( hasDraft(it.userDrafts.isNotEmpty()) itemClickListener( DebouncedClickListener(View.OnClickListener { _ -> - listener?.onRoomClicked(it) + listener?.onBreadcrumbClicked(it.roomId) }) ) } @@ -69,6 +69,6 @@ class BreadcrumbsController @Inject constructor( } interface Listener { - fun onRoomClicked(room: RoomSummary) + 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 index 036208ec6a..e57a2ddac4 100644 --- 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 @@ -20,7 +20,6 @@ import android.os.Bundle import android.view.View import androidx.recyclerview.widget.LinearLayoutManager import com.airbnb.mvrx.fragmentViewModel -import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.riotx.R import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.features.home.room.detail.RoomDetailSharedAction @@ -65,7 +64,7 @@ class BreadcrumbsFragment @Inject constructor( // BreadcrumbsController.Listener ************************************************************** - override fun onRoomClicked(room: RoomSummary) { - sharedActionViewModel.post(RoomDetailSharedAction.OpenRoom(room.roomId)) + override fun onBreadcrumbClicked(roomId: String) { + sharedActionViewModel.post(RoomDetailSharedAction.SwitchToRoom(roomId)) } } 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 index 4b462a05a6..83e9e0fb3f 100644 --- 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 @@ -59,8 +59,8 @@ class BreadcrumbsViewModel @AssistedInject constructor(@Assisted initialState: B session.rx() .liveBreadcrumbs() .observeOn(Schedulers.computation()) - .execute { asyncRooms -> - copy(asyncRooms = asyncRooms) + .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 index cb00db4c9f..7cc634c8b0 100644 --- 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 @@ -22,5 +22,5 @@ import com.airbnb.mvrx.Uninitialized import im.vector.matrix.android.api.session.room.model.RoomSummary data class BreadcrumbsViewState( - val asyncRooms: Async> = Uninitialized + 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 bdc3b59eff..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 @@ -57,14 +57,7 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable { .observe() .subscribe { sharedAction -> when (sharedAction) { - is RoomDetailSharedAction.OpenRoom -> { - drawerLayout.closeDrawer(GravityCompat.START) - // Do not replace the Fragment if it's the same roomId - if (currentRoomId != sharedAction.roomId) { - currentRoomId = sharedAction.roomId - replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, RoomDetailArgs(sharedAction.roomId)) - } - } + is RoomDetailSharedAction.SwitchToRoom -> switchToRoom(sharedAction) } } .disposeOnDestroy() @@ -72,6 +65,15 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable { 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() 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 index 6a88bb1f13..95dd34ebb8 100644 --- 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 @@ -22,5 +22,5 @@ import im.vector.riotx.core.platform.VectorSharedAction * Supported navigation actions for [RoomDetailActivity] */ sealed class RoomDetailSharedAction : VectorSharedAction { - data class OpenRoom(val roomId: String) : RoomDetailSharedAction() + data class SwitchToRoom(val roomId: String) : RoomDetailSharedAction() } 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/fragment_breadcrumbs.xml b/vector/src/main/res/layout/fragment_breadcrumbs.xml index c17b35fdee..22cceadc03 100644 --- a/vector/src/main/res/layout/fragment_breadcrumbs.xml +++ b/vector/src/main/res/layout/fragment_breadcrumbs.xml @@ -5,4 +5,4 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:background="?riotx_background" - tools:listitem="@layout/item_breadcrumbs" /> \ No newline at end of file + tools:listitem="@layout/item_breadcrumbs" /> From a41617e8aad41e64c29e03b84976b38a77cdc48c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 6 Dec 2019 22:00:49 +0100 Subject: [PATCH 12/12] Fix lint false positive issue --- vector/src/main/res/layout/item_breadcrumbs.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/main/res/layout/item_breadcrumbs.xml b/vector/src/main/res/layout/item_breadcrumbs.xml index 4d9616ab1b..f364ad8211 100644 --- a/vector/src/main/res/layout/item_breadcrumbs.xml +++ b/vector/src/main/res/layout/item_breadcrumbs.xml @@ -49,6 +49,7 @@ app:layout_constraintCircleAngle="45" app:layout_constraintCircleRadius="28dp" tools:background="@drawable/bg_unread_highlight" + tools:ignore="MissingConstraints" tools:text="24" tools:visibility="visible" /> @@ -63,6 +64,7 @@ app:layout_constraintCircle="@+id/breadcrumbsImageView" app:layout_constraintCircleAngle="135" app:layout_constraintCircleRadius="28dp" + tools:ignore="MissingConstraints" tools:visibility="visible" />