Compare commits

...

3 Commits

Author SHA1 Message Date
ganfra 12b681209f Use awaitRoom on Timeline screen 2022-07-06 18:40:15 +02:00
ganfra 2acfce2d20 Use awaitRoomSummary 2022-07-06 18:39:56 +02:00
ganfra ebd491c6f0 Introduce awaitRoom() and awaitRoomSummary() 2022-07-06 18:11:06 +02:00
17 changed files with 915 additions and 863 deletions

View File

@ -65,6 +65,11 @@ interface Room {
*/ */
fun roomSummary(): RoomSummary? fun roomSummary(): RoomSummary?
/**
* Suspending version of [roomSummary] method
*/
suspend fun awaitRoomSummary(): RoomSummary?
/** /**
* Use this room as a Space, if the type is correct. * Use this room as a Space, if the type is correct.
*/ */

View File

@ -92,6 +92,13 @@ interface RoomService {
*/ */
fun getRoom(roomId: String): Room? fun getRoom(roomId: String): Room?
/**
* Suspending version of [getRoom] method.
* @param roomId the roomId to look for.
* @return a room with roomId or null
*/
suspend fun awaitRoom(roomId: String): Room?
/** /**
* Get a roomSummary from a roomId or a room alias. * Get a roomSummary from a roomId or a room alias.
* @param roomIdOrAlias the roomId or the alias of a room to look for. * @param roomIdOrAlias the roomId or the alias of a room to look for.

View File

@ -82,6 +82,10 @@ internal class DefaultRoom(
return roomSummaryDataSource.getRoomSummary(roomId) return roomSummaryDataSource.getRoomSummary(roomId)
} }
override suspend fun awaitRoomSummary(): RoomSummary? {
return roomSummaryDataSource.awaitRoomSummary(roomId)
}
override fun asSpace(): Space? { override fun asSpace(): Space? {
if (roomSummary()?.roomType != RoomType.SPACE) return null if (roomSummary()?.roomType != RoomType.SPACE) return null
return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder) return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)

View File

@ -82,6 +82,10 @@ internal class DefaultRoomService @Inject constructor(
return roomGetter.getRoom(roomId) return roomGetter.getRoom(roomId)
} }
override suspend fun awaitRoom(roomId: String): Room? {
return roomGetter.awaitRoom(roomId)
}
override fun getExistingDirectRoomWithUser(otherUserId: String): String? { override fun getExistingDirectRoomWithUser(otherUserId: String): String? {
return roomGetter.getDirectRoomWith(otherUserId) return roomGetter.getDirectRoomWith(otherUserId)
} }

View File

@ -17,6 +17,8 @@
package org.matrix.android.sdk.internal.session.room package org.matrix.android.sdk.internal.session.room
import io.realm.Realm import io.realm.Realm
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.internal.database.RealmSessionProvider import org.matrix.android.sdk.internal.database.RealmSessionProvider
@ -30,13 +32,16 @@ import javax.inject.Inject
internal interface RoomGetter { internal interface RoomGetter {
fun getRoom(roomId: String): Room? fun getRoom(roomId: String): Room?
suspend fun awaitRoom(roomId: String): Room?
fun getDirectRoomWith(otherUserId: String): String? fun getDirectRoomWith(otherUserId: String): String?
} }
@SessionScope @SessionScope
internal class DefaultRoomGetter @Inject constructor( internal class DefaultRoomGetter @Inject constructor(
private val realmSessionProvider: RealmSessionProvider, private val realmSessionProvider: RealmSessionProvider,
private val roomFactory: RoomFactory private val roomFactory: RoomFactory,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) : RoomGetter { ) : RoomGetter {
override fun getRoom(roomId: String): Room? { override fun getRoom(roomId: String): Room? {
@ -45,6 +50,10 @@ internal class DefaultRoomGetter @Inject constructor(
} }
} }
override suspend fun awaitRoom(roomId: String) = withContext(coroutineDispatchers.io) {
getRoom(roomId)
}
override fun getDirectRoomWith(otherUserId: String): String? { override fun getDirectRoomWith(otherUserId: String): String? {
return realmSessionProvider.withRealm { realm -> return realmSessionProvider.withRealm { realm ->
RoomSummaryEntity.where(realm) RoomSummaryEntity.where(realm)

View File

@ -51,7 +51,7 @@ internal class DefaultLeaveRoomTask @Inject constructor(
} }
private suspend fun leaveRoom(roomId: String, reason: String?) { private suspend fun leaveRoom(roomId: String, reason: String?) {
val roomSummary = roomSummaryDataSource.getRoomSummary(roomId) val roomSummary = roomSummaryDataSource.awaitRoomSummary(roomId)
if (roomSummary?.membership?.isActive() == false) { if (roomSummary?.membership?.isActive() == false) {
Timber.v("Room $roomId is not joined so can't be left") Timber.v("Room $roomId is not joined so can't be left")
return return

View File

@ -26,6 +26,8 @@ import com.zhuinden.monarchy.Monarchy
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.kotlin.where import io.realm.kotlin.where
import kotlinx.coroutines.withContext
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomCategoryFilter
import org.matrix.android.sdk.api.query.SpaceFilter import org.matrix.android.sdk.api.query.SpaceFilter
@ -58,6 +60,7 @@ internal class RoomSummaryDataSource @Inject constructor(
@SessionDatabase private val monarchy: Monarchy, @SessionDatabase private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper, private val roomSummaryMapper: RoomSummaryMapper,
private val queryStringValueProcessor: QueryStringValueProcessor, private val queryStringValueProcessor: QueryStringValueProcessor,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) { ) {
fun getRoomSummary(roomIdOrAlias: String): RoomSummary? { fun getRoomSummary(roomIdOrAlias: String): RoomSummary? {
@ -75,6 +78,10 @@ internal class RoomSummaryDataSource @Inject constructor(
}) })
} }
suspend fun awaitRoomSummary(roomIdOrAlias: String) = withContext(coroutineDispatchers.io) {
getRoomSummary(roomIdOrAlias)
}
fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> { fun getRoomSummaryLive(roomId: String): LiveData<Optional<RoomSummary>> {
val liveData = monarchy.findAllMappedWithChanges( val liveData = monarchy.findAllMappedWithChanges(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },

View File

@ -53,7 +53,7 @@ internal class DefaultSpace(
) { ) {
// Find best via // Find best via
val bestVia = viaServers val bestVia = viaServers
?: (spaceSummaryDataSource.getRoomSummary(roomId) ?: (spaceSummaryDataSource.awaitRoomSummary(roomId)
?.takeIf { it.joinRules == RoomJoinRules.RESTRICTED } ?.takeIf { it.joinRules == RoomJoinRules.RESTRICTED }
?.let { ?.let {
// for restricted room, best to take via from users that can invite in the // for restricted room, best to take via from users that can invite in the

View File

@ -246,7 +246,7 @@ internal class DefaultSpaceService @Inject constructor(
// and if client want to bypass, it could use sendStateEvent directly? // and if client want to bypass, it could use sendStateEvent directly?
if (canonical) { if (canonical) {
// check that we can send m.child in the parent room // check that we can send m.child in the parent room
if (roomSummaryDataSource.getRoomSummary(parentSpaceId)?.membership != Membership.JOIN) { if (roomSummaryDataSource.awaitRoomSummary(parentSpaceId)?.membership != Membership.JOIN) {
throw UnsupportedOperationException("Cannot add canonical child if not member of parent") throw UnsupportedOperationException("Cannot add canonical child if not member of parent")
} }
val powerLevelsEvent = stateEventDataSource.getStateEvent( val powerLevelsEvent = stateEventDataSource.getStateEvent(

View File

@ -58,7 +58,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker:
protocolsChecker.awaitCheckProtocols() protocolsChecker.awaitCheckProtocols()
if (!protocolsChecker.supportVirtualRooms) return if (!protocolsChecker.supportVirtualRooms) return
val invitedRoom = session.getRoom(invitedRoomId) ?: return val invitedRoom = session.getRoom(invitedRoomId) ?: return
val inviterId = invitedRoom.roomSummary()?.inviterId ?: return val inviterId = invitedRoom.awaitRoomSummary()?.inviterId ?: return
val nativeLookup = session.sipNativeLookup(inviterId).firstOrNull() ?: return val nativeLookup = session.sipNativeLookup(inviterId).firstOrNull() ?: return
if (nativeLookup.fields.containsKey("is_virtual")) { if (nativeLookup.fields.containsKey("is_virtual")) {
val nativeUser = nativeLookup.userId val nativeUser = nativeLookup.userId

View File

@ -213,6 +213,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
@ -381,18 +382,20 @@ class TimelineFragment @Inject constructor(
) )
keyboardStateUtils = KeyboardStateUtils(requireActivity()) keyboardStateUtils = KeyboardStateUtils(requireActivity())
lazyLoadedViews.bind(views) lazyLoadedViews.bind(views)
setupToolbar(views.roomToolbar) viewLifecycleOwner.lifecycleScope.launch {
.allowBack() setupToolbar(views.roomToolbar)
setupRecyclerView() .allowBack()
setupComposer() setupRecyclerView()
setupNotificationView() setupComposer()
setupJumpToReadMarkerView() setupNotificationView()
setupActiveCallView() setupJumpToReadMarkerView()
setupJumpToBottomView() setupActiveCallView()
setupEmojiButton() setupJumpToBottomView()
setupRemoveJitsiWidgetView() setupEmojiButton()
setupVoiceMessageView() setupRemoveJitsiWidgetView()
setupLiveLocationIndicator() setupVoiceMessageView()
setupLiveLocationIndicator()
}
views.includeRoomToolbar.roomToolbarContentView.debouncedClicks { views.includeRoomToolbar.roomToolbarContentView.debouncedClicks {
navigator.openRoomProfile(requireActivity(), timelineArgs.roomId) navigator.openRoomProfile(requireActivity(), timelineArgs.roomId)
@ -979,16 +982,17 @@ class TimelineFragment @Inject constructor(
private fun setupJumpToBottomView() { private fun setupJumpToBottomView() {
views.jumpToBottomView.visibility = View.INVISIBLE views.jumpToBottomView.visibility = View.INVISIBLE
views.jumpToBottomView.debouncedClicks { views.jumpToBottomView.debouncedClicks {
timelineViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState) viewLifecycleOwner.lifecycleScope.launch {
views.jumpToBottomView.visibility = View.INVISIBLE timelineViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
if (!timelineViewModel.timeline.isLive) { views.jumpToBottomView.visibility = View.INVISIBLE
scrollOnNewMessageCallback.forceScrollOnNextUpdate() if (!timelineViewModel.timeline.await().isLive) {
timelineViewModel.timeline.restartWithEventId(null) scrollOnNewMessageCallback.forceScrollOnNextUpdate()
} else { timelineViewModel.timeline.await().restartWithEventId(null)
layoutManager.scrollToPosition(0) } else {
layoutManager.scrollToPosition(0)
}
} }
} }
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager( jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
views.jumpToBottomView, views.jumpToBottomView,
debouncer, debouncer,
@ -1216,12 +1220,14 @@ class TimelineFragment @Inject constructor(
} }
private fun handleSearchAction() { private fun handleSearchAction() {
navigator.openSearch( viewLifecycleOwner.lifecycleScope.launch {
context = requireContext(), navigator.openSearch(
roomId = timelineArgs.roomId, context = requireContext(),
roomDisplayName = timelineViewModel.getRoomSummary()?.displayName, roomId = timelineArgs.roomId,
roomAvatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl roomDisplayName = timelineViewModel.getRoomSummary()?.displayName,
) roomAvatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
)
}
} }
private fun displayDisabledIntegrationDialog() { private fun displayDisabledIntegrationDialog() {
@ -1416,9 +1422,9 @@ class TimelineFragment @Inject constructor(
// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************
private fun setupRecyclerView() { private suspend fun setupRecyclerView() {
timelineEventController.callback = this timelineEventController.callback = this
timelineEventController.timeline = timelineViewModel.timeline timelineEventController.timeline = timelineViewModel.timeline.await()
views.timelineRecyclerView.trackItemsVisibilityChange() views.timelineRecyclerView.trackItemsVisibilityChange()
layoutManager = object : LinearLayoutManager(context, RecyclerView.VERTICAL, true) { layoutManager = object : LinearLayoutManager(context, RecyclerView.VERTICAL, true) {
@ -2421,7 +2427,9 @@ class TimelineFragment @Inject constructor(
views.composerLayout.views.composerEditText.setText(Command.EMOTE.command + " ") views.composerLayout.views.composerEditText.setText(Command.EMOTE.command + " ")
views.composerLayout.views.composerEditText.setSelection(Command.EMOTE.command.length + 1) views.composerLayout.views.composerEditText.setSelection(Command.EMOTE.command.length + 1)
} else { } else {
val roomMember = timelineViewModel.getMember(userId) val roomMember = runBlocking {
timelineViewModel.getMember(userId)
}
// TODO move logic outside of fragment // TODO move logic outside of fragment
(roomMember?.displayName ?: userId) (roomMember?.displayName ?: userId)
.let { sanitizeDisplayName(it) } .let { sanitizeDisplayName(it) }
@ -2491,18 +2499,21 @@ class TimelineFragment @Inject constructor(
* using the ThreadsActivity. * using the ThreadsActivity.
*/ */
private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) { private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction()) viewLifecycleOwner.lifecycleScope.launch {
context?.let { analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
val roomThreadDetailArgs = ThreadTimelineArgs( context?.let {
startsThread = startsThread, val roomSummary = timelineViewModel.awaitState().asyncRoomSummary()
roomId = timelineArgs.roomId, val roomThreadDetailArgs = ThreadTimelineArgs(
displayName = timelineViewModel.getRoomSummary()?.displayName, startsThread = startsThread,
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl, roomId = timelineArgs.roomId,
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel, displayName = roomSummary?.displayName,
rootThreadEventId = rootThreadEventId, avatarUrl = roomSummary?.avatarUrl,
showKeyboard = showKeyboard roomEncryptionTrustLevel = roomSummary?.roomEncryptionTrustLevel,
) rootThreadEventId = rootThreadEventId,
navigator.openThread(it, roomThreadDetailArgs) showKeyboard = showKeyboard
)
navigator.openThread(it, roomThreadDetailArgs)
}
} }
} }
@ -2530,15 +2541,18 @@ class TimelineFragment @Inject constructor(
* using the ThreadsActivity. * using the ThreadsActivity.
*/ */
private fun navigateToThreadList() { private fun navigateToThreadList() {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction()) viewLifecycleOwner.lifecycleScope.launch {
context?.let { analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction())
val roomThreadDetailArgs = ThreadTimelineArgs( context?.let {
roomId = timelineArgs.roomId, val roomSummary = timelineViewModel.awaitState().asyncRoomSummary()
displayName = timelineViewModel.getRoomSummary()?.displayName, val roomThreadDetailArgs = ThreadTimelineArgs(
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel, roomId = timelineArgs.roomId,
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl displayName = roomSummary?.displayName,
) roomEncryptionTrustLevel = roomSummary?.roomEncryptionTrustLevel,
navigator.openThreadList(it, roomThreadDetailArgs) avatarUrl = roomSummary?.avatarUrl
)
navigator.openThreadList(it, roomThreadDetailArgs)
}
} }
} }

View File

@ -20,6 +20,7 @@ import im.vector.app.features.call.vectorCallService
import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory import im.vector.app.features.home.room.detail.timeline.helper.TimelineSettingsFactory
import im.vector.app.features.home.room.detail.timeline.merged.MergedTimelines import im.vector.app.features.home.room.detail.timeline.merged.MergedTimelines
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
@ -36,14 +37,14 @@ private val secondaryTimelineAllowedTypes = listOf(
class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) { class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) {
fun createTimeline( suspend fun createTimeline(
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
mainRoom: Room, room: Deferred<Room>,
eventId: String?, eventId: String?,
rootThreadEventId: String? rootThreadEventId: String?
): Timeline { ): Timeline {
val settings = timelineSettingsFactory.create(rootThreadEventId) val settings = timelineSettingsFactory.create(rootThreadEventId)
val mainRoom = room.await()
if (!session.vectorCallService.protocolChecker.supportVirtualRooms) { if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
return mainRoom.timelineService().createTimeline(eventId, settings) return mainRoom.timelineService().createTimeline(eventId, settings)
} }

View File

@ -294,7 +294,7 @@ class RoomListViewModel @AssistedInject constructor(
session.getRoom(action.roomId)?.let { room -> session.getRoom(action.roomId)?.let { room ->
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
if (room.roomSummary()?.hasTag(action.tag) == false) { if (room.awaitRoomSummary()?.hasTag(action.tag) == false) {
// Favorite and low priority tags are exclusive, so maybe delete the other tag first // Favorite and low priority tags are exclusive, so maybe delete the other tag first
action.tag.otherTag() action.tag.otherTag()
?.takeIf { room.roomSummary()?.hasTag(it).orFalse() } ?.takeIf { room.roomSummary()?.hasTag(it).orFalse() }

View File

@ -122,7 +122,7 @@ class InvitesAcceptor @Inject constructor(
// if we got 404 on invites, the inviting user have left or the hs is off. // if we got 404 on invites, the inviting user have left or the hs is off.
if (failure is Failure.ServerError && failure.httpCode == 404) { if (failure is Failure.ServerError && failure.httpCode == 404) {
val room = getRoom(roomId) ?: return val room = getRoom(roomId) ?: return
val inviterId = room.roomSummary()?.inviterId val inviterId = room.awaitRoomSummary()?.inviterId
// if the inviting user is on the same HS, there can only be one cause: they left, so we try to reject the invite. // if the inviting user is on the same HS, there can only be one cause: they left, so we try to reject the invite.
if (inviterId?.endsWith(sessionParams.credentials.homeServer.orEmpty()).orFalse()) { if (inviterId?.endsWith(sessionParams.credentials.homeServer.orEmpty()).orFalse()) {
shouldRejectRoomIds.add(roomId) shouldRejectRoomIds.add(roomId)

View File

@ -47,7 +47,7 @@ fun ElementWellKnown?.getOutboundSessionKeySharingStrategyOrDefault(): OutboundS
fun RawService.withElementWellKnown( fun RawService.withElementWellKnown(
coroutineScope: CoroutineScope, coroutineScope: CoroutineScope,
sessionParams: SessionParams, sessionParams: SessionParams,
block: ((ElementWellKnown?) -> Unit) block: suspend ((ElementWellKnown?) -> Unit)
) = with(coroutineScope) { ) = with(coroutineScope) {
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
block(getElementWellknown(sessionParams)) block(getElementWellknown(sessionParams))