Fix moar ktlint issues

This commit is contained in:
Benoit Marty 2024-01-11 09:41:14 +01:00 committed by Benoit Marty
parent a831f05f6e
commit 5d086ad82d
528 changed files with 146 additions and 629 deletions

View file

@ -88,9 +88,7 @@ class MessagesFlowNode @AssistedInject constructor(
buildContext = buildContext,
plugins = plugins
) {
sealed interface NavTarget : Parcelable {
@Parcelize
data object Empty : NavTarget

View file

@ -53,7 +53,6 @@ class MessagesNode @AssistedInject constructor(
private val timelineItemPresenterFactories: TimelineItemPresenterFactories,
private val mediaPlayer: MediaPlayer,
) : Node(buildContext, plugins = plugins), MessagesNavigator {
private val presenter = presenterFactory.create(this)
private val callback = plugins<Callback>().firstOrNull()

View file

@ -114,7 +114,6 @@ class MessagesPresenter @AssistedInject constructor(
private val buildMeta: BuildMeta,
private val currentSessionIdHolder: CurrentSessionIdHolder,
) : Presenter<MessagesState> {
private val timelinePresenter = timelinePresenterFactory.create(navigator = navigator)
@AssistedFactory

View file

@ -41,7 +41,6 @@ import javax.inject.Inject
class ActionListPresenter @Inject constructor(
private val preferencesStore: PreferencesStore,
) : Presenter<ActionListState> {
@Composable
override fun present(): ActionListState {
val localCoroutineScope = rememberCoroutineScope()

View file

@ -23,7 +23,6 @@ import kotlinx.parcelize.Parcelize
@Immutable
sealed interface Attachment : Parcelable {
@Parcelize
data class Media(val localMedia: LocalMedia, val compressIfPossible: Boolean) : Attachment
}

View file

@ -36,7 +36,6 @@ class AttachmentsPreviewNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>,
presenterFactory: AttachmentsPreviewPresenter.Factory,
) : Node(buildContext, plugins = plugins) {
data class Inputs(val attachment: Attachment) : NodeInputs
private val inputs: Inputs = inputs()

View file

@ -40,7 +40,6 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
@Assisted private val attachment: Attachment,
private val mediaSender: MediaSender,
) : Presenter<AttachmentsPreviewState> {
@AssistedFactory
interface Factory {
fun create(attachment: Attachment): AttachmentsPreviewPresenter

View file

@ -53,7 +53,6 @@ class ForwardMessagesNode @AssistedInject constructor(
buildContext = buildContext,
plugins = plugins,
) {
@Parcelize
object NavTarget : Parcelable

View file

@ -40,7 +40,6 @@ class ForwardMessagesPresenter @AssistedInject constructor(
private val room: MatrixRoom,
private val matrixCoroutineScope: CoroutineScope,
) : Presenter<ForwardMessagesState> {
private val eventId: EventId = EventId(eventId)
@AssistedFactory

View file

@ -29,7 +29,6 @@ import io.element.android.libraries.textcomposer.model.SuggestionType
* This class is responsible for processing mention suggestions when `@`, `/` or `#` are type in the composer.
*/
object MentionSuggestionsProcessor {
// We don't want to retrieve thousands of members
private const val MAX_BATCH_ITEMS = 100

View file

@ -94,7 +94,6 @@ class MessageComposerPresenter @Inject constructor(
private val currentSessionIdHolder: CurrentSessionIdHolder,
permissionsPresenterFactory: PermissionsPresenter.Factory,
) : Presenter<MessageComposerState> {
private val cameraPermissionPresenter = permissionsPresenterFactory.create(Manifest.permission.CAMERA)
private var pendingEvent: MessageComposerEvents? = null
@ -376,7 +375,8 @@ class MessageComposerPresenter @Inject constructor(
inThread = capturedMode.inThread,
isEditing = capturedMode.isEditing,
isReply = capturedMode.isReply,
messageType = Composer.MessageType.Text, // Set proper type when we'll be sending other types of messages.
// Set proper type when we'll be sending other types of messages.
messageType = Composer.MessageType.Text,
)
)
}

View file

@ -36,7 +36,6 @@ class ReportMessageNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>,
presenterFactory: ReportMessagePresenter.Factory,
) : Node(buildContext, plugins = plugins) {
data class Inputs(
val eventId: EventId,
val senderId: UserId,

View file

@ -44,7 +44,6 @@ class ReportMessagePresenter @AssistedInject constructor(
@Assisted private val inputs: Inputs,
private val snackbarDispatcher: SnackbarDispatcher,
) : Presenter<ReportMessageState> {
data class Inputs(
val eventId: EventId,
val senderId: UserId,

View file

@ -40,14 +40,13 @@ import javax.inject.Inject
@ContributesBinding(SessionScope::class)
@SingleIn(SessionScope::class)
class DefaultHtmlConverterProvider @Inject constructor() : HtmlConverterProvider {
private val htmlConverter: MutableState<HtmlConverter?> = mutableStateOf(null)
@Composable
override fun Update(currentUserId: UserId) {
val isInEditMode = LocalInspectionMode.current
val mentionDetector = remember(isInEditMode) {
if (isInEditMode) { null } else { newMentionDetector() }
if (isInEditMode) null else newMentionDetector()
}
val editorStyle = ElementRichTextEditorStyle.textStyle()

View file

@ -76,7 +76,6 @@ class TimelinePresenter @AssistedInject constructor(
private val sendPollResponseAction: SendPollResponseAction,
private val endPollAction: EndPollAction,
) : Presenter<TimelineState> {
@AssistedFactory
interface Factory {
fun create(navigator: MessagesNavigator): TimelinePresenter

View file

@ -145,7 +145,6 @@ private fun IconContent(
tint = ElementTheme.materialColors.secondary,
modifier = modifier
.size(ADD_EMOJI_SIZE)
)
@Composable

View file

@ -30,7 +30,6 @@ import javax.inject.Inject
class CustomReactionPresenter @Inject constructor(
private val emojibaseProvider: EmojibaseProvider
) : Presenter<CustomReactionState> {
@Composable
override fun present(): CustomReactionState {
val target: MutableState<CustomReactionState.Target> = remember {

View file

@ -26,7 +26,6 @@ data class CustomReactionState(
val eventSink: (CustomReactionEvents) -> Unit,
) {
sealed interface Target {
data object None : Target
data class Loading(val event: TimelineItem.Event) : Target
data class Success(

View file

@ -21,7 +21,6 @@ import io.element.android.emojibasebindings.EmojibaseDatasource
import io.element.android.emojibasebindings.EmojibaseStore
class DefaultEmojibaseProvider(val context: Context) : EmojibaseProvider {
override val emojibaseStore: EmojibaseStore by lazy {
EmojibaseDatasource().load(context)
}

View file

@ -128,7 +128,6 @@ data class ContentAvoidingLayoutData(
* A scope for the [ContentAvoidingLayout].
*/
interface ContentAvoidingLayoutScope {
/**
* It should be called when the content layout changes, so it can update the [ContentAvoidingLayoutData] and measure and layout the content properly.
*/

View file

@ -26,7 +26,6 @@ import io.element.android.libraries.architecture.Presenter
import javax.inject.Inject
class ReadReceiptBottomSheetPresenter @Inject constructor() : Presenter<ReadReceiptBottomSheetState> {
@Composable
override fun present(): ReadReceiptBottomSheetState {
var selectedEvent: TimelineItem.Event? by remember { mutableStateOf(null) }

View file

@ -31,7 +31,6 @@ import javax.inject.Inject
class RetrySendMenuPresenter @Inject constructor(
private val room: MatrixRoom,
) : Presenter<RetrySendMenuState> {
@Composable
override fun present(): RetrySendMenuState {
val coroutineScope = rememberCoroutineScope()

View file

@ -35,7 +35,6 @@ class EventDebugInfoNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
) : Node(buildContext, plugins = plugins) {
data class Inputs(
val eventId: EventId?,
val timelineItemDebugInfo: TimelineItemDebugInfo,

View file

@ -27,7 +27,6 @@ import io.element.android.libraries.androidutils.diff.MutableDiffCache
* This is needed because a timeline item is computed based on the previous and next items.
*/
internal class TimelineItemsCacheInvalidator : DiffCacheInvalidator<TimelineItem> {
private val delegate = DefaultDiffCacheInvalidator<TimelineItem>()
override fun onChanged(position: Int, count: Int, cache: MutableDiffCache<TimelineItem>) {

View file

@ -45,7 +45,6 @@ class TimelineItemContentFactory @Inject constructor(
private val failedToParseMessageFactory: TimelineItemContentFailedToParseMessageFactory,
private val failedToParseStateFactory: TimelineItemContentFailedToParseStateFactory
) {
suspend fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
return when (val itemContent = eventTimelineItem.content) {
is FailedToParseMessageLikeContent -> failedToParseMessageFactory.create(itemContent)

View file

@ -22,7 +22,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParse
import javax.inject.Inject
class TimelineItemContentFailedToParseMessageFactory @Inject constructor() {
fun create(@Suppress("UNUSED_PARAMETER") failedToParseMessageLike: FailedToParseMessageLikeContent): TimelineItemEventContent {
return TimelineItemUnknownContent
}

View file

@ -22,7 +22,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParse
import javax.inject.Inject
class TimelineItemContentFailedToParseStateFactory @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun create(failedToParseState: FailedToParseStateContent): TimelineItemEventContent {
return TimelineItemUnknownContent

View file

@ -68,7 +68,6 @@ class TimelineItemContentMessageFactory @Inject constructor(
private val featureFlagService: FeatureFlagService,
private val htmlConverterProvider: HtmlConverterProvider,
) {
suspend fun create(content: MessageContent, senderDisplayName: String, eventId: EventId?): TimelineItemEventContent {
return when (val messageType = content.type) {
is EmoteMessageType -> {
@ -269,7 +268,7 @@ class TimelineItemContentMessageFactory @Inject constructor(
@Suppress("USELESS_ELVIS")
private fun String.withLinks(): CharSequence? {
/* Note: toSpannable() can return null when running unit tests */
// Note: toSpannable() can return null when running unit tests
val spannable = toSpannable() ?: return null
val addedLinks = LinkifyCompat.addLinks(spannable, Linkify.WEB_URLS or Linkify.PHONE_NUMBERS or Linkify.EMAIL_ADDRESSES)
return spannable.takeIf { addedLinks }

View file

@ -30,7 +30,6 @@ class TimelineItemContentPollFactory @Inject constructor(
private val featureFlagService: FeatureFlagService,
private val pollContentStateFactory: PollContentStateFactory,
) {
suspend fun create(
event: EventTimelineItem,
content: PollContent,

View file

@ -26,7 +26,6 @@ import javax.inject.Inject
class TimelineItemContentProfileChangeFactory @Inject constructor(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
val text = timelineEventFormatter.format(eventTimelineItem)
return TimelineItemProfileChangeContent(text.orEmpty().toString())

View file

@ -22,7 +22,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.RedactedConte
import javax.inject.Inject
class TimelineItemContentRedactedFactory @Inject constructor() {
fun create(@Suppress("UNUSED_PARAMETER") content: RedactedContent): TimelineItemEventContent {
return TimelineItemRedactedContent
}

View file

@ -26,7 +26,6 @@ import javax.inject.Inject
class TimelineItemContentRoomMembershipFactory @Inject constructor(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
val text = timelineEventFormatter.format(eventTimelineItem)
return TimelineItemRoomMembershipContent(text.orEmpty().toString())

View file

@ -26,7 +26,6 @@ import javax.inject.Inject
class TimelineItemContentStateFactory @Inject constructor(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {
val text = timelineEventFormatter.format(eventTimelineItem)
return TimelineItemStateEventContent(text.orEmpty().toString())

View file

@ -22,7 +22,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
import javax.inject.Inject
class TimelineItemContentUTDFactory @Inject constructor() {
fun create(content: UnableToDecryptContent): TimelineItemEventContent {
return TimelineItemEncryptedContent(content.data)
}

View file

@ -43,7 +43,6 @@ class TimelineItemEventFactory @Inject constructor(
private val matrixClient: MatrixClient,
private val lastMessageTimestampFormatter: LastMessageTimestampFormatter,
) {
suspend fun create(
currentTimelineItem: MatrixTimelineItem.Event,
index: Int,
@ -193,7 +192,8 @@ class TimelineItemEventFactory @Inject constructor(
}
}
}
previousSender == currentSender /* && nextSender != currentSender (== true) */ -> {
// In the following case, we have nextSender != currentSender == true
previousSender == currentSender -> {
if (previousIsGroupable) {
TimelineItemGroupPosition.Last
} else {

View file

@ -23,7 +23,6 @@ import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTime
import javax.inject.Inject
class TimelineItemDaySeparatorFactory @Inject constructor(private val daySeparatorFormatter: DaySeparatorFormatter) {
fun create(virtualItem: VirtualTimelineItem.DayDivider): TimelineItemVirtualModel {
val formattedDate = daySeparatorFormatter.format(virtualItem.timestamp)
return TimelineItemDaySeparatorModel(

View file

@ -27,7 +27,6 @@ import javax.inject.Inject
class TimelineItemVirtualFactory @Inject constructor(
private val daySeparatorFactory: TimelineItemDaySeparatorFactory,
) {
fun create(
virtualTimelineItem: MatrixTimelineItem.Virtual,
): TimelineItem.Virtual {

View file

@ -25,7 +25,6 @@ import javax.inject.Inject
@SingleIn(RoomScope::class)
class TimelineItemGrouper @Inject constructor() {
/**
* Keys are identifier of items in a group, only one by group will be kept.
* Values are the actual groupIds.

View file

@ -35,7 +35,6 @@ import io.element.android.libraries.ui.strings.CommonStrings
@Immutable
internal sealed interface InReplyToMetadata {
val text: String?
data class Thumbnail(

View file

@ -21,5 +21,7 @@ package io.element.android.features.messages.impl.timeline.model
* This can be used to scroll to the bottom of the list when a new event is added.
*/
enum class NewEventState {
None, FromMe, FromOther
None,
FromMe,
FromOther
}

View file

@ -32,7 +32,6 @@ import kotlinx.collections.immutable.ImmutableList
@Immutable
sealed interface TimelineItem {
fun identifier(): String = when (this) {
is Event -> id
is Virtual -> id
@ -73,7 +72,6 @@ sealed interface TimelineItem {
val debugInfo: TimelineItemDebugInfo,
val origin: TimelineItemEventOrigin?,
) : TimelineItem {
val showSenderInformation = groupPosition.isNew() && !isMine
val safeSenderName: String = senderDisplayName ?: senderId.value

View file

@ -28,7 +28,6 @@ data class TimelineItemAudioContent(
val formattedFileSize: String,
val fileExtension: String,
) : TimelineItemEventContent {
val fileExtensionAndSize =
formatFileExtensionAndSize(
fileExtension,

View file

@ -46,7 +46,6 @@ class TimelineItemEventContentProvider : PreviewParameterProvider<TimelineItemEv
}
class TimelineItemTextBasedContentProvider : PreviewParameterProvider<TimelineItemTextBasedContent> {
private fun buildSpanned(text: String) = buildSpannedString {
inSpans(StyleSpan(Typeface.BOLD)) {
append("Rich Text")

View file

@ -42,7 +42,6 @@ import javax.inject.Inject
class MessageSummaryFormatterImpl @Inject constructor(
@ApplicationContext private val context: Context,
) : MessageSummaryFormatter {
companion object {
// Max characters to display in the summary message. This works around https://github.com/element-hq/element-x-android/issues/2105
private const val MAX_SAFE_LENGTH = 500

View file

@ -194,7 +194,6 @@ class VoiceMessageComposerPlayer @Inject constructor(
val currentPosition: Long,
val progress: Float,
) {
companion object {
val Initial = State(
playState = PlayState.Stopped,

View file

@ -121,7 +121,7 @@ class VoiceMessageComposerPresenter @Inject constructor(
}
}
}
val onPlayerEvent = { event: VoiceMessagePlayerEvent -> localCoroutineScope.launch {
val onPlayerEvent = { event: VoiceMessagePlayerEvent ->
localCoroutineScope.launch {
when (event) {
VoiceMessagePlayerEvent.Play -> player.play()
@ -129,7 +129,7 @@ class VoiceMessageComposerPresenter @Inject constructor(
is VoiceMessagePlayerEvent.Seek -> player.seek(event.position)
}
}
} }
}
val onAcceptPermissionsRationale = {
permissionState.eventSink(PermissionsEvents.OpenSystemSettingAndCloseDialog)

View file

@ -35,7 +35,6 @@ import java.io.File
* Whenever a given mxc is found in the cache, it is returned immediately.
*/
interface VoiceMessageMediaRepo {
/**
* Factory for [VoiceMessageMediaRepo].
*/
@ -73,7 +72,6 @@ class DefaultVoiceMessageMediaRepo @AssistedInject constructor(
@Assisted("mimeType") private val mimeType: String?,
@Assisted("body") private val body: String?,
) : VoiceMessageMediaRepo {
@ContributesBinding(RoomScope::class)
@AssistedFactory
fun interface Factory : VoiceMessageMediaRepo.Factory {

View file

@ -34,9 +34,7 @@ import javax.inject.Inject
* A media player specialized in playing a single voice message.
*/
interface VoiceMessagePlayer {
fun interface Factory {
/**
* Creates a [VoiceMessagePlayer].
*
@ -126,7 +124,6 @@ class DefaultVoiceMessagePlayer(
mimeType: String?,
body: String?,
) : VoiceMessagePlayer {
@ContributesBinding(RoomScope::class) // Scoped types can't use @AssistedInject.
class Factory @Inject constructor(
private val mediaPlayer: MediaPlayer,
@ -197,7 +194,8 @@ class DefaultVoiceMessagePlayer(
mediaPlayer.setMedia(
uri = mediaFile.path,
mediaId = eventId.value,
mimeType = MimeTypes.Ogg, // Files in the voice cache have no extension so we need to set the mime type manually.
// Files in the voice cache have no extension so we need to set the mime type manually.
mimeType = MimeTypes.Ogg,
startPositionMs = if (state.isEnded) 0L else state.currentPosition,
)
}

View file

@ -58,7 +58,6 @@ class VoiceMessagePresenter @AssistedInject constructor(
private val scope: CoroutineScope,
@Assisted private val content: TimelineItemVoiceContent,
) : Presenter<VoiceMessageState> {
@AssistedFactory
fun interface Factory : TimelineItemPresenterFactory<TimelineItemVoiceContent, VoiceMessageState> {
override fun create(content: TimelineItemVoiceContent): VoiceMessagePresenter

View file

@ -103,7 +103,6 @@ import kotlin.time.Duration.Companion.milliseconds
@Suppress("LargeClass")
class MessagesPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -39,7 +39,6 @@ import org.junit.Rule
import org.junit.Test
class ActionListPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()
@ -427,7 +426,8 @@ class ActionListPresenterTest {
}.test {
val initialState = awaitItem()
val messageEvent = aMessageEvent(
eventId = null, // No event id, so it's not sent yet
// No event id, so it's not sent yet
eventId = null,
isMine = true,
content = TimelineItemTextContent(body = A_MESSAGE, htmlDocument = null, isEdited = false, formattedBody = null),
)

View file

@ -41,7 +41,6 @@ import org.junit.Rule
import org.junit.Test
class AttachmentsPreviewPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -31,7 +31,6 @@ import org.junit.Rule
import org.junit.Test
class ForwardMessagesPresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -20,7 +20,6 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.utils.messagesummary.MessageSummaryFormatter
class FakeMessageSummaryFormatter : MessageSummaryFormatter {
private var result = "A message"
override fun format(event: TimelineItem.Event): String = result

View file

@ -32,7 +32,6 @@ import org.junit.Rule
import org.junit.Test
class ReportMessagePresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -90,7 +90,6 @@ import java.io.File
@Suppress("LargeClass")
class MessageComposerPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -28,7 +28,6 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
class DefaultHtmlConverterProviderTest {
@get:Rule val composeTestRule = createComposeRule()
@Test

View file

@ -65,7 +65,6 @@ import java.util.Date
private const val FAKE_UNIQUE_ID = "FAKE_UNIQUE_ID"
class TimelinePresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -29,7 +29,6 @@ import org.junit.Rule
import org.junit.Test
class CustomReactionPresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -35,7 +35,6 @@ import org.junit.Rule
import org.junit.Test
class ReactionSummaryPresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -27,7 +27,6 @@ import org.junit.Rule
import org.junit.Test
class ReadReceiptBottomSheetPresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -29,7 +29,6 @@ import org.junit.Rule
import org.junit.Test
class RetrySendMenuPresenterTests {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -76,7 +76,6 @@ import kotlin.time.Duration.Companion.minutes
@RunWith(RobolectricTestRunner::class)
class TimelineItemContentMessageFactoryTest {
@Test
fun `test create OtherMessageType`() = runTest {
val sut = createTimelineItemContentMessageFactory()

View file

@ -29,7 +29,6 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import org.junit.Test
class InReplyToDetailTest {
@Test
fun `map - with a not ready InReplyTo does not work`() {
assertThat(InReplyTo.Pending.map()).isNull()

View file

@ -57,7 +57,6 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
class VoiceMessageComposerPresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()

View file

@ -29,7 +29,6 @@ import org.junit.rules.TemporaryFolder
import java.io.File
class DefaultVoiceMessageMediaRepoTest {
@get:Rule
val temporaryFolder = TemporaryFolder()

View file

@ -29,7 +29,6 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
class DefaultVoiceMessagePlayerTest {
@Test
fun `initial state`() = runTest {
createDefaultVoiceMessagePlayer().state.test {

View file

@ -19,7 +19,6 @@ package io.element.android.features.messages.impl.voicemessages.timeline
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
class FakeRedactedVoiceMessageManager : RedactedVoiceMessageManager {
private val _invocations: MutableList<List<MatrixTimelineItem>> = mutableListOf()
val invocations: List<List<MatrixTimelineItem>>
get() = _invocations

View file

@ -23,7 +23,6 @@ import java.io.File
* A fake implementation of [VoiceMessageMediaRepo] for testing purposes.
*/
class FakeVoiceMessageMediaRepo : VoiceMessageMediaRepo {
var shouldFail = false
override suspend fun getMediaFile(): Result<File> = simulateLongTask {