Adapt to new DM definition changes in the SDK (#6748)
* Set `DmRoomDefinition.TwoPeople` in `ClientBuilder`. This applies the 'direct and with at most 2 non-service members' rule to what the SDK should consider a DM. * Map `RoomInfo.isDm` from the SDK * Map `NotificationData.isDm` from `NotificationInfo.roomInfo.isDm` * Remove `RoomIsDmCheck` file as its extension functions are now redundant. Move `Room.isDm` helper function to `BaseRoom`. * Map `isDm` in `SpaceRoom` from the SDK too * Replace `isDirect` with `isDm` where possible * Map `RoomMember.isServiceMember` from the SDK and use it to tell apart normal members of a room from service members (i.e. `RoomMembersState.getDirectRoomMember`)
This commit is contained in:
parent
a38b7a61ad
commit
4975f61eb8
66 changed files with 115 additions and 232 deletions
|
|
@ -14,7 +14,6 @@ import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
|
||||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||||
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
import io.element.android.services.appnavstate.api.ActiveRoomsHolder
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
|
import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter
|
||||||
import io.element.android.libraries.matrix.api.room.CallIntentConsensus
|
import io.element.android.libraries.matrix.api.room.CallIntentConsensus
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
|
import io.element.android.libraries.matrix.api.roomlist.LatestEventValue
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ package io.element.android.features.invite.api
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||||
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,7 @@ internal class DefaultInvitePeoplePresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - suggestions are loaded from recent direct rooms`() = runTest {
|
fun `present - suggestions are loaded from recent DM rooms`() = runTest {
|
||||||
val dmRoomId = RoomId("!dm_room:server.org")
|
val dmRoomId = RoomId("!dm_room:server.org")
|
||||||
val otherUserId = UserId("@frank:server.org")
|
val otherUserId = UserId("@frank:server.org")
|
||||||
val matrixClient = FakeMatrixClient(sessionId = A_USER_ID).apply {
|
val matrixClient = FakeMatrixClient(sessionId = A_USER_ID).apply {
|
||||||
|
|
@ -554,7 +554,7 @@ internal class DefaultInvitePeoplePresenterTest {
|
||||||
roomId = dmRoomId,
|
roomId = dmRoomId,
|
||||||
initialRoomInfo = aRoomInfo(
|
initialRoomInfo = aRoomInfo(
|
||||||
id = dmRoomId,
|
id = dmRoomId,
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2,
|
activeMembersCount = 2,
|
||||||
currentUserMembership = CurrentUserMembership.JOINED,
|
currentUserMembership = CurrentUserMembership.JOINED,
|
||||||
),
|
),
|
||||||
|
|
@ -591,7 +591,7 @@ internal class DefaultInvitePeoplePresenterTest {
|
||||||
roomId = dmRoomId,
|
roomId = dmRoomId,
|
||||||
initialRoomInfo = aRoomInfo(
|
initialRoomInfo = aRoomInfo(
|
||||||
id = dmRoomId,
|
id = dmRoomId,
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2,
|
activeMembersCount = 2,
|
||||||
currentUserMembership = CurrentUserMembership.JOINED,
|
currentUserMembership = CurrentUserMembership.JOINED,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
import io.element.android.libraries.matrix.api.room.RoomMembershipDetails
|
||||||
import io.element.android.libraries.matrix.api.room.RoomType
|
import io.element.android.libraries.matrix.api.room.RoomType
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.join.JoinRoom
|
import io.element.android.libraries.matrix.api.room.join.JoinRoom
|
||||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||||
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
import io.element.android.libraries.matrix.api.room.preview.RoomPreviewInfo
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.usersWithRole
|
import io.element.android.libraries.matrix.api.room.powerlevels.usersWithRole
|
||||||
import io.element.android.libraries.push.api.notifications.conversations.NotificationConversationService
|
import io.element.android.libraries.push.api.notifications.conversations.NotificationConversationService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ class LeaveBaseRoomPresenterTest {
|
||||||
givenGetRoomResult(
|
givenGetRoomResult(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
result = FakeBaseRoom().apply {
|
result = FakeBaseRoom().apply {
|
||||||
givenRoomInfo(aRoomInfo(isDirect = true, activeMembersCount = 2))
|
givenRoomInfo(aRoomInfo(isDm = true, activeMembersCount = 2))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||||
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
|
import io.element.android.libraries.matrix.api.room.draft.ComposerDraftType
|
||||||
import io.element.android.libraries.matrix.api.room.getDirectRoomMember
|
import io.element.android.libraries.matrix.api.room.getDirectRoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.use
|
import io.element.android.libraries.matrix.api.room.powerlevels.use
|
||||||
import io.element.android.libraries.matrix.api.timeline.TimelineException
|
import io.element.android.libraries.matrix.api.timeline.TimelineException
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTransactionId
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,7 @@ internal fun SuggestionsPickerViewPreview() {
|
||||||
isIgnored = false,
|
isIgnored = false,
|
||||||
role = RoomMember.Role.User,
|
role = RoomMember.Role.User,
|
||||||
membershipChangeReason = null,
|
membershipChangeReason = null,
|
||||||
|
isServiceMember = false,
|
||||||
)
|
)
|
||||||
val anAlias = remember { RoomAlias("#room:domain.org") }
|
val anAlias = remember { RoomAlias("#room:domain.org") }
|
||||||
SuggestionsPickerView(
|
SuggestionsPickerView(
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||||
import io.element.android.libraries.matrix.api.core.asEventId
|
import io.element.android.libraries.matrix.api.core.asEventId
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
|
|
|
||||||
|
|
@ -598,7 +598,7 @@ class MessagesPresenterTest {
|
||||||
baseRoom = FakeBaseRoom(
|
baseRoom = FakeBaseRoom(
|
||||||
roomPermissions = roomPermissions(),
|
roomPermissions = roomPermissions(),
|
||||||
).apply {
|
).apply {
|
||||||
givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1))
|
givenRoomInfo(aRoomInfo(isDm = true, joinedMembersCount = 1, activeMembersCount = 1))
|
||||||
},
|
},
|
||||||
typingNoticeResult = { Result.success(Unit) },
|
typingNoticeResult = { Result.success(Unit) },
|
||||||
)
|
)
|
||||||
|
|
@ -1112,7 +1112,7 @@ class MessagesPresenterTest {
|
||||||
canRedactOwn = true,
|
canRedactOwn = true,
|
||||||
canPinUnpin = true,
|
canPinUnpin = true,
|
||||||
),
|
),
|
||||||
initialRoomInfo = aRoomInfo(isDirect = true, isEncrypted = true)
|
initialRoomInfo = aRoomInfo(isDm = true, isEncrypted = true)
|
||||||
).apply {
|
).apply {
|
||||||
givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2))))
|
givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2))))
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1066,7 +1066,7 @@ class MessageComposerPresenterTest {
|
||||||
)
|
)
|
||||||
givenRoomInfo(
|
givenRoomInfo(
|
||||||
aRoomInfo(
|
aRoomInfo(
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2,
|
activeMembersCount = 2,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ class NotificationSettingsPresenter(
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||||
isEncrypted = encryptedGroupDefaultMode != RoomNotificationMode.ALL_MESSAGES,
|
isEncrypted = encryptedGroupDefaultMode != RoomNotificationMode.ALL_MESSAGES,
|
||||||
mode = RoomNotificationMode.ALL_MESSAGES,
|
mode = RoomNotificationMode.ALL_MESSAGES,
|
||||||
isOneToOne = false,
|
isDM = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,7 +234,7 @@ class NotificationSettingsPresenter(
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||||
isEncrypted = encryptedOneToOneDefaultMode != RoomNotificationMode.ALL_MESSAGES,
|
isEncrypted = encryptedOneToOneDefaultMode != RoomNotificationMode.ALL_MESSAGES,
|
||||||
mode = RoomNotificationMode.ALL_MESSAGES,
|
mode = RoomNotificationMode.ALL_MESSAGES,
|
||||||
isOneToOne = true,
|
isDM = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}.fold(
|
}.fold(
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,12 @@ class EditDefaultNotificationSettingNode(
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Inputs(
|
data class Inputs(
|
||||||
val isOneToOne: Boolean
|
val isDm: Boolean
|
||||||
) : NodeInputs
|
) : NodeInputs
|
||||||
|
|
||||||
private val callback: Callback = callback()
|
private val callback: Callback = callback()
|
||||||
private val inputs = inputs<Inputs>()
|
private val inputs = inputs<Inputs>()
|
||||||
private val presenter = presenterFactory.create(inputs.isOneToOne)
|
private val presenter = presenterFactory.create(inputs.isDm)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,12 @@ import kotlin.time.Duration.Companion.seconds
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
class EditDefaultNotificationSettingPresenter(
|
class EditDefaultNotificationSettingPresenter(
|
||||||
private val notificationSettingsService: NotificationSettingsService,
|
private val notificationSettingsService: NotificationSettingsService,
|
||||||
@Assisted private val isOneToOne: Boolean,
|
@Assisted private val isDm: Boolean,
|
||||||
private val roomListService: RoomListService,
|
private val roomListService: RoomListService,
|
||||||
) : Presenter<EditDefaultNotificationSettingState> {
|
) : Presenter<EditDefaultNotificationSettingState> {
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(isOneToOne: Boolean): EditDefaultNotificationSettingPresenter
|
fun create(isDm: Boolean): EditDefaultNotificationSettingPresenter
|
||||||
}
|
}
|
||||||
|
|
||||||
private val collator = Collator.getInstance().apply {
|
private val collator = Collator.getInstance().apply {
|
||||||
|
|
@ -86,7 +86,7 @@ class EditDefaultNotificationSettingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
return EditDefaultNotificationSettingState(
|
return EditDefaultNotificationSettingState(
|
||||||
isOneToOne = isOneToOne,
|
isOneToOne = isDm,
|
||||||
mode = mode.value,
|
mode = mode.value,
|
||||||
roomsWithUserDefinedMode = roomsWithUserDefinedMode.value.toImmutableList(),
|
roomsWithUserDefinedMode = roomsWithUserDefinedMode.value.toImmutableList(),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
||||||
|
|
@ -96,7 +96,7 @@ class EditDefaultNotificationSettingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.fetchSettings(mode: MutableState<RoomNotificationMode?>) = launch {
|
private fun CoroutineScope.fetchSettings(mode: MutableState<RoomNotificationMode?>) = launch {
|
||||||
mode.value = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = isOneToOne).getOrThrow()
|
mode.value = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = isDm).getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
|
|
@ -129,7 +129,7 @@ class EditDefaultNotificationSettingPresenter(
|
||||||
val roomWithUserDefinedRules: Set<RoomId> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet()
|
val roomWithUserDefinedRules: Set<RoomId> = notificationSettingsService.getRoomsWithUserDefinedRules().getOrDefault(emptyList()).toSet()
|
||||||
roomsWithUserDefinedMode.value = summaries
|
roomsWithUserDefinedMode.value = summaries
|
||||||
.filter { roomSummary ->
|
.filter { roomSummary ->
|
||||||
roomWithUserDefinedRules.contains(roomSummary.roomId) && roomSummary.isOneToOne == isOneToOne
|
roomWithUserDefinedRules.contains(roomSummary.roomId) && roomSummary.isDm == isDm
|
||||||
}
|
}
|
||||||
.map { roomSummary ->
|
.map { roomSummary ->
|
||||||
EditNotificationSettingRoomInfo(
|
EditNotificationSettingRoomInfo(
|
||||||
|
|
@ -154,9 +154,9 @@ class EditDefaultNotificationSettingPresenter(
|
||||||
private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode, action: MutableState<AsyncAction<Unit>>) = launch {
|
private fun CoroutineScope.setDefaultNotificationMode(mode: RoomNotificationMode, action: MutableState<AsyncAction<Unit>>) = launch {
|
||||||
action.runUpdatingStateNoSuccess {
|
action.runUpdatingStateNoSuccess {
|
||||||
// On modern clients, we don't have different settings for encrypted and non-encrypted rooms (Legacy clients did).
|
// On modern clients, we don't have different settings for encrypted and non-encrypted rooms (Legacy clients did).
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, mode = mode, isOneToOne = isOneToOne)
|
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, mode = mode, isDM = isDm)
|
||||||
.map {
|
.map {
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, mode = mode, isOneToOne = isOneToOne)
|
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, mode = mode, isDM = isDm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ class EditDefaultNotificationSettingsPresenterTest {
|
||||||
): EditDefaultNotificationSettingPresenter {
|
): EditDefaultNotificationSettingPresenter {
|
||||||
return EditDefaultNotificationSettingPresenter(
|
return EditDefaultNotificationSettingPresenter(
|
||||||
notificationSettingsService = notificationSettingsService,
|
notificationSettingsService = notificationSettingsService,
|
||||||
isOneToOne = false,
|
isDm = false,
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ class NotificationSettingsPresenterTest {
|
||||||
val notificationSettingsService = FakeNotificationSettingsService()
|
val notificationSettingsService = FakeNotificationSettingsService()
|
||||||
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isDM = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isDM = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||||
val updatedState = consumeItemsUntilPredicate {
|
val updatedState = consumeItemsUntilPredicate {
|
||||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)
|
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)
|
||||||
?.defaultGroupNotificationMode == RoomNotificationMode.ALL_MESSAGES
|
?.defaultGroupNotificationMode == RoomNotificationMode.ALL_MESSAGES
|
||||||
|
|
@ -79,12 +79,12 @@ class NotificationSettingsPresenterTest {
|
||||||
presenter.test {
|
presenter.test {
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||||
isEncrypted = true,
|
isEncrypted = true,
|
||||||
isOneToOne = false,
|
isDM = false,
|
||||||
mode = RoomNotificationMode.ALL_MESSAGES
|
mode = RoomNotificationMode.ALL_MESSAGES
|
||||||
)
|
)
|
||||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||||
isEncrypted = false,
|
isEncrypted = false,
|
||||||
isOneToOne = false,
|
isDM = false,
|
||||||
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||||
)
|
)
|
||||||
val updatedState = consumeItemsUntilPredicate {
|
val updatedState = consumeItemsUntilPredicate {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.matrix.api.notification.CallIntent
|
import io.element.android.libraries.matrix.api.notification.CallIntent
|
||||||
import io.element.android.libraries.matrix.api.room.CallIntentConsensus
|
import io.element.android.libraries.matrix.api.room.CallIntentConsensus
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canCall
|
import io.element.android.libraries.matrix.api.room.powerlevels.canCall
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,10 @@ class RoomCallStatePresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - initial state - when is direct room`() = runTest {
|
fun `present - initial state - when is DM room`() = runTest {
|
||||||
val room = FakeJoinedRoom(
|
val room = FakeJoinedRoom(
|
||||||
baseRoom = FakeBaseRoom(
|
baseRoom = FakeBaseRoom(
|
||||||
initialRoomInfo = aRoomInfo(isDirect = true),
|
initialRoomInfo = aRoomInfo(isDm = true),
|
||||||
roomPermissions = roomPermissions(true),
|
roomPermissions = roomPermissions(true),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
|
||||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
import io.element.android.libraries.matrix.api.room.join.JoinRule
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.canEditRolesAndPermissions
|
import io.element.android.libraries.matrix.api.room.powerlevels.canEditRolesAndPermissions
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsAsState
|
||||||
|
|
@ -53,7 +52,6 @@ import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
import io.element.android.services.analyticsproviders.api.trackers.captureInteraction
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -145,7 +143,7 @@ class RoomDetailsPresenter(
|
||||||
}
|
}
|
||||||
RoomDetailsEvent.UnmuteNotification -> {
|
RoomDetailsEvent.UnmuteNotification -> {
|
||||||
scope.launch(dispatchers.io) {
|
scope.launch(dispatchers.io) {
|
||||||
notificationSettingsService.unmuteRoom(room.roomId, isEncrypted, room.isOneToOne)
|
notificationSettingsService.unmuteRoom(room.roomId, isEncrypted, room.isDm())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is RoomDetailsEvent.SetFavorite -> scope.setFavorite(event.isFavorite)
|
is RoomDetailsEvent.SetFavorite -> scope.setFavorite(event.isFavorite)
|
||||||
|
|
@ -184,7 +182,7 @@ class RoomDetailsPresenter(
|
||||||
isFavorite = isFavorite,
|
isFavorite = isFavorite,
|
||||||
displayRolesAndPermissionsSettings = !isDm && permissions.canEditRolesAndPermissions,
|
displayRolesAndPermissionsSettings = !isDm && permissions.canEditRolesAndPermissions,
|
||||||
isPublic = joinRule == JoinRule.Public,
|
isPublic = joinRule == JoinRule.Public,
|
||||||
heroes = roomInfo.heroes.toImmutableList(),
|
heroes = roomInfo.heroes,
|
||||||
pinnedMessagesCount = pinnedMessagesCount,
|
pinnedMessagesCount = pinnedMessagesCount,
|
||||||
snackbarMessage = snackbarMessage,
|
snackbarMessage = snackbarMessage,
|
||||||
canShowKnockRequests = canShowKnockRequests,
|
canShowKnockRequests = canShowKnockRequests,
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ fun aDmRoomMember(
|
||||||
isIgnored: Boolean = false,
|
isIgnored: Boolean = false,
|
||||||
role: RoomMember.Role = RoomMember.Role.User,
|
role: RoomMember.Role = RoomMember.Role.User,
|
||||||
membershipChangeReason: String? = null,
|
membershipChangeReason: String? = null,
|
||||||
|
isServiceMember: Boolean = false,
|
||||||
) = RoomMember(
|
) = RoomMember(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
|
|
@ -83,7 +84,8 @@ fun aDmRoomMember(
|
||||||
powerLevel = powerLevel,
|
powerLevel = powerLevel,
|
||||||
isIgnored = isIgnored,
|
isIgnored = isIgnored,
|
||||||
role = role,
|
role = role,
|
||||||
membershipChangeReason = membershipChangeReason
|
membershipChangeReason = membershipChangeReason,
|
||||||
|
isServiceMember = isServiceMember,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomDetailsState(
|
fun aRoomDetailsState(
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ fun aRoomMember(
|
||||||
isIgnored: Boolean = false,
|
isIgnored: Boolean = false,
|
||||||
role: RoomMember.Role = RoomMember.Role.User,
|
role: RoomMember.Role = RoomMember.Role.User,
|
||||||
membershipChangeReason: String? = null,
|
membershipChangeReason: String? = null,
|
||||||
|
isServiceMember: Boolean = false,
|
||||||
) = RoomMember(
|
) = RoomMember(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
|
|
@ -138,6 +139,7 @@ fun aRoomMember(
|
||||||
isIgnored = isIgnored,
|
isIgnored = isIgnored,
|
||||||
role = role,
|
role = role,
|
||||||
membershipChangeReason = membershipChangeReason,
|
membershipChangeReason = membershipChangeReason,
|
||||||
|
isServiceMember = isServiceMember,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMemberList() = persistentListOf(
|
fun aRoomMemberList() = persistentListOf(
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ class RoomNotificationSettingsPresenter(
|
||||||
suspend {
|
suspend {
|
||||||
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
|
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
|
||||||
pendingModeState.value = null
|
pendingModeState.value = null
|
||||||
notificationSettingsService.getRoomNotificationSettings(room.roomId, isEncrypted, room.isOneToOne).getOrThrow()
|
notificationSettingsService.getRoomNotificationSettings(room.roomId, isEncrypted, room.isDm()).getOrThrow()
|
||||||
}.runCatchingUpdatingState(roomNotificationSettings)
|
}.runCatchingUpdatingState(roomNotificationSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,7 +170,7 @@ class RoomNotificationSettingsPresenter(
|
||||||
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
|
val isEncrypted = room.info().isEncrypted ?: room.getUpdatedIsEncrypted().getOrThrow()
|
||||||
defaultRoomNotificationMode.value = notificationSettingsService.getDefaultRoomNotificationMode(
|
defaultRoomNotificationMode.value = notificationSettingsService.getDefaultRoomNotificationMode(
|
||||||
isEncrypted,
|
isEncrypted,
|
||||||
room.isOneToOne
|
room.isDm()
|
||||||
).getOrThrow()
|
).getOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ class RoomDetailsPresenterTest {
|
||||||
givenRoomInfo(
|
givenRoomInfo(
|
||||||
aRoomInfo(
|
aRoomInfo(
|
||||||
isEncrypted = true,
|
isEncrypted = true,
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +284,7 @@ class RoomDetailsPresenterTest {
|
||||||
givenRoomInfo(
|
givenRoomInfo(
|
||||||
aRoomInfo(
|
aRoomInfo(
|
||||||
isEncrypted = true,
|
isEncrypted = true,
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +307,6 @@ class RoomDetailsPresenterTest {
|
||||||
val myRoomMember = aRoomMember(A_SESSION_ID)
|
val myRoomMember = aRoomMember(A_SESSION_ID)
|
||||||
val otherRoomMember = aRoomMember(A_USER_ID_2)
|
val otherRoomMember = aRoomMember(A_USER_ID_2)
|
||||||
val room = aJoinedRoom(
|
val room = aJoinedRoom(
|
||||||
isDirect = true,
|
|
||||||
topic = null,
|
topic = null,
|
||||||
roomPermissions = roomPermissions(),
|
roomPermissions = roomPermissions(),
|
||||||
userDisplayNameResult = { Result.success(A_USER_NAME) },
|
userDisplayNameResult = { Result.success(A_USER_NAME) },
|
||||||
|
|
@ -325,7 +324,7 @@ class RoomDetailsPresenterTest {
|
||||||
|
|
||||||
givenRoomInfo(
|
givenRoomInfo(
|
||||||
aRoomInfo(
|
aRoomInfo(
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2,
|
activeMembersCount = 2,
|
||||||
topic = null,
|
topic = null,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.recent.getRecentlyVisitedRoomInfoFlow
|
import io.element.android.libraries.matrix.api.room.recent.getRecentlyVisitedRoomInfoFlow
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class LeaveSpacePresenter(
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
.partition { it.spaceRoom.roomId == leaveSpaceHandle.id }
|
.partition { it.spaceRoom.roomId == leaveSpaceHandle.id }
|
||||||
// By default select all rooms that can be left
|
// By default select all rooms that can be left
|
||||||
val otherRoomsExcludingDm = otherRooms.filter { it.spaceRoom.isDirect != true }
|
val otherRoomsExcludingDm = otherRooms.filter { it.spaceRoom.isDm != true }
|
||||||
selectedRoomIds = otherRoomsExcludingDm
|
selectedRoomIds = otherRoomsExcludingDm
|
||||||
.filter { it.isLastOwner.not() }
|
.filter { it.isLastOwner.not() }
|
||||||
.map { it.spaceRoom.roomId }
|
.map { it.spaceRoom.roomId }
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ private fun aSpaceInfo(
|
||||||
avatarUrl = null,
|
avatarUrl = null,
|
||||||
isPublic = true,
|
isPublic = true,
|
||||||
isDirect = false,
|
isDirect = false,
|
||||||
|
isDm = false,
|
||||||
isEncrypted = false,
|
isEncrypted = false,
|
||||||
joinRule = joinRule,
|
joinRule = joinRule,
|
||||||
isSpace = true,
|
isSpace = true,
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ class LeaveSpacePresenterTest {
|
||||||
listOf(
|
listOf(
|
||||||
aLeaveSpaceRoom(spaceRoom = aSpace),
|
aLeaveSpaceRoom(spaceRoom = aSpace),
|
||||||
aLeaveSpaceRoom(
|
aLeaveSpaceRoom(
|
||||||
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID, isDirect = false)
|
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID, isDm = false)
|
||||||
),
|
),
|
||||||
aLeaveSpaceRoom(
|
aLeaveSpaceRoom(
|
||||||
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID_2, isDirect = true)
|
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID_2, isDm = true)
|
||||||
),
|
),
|
||||||
aLeaveSpaceRoom(
|
aLeaveSpaceRoom(
|
||||||
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID_3, isDirect = null)
|
spaceRoom = aSpaceRoom(roomId = A_ROOM_ID_3, isDm = null)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ fun BaseRoom.toAnalyticsViewRoom(
|
||||||
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
val activeSpace = selectedSpace?.toActiveSpace() ?: ViewRoom.ActiveSpace.Home
|
||||||
|
|
||||||
return ViewRoom(
|
return ViewRoom(
|
||||||
isDM = info().isDirect,
|
isDM = info().isDm,
|
||||||
isSpace = info().isSpace,
|
isSpace = info().isSpace,
|
||||||
trigger = trigger,
|
trigger = trigger,
|
||||||
activeSpace = activeSpace,
|
activeSpace = activeSpace,
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ interface NotificationSettingsService {
|
||||||
val notificationSettingsChangeFlow: SharedFlow<Unit>
|
val notificationSettingsChangeFlow: SharedFlow<Unit>
|
||||||
suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings>
|
suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings>
|
||||||
suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationMode>
|
suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationMode>
|
||||||
suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isOneToOne: Boolean): Result<Unit>
|
suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isDM: Boolean): Result<Unit>
|
||||||
suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit>
|
suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit>
|
||||||
suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit>
|
suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit>
|
||||||
suspend fun muteRoom(roomId: RoomId): Result<Unit>
|
suspend fun muteRoom(roomId: RoomId): Result<Unit>
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,12 @@ interface BaseRoom : Closeable {
|
||||||
*/
|
*/
|
||||||
fun info(): RoomInfo = roomInfoFlow.value
|
fun info(): RoomInfo = roomInfoFlow.value
|
||||||
|
|
||||||
fun predecessorRoom(): PredecessorRoom?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A one-to-one is a room with exactly 2 members.
|
* Returns whether the [BaseRoom] is a DM, with an updated state from the latest [RoomInfo].
|
||||||
* See [the Matrix spec](https://spec.matrix.org/latest/client-server-api/#default-underride-rules).
|
|
||||||
*/
|
*/
|
||||||
val isOneToOne: Boolean get() = info().activeMembersCount == 2L
|
fun isDm() = roomInfoFlow.value.isDm
|
||||||
|
|
||||||
|
fun predecessorRoom(): PredecessorRoom?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to load the room members and update the membersFlow.
|
* Try to load the room members and update the membersFlow.
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ data class RoomInfo(
|
||||||
val avatarUrl: String?,
|
val avatarUrl: String?,
|
||||||
val isPublic: Boolean?,
|
val isPublic: Boolean?,
|
||||||
val isDirect: Boolean,
|
val isDirect: Boolean,
|
||||||
|
val isDm: Boolean,
|
||||||
val isEncrypted: Boolean?,
|
val isEncrypted: Boolean?,
|
||||||
val joinRule: JoinRule?,
|
val joinRule: JoinRule?,
|
||||||
val isSpace: Boolean,
|
val isSpace: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
|
||||||
* Copyright 2024, 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.room
|
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the room with the provided info is a DM.
|
|
||||||
* A DM is a room with at most 2 active members (one of them may have left).
|
|
||||||
*
|
|
||||||
* @param isDirect true if the room is direct
|
|
||||||
* @param activeMembersCount the number of active members in the room (joined or invited)
|
|
||||||
*/
|
|
||||||
fun isDm(isDirect: Boolean, activeMembersCount: Int): Boolean {
|
|
||||||
return isDirect && activeMembersCount <= 2
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the [BaseRoom] is a DM, with an updated state from the latest [RoomInfo].
|
|
||||||
*/
|
|
||||||
suspend fun BaseRoom.isDm() = roomInfoFlow.first().isDm
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the [RoomInfo] is from a DM.
|
|
||||||
*/
|
|
||||||
val RoomInfo.isDm get() = isDm(isDirect, activeMembersCount.toInt())
|
|
||||||
|
|
@ -22,6 +22,7 @@ data class RoomMember(
|
||||||
val isIgnored: Boolean,
|
val isIgnored: Boolean,
|
||||||
val role: Role,
|
val role: Role,
|
||||||
val membershipChangeReason: String?,
|
val membershipChangeReason: String?,
|
||||||
|
val isServiceMember: Boolean,
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Role of the RoomMember, based on its [powerLevel].
|
* Role of the RoomMember, based on its [powerLevel].
|
||||||
|
|
|
||||||
|
|
@ -40,5 +40,5 @@ fun RoomMembersState.activeRoomMembers(): List<RoomMember> {
|
||||||
fun RoomMembersState.getDirectRoomMember(roomInfo: RoomInfo, sessionId: SessionId): RoomMember? {
|
fun RoomMembersState.getDirectRoomMember(roomInfo: RoomInfo, sessionId: SessionId): RoomMember? {
|
||||||
return roomMembers()
|
return roomMembers()
|
||||||
?.takeIf { roomInfo.isDm }
|
?.takeIf { roomInfo.isDm }
|
||||||
?.find { it.userId != sessionId && it.membership.isActive() }
|
?.find { !it.isServiceMember && it.userId != sessionId && it.membership.isActive() }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.toMatrixUser
|
import io.element.android.libraries.matrix.api.room.toMatrixUser
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,5 @@ data class RoomSummary(
|
||||||
is LatestEventValue.Remote -> latestEvent.timestamp
|
is LatestEventValue.Remote -> latestEvent.timestamp
|
||||||
is LatestEventValue.RoomInvite -> latestEvent.timestamp
|
is LatestEventValue.RoomInvite -> latestEvent.timestamp
|
||||||
}
|
}
|
||||||
val isOneToOne get() = info.activeMembersCount == 2L
|
val isDm = info.isDm
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ data class SpaceRoom(
|
||||||
*/
|
*/
|
||||||
val via: ImmutableList<String>,
|
val via: ImmutableList<String>,
|
||||||
val isDirect: Boolean?,
|
val isDirect: Boolean?,
|
||||||
|
val isDm: Boolean?,
|
||||||
) {
|
) {
|
||||||
val isSpace = roomType == RoomType.Space
|
val isSpace = roomType == RoomType.Space
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2025 Element Creations Ltd.
|
|
||||||
* Copyright 2024, 2025 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.room
|
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class RoomIsDmCheckTest {
|
|
||||||
@Test
|
|
||||||
fun `a room is a DM only if it has at most 2 members and is direct`() {
|
|
||||||
val isDirect = true
|
|
||||||
val activeMembersCount = 2
|
|
||||||
|
|
||||||
val isDm = isDm(isDirect, activeMembersCount)
|
|
||||||
|
|
||||||
assertThat(isDm).isTrue()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `a room can be a DM if it has also a single active user`() {
|
|
||||||
val isDirect = true
|
|
||||||
val activeMembersCount = 1
|
|
||||||
|
|
||||||
val isDm = isDm(isDirect, activeMembersCount)
|
|
||||||
|
|
||||||
assertThat(isDm).isTrue()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `a room is not a DM if it's not direct`() {
|
|
||||||
val isDirect = false
|
|
||||||
val activeMembersCount = 2
|
|
||||||
|
|
||||||
val isDm = isDm(isDirect, activeMembersCount)
|
|
||||||
|
|
||||||
assertThat(isDm).isFalse()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `a room is not a DM if it has more than 2 active users`() {
|
|
||||||
val isDirect = true
|
|
||||||
val activeMembersCount = 3
|
|
||||||
|
|
||||||
val isDm = isDm(isDirect, activeMembersCount)
|
|
||||||
|
|
||||||
assertThat(isDm).isFalse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,6 +41,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncVersion
|
||||||
import org.matrix.rustcomponents.sdk.SlidingSyncVersionBuilder
|
import org.matrix.rustcomponents.sdk.SlidingSyncVersionBuilder
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import uniffi.matrix_sdk_base.DmRoomDefinition
|
||||||
import uniffi.matrix_sdk_base.MediaRetentionPolicy
|
import uniffi.matrix_sdk_base.MediaRetentionPolicy
|
||||||
import uniffi.matrix_sdk_crypto.CollectStrategy
|
import uniffi.matrix_sdk_crypto.CollectStrategy
|
||||||
import uniffi.matrix_sdk_crypto.DecryptionSettings
|
import uniffi.matrix_sdk_crypto.DecryptionSettings
|
||||||
|
|
@ -169,6 +170,7 @@ class RustMatrixClientFactory(
|
||||||
)
|
)
|
||||||
.enableShareHistoryOnInvite(true)
|
.enableShareHistoryOnInvite(true)
|
||||||
.threadsEnabled(featureFlagService.isFeatureEnabled(FeatureFlags.Threads), threadSubscriptions = false)
|
.threadsEnabled(featureFlagService.isFeatureEnabled(FeatureFlags.Threads), threadSubscriptions = false)
|
||||||
|
.dmRoomDefinition(DmRoomDefinition.TWO_MEMBERS)
|
||||||
.requestConfig(
|
.requestConfig(
|
||||||
RequestConfig(
|
RequestConfig(
|
||||||
timeout = 30_000uL,
|
timeout = 30_000uL,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ package io.element.android.libraries.matrix.impl.analytics
|
||||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
import im.vector.app.features.analytics.plan.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.BaseRoom
|
import io.element.android.libraries.matrix.api.room.BaseRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomInfo
|
import io.element.android.libraries.matrix.api.room.RoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
|
private fun Long.toAnalyticsRoomSize(): JoinedRoom.RoomSize {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.notification.NotificationContent
|
import io.element.android.libraries.matrix.api.notification.NotificationContent
|
||||||
import io.element.android.libraries.matrix.api.notification.NotificationData
|
import io.element.android.libraries.matrix.api.notification.NotificationData
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.impl.room.join.map
|
import io.element.android.libraries.matrix.impl.room.join.map
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
import org.matrix.rustcomponents.sdk.NotificationEvent
|
import org.matrix.rustcomponents.sdk.NotificationEvent
|
||||||
|
|
@ -37,10 +36,6 @@ class NotificationMapper(
|
||||||
): Result<NotificationData> {
|
): Result<NotificationData> {
|
||||||
return runCatchingExceptions {
|
return runCatchingExceptions {
|
||||||
notificationItem.use { item ->
|
notificationItem.use { item ->
|
||||||
val isDm = isDm(
|
|
||||||
isDirect = item.roomInfo.isDirect,
|
|
||||||
activeMembersCount = item.roomInfo.joinedMembersCount.toInt(),
|
|
||||||
)
|
|
||||||
val timestamp = item.timestamp() ?: clock.epochMillis()
|
val timestamp = item.timestamp() ?: clock.epochMillis()
|
||||||
NotificationData(
|
NotificationData(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
|
|
@ -50,10 +45,10 @@ class NotificationMapper(
|
||||||
senderAvatarUrl = item.senderInfo.avatarUrl,
|
senderAvatarUrl = item.senderInfo.avatarUrl,
|
||||||
senderDisplayName = item.senderInfo.displayName,
|
senderDisplayName = item.senderInfo.displayName,
|
||||||
senderIsNameAmbiguous = item.senderInfo.isNameAmbiguous,
|
senderIsNameAmbiguous = item.senderInfo.isNameAmbiguous,
|
||||||
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { isDm },
|
roomAvatarUrl = item.roomInfo.avatarUrl ?: item.senderInfo.avatarUrl.takeIf { item.roomInfo.isDm },
|
||||||
roomDisplayName = item.roomInfo.displayName,
|
roomDisplayName = item.roomInfo.displayName,
|
||||||
isDirect = item.roomInfo.isDirect,
|
isDirect = item.roomInfo.isDirect,
|
||||||
isDm = isDm,
|
isDm = item.roomInfo.isDm,
|
||||||
isSpace = item.roomInfo.isSpace,
|
isSpace = item.roomInfo.isSpace,
|
||||||
isEncrypted = item.roomInfo.isEncrypted.orFalse(),
|
isEncrypted = item.roomInfo.isEncrypted.orFalse(),
|
||||||
isNoisy = item.isNoisy.orFalse(),
|
isNoisy = item.isNoisy.orFalse(),
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,11 @@ class RustNotificationSettingsService(
|
||||||
override suspend fun setDefaultRoomNotificationMode(
|
override suspend fun setDefaultRoomNotificationMode(
|
||||||
isEncrypted: Boolean,
|
isEncrypted: Boolean,
|
||||||
mode: RoomNotificationMode,
|
mode: RoomNotificationMode,
|
||||||
isOneToOne: Boolean
|
isDM: Boolean
|
||||||
): Result<Unit> = withContext(dispatchers.io) {
|
): Result<Unit> = withContext(dispatchers.io) {
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
try {
|
try {
|
||||||
notificationSettings.await().setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode))
|
notificationSettings.await().setDefaultRoomNotificationMode(isEncrypted, isDM, mode.let(RoomNotificationSettingsMapper::mapMode))
|
||||||
} catch (exception: NotificationSettingsException.RuleNotFound) {
|
} catch (exception: NotificationSettingsException.RuleNotFound) {
|
||||||
// `setDefaultRoomNotificationMode` updates multiple rules including unstable rules (e.g. the polls push rules defined in the MSC3930)
|
// `setDefaultRoomNotificationMode` updates multiple rules including unstable rules (e.g. the polls push rules defined in the MSC3930)
|
||||||
// since production home servers may not have these rules yet, we drop the RuleNotFound error
|
// since production home servers may not have these rules yet, we drop the RuleNotFound error
|
||||||
|
|
|
||||||
|
|
@ -348,7 +348,7 @@ class JoinedRustRoom(
|
||||||
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
|
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow()
|
val isEncrypted = roomInfoFlow.value.isEncrypted ?: getUpdatedIsEncrypted().getOrThrow()
|
||||||
notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
|
notificationSettingsService.getRoomNotificationSettings(roomId = roomId, isEncrypted = isEncrypted, isOneToOne = isDm()).getOrThrow()
|
||||||
}.map {
|
}.map {
|
||||||
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Ready(it)
|
roomNotificationSettingsStateFlow.value = RoomNotificationSettingsState.Ready(it)
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import org.matrix.rustcomponents.sdk.RoomInfo
|
||||||
*/
|
*/
|
||||||
fun RoomInfo.elementHeroes(): List<MatrixUser> {
|
fun RoomInfo.elementHeroes(): List<MatrixUser> {
|
||||||
return heroes
|
return heroes
|
||||||
.takeIf { isDirect && activeMembersCount.toLong() == 2L }
|
.takeIf { isDm }
|
||||||
?.takeIf { it.size == 1 }
|
?.takeIf { it.size == 1 }
|
||||||
?.map { it.map() }
|
?.map { it.map() }
|
||||||
.orEmpty()
|
.orEmpty()
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class RoomInfoMapper {
|
||||||
avatarUrl = it.avatarUrl,
|
avatarUrl = it.avatarUrl,
|
||||||
isPublic = it.isPublic,
|
isPublic = it.isPublic,
|
||||||
isDirect = it.isDirect,
|
isDirect = it.isDirect,
|
||||||
|
isDm = it.isDm,
|
||||||
isEncrypted = when (it.encryptionState) {
|
isEncrypted = when (it.encryptionState) {
|
||||||
EncryptionState.ENCRYPTED -> true
|
EncryptionState.ENCRYPTED -> true
|
||||||
EncryptionState.NOT_ENCRYPTED -> false
|
EncryptionState.NOT_ENCRYPTED -> false
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import io.element.android.libraries.matrix.api.room.RoomMember
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
import io.element.android.libraries.matrix.api.room.RoomMembersState
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||||
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
|
||||||
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
|
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
|
||||||
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
|
||||||
|
|
@ -119,7 +118,7 @@ class RustBaseRoom(
|
||||||
innerRoom.membersNoSync().use { members ->
|
innerRoom.membersNoSync().use { members ->
|
||||||
members.nextChunk(members.len())
|
members.nextChunk(members.len())
|
||||||
?.map(RoomMemberMapper::map)
|
?.map(RoomMemberMapper::map)
|
||||||
?.firstOrNull { roomMember -> roomMember.userId != sessionId && roomMember.membership.isActive() }
|
?.firstOrNull { roomMember -> !roomMember.isServiceMember && roomMember.userId != sessionId && roomMember.membership.isActive() }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ object RoomMemberMapper {
|
||||||
powerLevel = powerLevel,
|
powerLevel = powerLevel,
|
||||||
isIgnored = roomMember.isIgnored,
|
isIgnored = roomMember.isIgnored,
|
||||||
role = mapRole(roomMember.suggestedRoleForPowerLevel, powerLevel),
|
role = mapRole(roomMember.suggestedRoleForPowerLevel, powerLevel),
|
||||||
membershipChangeReason = roomMember.membershipChangeReason
|
membershipChangeReason = roomMember.membershipChangeReason,
|
||||||
|
isServiceMember = roomMember.isServiceMember,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class SpaceRoomMapper {
|
||||||
worldReadable = spaceRoom.worldReadable.orFalse(),
|
worldReadable = spaceRoom.worldReadable.orFalse(),
|
||||||
via = spaceRoom.via.toImmutableList(),
|
via = spaceRoom.via.toImmutableList(),
|
||||||
isDirect = spaceRoom.isDirect,
|
isDirect = spaceRoom.isDirect,
|
||||||
|
isDm = spaceRoom.isDm,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
import io.element.android.libraries.matrix.api.room.IntentionalMention
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
import io.element.android.libraries.matrix.api.timeline.MsgType
|
import io.element.android.libraries.matrix.api.timeline.MsgType
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,19 @@ class JoinedExtKtTest {
|
||||||
@Test
|
@Test
|
||||||
fun `test isDirect parameter mapping`() = runTest {
|
fun `test isDirect parameter mapping`() = runTest {
|
||||||
assertThat(aRoom(isDirect = true).toAnalyticsJoinedRoom(null))
|
assertThat(aRoom(isDirect = true).toAnalyticsJoinedRoom(null))
|
||||||
|
.isEqualTo(
|
||||||
|
JoinedRoom(
|
||||||
|
isDM = false,
|
||||||
|
isSpace = false,
|
||||||
|
roomSize = JoinedRoom.RoomSize.One,
|
||||||
|
trigger = null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test isDm parameter mapping`() = runTest {
|
||||||
|
assertThat(aRoom(isDm = true).toAnalyticsJoinedRoom(null))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
JoinedRoom(
|
JoinedRoom(
|
||||||
isDM = true,
|
isDM = true,
|
||||||
|
|
@ -80,12 +93,13 @@ class JoinedExtKtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun aRoom(
|
private fun aRoom(
|
||||||
|
isDm: Boolean = false,
|
||||||
isDirect: Boolean = false,
|
isDirect: Boolean = false,
|
||||||
isSpace: Boolean = false,
|
isSpace: Boolean = false,
|
||||||
joinedMemberCount: Long = 0
|
joinedMemberCount: Long = 0
|
||||||
): FakeBaseRoom {
|
): FakeBaseRoom {
|
||||||
return FakeBaseRoom().apply {
|
return FakeBaseRoom().apply {
|
||||||
givenRoomInfo(aRoomInfo(isDirect = isDirect, isSpace = isSpace, joinedMembersCount = joinedMemberCount))
|
givenRoomInfo(aRoomInfo(isDm = isDm, isDirect = isDirect, isSpace = isSpace, joinedMembersCount = joinedMemberCount))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,5 +50,5 @@ internal fun aRustSpaceRoom(
|
||||||
childrenCount = childrenCount,
|
childrenCount = childrenCount,
|
||||||
state = state,
|
state = state,
|
||||||
heroes = heroes,
|
heroes = heroes,
|
||||||
via = emptyList()
|
via = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import org.matrix.rustcomponents.sdk.RequestConfig
|
||||||
import org.matrix.rustcomponents.sdk.SlidingSyncVersionBuilder
|
import org.matrix.rustcomponents.sdk.SlidingSyncVersionBuilder
|
||||||
import org.matrix.rustcomponents.sdk.SqliteStoreBuilder
|
import org.matrix.rustcomponents.sdk.SqliteStoreBuilder
|
||||||
import uniffi.matrix_sdk.BackupDownloadStrategy
|
import uniffi.matrix_sdk.BackupDownloadStrategy
|
||||||
|
import uniffi.matrix_sdk_base.DmRoomDefinition
|
||||||
import uniffi.matrix_sdk_crypto.CollectStrategy
|
import uniffi.matrix_sdk_crypto.CollectStrategy
|
||||||
import uniffi.matrix_sdk_crypto.DecryptionSettings
|
import uniffi.matrix_sdk_crypto.DecryptionSettings
|
||||||
|
|
||||||
|
|
@ -47,5 +48,6 @@ class FakeFfiClientBuilder(
|
||||||
override fun sqliteStore(config: SqliteStoreBuilder): ClientBuilder = this
|
override fun sqliteStore(config: SqliteStoreBuilder): ClientBuilder = this
|
||||||
override fun inMemoryStore(): ClientBuilder = this
|
override fun inMemoryStore(): ClientBuilder = this
|
||||||
override fun crossProcessLockConfig(crossProcessLockConfig: CrossProcessLockConfig): ClientBuilder = this
|
override fun crossProcessLockConfig(crossProcessLockConfig: CrossProcessLockConfig): ClientBuilder = this
|
||||||
|
override fun dmRoomDefinition(dmRoomDefinition: DmRoomDefinition): ClientBuilder = this
|
||||||
override suspend fun build() = buildResult()
|
override suspend fun build() = buildResult()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ class RoomInfoExtTest {
|
||||||
@Test
|
@Test
|
||||||
fun `get non empty element Heroes`() {
|
fun `get non empty element Heroes`() {
|
||||||
val result = aRustRoomInfo(
|
val result = aRustRoomInfo(
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2uL,
|
|
||||||
heroes = listOf(aRustRoomHero())
|
heroes = listOf(aRustRoomHero())
|
||||||
).elementHeroes()
|
).elementHeroes()
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
|
|
@ -38,8 +37,7 @@ class RoomInfoExtTest {
|
||||||
@Test
|
@Test
|
||||||
fun `too many heroes and element Heroes is empty`() {
|
fun `too many heroes and element Heroes is empty`() {
|
||||||
val result = aRustRoomInfo(
|
val result = aRustRoomInfo(
|
||||||
isDirect = true,
|
isDm = true,
|
||||||
activeMembersCount = 2uL,
|
|
||||||
heroes = listOf(aRustRoomHero(), aRustRoomHero())
|
heroes = listOf(aRustRoomHero(), aRustRoomHero())
|
||||||
).elementHeroes()
|
).elementHeroes()
|
||||||
assertThat(result).isEmpty()
|
assertThat(result).isEmpty()
|
||||||
|
|
@ -48,18 +46,7 @@ class RoomInfoExtTest {
|
||||||
@Test
|
@Test
|
||||||
fun `not direct and element Heroes is empty`() {
|
fun `not direct and element Heroes is empty`() {
|
||||||
val result = aRustRoomInfo(
|
val result = aRustRoomInfo(
|
||||||
isDirect = false,
|
isDm = false,
|
||||||
activeMembersCount = 2uL,
|
|
||||||
heroes = listOf(aRustRoomHero())
|
|
||||||
).elementHeroes()
|
|
||||||
assertThat(result).isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `too many members and element Heroes is empty`() {
|
|
||||||
val result = aRustRoomInfo(
|
|
||||||
isDirect = true,
|
|
||||||
activeMembersCount = 3uL,
|
|
||||||
heroes = listOf(aRustRoomHero())
|
heroes = listOf(aRustRoomHero())
|
||||||
).elementHeroes()
|
).elementHeroes()
|
||||||
assertThat(result).isEmpty()
|
assertThat(result).isEmpty()
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ class RoomInfoMapperTest {
|
||||||
privilegedCreatorsRole = true,
|
privilegedCreatorsRole = true,
|
||||||
isLowPriority = true,
|
isLowPriority = true,
|
||||||
activeRoomCallConsensusIntent = RtcCallIntentConsensus.Full(RtcCallIntent.AUDIO),
|
activeRoomCallConsensusIntent = RtcCallIntentConsensus.Full(RtcCallIntent.AUDIO),
|
||||||
|
isDm = true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
|
|
@ -136,6 +137,7 @@ class RoomInfoMapperTest {
|
||||||
privilegedCreatorRole = true,
|
privilegedCreatorRole = true,
|
||||||
isLowPriority = true,
|
isLowPriority = true,
|
||||||
activeCallIntentConsensus = CallIntentConsensus.Full(CallIntent.AUDIO),
|
activeCallIntentConsensus = CallIntentConsensus.Full(CallIntent.AUDIO),
|
||||||
|
isDm = true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -181,6 +183,7 @@ class RoomInfoMapperTest {
|
||||||
privilegedCreatorsRole = true,
|
privilegedCreatorsRole = true,
|
||||||
isLowPriority = true,
|
isLowPriority = true,
|
||||||
activeRoomCallConsensusIntent = RtcCallIntentConsensus.None,
|
activeRoomCallConsensusIntent = RtcCallIntentConsensus.None,
|
||||||
|
isDm = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
|
|
@ -225,6 +228,7 @@ class RoomInfoMapperTest {
|
||||||
privilegedCreatorRole = true,
|
privilegedCreatorRole = true,
|
||||||
isLowPriority = true,
|
isLowPriority = true,
|
||||||
activeCallIntentConsensus = CallIntentConsensus.None,
|
activeCallIntentConsensus = CallIntentConsensus.None,
|
||||||
|
isDm = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,12 +70,12 @@ class FakeNotificationSettingsService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isOneToOne: Boolean): Result<Unit> {
|
override suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isDM: Boolean): Result<Unit> {
|
||||||
val error = setDefaultNotificationModeError
|
val error = setDefaultNotificationModeError
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
return Result.failure(error)
|
return Result.failure(error)
|
||||||
}
|
}
|
||||||
if (isOneToOne) {
|
if (isDM) {
|
||||||
if (isEncrypted) {
|
if (isEncrypted) {
|
||||||
defaultEncryptedOneToOneRoomNotificationMode = mode
|
defaultEncryptedOneToOneRoomNotificationMode = mode
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,11 @@ class FakeJoinedRoom(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||||
val notificationSettings = roomNotificationSettingsService.getRoomNotificationSettings(roomId, info().isEncrypted.orFalse(), isOneToOne).getOrThrow()
|
val notificationSettings = roomNotificationSettingsService.getRoomNotificationSettings(
|
||||||
|
roomId = roomId,
|
||||||
|
isEncrypted = info().isEncrypted.orFalse(),
|
||||||
|
isOneToOne = isDm(),
|
||||||
|
).getOrThrow()
|
||||||
(roomNotificationSettingsStateFlow as MutableStateFlow).value = RoomNotificationSettingsState.Ready(notificationSettings)
|
(roomNotificationSettingsStateFlow as MutableStateFlow).value = RoomNotificationSettingsState.Ready(notificationSettings)
|
||||||
return Result.success(Unit)
|
return Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ fun aRoomInfo(
|
||||||
privilegedCreatorRole: Boolean = false,
|
privilegedCreatorRole: Boolean = false,
|
||||||
isLowPriority: Boolean = false,
|
isLowPriority: Boolean = false,
|
||||||
activeCallIntentConsensus: CallIntentConsensus = CallIntentConsensus.None,
|
activeCallIntentConsensus: CallIntentConsensus = CallIntentConsensus.None,
|
||||||
|
isDm: Boolean = false,
|
||||||
) = RoomInfo(
|
) = RoomInfo(
|
||||||
id = id,
|
id = id,
|
||||||
name = name,
|
name = name,
|
||||||
|
|
@ -109,4 +110,5 @@ fun aRoomInfo(
|
||||||
privilegedCreatorRole = privilegedCreatorRole,
|
privilegedCreatorRole = privilegedCreatorRole,
|
||||||
isLowPriority = isLowPriority,
|
isLowPriority = isLowPriority,
|
||||||
activeCallIntentConsensus = activeCallIntentConsensus,
|
activeCallIntentConsensus = activeCallIntentConsensus,
|
||||||
|
isDm = isDm,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ fun aRoomMember(
|
||||||
isIgnored: Boolean = false,
|
isIgnored: Boolean = false,
|
||||||
role: RoomMember.Role = RoomMember.Role.User,
|
role: RoomMember.Role = RoomMember.Role.User,
|
||||||
membershipChangeReason: String? = null,
|
membershipChangeReason: String? = null,
|
||||||
|
isServiceMember: Boolean = false,
|
||||||
) = RoomMember(
|
) = RoomMember(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
|
|
@ -33,6 +34,7 @@ fun aRoomMember(
|
||||||
isIgnored = isIgnored,
|
isIgnored = isIgnored,
|
||||||
role = role,
|
role = role,
|
||||||
membershipChangeReason = membershipChangeReason,
|
membershipChangeReason = membershipChangeReason,
|
||||||
|
isServiceMember = isServiceMember,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMemberList() = persistentListOf(
|
fun aRoomMemberList() = persistentListOf(
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ fun aRoomSummary(
|
||||||
privilegedCreatorRole = privilegedCreatorRole,
|
privilegedCreatorRole = privilegedCreatorRole,
|
||||||
isLowPriority = isLowPriority,
|
isLowPriority = isLowPriority,
|
||||||
activeCallIntentConsensus = activeCallIntentConsensus,
|
activeCallIntentConsensus = activeCallIntentConsensus,
|
||||||
|
isDm = false,
|
||||||
),
|
),
|
||||||
latestEvent = latestEvent,
|
latestEvent = latestEvent,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,10 @@ class RoomMembersTest {
|
||||||
private val roomMember3 = aRoomMember(A_USER_ID_3)
|
private val roomMember3 = aRoomMember(A_USER_ID_3)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getDirectRoomMember emits other member for encrypted DM with 2 joined members`() = runTest {
|
fun `getDirectRoomMember emits other member for encrypted DM`() = runTest {
|
||||||
val joinedRoom = FakeBaseRoom(
|
val joinedRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(
|
initialRoomInfo = aRoomInfo(isDm = true, isEncrypted = true)
|
||||||
isDirect = true,
|
|
||||||
joinedMembersCount = 2,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
joinedRoom.getDirectRoomMember(
|
joinedRoom.getDirectRoomMember(
|
||||||
|
|
@ -51,7 +48,7 @@ class RoomMembersTest {
|
||||||
fun `getDirectRoomMember emit null if the room is not a dm`() = runTest {
|
fun `getDirectRoomMember emit null if the room is not a dm`() = runTest {
|
||||||
val joinedRoom = FakeBaseRoom(
|
val joinedRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(isDirect = false)
|
initialRoomInfo = aRoomInfo(isDm = false)
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
joinedRoom.getDirectRoomMember(
|
joinedRoom.getDirectRoomMember(
|
||||||
|
|
@ -66,10 +63,7 @@ class RoomMembersTest {
|
||||||
fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest {
|
fun `getDirectRoomMember emits other member even if the room is not encrypted`() = runTest {
|
||||||
val joinedRoom = FakeBaseRoom(
|
val joinedRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(
|
initialRoomInfo = aRoomInfo(isDm = true)
|
||||||
isDirect = true,
|
|
||||||
activeMembersCount = 2,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
joinedRoom.getDirectRoomMember(
|
joinedRoom.getDirectRoomMember(
|
||||||
|
|
@ -80,42 +74,11 @@ class RoomMembersTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getDirectRoomMember emit null if the room has only 1 member`() = runTest {
|
|
||||||
val joinedRoom = FakeBaseRoom(
|
|
||||||
sessionId = A_USER_ID,
|
|
||||||
initialRoomInfo = aRoomInfo(isDirect = true)
|
|
||||||
)
|
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
|
||||||
joinedRoom.getDirectRoomMember(
|
|
||||||
RoomMembersState.Ready(persistentListOf(roomMember1))
|
|
||||||
)
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().value).isNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getDirectRoomMember emit null if the room has only 3 members`() = runTest {
|
|
||||||
val joinedRoom = FakeBaseRoom(
|
|
||||||
sessionId = A_USER_ID,
|
|
||||||
).apply {
|
|
||||||
givenRoomInfo(aRoomInfo(isDirect = true, activeMembersCount = 3L))
|
|
||||||
}
|
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
|
||||||
joinedRoom.getDirectRoomMember(
|
|
||||||
RoomMembersState.Ready(persistentListOf(roomMember1, roomMember2, roomMember3))
|
|
||||||
)
|
|
||||||
}.test {
|
|
||||||
assertThat(awaitItem().value).isNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getDirectRoomMember emit null if the other member is not active`() = runTest {
|
fun `getDirectRoomMember emit null if the other member is not active`() = runTest {
|
||||||
val joinedRoom = FakeBaseRoom(
|
val joinedRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(isDirect = true),
|
initialRoomInfo = aRoomInfo(isDm = true),
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
joinedRoom.getDirectRoomMember(
|
joinedRoom.getDirectRoomMember(
|
||||||
|
|
@ -135,10 +98,7 @@ class RoomMembersTest {
|
||||||
fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest {
|
fun `getDirectRoomMember emit the other member if there are 2 active members`() = runTest {
|
||||||
val joinedRoom = FakeBaseRoom(
|
val joinedRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(
|
initialRoomInfo = aRoomInfo(isDm = true)
|
||||||
isDirect = true,
|
|
||||||
activeMembersCount = 2,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
joinedRoom.getDirectRoomMember(
|
joinedRoom.getDirectRoomMember(
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ fun aRoomMember(
|
||||||
isIgnored: Boolean = false,
|
isIgnored: Boolean = false,
|
||||||
role: RoomMember.Role = RoomMember.Role.User,
|
role: RoomMember.Role = RoomMember.Role.User,
|
||||||
membershipChangeReason: String? = null,
|
membershipChangeReason: String? = null,
|
||||||
|
isServiceMember: Boolean = false,
|
||||||
) = RoomMember(
|
) = RoomMember(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
displayName = displayName,
|
displayName = displayName,
|
||||||
|
|
@ -43,6 +44,7 @@ fun aRoomMember(
|
||||||
isIgnored = isIgnored,
|
isIgnored = isIgnored,
|
||||||
role = role,
|
role = role,
|
||||||
membershipChangeReason = membershipChangeReason,
|
membershipChangeReason = membershipChangeReason,
|
||||||
|
isServiceMember = isServiceMember,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMemberList() = persistentListOf(
|
fun aRoomMemberList() = persistentListOf(
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ fun aSpaceRoom(
|
||||||
topic: String? = null,
|
topic: String? = null,
|
||||||
worldReadable: Boolean = false,
|
worldReadable: Boolean = false,
|
||||||
isDirect: Boolean? = null,
|
isDirect: Boolean? = null,
|
||||||
|
isDm: Boolean? = null,
|
||||||
via: List<String> = emptyList(),
|
via: List<String> = emptyList(),
|
||||||
) = SpaceRoom(
|
) = SpaceRoom(
|
||||||
rawName = rawName,
|
rawName = rawName,
|
||||||
|
|
@ -51,5 +52,6 @@ fun aSpaceRoom(
|
||||||
topic = topic,
|
topic = topic,
|
||||||
worldReadable = worldReadable,
|
worldReadable = worldReadable,
|
||||||
via = via.toImmutableList(),
|
via = via.toImmutableList(),
|
||||||
isDirect = isDirect
|
isDirect = isDirect,
|
||||||
|
isDm = isDm,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
import io.element.android.libraries.matrix.api.room.CreateTimelineParams
|
||||||
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
import io.element.android.libraries.matrix.api.room.JoinedRoom
|
||||||
import io.element.android.libraries.matrix.api.room.isDm
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
import io.element.android.libraries.matrix.api.timeline.ReceiptType
|
||||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
import io.element.android.libraries.preferences.api.store.SessionPreferencesStoreFactory
|
import io.element.android.libraries.preferences.api.store.SessionPreferencesStoreFactory
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue