Merge branch 'develop' into feature/bma/addCommentOnSdkDep
This commit is contained in:
commit
3422b7d90a
43 changed files with 307 additions and 80 deletions
|
|
@ -29,6 +29,7 @@ interface ElementCallEntryPoint {
|
||||||
* @param senderName The name of the sender of the event that started the call.
|
* @param senderName The name of the sender of the event that started the call.
|
||||||
* @param avatarUrl The avatar url of the room or DM.
|
* @param avatarUrl The avatar url of the room or DM.
|
||||||
* @param timestamp The timestamp of the event that started the call.
|
* @param timestamp The timestamp of the event that started the call.
|
||||||
|
* @param expirationTimestamp The timestamp at which the call should stop ringing.
|
||||||
* @param notificationChannelId The id of the notification channel to use for the call notification.
|
* @param notificationChannelId The id of the notification channel to use for the call notification.
|
||||||
* @param textContent The text content of the notification. If null the default content from the system will be used.
|
* @param textContent The text content of the notification. If null the default content from the system will be used.
|
||||||
*/
|
*/
|
||||||
|
|
@ -40,6 +41,7 @@ interface ElementCallEntryPoint {
|
||||||
senderName: String?,
|
senderName: String?,
|
||||||
avatarUrl: String?,
|
avatarUrl: String?,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
|
expirationTimestamp: Long,
|
||||||
notificationChannelId: String,
|
notificationChannelId: String,
|
||||||
textContent: String?,
|
textContent: String?,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ dependencies {
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
testImplementation(projects.services.analytics.test)
|
testImplementation(projects.services.analytics.test)
|
||||||
testImplementation(projects.services.appnavstate.test)
|
testImplementation(projects.services.appnavstate.test)
|
||||||
|
testImplementation(projects.services.toolbox.test)
|
||||||
testImplementation(projects.tests.testutils)
|
testImplementation(projects.tests.testutils)
|
||||||
testImplementation(libs.androidx.compose.ui.test.junit)
|
testImplementation(libs.androidx.compose.ui.test.junit)
|
||||||
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
|
testReleaseImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ class DefaultElementCallEntryPoint(
|
||||||
senderName: String?,
|
senderName: String?,
|
||||||
avatarUrl: String?,
|
avatarUrl: String?,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
|
expirationTimestamp: Long,
|
||||||
notificationChannelId: String,
|
notificationChannelId: String,
|
||||||
textContent: String?,
|
textContent: String?,
|
||||||
) {
|
) {
|
||||||
|
|
@ -55,6 +56,7 @@ class DefaultElementCallEntryPoint(
|
||||||
senderName = senderName,
|
senderName = senderName,
|
||||||
avatarUrl = avatarUrl,
|
avatarUrl = avatarUrl,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
notificationChannelId = notificationChannelId,
|
notificationChannelId = notificationChannelId,
|
||||||
textContent = textContent,
|
textContent = textContent,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,6 @@ data class CallNotificationData(
|
||||||
val notificationChannelId: String,
|
val notificationChannelId: String,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
val textContent: String?,
|
val textContent: String?,
|
||||||
|
// Expiration timestamp in millis since epoch
|
||||||
|
val expirationTimestamp: Long,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ class RingingCallNotificationCreator(
|
||||||
roomAvatarUrl: String?,
|
roomAvatarUrl: String?,
|
||||||
notificationChannelId: String,
|
notificationChannelId: String,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
|
expirationTimestamp: Long,
|
||||||
textContent: String?,
|
textContent: String?,
|
||||||
): Notification? {
|
): Notification? {
|
||||||
val matrixClient = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return null
|
val matrixClient = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return null
|
||||||
|
|
@ -88,6 +89,7 @@ class RingingCallNotificationCreator(
|
||||||
notificationChannelId = notificationChannelId,
|
notificationChannelId = notificationChannelId,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
textContent = textContent,
|
textContent = textContent,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
)
|
)
|
||||||
|
|
||||||
val declineIntent = PendingIntentCompat.getBroadcast(
|
val declineIntent = PendingIntentCompat.getBroadcast(
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,7 @@ internal fun IncomingCallScreenPreview() = ElementPreview {
|
||||||
notificationChannelId = "incoming_call",
|
notificationChannelId = "incoming_call",
|
||||||
timestamp = 0L,
|
timestamp = 0L,
|
||||||
textContent = null,
|
textContent = null,
|
||||||
|
expirationTimestamp = 1000L,
|
||||||
),
|
),
|
||||||
onAnswer = {},
|
onAnswer = {},
|
||||||
onCancel = {},
|
onCancel = {},
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import io.element.android.libraries.push.api.notifications.ForegroundServiceType
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
|
||||||
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
|
import io.element.android.libraries.push.api.notifications.OnMissedCallNotificationHandler
|
||||||
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
import io.element.android.services.appnavstate.api.AppForegroundStateService
|
||||||
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -53,7 +54,7 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the active call state.
|
* Manages the active call state.
|
||||||
|
|
@ -98,6 +99,7 @@ class DefaultActiveCallManager(
|
||||||
private val defaultCurrentCallService: DefaultCurrentCallService,
|
private val defaultCurrentCallService: DefaultCurrentCallService,
|
||||||
private val appForegroundStateService: AppForegroundStateService,
|
private val appForegroundStateService: AppForegroundStateService,
|
||||||
private val imageLoaderHolder: ImageLoaderHolder,
|
private val imageLoaderHolder: ImageLoaderHolder,
|
||||||
|
private val systemClock: SystemClock,
|
||||||
) : ActiveCallManager {
|
) : ActiveCallManager {
|
||||||
private val tag = "DefaultActiveCallManager"
|
private val tag = "DefaultActiveCallManager"
|
||||||
private var timedOutCallJob: Job? = null
|
private var timedOutCallJob: Job? = null
|
||||||
|
|
@ -118,8 +120,20 @@ class DefaultActiveCallManager(
|
||||||
|
|
||||||
override suspend fun registerIncomingCall(notificationData: CallNotificationData) {
|
override suspend fun registerIncomingCall(notificationData: CallNotificationData) {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
|
val ringDuration =
|
||||||
|
min(
|
||||||
|
notificationData.expirationTimestamp - systemClock.epochMillis(),
|
||||||
|
ElementCallConfig.RINGING_CALL_DURATION_SECONDS * 1000L
|
||||||
|
)
|
||||||
|
|
||||||
|
if (ringDuration < 0) {
|
||||||
|
// Should already have stopped ringing, ignore.
|
||||||
|
Timber.tag(tag).d("Received timed-out incoming ringing call for room id: ${notificationData.roomId}, cancel ringing")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
appForegroundStateService.updateHasRingingCall(true)
|
appForegroundStateService.updateHasRingingCall(true)
|
||||||
Timber.tag(tag).d("Received incoming call for room id: ${notificationData.roomId}")
|
Timber.tag(tag).d("Received incoming call for room id: ${notificationData.roomId}, ringDuration(ms): $ringDuration")
|
||||||
if (activeCall.value != null) {
|
if (activeCall.value != null) {
|
||||||
displayMissedCallNotification(notificationData)
|
displayMissedCallNotification(notificationData)
|
||||||
Timber.tag(tag).w("Already have an active call, ignoring incoming call: $notificationData")
|
Timber.tag(tag).w("Already have an active call, ignoring incoming call: $notificationData")
|
||||||
|
|
@ -138,14 +152,14 @@ class DefaultActiveCallManager(
|
||||||
showIncomingCallNotification(notificationData)
|
showIncomingCallNotification(notificationData)
|
||||||
|
|
||||||
// Wait for the ringing call to time out
|
// Wait for the ringing call to time out
|
||||||
delay(ElementCallConfig.RINGING_CALL_DURATION_SECONDS.seconds)
|
delay(timeMillis = ringDuration)
|
||||||
incomingCallTimedOut(displayMissedCallNotification = true)
|
incomingCallTimedOut(displayMissedCallNotification = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a wake lock to keep the device awake during the incoming call, so we can process the room info data
|
// Acquire a wake lock to keep the device awake during the incoming call, so we can process the room info data
|
||||||
if (activeWakeLock?.isHeld == false) {
|
if (activeWakeLock?.isHeld == false) {
|
||||||
Timber.tag(tag).d("Acquiring partial wakelock")
|
Timber.tag(tag).d("Acquiring partial wakelock")
|
||||||
activeWakeLock.acquire(ElementCallConfig.RINGING_CALL_DURATION_SECONDS * 1000L)
|
activeWakeLock.acquire(ringDuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,6 +250,7 @@ class DefaultActiveCallManager(
|
||||||
notificationChannelId = notificationData.notificationChannelId,
|
notificationChannelId = notificationData.notificationChannelId,
|
||||||
timestamp = notificationData.timestamp,
|
timestamp = notificationData.timestamp,
|
||||||
textContent = notificationData.textContent,
|
textContent = notificationData.textContent,
|
||||||
|
expirationTimestamp = notificationData.expirationTimestamp,
|
||||||
) ?: return
|
) ?: return
|
||||||
runCatchingExceptions {
|
runCatchingExceptions {
|
||||||
notificationManagerCompat.notify(
|
notificationManagerCompat.notify(
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ class DefaultElementCallEntryPointTest {
|
||||||
senderName = "senderName",
|
senderName = "senderName",
|
||||||
avatarUrl = "avatarUrl",
|
avatarUrl = "avatarUrl",
|
||||||
timestamp = 0,
|
timestamp = 0,
|
||||||
|
expirationTimestamp = 0,
|
||||||
notificationChannelId = "notificationChannelId",
|
notificationChannelId = "notificationChannelId",
|
||||||
textContent = "textContent",
|
textContent = "textContent",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ class RingingCallNotificationCreatorTest {
|
||||||
roomAvatarUrl = "https://example.com/avatar.jpg",
|
roomAvatarUrl = "https://example.com/avatar.jpg",
|
||||||
notificationChannelId = "channelId",
|
notificationChannelId = "channelId",
|
||||||
timestamp = 0L,
|
timestamp = 0L,
|
||||||
|
expirationTimestamp = 20L,
|
||||||
textContent = "textContent",
|
textContent = "textContent",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ import io.element.android.libraries.push.test.notifications.FakeImageLoaderHolde
|
||||||
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
|
import io.element.android.libraries.push.test.notifications.FakeOnMissedCallNotificationHandler
|
||||||
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
import io.element.android.libraries.push.test.notifications.push.FakeNotificationBitmapLoader
|
||||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||||
|
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||||
|
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import io.element.android.tests.testutils.plantTestTimber
|
import io.element.android.tests.testutils.plantTestTimber
|
||||||
|
|
@ -368,6 +370,83 @@ class DefaultActiveCallManagerTest {
|
||||||
assertThat(manager.activeCall.value).isNotNull()
|
assertThat(manager.activeCall.value).isNotNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
fun `IncomingCall - rings no longer than expiration time`() = runTest {
|
||||||
|
setupShadowPowerManager()
|
||||||
|
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
|
||||||
|
val clock = FakeSystemClock()
|
||||||
|
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat, systemClock = clock)
|
||||||
|
|
||||||
|
assertThat(manager.activeWakeLock?.isHeld).isFalse()
|
||||||
|
assertThat(manager.activeCall.value).isNull()
|
||||||
|
|
||||||
|
val eventTimestamp = A_FAKE_TIMESTAMP
|
||||||
|
// The call should not ring more than 30 seconds after the initial event was sent
|
||||||
|
val expirationTimestamp = eventTimestamp + 30_000
|
||||||
|
|
||||||
|
val callNotificationData = aCallNotificationData(
|
||||||
|
timestamp = eventTimestamp,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
// suppose it took 10s to be notified
|
||||||
|
clock.epochMillisResult = eventTimestamp + 10_000
|
||||||
|
manager.registerIncomingCall(callNotificationData)
|
||||||
|
|
||||||
|
assertThat(manager.activeCall.value).isEqualTo(
|
||||||
|
ActiveCall(
|
||||||
|
callType = CallType.RoomCall(
|
||||||
|
sessionId = callNotificationData.sessionId,
|
||||||
|
roomId = callNotificationData.roomId,
|
||||||
|
),
|
||||||
|
callState = CallState.Ringing(callNotificationData)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
assertThat(manager.activeWakeLock?.isHeld).isTrue()
|
||||||
|
verify { notificationManagerCompat.notify(notificationId, any()) }
|
||||||
|
|
||||||
|
// advance by 21s it should have stopped ringing
|
||||||
|
advanceTimeBy(21_000)
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
verify { notificationManagerCompat.cancel(any()) }
|
||||||
|
}
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
@Test
|
||||||
|
fun `IncomingCall - ignore expired ring lifetime`() = runTest {
|
||||||
|
setupShadowPowerManager()
|
||||||
|
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
|
||||||
|
val clock = FakeSystemClock()
|
||||||
|
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat, systemClock = clock)
|
||||||
|
|
||||||
|
assertThat(manager.activeWakeLock?.isHeld).isFalse()
|
||||||
|
assertThat(manager.activeCall.value).isNull()
|
||||||
|
|
||||||
|
val eventTimestamp = A_FAKE_TIMESTAMP
|
||||||
|
// The call should not ring more than 30 seconds after the initial event was sent
|
||||||
|
val expirationTimestamp = eventTimestamp + 30_000
|
||||||
|
|
||||||
|
val callNotificationData = aCallNotificationData(
|
||||||
|
timestamp = eventTimestamp,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
|
)
|
||||||
|
|
||||||
|
// suppose it took 35s to be notified
|
||||||
|
clock.epochMillisResult = eventTimestamp + 35_000
|
||||||
|
manager.registerIncomingCall(callNotificationData)
|
||||||
|
|
||||||
|
assertThat(manager.activeCall.value).isNull()
|
||||||
|
|
||||||
|
runCurrent()
|
||||||
|
|
||||||
|
assertThat(manager.activeWakeLock?.isHeld).isFalse()
|
||||||
|
verify(exactly = 0) { notificationManagerCompat.notify(notificationId, any()) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupShadowPowerManager() {
|
private fun setupShadowPowerManager() {
|
||||||
shadowOf(InstrumentationRegistry.getInstrumentation().targetContext.getSystemService<PowerManager>()).apply {
|
shadowOf(InstrumentationRegistry.getInstrumentation().targetContext.getSystemService<PowerManager>()).apply {
|
||||||
setIsWakeLockLevelSupported(PowerManager.PARTIAL_WAKE_LOCK, true)
|
setIsWakeLockLevelSupported(PowerManager.PARTIAL_WAKE_LOCK, true)
|
||||||
|
|
@ -378,6 +457,7 @@ class DefaultActiveCallManagerTest {
|
||||||
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
|
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
|
||||||
onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(),
|
onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(),
|
||||||
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
|
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
|
||||||
|
systemClock: FakeSystemClock = FakeSystemClock(),
|
||||||
) = DefaultActiveCallManager(
|
) = DefaultActiveCallManager(
|
||||||
context = InstrumentationRegistry.getInstrumentation().targetContext,
|
context = InstrumentationRegistry.getInstrumentation().targetContext,
|
||||||
coroutineScope = backgroundScope,
|
coroutineScope = backgroundScope,
|
||||||
|
|
@ -393,5 +473,6 @@ class DefaultActiveCallManagerTest {
|
||||||
defaultCurrentCallService = DefaultCurrentCallService(),
|
defaultCurrentCallService = DefaultCurrentCallService(),
|
||||||
appForegroundStateService = FakeAppForegroundStateService(),
|
appForegroundStateService = FakeAppForegroundStateService(),
|
||||||
imageLoaderHolder = FakeImageLoaderHolder(),
|
imageLoaderHolder = FakeImageLoaderHolder(),
|
||||||
|
systemClock = systemClock,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ fun aCallNotificationData(
|
||||||
avatarUrl: String? = AN_AVATAR_URL,
|
avatarUrl: String? = AN_AVATAR_URL,
|
||||||
notificationChannelId: String = "channel_id",
|
notificationChannelId: String = "channel_id",
|
||||||
timestamp: Long = 0L,
|
timestamp: Long = 0L,
|
||||||
|
expirationTimestamp: Long = 30_000L,
|
||||||
textContent: String? = null,
|
textContent: String? = null,
|
||||||
): CallNotificationData = CallNotificationData(
|
): CallNotificationData = CallNotificationData(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
|
|
@ -41,5 +42,6 @@ fun aCallNotificationData(
|
||||||
avatarUrl = avatarUrl,
|
avatarUrl = avatarUrl,
|
||||||
notificationChannelId = notificationChannelId,
|
notificationChannelId = notificationChannelId,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
textContent = textContent,
|
textContent = textContent,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ class FakeElementCallEntryPoint(
|
||||||
senderName: String?,
|
senderName: String?,
|
||||||
avatarUrl: String?,
|
avatarUrl: String?,
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
|
expirationTimestamp: Long,
|
||||||
notificationChannelId: String,
|
notificationChannelId: String,
|
||||||
textContent: String?,
|
textContent: String?,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,12 @@ import io.element.android.features.messages.impl.actionlist.model.TimelineItemAc
|
||||||
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
|
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailure
|
||||||
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
|
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContentWithAttachment
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.canBeCopied
|
import io.element.android.features.messages.impl.timeline.model.event.canBeCopied
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.canBeForwarded
|
import io.element.android.features.messages.impl.timeline.model.event.canBeForwarded
|
||||||
|
|
@ -242,7 +242,7 @@ class DefaultActionListPresenter(
|
||||||
private fun Iterable<TimelineItemAction>.postFilter(content: TimelineItemEventContent): Iterable<TimelineItemAction> {
|
private fun Iterable<TimelineItemAction>.postFilter(content: TimelineItemEventContent): Iterable<TimelineItemAction> {
|
||||||
return filter { action ->
|
return filter { action ->
|
||||||
when (content) {
|
when (content) {
|
||||||
is TimelineItemCallNotifyContent,
|
is TimelineItemRtcNotificationContent,
|
||||||
is TimelineItemLegacyCallInviteContent,
|
is TimelineItemLegacyCallInviteContent,
|
||||||
is TimelineItemStateContent -> action == TimelineItemAction.ViewSource
|
is TimelineItemStateContent -> action == TimelineItemAction.ViewSource
|
||||||
is TimelineItemRedactedContent -> {
|
is TimelineItemRedactedContent -> {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ import io.element.android.features.messages.impl.timeline.a11y.a11yReactionActio
|
||||||
import io.element.android.features.messages.impl.timeline.components.MessageShieldView
|
import io.element.android.features.messages.impl.timeline.components.MessageShieldView
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
|
|
@ -64,6 +63,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||||
|
|
@ -306,7 +306,7 @@ private fun MessageSummary(
|
||||||
is TimelineItemLegacyCallInviteContent -> {
|
is TimelineItemLegacyCallInviteContent -> {
|
||||||
content = { ContentForBody(textContent) }
|
content = { ContentForBody(textContent) }
|
||||||
}
|
}
|
||||||
is TimelineItemCallNotifyContent -> {
|
is TimelineItemRtcNotificationContent -> {
|
||||||
content = { ContentForBody(stringResource(CommonStrings.common_call_started)) }
|
content = { ContentForBody(stringResource(CommonStrings.common_call_started)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.roomcall.api.RoomCallState
|
import io.element.android.features.roomcall.api.RoomCallState
|
||||||
import io.element.android.features.roomcall.api.RoomCallStateProvider
|
import io.element.android.features.roomcall.api.RoomCallStateProvider
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
|
|
@ -119,7 +119,7 @@ internal fun TimelineItemCallNotifyViewPreview() = ElementPreview {
|
||||||
.filter { it !is RoomCallState.Unavailable }
|
.filter { it !is RoomCallState.Unavailable }
|
||||||
.forEach { roomCallState ->
|
.forEach { roomCallState ->
|
||||||
TimelineItemCallNotifyView(
|
TimelineItemCallNotifyView(
|
||||||
event = aTimelineItemEvent(content = TimelineItemCallNotifyContent()),
|
event = aTimelineItemEvent(content = TimelineItemRtcNotificationContent()),
|
||||||
roomCallState = roomCallState,
|
roomCallState = roomCallState,
|
||||||
onLongClick = {},
|
onLongClick = {},
|
||||||
onJoinCallClick = {},
|
onJoinCallClick = {},
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,9 @@ import io.element.android.features.messages.impl.timeline.TimelineRoomInfo
|
||||||
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
|
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemEventContentView
|
||||||
import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData
|
import io.element.android.features.messages.impl.timeline.components.layout.ContentAvoidingLayoutData
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
|
||||||
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
|
||||||
|
|
@ -123,7 +123,7 @@ internal fun TimelineItemRow(
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is TimelineItemCallNotifyContent -> {
|
is TimelineItemRtcNotificationContent -> {
|
||||||
TimelineItemCallNotifyView(
|
TimelineItemCallNotifyView(
|
||||||
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
|
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
|
||||||
event = timelineItem,
|
event = timelineItem,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import io.element.android.features.messages.impl.timeline.components.layout.Cont
|
||||||
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
|
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
|
||||||
import io.element.android.features.messages.impl.timeline.di.rememberPresenter
|
import io.element.android.features.messages.impl.timeline.di.rememberPresenter
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
|
|
@ -23,6 +22,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||||
|
|
@ -133,6 +133,6 @@ fun TimelineItemEventContentView(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is TimelineItemCallNotifyContent -> error("This shouldn't be rendered as the content of a bubble")
|
is TimelineItemRtcNotificationContent -> error("This shouldn't be rendered as the content of a bubble")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
package io.element.android.features.messages.impl.timeline.factories.event
|
package io.element.android.features.messages.impl.timeline.factories.event
|
||||||
|
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLegacyCallInviteContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
|
|
@ -61,7 +61,7 @@ class TimelineItemContentFactory(
|
||||||
is StickerContent -> stickerFactory.create(itemContent)
|
is StickerContent -> stickerFactory.create(itemContent)
|
||||||
is PollContent -> pollFactory.create(eventTimelineItem, itemContent)
|
is PollContent -> pollFactory.create(eventTimelineItem, itemContent)
|
||||||
is UnableToDecryptContent -> utdFactory.create(itemContent)
|
is UnableToDecryptContent -> utdFactory.create(itemContent)
|
||||||
is CallNotifyContent -> TimelineItemCallNotifyContent()
|
is CallNotifyContent -> TimelineItemRtcNotificationContent()
|
||||||
is UnknownContent -> TimelineItemUnknownContent
|
is UnknownContent -> TimelineItemUnknownContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ package io.element.android.features.messages.impl.timeline.groups
|
||||||
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
|
|
@ -19,6 +18,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||||
|
|
@ -60,7 +60,7 @@ internal fun TimelineItem.Event.canBeGrouped(): Boolean {
|
||||||
TimelineItemRedactedContent,
|
TimelineItemRedactedContent,
|
||||||
TimelineItemUnknownContent,
|
TimelineItemUnknownContent,
|
||||||
is TimelineItemLegacyCallInviteContent,
|
is TimelineItemLegacyCallInviteContent,
|
||||||
is TimelineItemCallNotifyContent -> false
|
is TimelineItemRtcNotificationContent -> false
|
||||||
is TimelineItemProfileChangeContent,
|
is TimelineItemProfileChangeContent,
|
||||||
is TimelineItemRoomMembershipContent,
|
is TimelineItemRoomMembershipContent,
|
||||||
is TimelineItemStateEventContent -> true
|
is TimelineItemStateEventContent -> true
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ fun TimelineItemEventContent.canReact(): Boolean =
|
||||||
is TimelineItemStateContent,
|
is TimelineItemStateContent,
|
||||||
is TimelineItemRedactedContent,
|
is TimelineItemRedactedContent,
|
||||||
is TimelineItemLegacyCallInviteContent,
|
is TimelineItemLegacyCallInviteContent,
|
||||||
is TimelineItemCallNotifyContent,
|
is TimelineItemRtcNotificationContent,
|
||||||
TimelineItemUnknownContent -> false
|
TimelineItemUnknownContent -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@
|
||||||
|
|
||||||
package io.element.android.features.messages.impl.timeline.model.event
|
package io.element.android.features.messages.impl.timeline.model.event
|
||||||
|
|
||||||
class TimelineItemCallNotifyContent : TimelineItemEventContent {
|
class TimelineItemRtcNotificationContent : TimelineItemEventContent {
|
||||||
override val type: String = "m.call.notify"
|
override val type: String = "org.matrix.msc4075.rtc.notification"
|
||||||
}
|
}
|
||||||
|
|
@ -9,7 +9,6 @@ package io.element.android.features.messages.impl.timeline.protection
|
||||||
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
|
|
@ -21,6 +20,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRoomMembershipContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateEventContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||||
|
|
@ -38,7 +38,7 @@ fun TimelineItem.mustBeProtected(): Boolean {
|
||||||
is TimelineItemVideoContent,
|
is TimelineItemVideoContent,
|
||||||
is TimelineItemStickerContent -> true
|
is TimelineItemStickerContent -> true
|
||||||
is TimelineItemAudioContent,
|
is TimelineItemAudioContent,
|
||||||
is TimelineItemCallNotifyContent,
|
is TimelineItemRtcNotificationContent,
|
||||||
is TimelineItemEncryptedContent,
|
is TimelineItemEncryptedContent,
|
||||||
is TimelineItemFileContent,
|
is TimelineItemFileContent,
|
||||||
TimelineItemLegacyCallInviteContent,
|
TimelineItemLegacyCallInviteContent,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import dev.zacsweers.metro.ContributesBinding
|
||||||
import dev.zacsweers.metro.Inject
|
import dev.zacsweers.metro.Inject
|
||||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
import io.element.android.features.messages.impl.timeline.model.TimelineItem
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent
|
||||||
|
|
@ -21,6 +20,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemPollContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemProfileChangeContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStickerContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextBasedContent
|
||||||
|
|
@ -54,7 +54,7 @@ class DefaultMessageSummaryFormatter(
|
||||||
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
|
is TimelineItemFileContent -> context.getString(CommonStrings.common_file)
|
||||||
is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio)
|
is TimelineItemAudioContent -> context.getString(CommonStrings.common_audio)
|
||||||
is TimelineItemLegacyCallInviteContent -> context.getString(CommonStrings.common_unsupported_call)
|
is TimelineItemLegacyCallInviteContent -> context.getString(CommonStrings.common_unsupported_call)
|
||||||
is TimelineItemCallNotifyContent -> context.getString(CommonStrings.common_call_started)
|
is TimelineItemRtcNotificationContent -> context.getString(CommonStrings.common_call_started)
|
||||||
}
|
}
|
||||||
// Truncate the message to a safe length to avoid crashes in Compose
|
// Truncate the message to a safe length to avoid crashes in Compose
|
||||||
.toSafeLength()
|
.toSafeLength()
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUser
|
||||||
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
|
import io.element.android.features.messages.impl.crypto.sendfailure.VerifiedUserSendFailureFactory
|
||||||
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
import io.element.android.features.messages.impl.fixtures.aMessageEvent
|
||||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
|
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
|
||||||
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRtcNotificationContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemImageContent
|
||||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
|
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
|
||||||
|
|
@ -1193,7 +1193,7 @@ class ActionListPresenterTest {
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
val messageEvent = aMessageEvent(
|
val messageEvent = aMessageEvent(
|
||||||
isMine = true,
|
isMine = true,
|
||||||
content = TimelineItemCallNotifyContent(),
|
content = TimelineItemRtcNotificationContent(),
|
||||||
)
|
)
|
||||||
initialState.eventSink.invoke(
|
initialState.eventSink.invoke(
|
||||||
ActionListEvents.ComputeForMessage(
|
ActionListEvents.ComputeForMessage(
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ showkase = "1.0.5"
|
||||||
appyx = "1.7.1"
|
appyx = "1.7.1"
|
||||||
sqldelight = "2.1.0"
|
sqldelight = "2.1.0"
|
||||||
wysiwyg = "2.39.0"
|
wysiwyg = "2.39.0"
|
||||||
telephoto = "0.16.0"
|
telephoto = "0.17.0"
|
||||||
haze = "1.6.10"
|
haze = "1.6.10"
|
||||||
|
|
||||||
# Dependency analysis
|
# Dependency analysis
|
||||||
|
|
@ -166,7 +166,7 @@ test_detekt_test = { module = "io.gitlab.arturbosch.detekt:detekt-test", version
|
||||||
# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
|
# https://github.com/matrix-org/matrix-rust-components-kotlin/commits/main/sdk/sdk-android/src/main/kotlin/org/matrix/rustcomponents/sdk/matrix_sdk_ffi.kt
|
||||||
# All new features should not be implemented in the pull request that upgrades the version, developers should
|
# All new features should not be implemented in the pull request that upgrades the version, developers should
|
||||||
# only fix API breaks and may add some TODOs.
|
# only fix API breaks and may add some TODOs.
|
||||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.9.16"
|
matrix_sdk = "org.matrix.rustcomponents:sdk-android:25.9.18"
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
|
coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" }
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,10 @@ sealed interface NotificationContent {
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data class CallNotify(
|
data class RtcNotification(
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val type: CallNotifyType,
|
val type: RtcNotificationType,
|
||||||
|
val expirationTimestampMillis: Long
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data object CallHangup : MessageLike
|
data object CallHangup : MessageLike
|
||||||
|
|
@ -118,7 +119,7 @@ sealed interface NotificationContent {
|
||||||
) : NotificationContent
|
) : NotificationContent
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CallNotifyType {
|
enum class RtcNotificationType {
|
||||||
RING,
|
RING,
|
||||||
NOTIFY
|
NOTIFY
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ enum class MessageEventType {
|
||||||
CALL_INVITE,
|
CALL_INVITE,
|
||||||
CALL_HANGUP,
|
CALL_HANGUP,
|
||||||
CALL_CANDIDATES,
|
CALL_CANDIDATES,
|
||||||
CALL_NOTIFY,
|
RTC_NOTIFICATION,
|
||||||
KEY_VERIFICATION_READY,
|
KEY_VERIFICATION_READY,
|
||||||
KEY_VERIFICATION_START,
|
KEY_VERIFICATION_START,
|
||||||
KEY_VERIFICATION_CANCEL,
|
KEY_VERIFICATION_CANCEL,
|
||||||
|
|
|
||||||
|
|
@ -15,5 +15,6 @@ object EventType {
|
||||||
|
|
||||||
// Call Events
|
// Call Events
|
||||||
const val CALL_INVITE = "m.call.invite"
|
const val CALL_INVITE = "m.call.invite"
|
||||||
const val CALL_NOTIFY = "m.call.notify"
|
|
||||||
|
const val RTC_NOTIFICATION = "org.matrix.msc4075.rtc.notification"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.core.extensions.runCatchingExceptions
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
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.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.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.room.member.RoomMemberMapper
|
||||||
import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper
|
import io.element.android.libraries.matrix.impl.timeline.item.event.EventMessageMapper
|
||||||
import org.matrix.rustcomponents.sdk.MessageLikeEventContent
|
import org.matrix.rustcomponents.sdk.MessageLikeEventContent
|
||||||
import org.matrix.rustcomponents.sdk.NotifyType
|
|
||||||
import org.matrix.rustcomponents.sdk.StateEventContent
|
import org.matrix.rustcomponents.sdk.StateEventContent
|
||||||
import org.matrix.rustcomponents.sdk.TimelineEvent
|
import org.matrix.rustcomponents.sdk.TimelineEvent
|
||||||
import org.matrix.rustcomponents.sdk.TimelineEventType
|
import org.matrix.rustcomponents.sdk.TimelineEventType
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
|
import org.matrix.rustcomponents.sdk.RtcNotificationType as SdkRtcNotificationType
|
||||||
|
|
||||||
class TimelineEventToNotificationContentMapper {
|
class TimelineEventToNotificationContentMapper {
|
||||||
fun map(timelineEvent: TimelineEvent): Result<NotificationContent> {
|
fun map(timelineEvent: TimelineEvent): Result<NotificationContent> {
|
||||||
|
|
@ -78,7 +78,11 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
|
||||||
MessageLikeEventContent.CallCandidates -> NotificationContent.MessageLike.CallCandidates
|
MessageLikeEventContent.CallCandidates -> NotificationContent.MessageLike.CallCandidates
|
||||||
MessageLikeEventContent.CallHangup -> NotificationContent.MessageLike.CallHangup
|
MessageLikeEventContent.CallHangup -> NotificationContent.MessageLike.CallHangup
|
||||||
MessageLikeEventContent.CallInvite -> NotificationContent.MessageLike.CallInvite(senderId)
|
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.KeyVerificationAccept -> NotificationContent.MessageLike.KeyVerificationAccept
|
||||||
MessageLikeEventContent.KeyVerificationCancel -> NotificationContent.MessageLike.KeyVerificationCancel
|
MessageLikeEventContent.KeyVerificationCancel -> NotificationContent.MessageLike.KeyVerificationCancel
|
||||||
MessageLikeEventContent.KeyVerificationDone -> NotificationContent.MessageLike.KeyVerificationDone
|
MessageLikeEventContent.KeyVerificationDone -> NotificationContent.MessageLike.KeyVerificationDone
|
||||||
|
|
@ -101,7 +105,7 @@ private fun MessageLikeEventContent.toContent(senderId: UserId): NotificationCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun NotifyType.map(): CallNotifyType = when (this) {
|
private fun SdkRtcNotificationType.map(): RtcNotificationType = when (this) {
|
||||||
NotifyType.NOTIFY -> CallNotifyType.NOTIFY
|
SdkRtcNotificationType.NOTIFICATION -> RtcNotificationType.NOTIFY
|
||||||
NotifyType.RING -> CallNotifyType.RING
|
SdkRtcNotificationType.RING -> RtcNotificationType.RING
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ fun MessageEventType.map(): MessageLikeEventType = when (this) {
|
||||||
MessageEventType.CALL_INVITE -> MessageLikeEventType.CALL_INVITE
|
MessageEventType.CALL_INVITE -> MessageLikeEventType.CALL_INVITE
|
||||||
MessageEventType.CALL_HANGUP -> MessageLikeEventType.CALL_HANGUP
|
MessageEventType.CALL_HANGUP -> MessageLikeEventType.CALL_HANGUP
|
||||||
MessageEventType.CALL_CANDIDATES -> MessageLikeEventType.CALL_CANDIDATES
|
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_READY -> MessageLikeEventType.KEY_VERIFICATION_READY
|
||||||
MessageEventType.KEY_VERIFICATION_START -> MessageLikeEventType.KEY_VERIFICATION_START
|
MessageEventType.KEY_VERIFICATION_START -> MessageLikeEventType.KEY_VERIFICATION_START
|
||||||
MessageEventType.KEY_VERIFICATION_CANCEL -> MessageLikeEventType.KEY_VERIFICATION_CANCEL
|
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_INVITE -> MessageEventType.CALL_INVITE
|
||||||
MessageLikeEventType.CALL_HANGUP -> MessageEventType.CALL_HANGUP
|
MessageLikeEventType.CALL_HANGUP -> MessageEventType.CALL_HANGUP
|
||||||
MessageLikeEventType.CALL_CANDIDATES -> MessageEventType.CALL_CANDIDATES
|
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_READY -> MessageEventType.KEY_VERIFICATION_READY
|
||||||
MessageLikeEventType.KEY_VERIFICATION_START -> MessageEventType.KEY_VERIFICATION_START
|
MessageLikeEventType.KEY_VERIFICATION_START -> MessageEventType.KEY_VERIFICATION_START
|
||||||
MessageLikeEventType.KEY_VERIFICATION_CANCEL -> MessageEventType.KEY_VERIFICATION_CANCEL
|
MessageLikeEventType.KEY_VERIFICATION_CANCEL -> MessageEventType.KEY_VERIFICATION_CANCEL
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ class TimelineEventContentMapper(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is TimelineItemContent.CallInvite -> LegacyCallInviteContent
|
is TimelineItemContent.CallInvite -> LegacyCallInviteContent
|
||||||
is TimelineItemContent.CallNotify -> CallNotifyContent
|
is TimelineItemContent.RtcNotification -> CallNotifyContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,4 +43,5 @@ fun aRustSpaceRoom(
|
||||||
childrenCount = childrenCount,
|
childrenCount = childrenCount,
|
||||||
state = state,
|
state = state,
|
||||||
heroes = heroes,
|
heroes = heroes,
|
||||||
|
via = emptyList()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class MessageEventTypeKtTest {
|
||||||
assertThat(MessageLikeEventType.CALL_INVITE.map()).isEqualTo(MessageEventType.CALL_INVITE)
|
assertThat(MessageLikeEventType.CALL_INVITE.map()).isEqualTo(MessageEventType.CALL_INVITE)
|
||||||
assertThat(MessageLikeEventType.CALL_HANGUP.map()).isEqualTo(MessageEventType.CALL_HANGUP)
|
assertThat(MessageLikeEventType.CALL_HANGUP.map()).isEqualTo(MessageEventType.CALL_HANGUP)
|
||||||
assertThat(MessageLikeEventType.CALL_CANDIDATES.map()).isEqualTo(MessageEventType.CALL_CANDIDATES)
|
assertThat(MessageLikeEventType.CALL_CANDIDATES.map()).isEqualTo(MessageEventType.CALL_CANDIDATES)
|
||||||
assertThat(MessageLikeEventType.CALL_NOTIFY.map()).isEqualTo(MessageEventType.CALL_NOTIFY)
|
assertThat(MessageLikeEventType.RTC_NOTIFICATION.map()).isEqualTo(MessageEventType.RTC_NOTIFICATION)
|
||||||
assertThat(MessageLikeEventType.KEY_VERIFICATION_READY.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_READY)
|
assertThat(MessageLikeEventType.KEY_VERIFICATION_READY.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_READY)
|
||||||
assertThat(MessageLikeEventType.KEY_VERIFICATION_START.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_START)
|
assertThat(MessageLikeEventType.KEY_VERIFICATION_START.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_START)
|
||||||
assertThat(MessageLikeEventType.KEY_VERIFICATION_CANCEL.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_CANCEL)
|
assertThat(MessageLikeEventType.KEY_VERIFICATION_CANCEL.map()).isEqualTo(MessageEventType.KEY_VERIFICATION_CANCEL)
|
||||||
|
|
@ -46,7 +46,7 @@ class MessageEventTypeKtTest {
|
||||||
assertThat(MessageEventType.CALL_INVITE.map()).isEqualTo(MessageLikeEventType.CALL_INVITE)
|
assertThat(MessageEventType.CALL_INVITE.map()).isEqualTo(MessageLikeEventType.CALL_INVITE)
|
||||||
assertThat(MessageEventType.CALL_HANGUP.map()).isEqualTo(MessageLikeEventType.CALL_HANGUP)
|
assertThat(MessageEventType.CALL_HANGUP.map()).isEqualTo(MessageLikeEventType.CALL_HANGUP)
|
||||||
assertThat(MessageEventType.CALL_CANDIDATES.map()).isEqualTo(MessageLikeEventType.CALL_CANDIDATES)
|
assertThat(MessageEventType.CALL_CANDIDATES.map()).isEqualTo(MessageLikeEventType.CALL_CANDIDATES)
|
||||||
assertThat(MessageEventType.CALL_NOTIFY.map()).isEqualTo(MessageLikeEventType.CALL_NOTIFY)
|
assertThat(MessageEventType.RTC_NOTIFICATION.map()).isEqualTo(MessageLikeEventType.RTC_NOTIFICATION)
|
||||||
assertThat(MessageEventType.KEY_VERIFICATION_READY.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_READY)
|
assertThat(MessageEventType.KEY_VERIFICATION_READY.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_READY)
|
||||||
assertThat(MessageEventType.KEY_VERIFICATION_START.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_START)
|
assertThat(MessageEventType.KEY_VERIFICATION_START.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_START)
|
||||||
assertThat(MessageEventType.KEY_VERIFICATION_CANCEL.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_CANCEL)
|
assertThat(MessageEventType.KEY_VERIFICATION_CANCEL.map()).isEqualTo(MessageLikeEventType.KEY_VERIFICATION_CANCEL)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ package io.element.android.libraries.mediaviewer.impl.gallery
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import app.cash.turbine.ReceiveTurbine
|
import app.cash.turbine.ReceiveTurbine
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
|
||||||
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
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.timeline.Timeline
|
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||||
|
|
@ -29,6 +31,7 @@ import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetSta
|
||||||
import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage
|
import io.element.android.libraries.mediaviewer.impl.model.aMediaItemImage
|
||||||
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions
|
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions
|
||||||
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
|
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
|
||||||
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
|
|
@ -147,8 +150,8 @@ class MediaGalleryPresenterTest {
|
||||||
val presenter = createMediaGalleryPresenter(
|
val presenter = createMediaGalleryPresenter(
|
||||||
room = FakeJoinedRoom(
|
room = FakeJoinedRoom(
|
||||||
baseRoom = FakeBaseRoom(
|
baseRoom = FakeBaseRoom(
|
||||||
sessionId = A_USER_ID,
|
sessionId = A_USER_ID,
|
||||||
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
|
||||||
canRedactOtherResult = { Result.success(canDeleteOther) },
|
canRedactOtherResult = { Result.success(canDeleteOther) },
|
||||||
),
|
),
|
||||||
createTimelineResult = { Result.success(FakeTimeline()) }
|
createTimelineResult = { Result.success(FakeTimeline()) }
|
||||||
|
|
@ -223,23 +226,122 @@ class MediaGalleryPresenterTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - share item`() = runTest {
|
fun `present - share item - item not found`() = runTest {
|
||||||
val presenter = createMediaGalleryPresenter()
|
val presenter = createMediaGalleryPresenter()
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitFirstItem()
|
val initialState = awaitFirstItem()
|
||||||
initialState.eventSink(MediaGalleryEvents.Share(AN_EVENT_ID))
|
initialState.eventSink(MediaGalleryEvents.Share(AN_EVENT_ID))
|
||||||
}
|
}
|
||||||
// TODO Add more test on this part
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - save on disk`() = runTest {
|
fun `present - share item - item found`() = runTest {
|
||||||
|
val mediaGalleryDataSource = FakeMediaGalleryDataSource(
|
||||||
|
startLambda = { },
|
||||||
|
)
|
||||||
|
mediaGalleryDataSource.emitGroupedMediaItems(
|
||||||
|
AsyncData.Success(
|
||||||
|
aGroupedMediaItems(
|
||||||
|
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||||
|
fileItems = emptyList(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val presenter = createMediaGalleryPresenter(
|
||||||
|
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitFirstItem()
|
||||||
|
initialState.eventSink(MediaGalleryEvents.Share(AN_EVENT_ID))
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.snackbarMessage).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - share item - item found - download error`() = runTest {
|
||||||
|
val mediaGalleryDataSource = FakeMediaGalleryDataSource(
|
||||||
|
startLambda = { },
|
||||||
|
)
|
||||||
|
mediaGalleryDataSource.emitGroupedMediaItems(
|
||||||
|
AsyncData.Success(
|
||||||
|
aGroupedMediaItems(
|
||||||
|
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||||
|
fileItems = emptyList(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val presenter = createMediaGalleryPresenter(
|
||||||
|
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||||
|
matrixMediaLoader = FakeMatrixMediaLoader().apply { shouldFail = true },
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitFirstItem()
|
||||||
|
initialState.eventSink(MediaGalleryEvents.Share(AN_EVENT_ID))
|
||||||
|
skipItems(1)
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.snackbarMessage).isInstanceOf(SnackbarMessage::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - save on disk - item not found`() = runTest {
|
||||||
val presenter = createMediaGalleryPresenter()
|
val presenter = createMediaGalleryPresenter()
|
||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = awaitFirstItem()
|
val initialState = awaitFirstItem()
|
||||||
initialState.eventSink(MediaGalleryEvents.SaveOnDisk(AN_EVENT_ID))
|
initialState.eventSink(MediaGalleryEvents.SaveOnDisk(AN_EVENT_ID))
|
||||||
}
|
}
|
||||||
// TODO Add more test on this part
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - save on disk - item found`() = runTest {
|
||||||
|
val mediaGalleryDataSource = FakeMediaGalleryDataSource(
|
||||||
|
startLambda = { },
|
||||||
|
)
|
||||||
|
mediaGalleryDataSource.emitGroupedMediaItems(
|
||||||
|
AsyncData.Success(
|
||||||
|
aGroupedMediaItems(
|
||||||
|
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||||
|
fileItems = emptyList(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val presenter = createMediaGalleryPresenter(
|
||||||
|
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitFirstItem()
|
||||||
|
initialState.eventSink(MediaGalleryEvents.SaveOnDisk(AN_EVENT_ID))
|
||||||
|
skipItems(1)
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.snackbarMessage?.messageResId).isEqualTo(CommonStrings.common_file_saved_on_disk_android)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - save on disk - item found - download error`() = runTest {
|
||||||
|
val mediaGalleryDataSource = FakeMediaGalleryDataSource(
|
||||||
|
startLambda = { },
|
||||||
|
)
|
||||||
|
mediaGalleryDataSource.emitGroupedMediaItems(
|
||||||
|
AsyncData.Success(
|
||||||
|
aGroupedMediaItems(
|
||||||
|
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||||
|
fileItems = emptyList(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val presenter = createMediaGalleryPresenter(
|
||||||
|
mediaGalleryDataSource = mediaGalleryDataSource,
|
||||||
|
matrixMediaLoader = FakeMatrixMediaLoader().apply { shouldFail = true },
|
||||||
|
)
|
||||||
|
presenter.test {
|
||||||
|
val initialState = awaitFirstItem()
|
||||||
|
initialState.eventSink(MediaGalleryEvents.SaveOnDisk(AN_EVENT_ID))
|
||||||
|
skipItems(1)
|
||||||
|
val finalState = awaitItem()
|
||||||
|
assertThat(finalState.snackbarMessage).isInstanceOf(SnackbarMessage::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ 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.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
||||||
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.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.notification.RtcNotificationType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||||
|
|
@ -58,13 +58,13 @@ class DefaultCallNotificationEventResolver(
|
||||||
notificationData: NotificationData,
|
notificationData: NotificationData,
|
||||||
forceNotify: Boolean
|
forceNotify: Boolean
|
||||||
): Result<NotifiableEvent> = runCatchingExceptions {
|
): Result<NotifiableEvent> = runCatchingExceptions {
|
||||||
val content = notificationData.content as? NotificationContent.MessageLike.CallNotify
|
val content = notificationData.content as? NotificationContent.MessageLike.RtcNotification
|
||||||
?: throw NotificationResolverException.UnknownError("content is not a call notify")
|
?: throw NotificationResolverException.UnknownError("content is not a call notify")
|
||||||
|
|
||||||
val previousRingingCallStatus = appForegroundStateService.hasRingingCall.value
|
val previousRingingCallStatus = appForegroundStateService.hasRingingCall.value
|
||||||
// We need the sync service working to get the updated room info
|
// We need the sync service working to get the updated room info
|
||||||
val isRoomCallActive = runCatchingExceptions {
|
val isRoomCallActive = runCatchingExceptions {
|
||||||
if (content.type == CallNotifyType.RING) {
|
if (content.type == RtcNotificationType.RING) {
|
||||||
appForegroundStateService.updateHasRingingCall(true)
|
appForegroundStateService.updateHasRingingCall(true)
|
||||||
|
|
||||||
val client = clientProvider.getOrRestore(
|
val client = clientProvider.getOrRestore(
|
||||||
|
|
@ -90,7 +90,7 @@ class DefaultCallNotificationEventResolver(
|
||||||
}.getOrDefault(false)
|
}.getOrDefault(false)
|
||||||
|
|
||||||
notificationData.run {
|
notificationData.run {
|
||||||
if (content.type == CallNotifyType.RING && isRoomCallActive && !forceNotify) {
|
if (content.type == RtcNotificationType.RING && isRoomCallActive && !forceNotify) {
|
||||||
NotifiableRingingCallEvent(
|
NotifiableRingingCallEvent(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
@ -104,9 +104,10 @@ class DefaultCallNotificationEventResolver(
|
||||||
description = stringProvider.getString(R.string.notification_incoming_call),
|
description = stringProvider.getString(R.string.notification_incoming_call),
|
||||||
senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId),
|
senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.senderId),
|
||||||
roomAvatarUrl = roomAvatarUrl,
|
roomAvatarUrl = roomAvatarUrl,
|
||||||
callNotifyType = content.type,
|
rtcNotificationType = content.type,
|
||||||
senderId = content.senderId,
|
senderId = content.senderId,
|
||||||
senderAvatarUrl = senderAvatarUrl,
|
senderAvatarUrl = senderAvatarUrl,
|
||||||
|
expirationTimestamp = content.expirationTimestampMillis,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Event $eventId is call notify but should not ring: $isRoomCallActive, notify: ${content.type}")
|
Timber.d("Event $eventId is call notify but should not ring: $isRoomCallActive, notify: ${content.type}")
|
||||||
|
|
@ -124,7 +125,7 @@ class DefaultCallNotificationEventResolver(
|
||||||
roomIsDm = isDm,
|
roomIsDm = isDm,
|
||||||
roomAvatarPath = roomAvatarUrl,
|
roomAvatarPath = roomAvatarUrl,
|
||||||
senderAvatarPath = senderAvatarUrl,
|
senderAvatarPath = senderAvatarUrl,
|
||||||
type = EventType.CALL_NOTIFY,
|
type = EventType.RTC_NOTIFICATION,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ class DefaultNotifiableEventResolver(
|
||||||
)
|
)
|
||||||
ResolvedPushEvent.Event(notifiableMessageEvent)
|
ResolvedPushEvent.Event(notifiableMessageEvent)
|
||||||
}
|
}
|
||||||
is NotificationContent.MessageLike.CallNotify -> {
|
is NotificationContent.MessageLike.RtcNotification -> {
|
||||||
val notifiableEvent = callNotificationEventResolver.resolveEvent(userId, this).getOrThrow()
|
val notifiableEvent = callNotificationEventResolver.resolveEvent(userId, this).getOrThrow()
|
||||||
ResolvedPushEvent.Event(notifiableEvent)
|
ResolvedPushEvent.Event(notifiableEvent)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ class DefaultNotificationCreator(
|
||||||
|
|
||||||
val smallIcon = CommonDrawables.ic_notification
|
val smallIcon = CommonDrawables.ic_notification
|
||||||
|
|
||||||
val containsMissedCall = events.any { it.type == EventType.CALL_NOTIFY }
|
val containsMissedCall = events.any { it.type == EventType.RTC_NOTIFICATION }
|
||||||
val channelId = if (containsMissedCall) {
|
val channelId = if (containsMissedCall) {
|
||||||
notificationChannels.getChannelForIncomingCall(false)
|
notificationChannels.getChannelForIncomingCall(false)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -213,8 +213,8 @@ class DefaultNotificationCreator(
|
||||||
}
|
}
|
||||||
setDeleteIntent(pendingIntentFactory.createDismissRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId))
|
setDeleteIntent(pendingIntentFactory.createDismissRoomPendingIntent(roomInfo.sessionId, roomInfo.roomId))
|
||||||
|
|
||||||
// If any of the events are of call notify type it means a missed call, set the category to the right value
|
// If any of the events are of rtc notification type it means a missed call, set the category to the right value
|
||||||
if (events.any { it.type == EventType.CALL_NOTIFY }) {
|
if (events.any { it.type == EventType.RTC_NOTIFICATION }) {
|
||||||
setCategory(NotificationCompat.CATEGORY_MISSED_CALL)
|
setCategory(NotificationCompat.CATEGORY_MISSED_CALL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
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.core.UserId
|
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.RtcNotificationType
|
||||||
|
|
||||||
data class NotifiableRingingCallEvent(
|
data class NotifiableRingingCallEvent(
|
||||||
override val sessionId: SessionId,
|
override val sessionId: SessionId,
|
||||||
|
|
@ -27,6 +27,7 @@ data class NotifiableRingingCallEvent(
|
||||||
val senderDisambiguatedDisplayName: String?,
|
val senderDisambiguatedDisplayName: String?,
|
||||||
val senderAvatarUrl: String?,
|
val senderAvatarUrl: String?,
|
||||||
val roomAvatarUrl: String? = null,
|
val roomAvatarUrl: String? = null,
|
||||||
val callNotifyType: CallNotifyType,
|
val rtcNotificationType: RtcNotificationType,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
|
val expirationTimestamp: Long,
|
||||||
) : NotifiableEvent
|
) : NotifiableEvent
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,7 @@ class DefaultPushHandler(
|
||||||
senderName = notifiableEvent.senderDisambiguatedDisplayName,
|
senderName = notifiableEvent.senderDisambiguatedDisplayName,
|
||||||
avatarUrl = notifiableEvent.roomAvatarUrl,
|
avatarUrl = notifiableEvent.roomAvatarUrl,
|
||||||
timestamp = notifiableEvent.timestamp,
|
timestamp = notifiableEvent.timestamp,
|
||||||
|
expirationTimestamp = notifiableEvent.expirationTimestamp,
|
||||||
notificationChannelId = notificationChannels.getChannelForIncomingCall(ring = true),
|
notificationChannelId = notificationChannels.getChannelForIncomingCall(ring = true),
|
||||||
textContent = notifiableEvent.description,
|
textContent = notifiableEvent.description,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
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.NotificationContent
|
||||||
|
import io.element.android.libraries.matrix.api.notification.RtcNotificationType
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||||
|
|
@ -61,11 +61,12 @@ class DefaultCallNotificationEventResolverTest {
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
senderDisambiguatedDisplayName = A_USER_NAME_2,
|
senderDisambiguatedDisplayName = A_USER_NAME_2,
|
||||||
senderAvatarUrl = null,
|
senderAvatarUrl = null,
|
||||||
callNotifyType = CallNotifyType.RING,
|
expirationTimestamp = 1567L,
|
||||||
|
rtcNotificationType = RtcNotificationType.RING,
|
||||||
)
|
)
|
||||||
|
|
||||||
val notificationData = aNotificationData(
|
val notificationData = aNotificationData(
|
||||||
content = NotificationContent.MessageLike.CallNotify(A_USER_ID_2, CallNotifyType.RING)
|
content = NotificationContent.MessageLike.RtcNotification(A_USER_ID_2, RtcNotificationType.RING, 1567)
|
||||||
)
|
)
|
||||||
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
||||||
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
||||||
|
|
@ -105,11 +106,11 @@ class DefaultCallNotificationEventResolverTest {
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
imageMimeType = null,
|
imageMimeType = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
type = "m.call.notify",
|
type = "org.matrix.msc4075.rtc.notification",
|
||||||
)
|
)
|
||||||
|
|
||||||
val notificationData = aNotificationData(
|
val notificationData = aNotificationData(
|
||||||
content = NotificationContent.MessageLike.CallNotify(A_USER_ID_2, CallNotifyType.NOTIFY)
|
content = NotificationContent.MessageLike.RtcNotification(A_USER_ID_2, RtcNotificationType.NOTIFY, 0)
|
||||||
)
|
)
|
||||||
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
||||||
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
||||||
|
|
@ -149,11 +150,11 @@ class DefaultCallNotificationEventResolverTest {
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
imageMimeType = null,
|
imageMimeType = null,
|
||||||
threadId = null,
|
threadId = null,
|
||||||
type = "m.call.notify",
|
type = "org.matrix.msc4075.rtc.notification",
|
||||||
)
|
)
|
||||||
|
|
||||||
val notificationData = aNotificationData(
|
val notificationData = aNotificationData(
|
||||||
content = NotificationContent.MessageLike.CallNotify(A_USER_ID_2, CallNotifyType.RING)
|
content = NotificationContent.MessageLike.RtcNotification(A_USER_ID_2, RtcNotificationType.RING, 0)
|
||||||
)
|
)
|
||||||
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
val result = resolver.resolveEvent(A_SESSION_ID, notificationData)
|
||||||
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
assertThat(result.getOrNull()).isEqualTo(expectedResult)
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
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.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.notification.RtcNotificationType
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
import io.element.android.libraries.matrix.api.room.RoomMembershipState
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
|
||||||
|
|
@ -693,9 +693,10 @@ class DefaultNotifiableEventResolverTest {
|
||||||
notificationResult = Result.success(
|
notificationResult = Result.success(
|
||||||
mapOf(
|
mapOf(
|
||||||
AN_EVENT_ID to Result.success(aNotificationData(
|
AN_EVENT_ID to Result.success(aNotificationData(
|
||||||
content = NotificationContent.MessageLike.CallNotify(
|
content = NotificationContent.MessageLike.RtcNotification(
|
||||||
A_USER_ID_2,
|
A_USER_ID_2,
|
||||||
CallNotifyType.NOTIFY
|
RtcNotificationType.NOTIFY,
|
||||||
|
0
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
@ -719,7 +720,7 @@ class DefaultNotifiableEventResolverTest {
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
imageUriString = null,
|
imageUriString = null,
|
||||||
imageMimeType = null,
|
imageMimeType = null,
|
||||||
type = EventType.CALL_NOTIFY,
|
type = EventType.RTC_NOTIFICATION,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
callNotificationEventResolver.resolveEventLambda = { _, _, _ -> Result.success(expectedResult.notifiableEvent) }
|
callNotificationEventResolver.resolveEventLambda = { _, _, _ -> Result.success(expectedResult.notifiableEvent) }
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ 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.core.ThreadId
|
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.CallNotifyType
|
import io.element.android.libraries.matrix.api.notification.RtcNotificationType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
|
@ -119,8 +119,9 @@ fun aNotifiableCallEvent(
|
||||||
senderName: String? = null,
|
senderName: String? = null,
|
||||||
roomAvatarUrl: String? = AN_AVATAR_URL,
|
roomAvatarUrl: String? = AN_AVATAR_URL,
|
||||||
senderAvatarUrl: String? = AN_AVATAR_URL,
|
senderAvatarUrl: String? = AN_AVATAR_URL,
|
||||||
callNotifyType: CallNotifyType = CallNotifyType.NOTIFY,
|
rtcNotificationType: RtcNotificationType = RtcNotificationType.NOTIFY,
|
||||||
timestamp: Long = 0L,
|
timestamp: Long = 0L,
|
||||||
|
expirationTimestamp: Long = 0L,
|
||||||
) = NotifiableRingingCallEvent(
|
) = NotifiableRingingCallEvent(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
eventId = eventId,
|
eventId = eventId,
|
||||||
|
|
@ -129,6 +130,7 @@ fun aNotifiableCallEvent(
|
||||||
editedEventId = null,
|
editedEventId = null,
|
||||||
description = "description",
|
description = "description",
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
|
expirationTimestamp = expirationTimestamp,
|
||||||
canBeReplaced = false,
|
canBeReplaced = false,
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
|
|
@ -136,5 +138,5 @@ fun aNotifiableCallEvent(
|
||||||
senderId = senderId,
|
senderId = senderId,
|
||||||
roomAvatarUrl = roomAvatarUrl,
|
roomAvatarUrl = roomAvatarUrl,
|
||||||
senderAvatarUrl = senderAvatarUrl,
|
senderAvatarUrl = senderAvatarUrl,
|
||||||
callNotifyType = callNotifyType,
|
rtcNotificationType = rtcNotificationType,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ 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.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
import io.element.android.libraries.matrix.api.exception.NotificationResolverException
|
||||||
import io.element.android.libraries.matrix.api.notification.CallNotifyType
|
import io.element.android.libraries.matrix.api.notification.RtcNotificationType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
||||||
|
|
@ -388,7 +388,7 @@ class DefaultPushHandlerTest {
|
||||||
mapOf(
|
mapOf(
|
||||||
request to Result.success(
|
request to Result.success(
|
||||||
ResolvedPushEvent.Event(
|
ResolvedPushEvent.Event(
|
||||||
aNotifiableCallEvent(callNotifyType = CallNotifyType.RING, timestamp = Instant.now().toEpochMilli())
|
aNotifiableCallEvent(rtcNotificationType = RtcNotificationType.RING, timestamp = Instant.now().toEpochMilli())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -440,7 +440,7 @@ class DefaultPushHandlerTest {
|
||||||
onNotifiableEventsReceived = onNotifiableEventsReceived,
|
onNotifiableEventsReceived = onNotifiableEventsReceived,
|
||||||
notifiableEventsResult = { _, _ ->
|
notifiableEventsResult = { _, _ ->
|
||||||
val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO)
|
val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO)
|
||||||
Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent(type = EventType.CALL_NOTIFY)))))
|
Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableMessageEvent(type = EventType.RTC_NOTIFICATION)))))
|
||||||
},
|
},
|
||||||
incrementPushCounterResult = {},
|
incrementPushCounterResult = {},
|
||||||
pushClientSecret = FakePushClientSecret(
|
pushClientSecret = FakePushClientSecret(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue