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?
/**
* Suspending version of [roomSummary] method
*/
suspend fun awaitRoomSummary(): RoomSummary?
/**
* Use this room as a Space, if the type is correct.
*/

View File

@ -92,6 +92,13 @@ interface RoomService {
*/
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.
* @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)
}
override suspend fun awaitRoomSummary(): RoomSummary? {
return roomSummaryDataSource.awaitRoomSummary(roomId)
}
override fun asSpace(): Space? {
if (roomSummary()?.roomType != RoomType.SPACE) return null
return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)

View File

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

View File

@ -17,6 +17,8 @@
package org.matrix.android.sdk.internal.session.room
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.model.Membership
import org.matrix.android.sdk.internal.database.RealmSessionProvider
@ -30,13 +32,16 @@ import javax.inject.Inject
internal interface RoomGetter {
fun getRoom(roomId: String): Room?
suspend fun awaitRoom(roomId: String): Room?
fun getDirectRoomWith(otherUserId: String): String?
}
@SessionScope
internal class DefaultRoomGetter @Inject constructor(
private val realmSessionProvider: RealmSessionProvider,
private val roomFactory: RoomFactory
private val roomFactory: RoomFactory,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) : RoomGetter {
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? {
return realmSessionProvider.withRealm { realm ->
RoomSummaryEntity.where(realm)

View File

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

View File

@ -26,6 +26,8 @@ import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmQuery
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.RoomCategoryFilter
import org.matrix.android.sdk.api.query.SpaceFilter
@ -58,6 +60,7 @@ internal class RoomSummaryDataSource @Inject constructor(
@SessionDatabase private val monarchy: Monarchy,
private val roomSummaryMapper: RoomSummaryMapper,
private val queryStringValueProcessor: QueryStringValueProcessor,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
) {
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>> {
val liveData = monarchy.findAllMappedWithChanges(
{ realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) },

View File

@ -53,7 +53,7 @@ internal class DefaultSpace(
) {
// Find best via
val bestVia = viaServers
?: (spaceSummaryDataSource.getRoomSummary(roomId)
?: (spaceSummaryDataSource.awaitRoomSummary(roomId)
?.takeIf { it.joinRules == RoomJoinRules.RESTRICTED }
?.let {
// 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?
if (canonical) {
// 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")
}
val powerLevelsEvent = stateEventDataSource.getStateEvent(

View File

@ -58,7 +58,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker:
protocolsChecker.awaitCheckProtocols()
if (!protocolsChecker.supportVirtualRooms) 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
if (nativeLookup.fields.containsKey("is_virtual")) {
val nativeUser = nativeLookup.userId

View File

@ -213,6 +213,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.billcarsonfr.jsonviewer.JSonViewerDialog
import org.commonmark.parser.Parser
@ -381,18 +382,20 @@ class TimelineFragment @Inject constructor(
)
keyboardStateUtils = KeyboardStateUtils(requireActivity())
lazyLoadedViews.bind(views)
setupToolbar(views.roomToolbar)
.allowBack()
setupRecyclerView()
setupComposer()
setupNotificationView()
setupJumpToReadMarkerView()
setupActiveCallView()
setupJumpToBottomView()
setupEmojiButton()
setupRemoveJitsiWidgetView()
setupVoiceMessageView()
setupLiveLocationIndicator()
viewLifecycleOwner.lifecycleScope.launch {
setupToolbar(views.roomToolbar)
.allowBack()
setupRecyclerView()
setupComposer()
setupNotificationView()
setupJumpToReadMarkerView()
setupActiveCallView()
setupJumpToBottomView()
setupEmojiButton()
setupRemoveJitsiWidgetView()
setupVoiceMessageView()
setupLiveLocationIndicator()
}
views.includeRoomToolbar.roomToolbarContentView.debouncedClicks {
navigator.openRoomProfile(requireActivity(), timelineArgs.roomId)
@ -979,16 +982,17 @@ class TimelineFragment @Inject constructor(
private fun setupJumpToBottomView() {
views.jumpToBottomView.visibility = View.INVISIBLE
views.jumpToBottomView.debouncedClicks {
timelineViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
views.jumpToBottomView.visibility = View.INVISIBLE
if (!timelineViewModel.timeline.isLive) {
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
timelineViewModel.timeline.restartWithEventId(null)
} else {
layoutManager.scrollToPosition(0)
viewLifecycleOwner.lifecycleScope.launch {
timelineViewModel.handle(RoomDetailAction.ExitTrackingUnreadMessagesState)
views.jumpToBottomView.visibility = View.INVISIBLE
if (!timelineViewModel.timeline.await().isLive) {
scrollOnNewMessageCallback.forceScrollOnNextUpdate()
timelineViewModel.timeline.await().restartWithEventId(null)
} else {
layoutManager.scrollToPosition(0)
}
}
}
jumpToBottomViewVisibilityManager = JumpToBottomViewVisibilityManager(
views.jumpToBottomView,
debouncer,
@ -1216,12 +1220,14 @@ class TimelineFragment @Inject constructor(
}
private fun handleSearchAction() {
navigator.openSearch(
context = requireContext(),
roomId = timelineArgs.roomId,
roomDisplayName = timelineViewModel.getRoomSummary()?.displayName,
roomAvatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
)
viewLifecycleOwner.lifecycleScope.launch {
navigator.openSearch(
context = requireContext(),
roomId = timelineArgs.roomId,
roomDisplayName = timelineViewModel.getRoomSummary()?.displayName,
roomAvatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
)
}
}
private fun displayDisabledIntegrationDialog() {
@ -1416,9 +1422,9 @@ class TimelineFragment @Inject constructor(
// PRIVATE METHODS *****************************************************************************
private fun setupRecyclerView() {
private suspend fun setupRecyclerView() {
timelineEventController.callback = this
timelineEventController.timeline = timelineViewModel.timeline
timelineEventController.timeline = timelineViewModel.timeline.await()
views.timelineRecyclerView.trackItemsVisibilityChange()
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.setSelection(Command.EMOTE.command.length + 1)
} else {
val roomMember = timelineViewModel.getMember(userId)
val roomMember = runBlocking {
timelineViewModel.getMember(userId)
}
// TODO move logic outside of fragment
(roomMember?.displayName ?: userId)
.let { sanitizeDisplayName(it) }
@ -2491,18 +2499,21 @@ class TimelineFragment @Inject constructor(
* using the ThreadsActivity.
*/
private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
context?.let {
val roomThreadDetailArgs = ThreadTimelineArgs(
startsThread = startsThread,
roomId = timelineArgs.roomId,
displayName = timelineViewModel.getRoomSummary()?.displayName,
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl,
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
rootThreadEventId = rootThreadEventId,
showKeyboard = showKeyboard
)
navigator.openThread(it, roomThreadDetailArgs)
viewLifecycleOwner.lifecycleScope.launch {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
context?.let {
val roomSummary = timelineViewModel.awaitState().asyncRoomSummary()
val roomThreadDetailArgs = ThreadTimelineArgs(
startsThread = startsThread,
roomId = timelineArgs.roomId,
displayName = roomSummary?.displayName,
avatarUrl = roomSummary?.avatarUrl,
roomEncryptionTrustLevel = roomSummary?.roomEncryptionTrustLevel,
rootThreadEventId = rootThreadEventId,
showKeyboard = showKeyboard
)
navigator.openThread(it, roomThreadDetailArgs)
}
}
}
@ -2530,15 +2541,18 @@ class TimelineFragment @Inject constructor(
* using the ThreadsActivity.
*/
private fun navigateToThreadList() {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction())
context?.let {
val roomThreadDetailArgs = ThreadTimelineArgs(
roomId = timelineArgs.roomId,
displayName = timelineViewModel.getRoomSummary()?.displayName,
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl
)
navigator.openThreadList(it, roomThreadDetailArgs)
viewLifecycleOwner.lifecycleScope.launch {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadListButton.toAnalyticsInteraction())
context?.let {
val roomSummary = timelineViewModel.awaitState().asyncRoomSummary()
val roomThreadDetailArgs = ThreadTimelineArgs(
roomId = timelineArgs.roomId,
displayName = roomSummary?.displayName,
roomEncryptionTrustLevel = roomSummary?.roomEncryptionTrustLevel,
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.merged.MergedTimelines
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
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.getRoom
@ -36,14 +37,14 @@ private val secondaryTimelineAllowedTypes = listOf(
class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) {
fun createTimeline(
suspend fun createTimeline(
coroutineScope: CoroutineScope,
mainRoom: Room,
room: Deferred<Room>,
eventId: String?,
rootThreadEventId: String?
): Timeline {
val settings = timelineSettingsFactory.create(rootThreadEventId)
val mainRoom = room.await()
if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
return mainRoom.timelineService().createTimeline(eventId, settings)
}

View File

@ -294,7 +294,7 @@ class RoomListViewModel @AssistedInject constructor(
session.getRoom(action.roomId)?.let { room ->
viewModelScope.launch(Dispatchers.IO) {
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
action.tag.otherTag()
?.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 (failure is Failure.ServerError && failure.httpCode == 404) {
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 (inviterId?.endsWith(sessionParams.credentials.homeServer.orEmpty()).orFalse()) {
shouldRejectRoomIds.add(roomId)

View File

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