Merge branch 'develop' into feature/fga/join_space

This commit is contained in:
ganfra 2025-09-19 16:35:55 +02:00
commit c4308e9810
446 changed files with 5669 additions and 2617 deletions

View file

@ -287,7 +287,6 @@ class RustMatrixClient(
}
override suspend fun getRoom(roomId: RoomId): BaseRoom? = withContext(sessionDispatcher) {
innerClient.rooms()
roomFactory.getBaseRoom(roomId)
}
@ -689,12 +688,6 @@ class RustMatrixClient(
})
}.buffer(Channel.UNLIMITED)
override suspend fun availableSlidingSyncVersions(): Result<List<SlidingSyncVersion>> = withContext(sessionDispatcher) {
runCatchingExceptions {
innerClient.availableSlidingSyncVersions().map { it.map() }
}
}
override suspend fun currentSlidingSyncVersion(): Result<SlidingSyncVersion> = withContext(sessionDispatcher) {
runCatchingExceptions {
innerClient.session().slidingSyncVersion.map()

View file

@ -33,11 +33,9 @@ import io.element.android.libraries.matrix.impl.keys.PassphraseGenerator
import io.element.android.libraries.matrix.impl.mapper.toSessionData
import io.element.android.libraries.matrix.impl.paths.SessionPaths
import io.element.android.libraries.matrix.impl.paths.SessionPathsFactory
import io.element.android.libraries.sessionstorage.api.LoggedInState
import io.element.android.libraries.sessionstorage.api.LoginType
import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
@ -83,14 +81,6 @@ class RustMatrixAuthenticationService(
.also { sessionPaths = it }
}
override fun loggedInStateFlow(): Flow<LoggedInState> {
return sessionStore.isLoggedIn()
}
override suspend fun getLatestSessionId(): SessionId? = withContext(coroutineDispatchers.io) {
sessionStore.getLatestSession()?.userId?.let { SessionId(it) }
}
override suspend fun restoreSession(sessionId: SessionId): Result<MatrixClient> = withContext(coroutineDispatchers.io) {
runCatchingExceptions {
val sessionData = sessionStore.getSession(sessionId.value)
@ -158,7 +148,7 @@ class RustMatrixAuthenticationService(
)
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
sessionStore.storeData(sessionData)
sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null
@ -182,7 +172,7 @@ class RustMatrixAuthenticationService(
sessionPaths = currentSessionPaths,
)
clear()
sessionStore.storeData(sessionData)
sessionStore.addSession(sessionData)
SessionId(sessionData.userId)
}
}
@ -250,7 +240,7 @@ class RustMatrixAuthenticationService(
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
sessionStore.storeData(sessionData)
sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null
@ -295,7 +285,7 @@ class RustMatrixAuthenticationService(
)
val matrixClient = rustMatrixClientFactory.create(client)
newMatrixClientObservers.forEach { it.invoke(matrixClient) }
sessionStore.storeData(sessionData)
sessionStore.addSession(sessionData)
// Clean up the strong reference held here since it's no longer necessary
currentClient = null

View file

@ -10,16 +10,16 @@ package io.element.android.libraries.matrix.impl.notification
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.notification.CallNotifyType
import io.element.android.libraries.matrix.api.notification.NotificationContent
import io.element.android.libraries.matrix.api.notification.RtcNotificationType
import io.element.android.libraries.matrix.impl.room.member.RoomMemberMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper
import org.matrix.rustcomponents.sdk.MessageLikeEventContent
import org.matrix.rustcomponents.sdk.NotifyType
import org.matrix.rustcomponents.sdk.StateEventContent
import org.matrix.rustcomponents.sdk.TimelineEvent
import org.matrix.rustcomponents.sdk.TimelineEventType
import org.matrix.rustcomponents.sdk.use
import org.matrix.rustcomponents.sdk.RtcNotificationType as SdkRtcNotificationType
class TimelineEventToNotificationContentMapper {
fun map(timelineEvent: TimelineEvent): Result<NotificationContent> {
@ -78,7 +78,11 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
MessageLikeEventContent.CallCandidates -> NotificationContent.MessageLike.CallCandidates
MessageLikeEventContent.CallHangup -> NotificationContent.MessageLike.CallHangup
MessageLikeEventContent.CallInvite -> NotificationContent.MessageLike.CallInvite(senderId)
is MessageLikeEventContent.CallNotify -> NotificationContent.MessageLike.CallNotify(senderId, notifyType.map())
is MessageLikeEventContent.RtcNotification -> NotificationContent.MessageLike.RtcNotification(
senderId = senderId,
type = notificationType.map(),
expirationTimestampMillis = expirationTs.toLong()
)
MessageLikeEventContent.KeyVerificationAccept -> NotificationContent.MessageLike.KeyVerificationAccept
MessageLikeEventContent.KeyVerificationCancel -> NotificationContent.MessageLike.KeyVerificationCancel
MessageLikeEventContent.KeyVerificationDone -> NotificationContent.MessageLike.KeyVerificationDone
@ -101,7 +105,7 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
}
}
private fun NotifyType.map(): CallNotifyType = when (this) {
NotifyType.NOTIFY -> CallNotifyType.NOTIFY
NotifyType.RING -> CallNotifyType.RING
private fun SdkRtcNotificationType.map(): RtcNotificationType = when (this) {
SdkRtcNotificationType.NOTIFICATION -> RtcNotificationType.NOTIFY
SdkRtcNotificationType.RING -> RtcNotificationType.RING
}

View file

@ -15,7 +15,7 @@ fun MessageEventType.map(): MessageLikeEventType = when (this) {
MessageEventType.CALL_INVITE -> MessageLikeEventType.CALL_INVITE
MessageEventType.CALL_HANGUP -> MessageLikeEventType.CALL_HANGUP
MessageEventType.CALL_CANDIDATES -> MessageLikeEventType.CALL_CANDIDATES
MessageEventType.CALL_NOTIFY -> MessageLikeEventType.CALL_NOTIFY
MessageEventType.RTC_NOTIFICATION -> MessageLikeEventType.RTC_NOTIFICATION
MessageEventType.KEY_VERIFICATION_READY -> MessageLikeEventType.KEY_VERIFICATION_READY
MessageEventType.KEY_VERIFICATION_START -> MessageLikeEventType.KEY_VERIFICATION_START
MessageEventType.KEY_VERIFICATION_CANCEL -> MessageLikeEventType.KEY_VERIFICATION_CANCEL
@ -41,7 +41,7 @@ fun MessageLikeEventType.map(): MessageEventType = when (this) {
MessageLikeEventType.CALL_INVITE -> MessageEventType.CALL_INVITE
MessageLikeEventType.CALL_HANGUP -> MessageEventType.CALL_HANGUP
MessageLikeEventType.CALL_CANDIDATES -> MessageEventType.CALL_CANDIDATES
MessageLikeEventType.CALL_NOTIFY -> MessageEventType.CALL_NOTIFY
MessageLikeEventType.RTC_NOTIFICATION -> MessageEventType.RTC_NOTIFICATION
MessageLikeEventType.KEY_VERIFICATION_READY -> MessageEventType.KEY_VERIFICATION_READY
MessageLikeEventType.KEY_VERIFICATION_START -> MessageEventType.KEY_VERIFICATION_START
MessageLikeEventType.KEY_VERIFICATION_CANCEL -> MessageEventType.KEY_VERIFICATION_CANCEL

View file

@ -38,10 +38,12 @@ import io.element.android.libraries.matrix.impl.timeline.toRustReceiptType
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.CallDeclineListener
import org.matrix.rustcomponents.sdk.RoomInfoListener
import org.matrix.rustcomponents.sdk.use
import timber.log.Timber
@ -300,4 +302,20 @@ class RustBaseRoom(
innerRoom.reportRoom(reason.orEmpty())
}
}
override suspend fun declineCall(notificationEventId: EventId): Result<Unit> = withContext(roomDispatcher) {
runCatchingExceptions {
innerRoom.declineCall(notificationEventId.value)
}
}
override suspend fun subscribeToCallDecline(notificationEventId: EventId): Flow<UserId> = withContext(roomDispatcher) {
mxCallbackFlow {
innerRoom.subscribeToCallDeclineEvents(notificationEventId.value, object : CallDeclineListener {
override fun call(declinerUserId: String) {
trySend(UserId(declinerUserId))
}
})
}
}
}

View file

@ -20,7 +20,7 @@ fun RustAllowRule.map(): AllowRule {
fun AllowRule.map(): RustAllowRule {
return when (this) {
is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.toString())
is AllowRule.RoomMembership -> RustAllowRule.RoomMembership(roomId.value)
is AllowRule.Custom -> RustAllowRule.Custom(json)
}
}

View file

@ -25,7 +25,6 @@ object RoomMemberMapper {
membership = mapMembership(roomMember.membership),
isNameAmbiguous = roomMember.isNameAmbiguous,
powerLevel = powerLevel,
normalizedPowerLevel = roomMember.normalizedPowerLevel.into(),
isIgnored = roomMember.isIgnored,
role = mapRole(roomMember.suggestedRoleForPowerLevel, powerLevel),
membershipChangeReason = roomMember.membershipChangeReason

View file

@ -431,7 +431,7 @@ class RustTimeline(
}
}
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Unit> = withContext(dispatcher) {
override suspend fun toggleReaction(emoji: String, eventOrTransactionId: EventOrTransactionId): Result<Boolean> = withContext(dispatcher) {
runCatchingExceptions {
inner.toggleReaction(
key = emoji,

View file

@ -149,7 +149,7 @@ class TimelineEventContentMapper(
)
}
is TimelineItemContent.CallInvite -> LegacyCallInviteContent
is TimelineItemContent.CallNotify -> CallNotifyContent
is TimelineItemContent.RtcNotification -> CallNotifyContent
}
}
}

View file

@ -18,10 +18,10 @@ import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.flow.first
import org.matrix.rustcomponents.sdk.newVirtualElementCallWidget
import timber.log.Timber
import uniffi.matrix_sdk.EncryptionSystem
import uniffi.matrix_sdk.HeaderStyle
import uniffi.matrix_sdk.NotificationType
import uniffi.matrix_sdk.VirtualElementCallWidgetOptions
import uniffi.matrix_sdk.VirtualElementCallWidgetConfig
import uniffi.matrix_sdk.VirtualElementCallWidgetProperties
import uniffi.matrix_sdk.Intent as CallIntent
@ContributesBinding(AppScope::class)
@ -31,19 +31,14 @@ class DefaultCallWidgetSettingsProvider(
private val callAnalyticsCredentialsProvider: CallAnalyticCredentialsProvider,
private val analyticsService: AnalyticsService,
) : CallWidgetSettingsProvider {
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean, direct: Boolean): MatrixWidgetSettings {
override suspend fun provide(baseUrl: String, widgetId: String, encrypted: Boolean, direct: Boolean, hasActiveCall: Boolean): MatrixWidgetSettings {
val isAnalyticsEnabled = analyticsService.userConsentFlow.first()
val options = VirtualElementCallWidgetOptions(
val properties = VirtualElementCallWidgetProperties(
elementCallUrl = baseUrl,
widgetId = widgetId,
preload = null,
fontScale = null,
appPrompt = false,
confineToRoom = true,
font = null,
encryption = if (encrypted) EncryptionSystem.PerParticipantKeys else EncryptionSystem.Unencrypted,
intent = CallIntent.START_CALL,
hideScreensharing = false,
posthogUserId = callAnalyticsCredentialsProvider.posthogUserId.takeIf { isAnalyticsEnabled },
posthogApiHost = callAnalyticsCredentialsProvider.posthogApiHost.takeIf { isAnalyticsEnabled },
posthogApiKey = callAnalyticsCredentialsProvider.posthogApiKey.takeIf { isAnalyticsEnabled },
@ -51,13 +46,25 @@ class DefaultCallWidgetSettingsProvider(
sentryDsn = callAnalyticsCredentialsProvider.sentryDsn.takeIf { isAnalyticsEnabled },
sentryEnvironment = if (buildMeta.buildType == BuildType.RELEASE) "RELEASE" else "DEBUG",
parentUrl = null,
// For backwards compatibility, it'll be ignored in recent versions of Element Call
hideHeader = true,
controlledMediaDevices = true,
header = HeaderStyle.APP_BAR,
sendNotificationType = if (direct) NotificationType.RING else NotificationType.NOTIFICATION,
)
val rustWidgetSettings = newVirtualElementCallWidget(options)
val config = VirtualElementCallWidgetConfig(
// TODO remove this once we have the next EC version
preload = false,
// TODO remove this once we have the next EC version
skipLobby = null,
intent = when {
direct && hasActiveCall -> CallIntent.JOIN_EXISTING_DM
hasActiveCall -> CallIntent.JOIN_EXISTING
direct -> CallIntent.START_CALL_DM
else -> CallIntent.START_CALL
}.also {
Timber.d("Starting/joining call with intent: $it")
}
)
val rustWidgetSettings = newVirtualElementCallWidget(
props = properties,
config = config,
)
return MatrixWidgetSettings.fromRustWidgetSettings(rustWidgetSettings)
}
}