Merge branch 'develop' into fix/crash-on-nightly-incorrect-di-cast

This commit is contained in:
Jorge Martin Espinosa 2025-12-22 16:04:25 +01:00 committed by GitHub
commit 55185b540d
11 changed files with 119 additions and 107 deletions

4
.idea/kotlinc.xml generated
View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="2.2.20" /> <option name="version" value="2.3.0" />
</component> </component>
</project> </project>

View file

@ -177,8 +177,8 @@ class DefaultActiveCallManager(
suspend fun incomingCallTimedOut(displayMissedCallNotification: Boolean) = mutex.withLock { suspend fun incomingCallTimedOut(displayMissedCallNotification: Boolean) = mutex.withLock {
Timber.tag(tag).d("Incoming call timed out") Timber.tag(tag).d("Incoming call timed out")
val previousActiveCall = activeCall.value ?: return val previousActiveCall = activeCall.value ?: return@withLock
val notificationData = (previousActiveCall.callState as? CallState.Ringing)?.notificationData ?: return val notificationData = (previousActiveCall.callState as? CallState.Ringing)?.notificationData ?: return@withLock
activeCall.value = null activeCall.value = null
if (activeWakeLock?.isHeld == true) { if (activeWakeLock?.isHeld == true) {
Timber.tag(tag).d("Releasing partial wakelock after timeout") Timber.tag(tag).d("Releasing partial wakelock after timeout")
@ -196,11 +196,11 @@ class DefaultActiveCallManager(
Timber.tag(tag).d("Hung up call: $callType") Timber.tag(tag).d("Hung up call: $callType")
val currentActiveCall = activeCall.value ?: run { val currentActiveCall = activeCall.value ?: run {
Timber.tag(tag).w("No active call, ignoring hang up") Timber.tag(tag).w("No active call, ignoring hang up")
return return@withLock
} }
if (currentActiveCall.callType != callType) { if (currentActiveCall.callType != callType) {
Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring") Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring")
return return@withLock
} }
if (currentActiveCall.callState is CallState.Ringing) { if (currentActiveCall.callState is CallState.Ringing) {
// Decline the call // Decline the call

View file

@ -51,15 +51,10 @@ import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.unmockkAll
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -76,17 +71,6 @@ class ConfigureRoomPresenterTest {
@get:Rule @get:Rule
val warmUpRule = WarmUpRule() val warmUpRule = WarmUpRule()
@Before
fun setup() {
mockkStatic(File::readBytes)
every { any<File>().readBytes() } returns byteArrayOf()
}
@After
fun tearDown() {
unmockkAll()
}
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val presenter = createConfigureRoomPresenter() val presenter = createConfigureRoomPresenter()
@ -261,20 +245,25 @@ class ConfigureRoomPresenterTest {
val initialState = initialState() val initialState = initialState()
dataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY)) dataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY))
skipItems(1) skipItems(1)
mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk()))) val file = File.createTempFile("test", "jpg")
matrixClient.givenUploadMediaResult(Result.failure(AN_EXCEPTION)) try {
mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(file, mockk(), mockk())))
matrixClient.givenUploadMediaResult(Result.failure(AN_EXCEPTION))
initialState.eventSink(ConfigureRoomEvents.CreateRoom) initialState.eventSink(ConfigureRoomEvents.CreateRoom)
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
val stateAfterCreateRoom = awaitItem() val stateAfterCreateRoom = awaitItem()
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java) assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
assertThat(analyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty() assertThat(analyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
matrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL)) matrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL))
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom) stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom)
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Success::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Success::class.java)
} finally {
file.delete()
}
} }
} }

View file

@ -394,9 +394,8 @@ class TimelinePresenter(
newMostRecentItemId != prevMostRecentItemIdValue newMostRecentItemId != prevMostRecentItemIdValue
if (hasNewEvent) { if (hasNewEvent) {
val newMostRecentEvent = newMostRecentItem
// Scroll to bottom if the new event is from me, even if sent from another device // Scroll to bottom if the new event is from me, even if sent from another device
val fromMe = newMostRecentEvent?.isMine == true val fromMe = newMostRecentItem.isMine
newEventState.value = if (fromMe) { newEventState.value = if (fromMe) {
NewEventState.FromMe NewEventState.FromMe
} else { } else {

View file

@ -56,8 +56,6 @@ class EditUserProfilePresenterTest {
private val userAvatarUri: Uri = mockk() private val userAvatarUri: Uri = mockk()
private val anotherAvatarUri: Uri = mockk() private val anotherAvatarUri: Uri = mockk()
private val fakeFileContents = ByteArray(2)
@Before @Before
fun setup() { fun setup() {
fakePickerProvider = FakePickerProvider() fakePickerProvider = FakePickerProvider()
@ -397,7 +395,7 @@ class EditUserProfilePresenterTest {
fun `present - save processes and sets avatar when processor returns successfully`() = runTest { fun `present - save processes and sets avatar when processor returns successfully`() = runTest {
val matrixClient = FakeMatrixClient() val matrixClient = FakeMatrixClient()
val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL) val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL)
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val presenter = createEditUserProfilePresenter( val presenter = createEditUserProfilePresenter(
matrixClient = matrixClient, matrixClient = matrixClient,
matrixUser = user, matrixUser = user,
@ -405,12 +403,16 @@ class EditUserProfilePresenterTest {
deleteLambda = { assertThat(it).isEqualTo(userAvatarUri) } deleteLambda = { assertThat(it).isEqualTo(userAvatarUri) }
), ),
) )
presenter.test { try {
val initialState = awaitItem() presenter.test {
initialState.eventSink(EditUserProfileEvent.HandleAvatarAction(AvatarAction.ChoosePhoto)) val initialState = awaitItem()
initialState.eventSink(EditUserProfileEvent.Save) initialState.eventSink(EditUserProfileEvent.HandleAvatarAction(AvatarAction.ChoosePhoto))
consumeItemsUntilPredicate { matrixClient.uploadAvatarCalled } initialState.eventSink(EditUserProfileEvent.Save)
assertThat(matrixClient.uploadAvatarCalled).isTrue() consumeItemsUntilPredicate { matrixClient.uploadAvatarCalled }
assertThat(matrixClient.uploadAvatarCalled).isTrue()
}
} finally {
tmpFile.delete()
} }
} }
@ -457,30 +459,38 @@ class EditUserProfilePresenterTest {
@Test @Test
fun `present - sets save action to failure if setting avatar fails`() = runTest { fun `present - sets save action to failure if setting avatar fails`() = runTest {
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL) val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL)
val matrixClient = FakeMatrixClient().apply { val matrixClient = FakeMatrixClient().apply {
givenUploadAvatarResult(Result.failure(RuntimeException("!"))) givenUploadAvatarResult(Result.failure(RuntimeException("!")))
} }
saveAndAssertFailure(user, matrixClient, EditUserProfileEvent.HandleAvatarAction(AvatarAction.ChoosePhoto)) try {
saveAndAssertFailure(user, matrixClient, EditUserProfileEvent.HandleAvatarAction(AvatarAction.ChoosePhoto))
} finally {
tmpFile.delete()
}
} }
@Test @Test
fun `present - CloseDialog resets save action state`() = runTest { fun `present - CloseDialog resets save action state`() = runTest {
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL) val user = aMatrixUser(id = A_USER_ID.value, displayName = "Name", avatarUrl = AN_AVATAR_URL)
val matrixClient = FakeMatrixClient().apply { val matrixClient = FakeMatrixClient().apply {
givenSetDisplayNameResult(Result.failure(RuntimeException("!"))) givenSetDisplayNameResult(Result.failure(RuntimeException("!")))
} }
val presenter = createEditUserProfilePresenter(matrixUser = user, matrixClient = matrixClient) val presenter = createEditUserProfilePresenter(matrixUser = user, matrixClient = matrixClient)
presenter.test { try {
val initialState = awaitItem() presenter.test {
initialState.eventSink(EditUserProfileEvent.UpdateDisplayName("foo")) val initialState = awaitItem()
initialState.eventSink(EditUserProfileEvent.Save) initialState.eventSink(EditUserProfileEvent.UpdateDisplayName("foo"))
skipItems(2) initialState.eventSink(EditUserProfileEvent.Save)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java) skipItems(2)
initialState.eventSink(EditUserProfileEvent.CloseDialog) assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Uninitialized::class.java) initialState.eventSink(EditUserProfileEvent.CloseDialog)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
} finally {
tmpFile.delete()
} }
} }
@ -502,20 +512,18 @@ class EditUserProfilePresenterTest {
} }
} }
private fun givenPickerReturnsFile() { private fun givenPickerReturnsFile(): File {
mockkStatic(File::readBytes) val file = File.createTempFile("test", "jpg")
val processedFile: File = mockk {
every { readBytes() } returns fakeFileContents
}
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult( fakeMediaPreProcessor.givenResult(
Result.success( Result.success(
MediaUploadInfo.AnyFile( MediaUploadInfo.AnyFile(
file = processedFile, file = file,
fileInfo = mockk(), fileInfo = mockk(),
) )
) )
) )
return file
} }
companion object { companion object {

View file

@ -323,7 +323,7 @@ class DefaultBugReporterTest {
while (part != null) { while (part != null) {
part.headers["Content-Disposition"]?.let { contentDisposition -> part.headers["Content-Disposition"]?.let { contentDisposition ->
regex.find(contentDisposition)?.groupValues?.get(1)?.let { name -> regex.find(contentDisposition)?.groupValues?.get(1)?.let { name ->
foundValues.put(name, part!!.body.readUtf8()) foundValues.put(name, part.body.readUtf8())
} }
} }
part = multipartReader.nextPart() part = multipartReader.nextPart()

View file

@ -35,6 +35,7 @@ import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.fake.FakeTemporaryUriDeleter import io.element.android.tests.testutils.fake.FakeTemporaryUriDeleter
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.matching
import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import io.mockk.every import io.mockk.every
@ -528,22 +529,29 @@ class RoomDetailsEditPresenterTest {
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
updateAvatarResult = updateAvatarResult, updateAvatarResult = updateAvatarResult,
) )
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
room = room, room = room,
temporaryUriDeleter = FakeTemporaryUriDeleter(deleteCallback), temporaryUriDeleter = FakeTemporaryUriDeleter(deleteCallback),
) )
presenter.test { try {
val initialState = awaitItem() presenter.test {
initialState.eventSink(RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto)) val initialState = awaitItem()
initialState.eventSink(RoomDetailsEditEvent.Save) initialState.eventSink(RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto))
skipItems(4) initialState.eventSink(RoomDetailsEditEvent.Save)
updateAvatarResult.assertions().isCalledOnce().with(value(MimeTypes.Jpeg), value(fakeFileContents)) skipItems(4)
deleteCallback.assertions().isCalledExactly(2).withSequence( updateAvatarResult.assertions().isCalledOnce().with(
listOf(value(null)), value(MimeTypes.Jpeg),
listOf(value(roomAvatarUri)), matching<ByteArray> { it.contentEquals(fakeFileContents) }
) )
deleteCallback.assertions().isCalledExactly(2).withSequence(
listOf(value(null)),
listOf(value(roomAvatarUri)),
)
}
} finally {
tmpFile.delete()
} }
} }
@ -605,19 +613,23 @@ class RoomDetailsEditPresenterTest {
@Test @Test
fun `present - sets save action to failure if setting avatar fails`() = runTest { fun `present - sets save action to failure if setting avatar fails`() = runTest {
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val room = aJoinedRoom( val room = aJoinedRoom(
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
updateAvatarResult = { _, _ -> Result.failure(RuntimeException("!")) }, updateAvatarResult = { _, _ -> Result.failure(RuntimeException("!")) },
) )
saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto), deleteCallbackNumberOfInvocation = 2) try {
saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto), deleteCallbackNumberOfInvocation = 2)
} finally {
tmpFile.delete()
}
} }
@Test @Test
fun `present - CancelSaveChanges resets save action state`() = runTest { fun `present - CancelSaveChanges resets save action state`() = runTest {
givenPickerReturnsFile() val tmpFile = givenPickerReturnsFile()
val room = aJoinedRoom( val room = aJoinedRoom(
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
@ -629,14 +641,18 @@ class RoomDetailsEditPresenterTest {
room = room, room = room,
temporaryUriDeleter = FakeTemporaryUriDeleter(deleteCallback), temporaryUriDeleter = FakeTemporaryUriDeleter(deleteCallback),
) )
presenter.test { try {
val initialState = awaitItem() presenter.test {
initialState.eventSink(RoomDetailsEditEvent.UpdateRoomTopic("foo")) val initialState = awaitItem()
initialState.eventSink(RoomDetailsEditEvent.Save) initialState.eventSink(RoomDetailsEditEvent.UpdateRoomTopic("foo"))
skipItems(3) initialState.eventSink(RoomDetailsEditEvent.Save)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java) skipItems(3)
initialState.eventSink(RoomDetailsEditEvent.CloseDialog) assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Failure::class.java)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Uninitialized::class.java) initialState.eventSink(RoomDetailsEditEvent.CloseDialog)
assertThat(awaitItem().saveAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
} finally {
tmpFile.delete()
} }
} }
@ -736,20 +752,19 @@ class RoomDetailsEditPresenterTest {
} }
} }
private fun givenPickerReturnsFile() { private fun givenPickerReturnsFile(): File {
mockkStatic(File::readBytes) val tmpFile = File.createTempFile("test", "jpg")
val processedFile: File = mockk { tmpFile.writeBytes(fakeFileContents)
every { readBytes() } returns fakeFileContents
}
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult( fakeMediaPreProcessor.givenResult(
Result.success( Result.success(
MediaUploadInfo.AnyFile( MediaUploadInfo.AnyFile(
file = processedFile, file = tmpFile,
fileInfo = mockk(), fileInfo = mockk(),
) )
) )
) )
return tmpFile
} }
private fun aJoinedRoom( private fun aJoinedRoom(

View file

@ -5,9 +5,9 @@
# Project # Project
android_gradle_plugin = "8.13.2" android_gradle_plugin = "8.13.2"
# When updateing this, please also update the version in the file ./idea/kotlinc.xml # When updateing this, please also update the version in the file ./idea/kotlinc.xml
kotlin = "2.2.20" kotlin = "2.3.0"
kotlinpoet = "2.2.0" kotlinpoet = "2.2.0"
ksp = "2.2.20-2.0.4" ksp = "2.3.4"
firebaseAppDistribution = "5.2.0" firebaseAppDistribution = "5.2.0"
# AndroidX # AndroidX
@ -62,7 +62,7 @@ detekt = "1.23.8"
# See https://github.com/pinterest/ktlint/releases/ # See https://github.com/pinterest/ktlint/releases/
ktlint = "1.8.0" ktlint = "1.8.0"
androidx-test-ext-junit = "1.3.0" androidx-test-ext-junit = "1.3.0"
kover = "0.9.2" kover = "0.9.4"
[libraries] [libraries]
# Project # Project

View file

@ -28,7 +28,7 @@ class DiffCacheUpdater<ListItem, CachedItem>(
private val cacheInvalidator: DiffCacheInvalidator<CachedItem> = DefaultDiffCacheInvalidator(), private val cacheInvalidator: DiffCacheInvalidator<CachedItem> = DefaultDiffCacheInvalidator(),
private val areItemsTheSame: (oldItem: ListItem?, newItem: ListItem?) -> Boolean, private val areItemsTheSame: (oldItem: ListItem?, newItem: ListItem?) -> Boolean,
) { ) {
private val lock = Object() private val lock = Any()
private var prevOriginalList: List<ListItem> = emptyList() private var prevOriginalList: List<ListItem> = emptyList()
private val listUpdateCallback = object : ListUpdateCallback { private val listUpdateCallback = object : ListUpdateCallback {

View file

@ -30,6 +30,7 @@ object LinkifyHelper {
@LinkifyCompat.LinkifyMask linkifyMask: Int = Linkify.WEB_URLS or Linkify.PHONE_NUMBERS or Linkify.EMAIL_ADDRESSES, @LinkifyCompat.LinkifyMask linkifyMask: Int = Linkify.WEB_URLS or Linkify.PHONE_NUMBERS or Linkify.EMAIL_ADDRESSES,
): CharSequence { ): CharSequence {
// Convert the text to a Spannable to be able to add URL spans, return the original text if it's not possible (in tests, i.e.) // Convert the text to a Spannable to be able to add URL spans, return the original text if it's not possible (in tests, i.e.)
@Suppress("USELESS_ELVIS")
val spannable = text.toSpannable() ?: return text val spannable = text.toSpannable() ?: return text
// Get all URL spans, as they will be removed by LinkifyCompat.addLinks // Get all URL spans, as they will be removed by LinkifyCompat.addLinks

View file

@ -158,7 +158,7 @@ class FakeTimeline(
imageInfo: ImageInfo, imageInfo: ImageInfo,
body: String?, body: String?,
formattedBody: String?, formattedBody: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<MediaUploadHandler> = { _, _, _, _, _, _ -> ) -> Result<MediaUploadHandler> = { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
@ -169,7 +169,7 @@ class FakeTimeline(
imageInfo: ImageInfo, imageInfo: ImageInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<MediaUploadHandler> = simulateLongTask { ): Result<MediaUploadHandler> = simulateLongTask {
sendImageLambda( sendImageLambda(
file, file,
@ -187,7 +187,7 @@ class FakeTimeline(
videoInfo: VideoInfo, videoInfo: VideoInfo,
body: String?, body: String?,
formattedBody: String?, formattedBody: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<MediaUploadHandler> = { _, _, _, _, _, _ -> ) -> Result<MediaUploadHandler> = { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
@ -198,7 +198,7 @@ class FakeTimeline(
videoInfo: VideoInfo, videoInfo: VideoInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<MediaUploadHandler> = simulateLongTask { ): Result<MediaUploadHandler> = simulateLongTask {
sendVideoLambda( sendVideoLambda(
file, file,
@ -215,7 +215,7 @@ class FakeTimeline(
audioInfo: AudioInfo, audioInfo: AudioInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<MediaUploadHandler> = { _, _, _, _, _ -> ) -> Result<MediaUploadHandler> = { _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
@ -225,7 +225,7 @@ class FakeTimeline(
audioInfo: AudioInfo, audioInfo: AudioInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<MediaUploadHandler> = simulateLongTask { ): Result<MediaUploadHandler> = simulateLongTask {
sendAudioLambda( sendAudioLambda(
file, file,
@ -241,7 +241,7 @@ class FakeTimeline(
fileInfo: FileInfo, fileInfo: FileInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<MediaUploadHandler> = { _, _, _, _, _ -> ) -> Result<MediaUploadHandler> = { _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
@ -251,7 +251,7 @@ class FakeTimeline(
fileInfo: FileInfo, fileInfo: FileInfo,
caption: String?, caption: String?,
formattedCaption: String?, formattedCaption: String?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<MediaUploadHandler> = simulateLongTask { ): Result<MediaUploadHandler> = simulateLongTask {
sendFileLambda( sendFileLambda(
file, file,
@ -266,7 +266,7 @@ class FakeTimeline(
file: File, file: File,
audioInfo: AudioInfo, audioInfo: AudioInfo,
waveform: List<Float>, waveform: List<Float>,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<MediaUploadHandler> = { _, _, _, _ -> ) -> Result<MediaUploadHandler> = { _, _, _, _ ->
Result.success(FakeMediaUploadHandler()) Result.success(FakeMediaUploadHandler())
} }
@ -275,7 +275,7 @@ class FakeTimeline(
file: File, file: File,
audioInfo: AudioInfo, audioInfo: AudioInfo,
waveform: List<Float>, waveform: List<Float>,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<MediaUploadHandler> = simulateLongTask { ): Result<MediaUploadHandler> = simulateLongTask {
sendVoiceMessageLambda( sendVoiceMessageLambda(
file, file,
@ -291,7 +291,7 @@ class FakeTimeline(
description: String?, description: String?,
zoomLevel: Int?, zoomLevel: Int?,
assetType: AssetType?, assetType: AssetType?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
) -> Result<Unit> = { _, _, _, _, _, _ -> ) -> Result<Unit> = { _, _, _, _, _, _ ->
lambdaError() lambdaError()
} }
@ -302,7 +302,7 @@ class FakeTimeline(
description: String?, description: String?,
zoomLevel: Int?, zoomLevel: Int?,
assetType: AssetType?, assetType: AssetType?,
inReplyToEventId: EventId??, inReplyToEventId: EventId?,
): Result<Unit> = simulateLongTask { ): Result<Unit> = simulateLongTask {
sendLocationLambda( sendLocationLambda(
body, body,