From 2399f30ec4b1fb014fec43326bc154f740e0b4f6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Jun 2025 15:25:23 +0200 Subject: [PATCH 1/2] Inject the session scope instead of the application scope where it's possible. --- .../io/element/android/appnav/LoggedInFlowNode.kt | 8 +++++--- .../appnav/room/joined/JoinedRoomLoadedFlowNode.kt | 6 ++++-- .../android/appnav/JoinedRoomLoadedFlowNodeTest.kt | 2 +- .../impl/banner/KnockRequestsBannerPresenter.kt | 8 +++++--- .../impl/banner/KnockRequestsBannerPresenterTest.kt | 2 +- .../android/features/messages/impl/MessagesNode.kt | 6 ++++-- .../impl/forward/ForwardMessagesPresenter.kt | 6 ++++-- .../impl/messagecomposer/MessageComposerPresenter.kt | 12 +++++++----- .../impl/pinned/list/PinnedMessagesListPresenter.kt | 6 ++++-- .../messages/impl/timeline/TimelinePresenter.kt | 10 ++++++---- .../composer/VoiceMessageComposerPlayer.kt | 8 +++++--- .../composer/VoiceMessageComposerPresenter.kt | 10 ++++++---- .../impl/forward/ForwardMessagesPresenterTest.kt | 2 +- .../messagecomposer/MessageComposerPresenterTest.kt | 2 +- .../pinned/list/PinnedMessagesListPresenterTest.kt | 2 +- .../messages/impl/timeline/TimelinePresenterTest.kt | 2 +- .../poll/impl/history/PollHistoryPresenter.kt | 8 +++++--- .../poll/impl/history/PollHistoryPresenterTest.kt | 2 +- .../roomlist/impl/datasource/RoomListDataSource.kt | 8 +++++--- .../features/roomlist/impl/RoomListPresenterTest.kt | 2 +- .../impl/datasource/RoomListDataSourceTest.kt | 2 +- .../securebackup/impl/reset/ResetIdentityFlowNode.kt | 12 +++++++----- .../android/features/share/impl/SharePresenter.kt | 6 ++++-- .../features/share/impl/SharePresenterTest.kt | 2 +- .../libraries/mediaplayer/impl/DefaultMediaPlayer.kt | 6 ++++-- .../mediaplayer/impl/DefaultMediaPlayerTest.kt | 2 +- .../impl/DefaultVoiceMessagePresenterFactory.kt | 6 ++++-- .../voiceplayer/impl/VoiceMessagePresenter.kt | 4 ++-- .../voiceplayer/impl/VoiceMessagePresenterTest.kt | 2 +- .../voicerecorder/impl/DefaultVoiceRecorder.kt | 6 ++++-- .../voicerecorder/impl/DefaultVoiceRecorderTest.kt | 2 +- 31 files changed, 98 insertions(+), 64 deletions(-) diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index abcdca12cc6..9a07c04f576 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -65,6 +65,7 @@ import io.element.android.libraries.architecture.waitForNavTargetAttached import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.MAIN_SPACE @@ -104,7 +105,8 @@ class LoggedInFlowNode @AssistedInject constructor( private val secureBackupEntryPoint: SecureBackupEntryPoint, private val userProfileEntryPoint: UserProfileEntryPoint, private val ftueEntryPoint: FtueEntryPoint, - private val coroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val ftueService: FtueService, private val roomDirectoryEntryPoint: RoomDirectoryEntryPoint, private val shareEntryPoint: ShareEntryPoint, @@ -175,7 +177,7 @@ class LoggedInFlowNode @AssistedInject constructor( appNavigationStateService.onNavigateToSession(id, matrixClient.sessionId) // TODO We do not support Space yet, so directly navigate to main space appNavigationStateService.onNavigateToSpace(id, MAIN_SPACE) - loggedInFlowProcessor.observeEvents(coroutineScope) + loggedInFlowProcessor.observeEvents(sessionCoroutineScope) matrixClient.sessionVerificationService().setListener(verificationListener) ftueService.state @@ -313,7 +315,7 @@ class LoggedInFlowNode @AssistedInject constructor( } override fun onForwardedToSingleRoom(roomId: RoomId) { - coroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias(), clearBackstack = false) } + sessionCoroutineScope.launch { attachRoom(roomId.toRoomIdOrAlias(), clearBackstack = false) } } override fun onPermalinkClick(data: PermalinkData, pushToBackstack: Boolean) { diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt index c6b42e1d117..3e5947aada9 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/joined/JoinedRoomLoadedFlowNode.kt @@ -30,6 +30,7 @@ import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.inputs import io.element.android.libraries.di.DaggerComponentOwner import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -50,7 +51,8 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( private val messagesEntryPoint: MessagesEntryPoint, private val roomDetailsEntryPoint: RoomDetailsEntryPoint, private val appNavigationStateService: AppNavigationStateService, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val matrixClient: MatrixClient, private val activeRoomsHolder: ActiveRoomsHolder, roomComponentFactory: RoomComponentFactory, @@ -92,7 +94,7 @@ class JoinedRoomLoadedFlowNode @AssistedInject constructor( trackVisitedRoom() }, onResume = { - appCoroutineScope.launch { + sessionCoroutineScope.launch { inputs.room.subscribeToSync() } }, diff --git a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt index 15175303ddc..bbaa1965202 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/JoinedRoomLoadedFlowNodeTest.kt @@ -109,7 +109,7 @@ class JoinedRoomLoadedFlowNodeTest { messagesEntryPoint = messagesEntryPoint, roomDetailsEntryPoint = roomDetailsEntryPoint, appNavigationStateService = FakeAppNavigationStateService(), - appCoroutineScope = this, + sessionCoroutineScope = this, roomComponentFactory = FakeRoomComponentFactory(), matrixClient = FakeMatrixClient(), activeRoomsHolder = activeRoomsHolder, diff --git a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenter.kt b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenter.kt index 204a9dc4d61..737a3b0562c 100644 --- a/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenter.kt +++ b/features/knockrequests/impl/src/main/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenter.kt @@ -18,6 +18,7 @@ import io.element.android.features.knockrequests.impl.data.KnockRequestPresentab import io.element.android.features.knockrequests.impl.data.KnockRequestsService import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.mapState +import io.element.android.libraries.di.annotations.SessionCoroutineScope import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay @@ -28,7 +29,8 @@ private const val ACCEPT_ERROR_DISPLAY_DURATION = 1500L class KnockRequestsBannerPresenter @Inject constructor( private val knockRequestsService: KnockRequestsService, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, ) : Presenter { @Composable override fun present(): KnockRequestsBannerState { @@ -52,13 +54,13 @@ class KnockRequestsBannerPresenter @Inject constructor( fun handleEvents(event: KnockRequestsBannerEvents) { when (event) { is KnockRequestsBannerEvents.AcceptSingleRequest -> { - appCoroutineScope.acceptSingleKnockRequest( + sessionCoroutineScope.acceptSingleKnockRequest( knockRequests = knockRequests, displayAcceptError = showAcceptError, ) } is KnockRequestsBannerEvents.Dismiss -> { - appCoroutineScope.launch { + sessionCoroutineScope.launch { knockRequestsService.markAllKnockRequestsAsSeen() } } diff --git a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenterTest.kt b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenterTest.kt index f30db6ad5b7..252a0ceaeb7 100644 --- a/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenterTest.kt +++ b/features/knockrequests/impl/src/test/kotlin/io/element/android/features/knockrequests/impl/banner/KnockRequestsBannerPresenterTest.kt @@ -238,6 +238,6 @@ private fun TestScope.createKnockRequestsBannerPresenter( ) return KnockRequestsBannerPresenter( knockRequestsService = knockRequestsService, - appCoroutineScope = this, + sessionCoroutineScope = this, ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt index 6acf48e58be..fc6d01d3a98 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesNode.kt @@ -50,6 +50,7 @@ import io.element.android.libraries.architecture.inputs import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -69,7 +70,8 @@ import kotlinx.coroutines.launch class MessagesNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val coroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val room: BaseRoom, private val analyticsService: AnalyticsService, messageComposerPresenterFactory: MessageComposerPresenter.Factory, @@ -115,7 +117,7 @@ class MessagesNode @AssistedInject constructor( super.onBuilt() lifecycle.subscribe( onCreate = { - coroutineScope.launch { analyticsService.capture(room.toAnalyticsViewRoom()) } + sessionCoroutineScope.launch { analyticsService.capture(room.toAnalyticsViewRoom()) } }, onDestroy = { mediaPlayer.close() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenter.kt index 960d54487af..013003e4b7e 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenter.kt @@ -16,6 +16,7 @@ import dagger.assisted.AssistedInject import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState +import io.element.android.libraries.di.annotations.SessionCoroutineScope 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.timeline.TimelineProvider @@ -28,7 +29,8 @@ import kotlinx.coroutines.launch class ForwardMessagesPresenter @AssistedInject constructor( @Assisted eventId: String, @Assisted private val timelineProvider: TimelineProvider, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, ) : Presenter { private val eventId: EventId = EventId(eventId) @@ -40,7 +42,7 @@ class ForwardMessagesPresenter @AssistedInject constructor( private val forwardingActionState: MutableState>> = mutableStateOf(AsyncAction.Uninitialized) fun onRoomSelected(roomIds: List) { - appCoroutineScope.forwardEvent(eventId, roomIds.toPersistentList(), forwardingActionState) + sessionCoroutineScope.forwardEvent(eventId, roomIds.toPersistentList(), forwardingActionState) } @Composable diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt index c8d3956fe9b..728087fe1c7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenter.kt @@ -44,6 +44,7 @@ import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.core.UserId @@ -98,7 +99,8 @@ import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes class MessageComposerPresenter @AssistedInject constructor( @Assisted private val navigator: MessagesNavigator, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val room: JoinedRoom, private val mediaPickerProvider: PickerProvider, private val featureFlagService: FeatureFlagService, @@ -200,7 +202,7 @@ class MessageComposerPresenter @AssistedInject constructor( DisposableEffect(Unit) { // Declare that the user is not typing anymore when the composer is disposed onDispose { - appCoroutineScope.launch { + sessionCoroutineScope.launch { if (sendTypingNotifications) { room.typingNotice(false) } @@ -236,12 +238,12 @@ class MessageComposerPresenter @AssistedInject constructor( } } is MessageComposerEvents.SendMessage -> { - appCoroutineScope.sendMessage( + sessionCoroutineScope.sendMessage( markdownTextEditorState = markdownTextEditorState, richTextEditorState = richTextEditorState, ) } - is MessageComposerEvents.SendUri -> appCoroutineScope.sendAttachment( + is MessageComposerEvents.SendUri -> sessionCoroutineScope.sendAttachment( attachment = Attachment.Media( localMedia = localMediaFactory.createFromUri( uri = event.uri, @@ -338,7 +340,7 @@ class MessageComposerPresenter @AssistedInject constructor( } MessageComposerEvents.SaveDraft -> { val draft = createDraftFromState(markdownTextEditorState, richTextEditorState) - appCoroutineScope.updateDraft(draft, isVolatile = false) + sessionCoroutineScope.updateDraft(draft, isVolatile = false) } } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt index 82f98724f16..a7901ff52d5 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenter.kt @@ -38,6 +38,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.snackbar.SnackbarMessage +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther @@ -67,7 +68,8 @@ class PinnedMessagesListPresenter @AssistedInject constructor( private val linkPresenter: Presenter, private val snackbarDispatcher: SnackbarDispatcher, @Assisted private val actionListPresenter: Presenter, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val analyticsService: AnalyticsService, ) : Presenter { @AssistedFactory @@ -123,7 +125,7 @@ class PinnedMessagesListPresenter @AssistedInject constructor( fun handleEvents(event: PinnedMessagesListEvents) { when (event) { - is PinnedMessagesListEvents.HandleAction -> appCoroutineScope.handleTimelineAction(event.action, event.event) + is PinnedMessagesListEvents.HandleAction -> sessionCoroutineScope.handleTimelineAction(event.action, event.event) } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt index 3be27fe7d0a..0de2d901f47 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt @@ -37,6 +37,7 @@ import io.element.android.features.roomcall.api.RoomCallState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -65,7 +66,8 @@ class TimelinePresenter @AssistedInject constructor( timelineItemsFactoryCreator: TimelineItemsFactory.Creator, private val room: JoinedRoom, private val dispatchers: CoroutineDispatchers, - private val appScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, @Assisted private val navigator: MessagesNavigator, private val redactedVoiceMessageManager: RedactedVoiceMessageManager, private val sendPollResponseAction: SendPollResponseAction, @@ -133,7 +135,7 @@ class TimelinePresenter @AssistedInject constructor( newEventState.value = NewEventState.None } Timber.d("## sendReadReceiptIfNeeded firstVisibleIndex: ${event.firstIndex}") - appScope.sendReadReceiptIfNeeded( + sessionCoroutineScope.sendReadReceiptIfNeeded( firstVisibleIndex = event.firstIndex, timelineItems = timelineItems, lastReadReceiptId = lastReadReceiptId, @@ -143,13 +145,13 @@ class TimelinePresenter @AssistedInject constructor( newEventState.value = NewEventState.None } } - is TimelineEvents.SelectPollAnswer -> appScope.launch { + is TimelineEvents.SelectPollAnswer -> sessionCoroutineScope.launch { sendPollResponseAction.execute( pollStartId = event.pollStartId, answerId = event.answerId ) } - is TimelineEvents.EndPoll -> appScope.launch { + is TimelineEvents.EndPoll -> sessionCoroutineScope.launch { endPollAction.execute( pollStartId = event.pollStartId, ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt index 6f0fa9735ad..57b18817f5b 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPlayer.kt @@ -8,6 +8,7 @@ package io.element.android.features.messages.impl.voicemessages.composer import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.mediaplayer.api.MediaPlayer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -26,11 +27,12 @@ import javax.inject.Inject * A media player for the voice message composer. * * @param mediaPlayer The [MediaPlayer] to use. - * @param coroutineScope + * @param sessionCoroutineScope */ class VoiceMessageComposerPlayer @Inject constructor( private val mediaPlayer: MediaPlayer, - private val coroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, ) { companion object { const val MIME_TYPE = MimeTypes.Ogg @@ -116,7 +118,7 @@ class VoiceMessageComposerPlayer @Inject constructor( seekJob?.cancelAndJoin() seekingTo.value = position - seekJob = coroutineScope.launch { + seekJob = sessionCoroutineScope.launch { val mediaState = mediaPlayer.ensureMediaReady(mediaPath) val duration = mediaState.duration ?: return@launch val positionMs = (duration * position).toLong() diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt index 032e00cd368..9b723ff72a7 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/voicemessages/composer/VoiceMessageComposerPresenter.kt @@ -22,6 +22,7 @@ import androidx.lifecycle.Lifecycle import im.vector.app.features.analytics.plan.Composer import io.element.android.features.messages.api.MessageComposerContext import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.permissions.api.PermissionsEvents import io.element.android.libraries.permissions.api.PermissionsPresenter @@ -44,7 +45,8 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds class VoiceMessageComposerPresenter @Inject constructor( - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val voiceRecorder: VoiceRecorder, private val analyticsService: AnalyticsService, private val mediaSender: MediaSender, @@ -74,11 +76,11 @@ class VoiceMessageComposerPresenter @Inject constructor( val onLifecycleEvent = { event: Lifecycle.Event -> when (event) { Lifecycle.Event.ON_PAUSE -> { - appCoroutineScope.finishRecording() + sessionCoroutineScope.finishRecording() player.pause() } Lifecycle.Event.ON_DESTROY -> { - appCoroutineScope.cancelRecording() + sessionCoroutineScope.cancelRecording() } else -> {} } @@ -145,7 +147,7 @@ class VoiceMessageComposerPresenter @Inject constructor( isSending = true player.pause() analyticsService.captureComposerEvent() - appCoroutineScope.launch { + sessionCoroutineScope.launch { val result = sendMessage( file = finishedState.file, mimeType = finishedState.mimeType, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt index 1b4caa8bdd3..757e682592e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/forward/ForwardMessagesPresenterTest.kt @@ -97,6 +97,6 @@ class ForwardMessagesPresenterTest { ) = ForwardMessagesPresenter( eventId = eventId.value, timelineProvider = LiveTimelineProvider(fakeRoom), - appCoroutineScope = this, + sessionCoroutineScope = this, ) } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt index 5e669ca0277..f3d815d5630 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/messagecomposer/MessageComposerPresenterTest.kt @@ -1539,7 +1539,7 @@ class MessageComposerPresenterTest { draftService: ComposerDraftService = FakeComposerDraftService(), ) = MessageComposerPresenter( navigator = navigator, - appCoroutineScope = this, + sessionCoroutineScope = this, room = room, mediaPickerProvider = pickerProvider, featureFlagService = featureFlagService, diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt index 70f1d3f51b2..535b11c5220 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt @@ -337,7 +337,7 @@ class PinnedMessagesListPresenterTest { actionListPresenter = { anActionListState() }, linkPresenter = { aLinkState() }, analyticsService = analyticsService, - appCoroutineScope = this, + sessionCoroutineScope = this, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt index 9cbce38709f..a5ddfe3396e 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenterTest.kt @@ -679,7 +679,7 @@ import kotlin.time.Duration.Companion.seconds timelineItemsFactoryCreator = aTimelineItemsFactoryCreator(), room = room, dispatchers = testCoroutineDispatchers(), - appScope = this, + sessionCoroutineScope = this, navigator = messagesNavigator, redactedVoiceMessageManager = redactedVoiceMessageManager, endPollAction = endPollAction, diff --git a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt index cef19ef6873..e3d76322657 100644 --- a/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt +++ b/features/poll/impl/src/main/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenter.kt @@ -23,6 +23,7 @@ import io.element.android.features.poll.impl.history.model.PollHistoryFilter import io.element.android.features.poll.impl.history.model.PollHistoryItems import io.element.android.features.poll.impl.history.model.PollHistoryItemsFactory import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.timeline.Timeline import kotlinx.coroutines.CoroutineScope @@ -31,7 +32,8 @@ import kotlinx.coroutines.launch import javax.inject.Inject class PollHistoryPresenter @Inject constructor( - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val sendPollResponseAction: SendPollResponseAction, private val endPollAction: EndPollAction, private val pollHistoryItemFactory: PollHistoryItemsFactory, @@ -64,10 +66,10 @@ class PollHistoryPresenter @Inject constructor( is PollHistoryEvents.LoadMore -> { coroutineScope.loadMore(timeline) } - is PollHistoryEvents.SelectPollAnswer -> appCoroutineScope.launch { + is PollHistoryEvents.SelectPollAnswer -> sessionCoroutineScope.launch { sendPollResponseAction.execute(pollStartId = event.pollStartId, answerId = event.answerId) } - is PollHistoryEvents.EndPoll -> appCoroutineScope.launch { + is PollHistoryEvents.EndPoll -> sessionCoroutineScope.launch { endPollAction.execute(pollStartId = event.pollStartId) } is PollHistoryEvents.SelectFilter -> { diff --git a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt index 17d270f5ec2..eeb4d0d2237 100644 --- a/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt +++ b/features/poll/impl/src/test/kotlin/io/element/android/features/poll/impl/history/PollHistoryPresenterTest.kt @@ -163,7 +163,7 @@ class PollHistoryPresenterTest { ), ): PollHistoryPresenter { return PollHistoryPresenter( - appCoroutineScope = this, + sessionCoroutineScope = this, sendPollResponseAction = sendPollResponseAction, endPollAction = endPollAction, pollHistoryItemFactory = pollHistoryItemFactory, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt index e81c8828ae7..6d59837988a 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSource.kt @@ -12,6 +12,7 @@ import io.element.android.libraries.androidutils.diff.DiffCacheUpdater import io.element.android.libraries.androidutils.diff.MutableListDiffCache import io.element.android.libraries.androidutils.system.DateTimeObserver import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.roomlist.RoomListService @@ -36,7 +37,8 @@ class RoomListDataSource @Inject constructor( private val roomListRoomSummaryFactory: RoomListRoomSummaryFactory, private val coroutineDispatchers: CoroutineDispatchers, private val notificationSettingsService: NotificationSettingsService, - private val appScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val dateTimeObserver: DateTimeObserver, ) { init { @@ -77,7 +79,7 @@ class RoomListDataSource @Inject constructor( .onEach { roomListService.allRooms.rebuildSummaries() } - .launchIn(appScope) + .launchIn(sessionCoroutineScope) } private fun observeDateTimeChanges() { @@ -88,7 +90,7 @@ class RoomListDataSource @Inject constructor( is DateTimeObserver.Event.DateChanged -> rebuildAllRoomSummaries() } } - .launchIn(appScope) + .launchIn(sessionCoroutineScope) } private suspend fun replaceWith(roomSummaries: List) = withContext(coroutineDispatchers.computation) { diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt index 5726eb1eb0b..e6f673c3736 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTest.kt @@ -694,7 +694,7 @@ class RoomListPresenterTest { ), coroutineDispatchers = testCoroutineDispatchers(), notificationSettingsService = client.notificationSettingsService(), - appScope = backgroundScope, + sessionCoroutineScope = backgroundScope, dateTimeObserver = FakeDateTimeObserver(), ), featureFlagService = featureFlagService, diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSourceTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSourceTest.kt index dcf6cdc0325..bcb6552d303 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSourceTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/datasource/RoomListDataSourceTest.kt @@ -100,7 +100,7 @@ class RoomListDataSourceTest { roomListRoomSummaryFactory = roomListRoomSummaryFactory, coroutineDispatchers = testCoroutineDispatchers(), notificationSettingsService = notificationSettingsService, - appScope = backgroundScope, + sessionCoroutineScope = backgroundScope, dateTimeObserver = dateTimeObserver, ) } diff --git a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt index c8e9072c6b2..c7b8fa7396c 100644 --- a/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt +++ b/features/securebackup/impl/src/main/kotlin/io/element/android/features/securebackup/impl/reset/ResetIdentityFlowNode.kt @@ -35,6 +35,7 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.createNode import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.encryption.IdentityOidcResetHandle import io.element.android.libraries.matrix.api.encryption.IdentityPasswordResetHandle import io.element.android.libraries.oidc.api.OidcEntryPoint @@ -50,7 +51,8 @@ class ResetIdentityFlowNode @AssistedInject constructor( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val resetIdentityFlowManager: ResetIdentityFlowManager, - private val coroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val oidcEntryPoint: OidcEntryPoint, ) : BaseFlowNode( backstack = BackStack(initialElement = NavTarget.Root, savedStateMap = buildContext.savedStateMap), @@ -82,7 +84,7 @@ class ResetIdentityFlowNode @AssistedInject constructor( override fun onStart(owner: LifecycleOwner) { // If the custom tab was opened, we need to cancel the reset job // when we come back to the node if the reset wasn't successful - coroutineScope.launch { + sessionCoroutineScope.launch { cancelResetJob() resetIdentityFlowManager.whenResetIsDone { @@ -93,7 +95,7 @@ class ResetIdentityFlowNode @AssistedInject constructor( override fun onDestroy(owner: LifecycleOwner) { // Make sure we cancel the reset job when the node is destroyed, just in case - coroutineScope.launch { cancelResetJob() } + sessionCoroutineScope.launch { cancelResetJob() } } }) } @@ -103,7 +105,7 @@ class ResetIdentityFlowNode @AssistedInject constructor( is NavTarget.Root -> { val callback = object : ResetIdentityRootNode.Callback { override fun onContinue() { - coroutineScope.startReset() + sessionCoroutineScope.startReset() } } createNode(buildContext, listOf(callback)) @@ -167,7 +169,7 @@ class ResetIdentityFlowNode @AssistedInject constructor( if (startResetState.isLoading()) { ProgressDialog( properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true), - onDismissRequest = { coroutineScope.launch { cancelResetJob() } } + onDismissRequest = { sessionCoroutineScope.launch { cancelResetJob() } } ) } diff --git a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt index e953b3568a3..6dac12a6e28 100644 --- a/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt +++ b/features/share/impl/src/main/kotlin/io/element/android/features/share/impl/SharePresenter.kt @@ -18,6 +18,7 @@ import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -31,7 +32,8 @@ import kotlin.coroutines.cancellation.CancellationException class SharePresenter @AssistedInject constructor( @Assisted private val intent: Intent, - private val appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val shareIntentHandler: ShareIntentHandler, private val matrixClient: MatrixClient, private val mediaPreProcessor: MediaPreProcessor, @@ -46,7 +48,7 @@ class SharePresenter @AssistedInject constructor( private val shareActionState: MutableState>> = mutableStateOf(AsyncAction.Uninitialized) fun onRoomSelected(roomIds: List) { - appCoroutineScope.share(intent, roomIds) + sessionCoroutineScope.share(intent, roomIds) } @Composable diff --git a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt index 07424aa384d..979d6aa61c9 100644 --- a/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt +++ b/features/share/impl/src/test/kotlin/io/element/android/features/share/impl/SharePresenterTest.kt @@ -169,7 +169,7 @@ class SharePresenterTest { ): SharePresenter { return SharePresenter( intent = intent, - appCoroutineScope = this, + sessionCoroutineScope = this, shareIntentHandler = shareIntentHandler, matrixClient = matrixClient, mediaPreProcessor = mediaPreProcessor, diff --git a/libraries/mediaplayer/impl/src/main/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayer.kt b/libraries/mediaplayer/impl/src/main/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayer.kt index cda3bd94b36..45e600f8b91 100644 --- a/libraries/mediaplayer/impl/src/main/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayer.kt +++ b/libraries/mediaplayer/impl/src/main/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayer.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.audio.api.AudioFocus import io.element.android.libraries.audio.api.AudioFocusRequester import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.mediaplayer.api.MediaPlayer import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview @@ -37,7 +38,8 @@ import kotlin.time.Duration.Companion.seconds @SingleIn(RoomScope::class) class DefaultMediaPlayer @Inject constructor( private val player: SimplePlayer, - private val coroutineScope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val audioFocus: AudioFocus, ) : MediaPlayer { private val listener = object : SimplePlayer.Listener { @@ -50,7 +52,7 @@ class DefaultMediaPlayer @Inject constructor( ) } if (isPlaying) { - job = coroutineScope.launch { updateCurrentPosition() } + job = sessionCoroutineScope.launch { updateCurrentPosition() } } else { audioFocus.releaseAudioFocus() job?.cancel() diff --git a/libraries/mediaplayer/impl/src/test/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayerTest.kt b/libraries/mediaplayer/impl/src/test/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayerTest.kt index 8fe6ed00ab9..a91a2043784 100644 --- a/libraries/mediaplayer/impl/src/test/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayerTest.kt +++ b/libraries/mediaplayer/impl/src/test/kotlin/io/element/android/libraries/mediaplayer/impl/DefaultMediaPlayerTest.kt @@ -423,7 +423,7 @@ class DefaultMediaPlayerTest { audioFocus: AudioFocus = FakeAudioFocus(), ): DefaultMediaPlayer = DefaultMediaPlayer( player = simplePlayer, - coroutineScope = backgroundScope, + sessionCoroutineScope = backgroundScope, audioFocus = audioFocus, ) } diff --git a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/DefaultVoiceMessagePresenterFactory.kt b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/DefaultVoiceMessagePresenterFactory.kt index 726fccdca0f..e6d596e90a1 100644 --- a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/DefaultVoiceMessagePresenterFactory.kt +++ b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/DefaultVoiceMessagePresenterFactory.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.voiceplayer.impl import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory @@ -22,7 +23,8 @@ import kotlin.time.Duration @ContributesBinding(RoomScope::class) class DefaultVoiceMessagePresenterFactory @Inject constructor( private val analyticsService: AnalyticsService, - private val scope: CoroutineScope, + @SessionCoroutineScope + private val sessionCoroutineScope: CoroutineScope, private val voiceMessagePlayerFactory: VoiceMessagePlayer.Factory, ) : VoiceMessagePresenterFactory { override fun createVoiceMessagePresenter( @@ -41,7 +43,7 @@ class DefaultVoiceMessagePresenterFactory @Inject constructor( return VoiceMessagePresenter( analyticsService = analyticsService, - scope = scope, + sessionCoroutineScope = sessionCoroutineScope, player = player, eventId = eventId, duration = duration, diff --git a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenter.kt b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenter.kt index 58824b857e9..c7811f6d179 100644 --- a/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenter.kt +++ b/libraries/voiceplayer/impl/src/main/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenter.kt @@ -31,7 +31,7 @@ import kotlin.time.Duration.Companion.milliseconds class VoiceMessagePresenter( private val analyticsService: AnalyticsService, - private val scope: CoroutineScope, + private val sessionCoroutineScope: CoroutineScope, private val player: VoiceMessagePlayer, private val eventId: EventId?, private val duration: Duration, @@ -92,7 +92,7 @@ class VoiceMessagePresenter( } else if (playerState.isReady) { player.play() } else { - scope.launch { + sessionCoroutineScope.launch { play.runUpdatingState( errorTransform = { analyticsService.trackError( diff --git a/libraries/voiceplayer/impl/src/test/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenterTest.kt b/libraries/voiceplayer/impl/src/test/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenterTest.kt index c10b263b759..9d16cd6bcc1 100644 --- a/libraries/voiceplayer/impl/src/test/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenterTest.kt +++ b/libraries/voiceplayer/impl/src/test/kotlin/io/element/android/libraries/voiceplayer/impl/VoiceMessagePresenterTest.kt @@ -236,7 +236,7 @@ fun TestScope.createVoiceMessagePresenter( mediaSource: MediaSource = MediaSource(contentUri), ) = VoiceMessagePresenter( analyticsService = analyticsService, - scope = this, + sessionCoroutineScope = this, player = DefaultVoiceMessagePlayer( mediaPlayer = mediaPlayer, voiceMessageMediaRepoFactory = { _, _, _ -> voiceMessageMediaRepo }, diff --git a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt index 64f57b05740..5e690ab1f7b 100644 --- a/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt +++ b/libraries/voicerecorder/impl/src/main/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorder.kt @@ -15,6 +15,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.childScope import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.voicerecorder.api.VoiceRecorder import io.element.android.libraries.voicerecorder.api.VoiceRecorderState import io.element.android.libraries.voicerecorder.impl.audio.Audio @@ -51,10 +52,11 @@ class DefaultVoiceRecorder @Inject constructor( private val config: AudioConfig, private val fileConfig: VoiceFileConfig, private val audioLevelCalculator: AudioLevelCalculator, - appCoroutineScope: CoroutineScope, + @SessionCoroutineScope + sessionCoroutineScope: CoroutineScope, ) : VoiceRecorder { private val voiceCoroutineScope by lazy { - appCoroutineScope.childScope(dispatchers.io, "VoiceRecorder-${UUID.randomUUID()}") + sessionCoroutineScope.childScope(dispatchers.io, "VoiceRecorder-${UUID.randomUUID()}") } private var outputFile: File? = null diff --git a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt index 639686fbf8a..6ed540a2f40 100644 --- a/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt +++ b/libraries/voicerecorder/impl/src/test/kotlin/io/element/android/libraries/voicerecorder/impl/DefaultVoiceRecorderTest.kt @@ -141,7 +141,7 @@ class DefaultVoiceRecorderTest { fileConfig = fileConfig, fileManager = FakeVoiceFileManager(fakeFileSystem, fileConfig, FILE_ID), audioLevelCalculator = FakeAudioLevelCalculator(), - appCoroutineScope = backgroundScope, + sessionCoroutineScope = backgroundScope, ) } From 4cb39fdca824c48a572ef9b7c4fb8a8e676fc2ee Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 4 Jun 2025 15:59:34 +0200 Subject: [PATCH 2/2] Create AppCoroutineScope annotation to let developers explicitly choose the appropriate CoroutineScope when injecting one. --- .../io/element/android/x/di/AppModule.kt | 2 ++ .../cachecleaner/impl/DefaultCacheCleaner.kt | 6 ++++-- .../impl/DefaultCacheCleanerTest.kt | 2 +- .../receivers/DeclineCallBroadcastReceiver.kt | 5 +++-- .../call/impl/ui/CallScreenPresenter.kt | 2 ++ .../call/impl/ui/IncomingCallActivity.kt | 5 +++-- .../call/impl/utils/ActiveCallManager.kt | 2 ++ .../NotificationsOptInPresenter.kt | 2 ++ .../impl/DefaultLockScreenService.kt | 2 ++ .../DefaultBiometricAuthenticatorManager.kt | 2 ++ .../settings/LockScreenSettingsPresenter.kt | 2 ++ .../impl/unlock/PinUnlockPresenter.kt | 2 ++ .../impl/DefaultNetworkMonitor.kt | 2 ++ .../impl/bugreport/BugReportPresenter.kt | 2 ++ .../di/annotations/AppCoroutineScope.kt | 18 ++++++++++++++++++ .../matrix/impl/RustMatrixClientFactory.kt | 2 ++ .../DefaultNotificationDrawerManager.kt | 2 ++ .../NotificationBroadcastReceiverHandler.kt | 2 ++ .../notifications/NotificationResolverQueue.kt | 2 ++ .../push/impl/push/DefaultPushHandler.kt | 2 ++ .../impl/push/OnNotifiableEventReceived.kt | 2 ++ .../push/impl/push/OnRedactedEventReceived.kt | 2 ++ .../firebase/VectorFirebaseMessagingService.kt | 2 ++ .../VectorUnifiedPushMessagingReceiver.kt | 2 ++ .../impl/observer/DefaultSessionObserver.kt | 2 ++ .../analytics/impl/DefaultAnalyticsService.kt | 2 ++ .../impl/DefaultAppNavigationStateService.kt | 4 +++- 27 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/AppCoroutineScope.kt diff --git a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt index 53d84f473b3..c5bc3f4598b 100644 --- a/app/src/main/kotlin/io/element/android/x/di/AppModule.kt +++ b/app/src/main/kotlin/io/element/android/x/di/AppModule.kt @@ -27,6 +27,7 @@ import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.CacheDirectory import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.x.BuildConfig import io.element.android.x.R import kotlinx.coroutines.CoroutineName @@ -56,6 +57,7 @@ object AppModule { } @Provides + @AppCoroutineScope @SingleIn(AppScope::class) fun providesAppCoroutineScope(): CoroutineScope { return MainScope() + CoroutineName("ElementX Scope") diff --git a/features/cachecleaner/impl/src/main/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleaner.kt b/features/cachecleaner/impl/src/main/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleaner.kt index 7951c3e78d2..86e6432cc5d 100644 --- a/features/cachecleaner/impl/src/main/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleaner.kt +++ b/features/cachecleaner/impl/src/main/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleaner.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.CacheDirectory +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import timber.log.Timber @@ -24,7 +25,8 @@ import javax.inject.Inject */ @ContributesBinding(AppScope::class) class DefaultCacheCleaner @Inject constructor( - private val scope: CoroutineScope, + @AppCoroutineScope + private val coroutineScope: CoroutineScope, private val dispatchers: CoroutineDispatchers, @CacheDirectory private val cacheDir: File, ) : CacheCleaner { @@ -33,7 +35,7 @@ class DefaultCacheCleaner @Inject constructor( } override fun clearCache() { - scope.launch(dispatchers.io) { + coroutineScope.launch(dispatchers.io) { runCatchingExceptions { SUBDIRS_TO_CLEANUP.forEach { File(cacheDir.path, it).apply { diff --git a/features/cachecleaner/impl/src/test/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleanerTest.kt b/features/cachecleaner/impl/src/test/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleanerTest.kt index 884d29ac88e..997c0fe7039 100644 --- a/features/cachecleaner/impl/src/test/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleanerTest.kt +++ b/features/cachecleaner/impl/src/test/kotlin/io/element/android/features/cachecleaner/impl/DefaultCacheCleanerTest.kt @@ -55,7 +55,7 @@ class DefaultCacheCleanerTest { } private fun TestScope.aCacheCleaner() = DefaultCacheCleaner( - scope = this, + coroutineScope = this, dispatchers = this.testCoroutineDispatchers(true), cacheDir = temporaryFolder.root, ) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt index bbc0611083f..c857c9e2c86 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/receivers/DeclineCallBroadcastReceiver.kt @@ -16,6 +16,7 @@ import io.element.android.features.call.impl.di.CallBindings import io.element.android.features.call.impl.notifications.CallNotificationData import io.element.android.features.call.impl.utils.ActiveCallManager import io.element.android.libraries.architecture.bindings +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -30,8 +31,8 @@ class DeclineCallBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var activeCallManager: ActiveCallManager - @Inject - lateinit var appCoroutineScope: CoroutineScope + @AppCoroutineScope + @Inject lateinit var appCoroutineScope: CoroutineScope override fun onReceive(context: Context, intent: Intent?) { val notificationData = intent?.let { IntentCompat.getParcelableExtra(it, EXTRA_NOTIFICATION_DATA, CallNotificationData::class.java) } diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt index 8550f06f3d2..053b9e93bb0 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt @@ -32,6 +32,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.coroutine.CoroutineDispatchers +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.RoomId @@ -64,6 +65,7 @@ class CallScreenPresenter @AssistedInject constructor( private val languageTagProvider: LanguageTagProvider, private val appForegroundStateService: AppForegroundStateService, private val activeRoomsHolder: ActiveRoomsHolder, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) : Presenter { @AssistedFactory diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt index c5162d9a9e7..dc77af9b774 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt @@ -23,6 +23,7 @@ import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.architecture.bindings import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.designsystem.theme.ElementThemeApp +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.preferences.api.store.AppPreferencesStore import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.filter @@ -57,8 +58,8 @@ class IncomingCallActivity : AppCompatActivity() { @Inject lateinit var buildMeta: BuildMeta - @Inject - lateinit var appCoroutineScope: CoroutineScope + @AppCoroutineScope + @Inject lateinit var appCoroutineScope: CoroutineScope override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt index 57a02de56aa..0d742cba985 100644 --- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt +++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt @@ -25,6 +25,7 @@ import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder @@ -87,6 +88,7 @@ interface ActiveCallManager { @ContributesBinding(AppScope::class) class DefaultActiveCallManager @Inject constructor( @ApplicationContext context: Context, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val onMissedCallNotificationHandler: OnMissedCallNotificationHandler, private val ringingCallNotificationCreator: RingingCallNotificationCreator, diff --git a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInPresenter.kt b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInPresenter.kt index 05bd14efcd4..5db0955c5ac 100644 --- a/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInPresenter.kt +++ b/features/ftue/impl/src/main/kotlin/io/element/android/features/ftue/impl/notifications/NotificationsOptInPresenter.kt @@ -16,6 +16,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.permissions.api.PermissionStateProvider import io.element.android.libraries.permissions.api.PermissionsEvents import io.element.android.libraries.permissions.api.PermissionsPresenter @@ -27,6 +28,7 @@ import kotlinx.coroutines.launch class NotificationsOptInPresenter @AssistedInject constructor( permissionsPresenterFactory: PermissionsPresenter.Factory, @Assisted private val callback: NotificationsOptInNode.Callback, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, private val permissionStateProvider: PermissionStateProvider, private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenService.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenService.kt index 681375357b8..85ec2e31307 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenService.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/DefaultLockScreenService.kt @@ -17,6 +17,7 @@ import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.storage.LockScreenStore import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.sessionstorage.api.observer.SessionListener @@ -42,6 +43,7 @@ class DefaultLockScreenService @Inject constructor( private val featureFlagService: FeatureFlagService, private val lockScreenStore: LockScreenStore, private val pinCodeManager: PinCodeManager, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val sessionObserver: SessionObserver, private val appForegroundStateService: AppForegroundStateService, diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt index 5c2b1fdd53f..a817faf3533 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/biometric/DefaultBiometricAuthenticatorManager.kt @@ -31,6 +31,7 @@ import io.element.android.libraries.cryptography.api.SecretKeyRepository import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.ui.strings.CommonStrings import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -47,6 +48,7 @@ class DefaultBiometricAuthenticatorManager @Inject constructor( private val lockScreenConfig: LockScreenConfig, private val encryptionDecryptionService: EncryptionDecryptionService, private val secretKeyRepository: SecretKeyRepository, + @AppCoroutineScope private val coroutineScope: CoroutineScope, ) : BiometricAuthenticatorManager { private val callbacks = CopyOnWriteArrayList() diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsPresenter.kt index 97dd875b01e..9f44b03a100 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/settings/LockScreenSettingsPresenter.kt @@ -20,6 +20,7 @@ import io.element.android.features.lockscreen.impl.biometric.BiometricAuthentica import io.element.android.features.lockscreen.impl.pin.PinCodeManager import io.element.android.features.lockscreen.impl.storage.LockScreenStore import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -29,6 +30,7 @@ class LockScreenSettingsPresenter @Inject constructor( private val pinCodeManager: PinCodeManager, private val lockScreenStore: LockScreenStore, private val biometricAuthenticatorManager: BiometricAuthenticatorManager, + @AppCoroutineScope private val coroutineScope: CoroutineScope, ) : Presenter { @Composable diff --git a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt index 9f3bf082e2c..707ca6b710e 100644 --- a/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt +++ b/features/lockscreen/impl/src/main/kotlin/io/element/android/features/lockscreen/impl/unlock/PinUnlockPresenter.kt @@ -26,6 +26,7 @@ import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.runCatchingUpdatingState import io.element.android.libraries.core.bool.orFalse +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -34,6 +35,7 @@ class PinUnlockPresenter @Inject constructor( private val pinCodeManager: PinCodeManager, private val biometricAuthenticatorManager: BiometricAuthenticatorManager, private val logoutUseCase: LogoutUseCase, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val pinUnlockHelper: PinUnlockHelper, ) : Presenter { diff --git a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt index 6d6952ab141..a69cf4bcbc6 100644 --- a/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt +++ b/features/networkmonitor/impl/src/main/kotlin/io/element/android/features/networkmonitor/impl/DefaultNetworkMonitor.kt @@ -19,6 +19,7 @@ import io.element.android.features.networkmonitor.api.NetworkStatus import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.channels.awaitClose @@ -38,6 +39,7 @@ import javax.inject.Inject @SingleIn(AppScope::class) class DefaultNetworkMonitor @Inject constructor( @ApplicationContext context: Context, + @AppCoroutineScope appCoroutineScope: CoroutineScope, ) : NetworkMonitor { private val connectivityManager: ConnectivityManager = context.getSystemService(ConnectivityManager::class.java) diff --git a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt index 455cefdb24d..f42d2520800 100644 --- a/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt +++ b/features/rageshake/impl/src/main/kotlin/io/element/android/features/rageshake/impl/bugreport/BugReportPresenter.kt @@ -22,6 +22,7 @@ import io.element.android.features.rageshake.impl.crash.CrashDataStore import io.element.android.features.rageshake.impl.screenshot.ScreenshotHolder import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.di.annotations.AppCoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import javax.inject.Inject @@ -30,6 +31,7 @@ class BugReportPresenter @Inject constructor( private val bugReporter: BugReporter, private val crashDataStore: CrashDataStore, private val screenshotHolder: ScreenshotHolder, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) : Presenter { private class BugReporterUploadListener( diff --git a/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/AppCoroutineScope.kt b/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/AppCoroutineScope.kt new file mode 100644 index 00000000000..ea597e56e17 --- /dev/null +++ b/libraries/di/src/main/kotlin/io/element/android/libraries/di/annotations/AppCoroutineScope.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.di.annotations + +import javax.inject.Qualifier + +/** + * Qualifies a [CoroutineScope] object which represents the base coroutine scope to use for the application. + */ +@Retention(AnnotationRetention.RUNTIME) +@MustBeDocumented +@Qualifier +annotation class AppCoroutineScope diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt index a88c9bab149..bc8e337adaa 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClientFactory.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.CacheDirectory +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.impl.analytics.UtdTracker @@ -40,6 +41,7 @@ import javax.inject.Inject class RustMatrixClientFactory @Inject constructor( private val baseDirectory: File, @CacheDirectory private val cacheDirectory: File, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, private val coroutineDispatchers: CoroutineDispatchers, private val sessionStore: SessionStore, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt index 4ac0307291b..e50536b3132 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationDrawerManager.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.EventId @@ -48,6 +49,7 @@ class DefaultNotificationDrawerManager @Inject constructor( private val notificationManager: NotificationManagerCompat, private val notificationRenderer: NotificationRenderer, private val appNavigationStateService: AppNavigationStateService, + @AppCoroutineScope coroutineScope: CoroutineScope, private val matrixClientProvider: MatrixClientProvider, private val imageLoaderHolder: ImageLoaderHolder, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt index 594575bc449..fab6e3a53a7 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationBroadcastReceiverHandler.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.notifications import android.content.Intent import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.MatrixClientProvider import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId @@ -36,6 +37,7 @@ import javax.inject.Inject private val loggerTag = LoggerTag("NotificationBroadcastReceiverHandler", LoggerTag.NotificationLoggerTag) class NotificationBroadcastReceiverHandler @Inject constructor( + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, private val matrixClientProvider: MatrixClientProvider, private val sessionPreferencesStore: SessionPreferencesStoreFactory, diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt index 1009cc3d36b..a3ba36cfe85 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResolverQueue.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.notifications import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope 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.SessionId @@ -34,6 +35,7 @@ import kotlin.time.Duration.Companion.milliseconds @SingleIn(AppScope::class) class NotificationResolverQueue @Inject constructor( private val notifiableEventResolver: NotifiableEventResolver, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) { companion object { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt index 19b060d36b9..b3ff0010318 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/DefaultPushHandler.kt @@ -14,6 +14,7 @@ import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService import io.element.android.libraries.push.impl.history.PushHistoryService import io.element.android.libraries.push.impl.history.onDiagnosticPush @@ -58,6 +59,7 @@ class DefaultPushHandler @Inject constructor( private val notificationChannels: NotificationChannels, private val pushHistoryService: PushHistoryService, private val resolverQueue: NotificationResolverQueue, + @AppCoroutineScope private val appCoroutineScope: CoroutineScope, ) : PushHandler { init { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt index 14cb3d8ac64..b311aab4e2c 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnNotifiableEventReceived.kt @@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.push import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent @@ -23,6 +24,7 @@ interface OnNotifiableEventReceived { @ContributesBinding(AppScope::class) class DefaultOnNotifiableEventReceived @Inject constructor( private val defaultNotificationDrawerManager: DefaultNotificationDrawerManager, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val syncOnNotifiableEvent: SyncOnNotifiableEvent, ) : OnNotifiableEventReceived { diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnRedactedEventReceived.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnRedactedEventReceived.kt index 8cf77b18988..991baba4041 100644 --- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnRedactedEventReceived.kt +++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/push/OnRedactedEventReceived.kt @@ -17,6 +17,7 @@ import androidx.core.text.inSpans import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.ApplicationContext +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.push.impl.notifications.ActiveNotificationsProvider import io.element.android.libraries.push.impl.notifications.NotificationDisplayer import io.element.android.libraries.push.impl.notifications.factories.DefaultNotificationCreator @@ -36,6 +37,7 @@ interface OnRedactedEventReceived { class DefaultOnRedactedEventReceived @Inject constructor( private val activeNotificationsProvider: ActiveNotificationsProvider, private val notificationDisplayer: NotificationDisplayer, + @AppCoroutineScope private val coroutineScope: CoroutineScope, @ApplicationContext private val context: Context, private val stringProvider: StringProvider, diff --git a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt index d7c77771688..2c138c3cb62 100644 --- a/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt +++ b/libraries/pushproviders/firebase/src/main/kotlin/io/element/android/libraries/pushproviders/firebase/VectorFirebaseMessagingService.kt @@ -11,6 +11,7 @@ import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import io.element.android.libraries.architecture.bindings import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.pushproviders.api.PushHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -23,6 +24,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { @Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler @Inject lateinit var pushParser: FirebasePushParser @Inject lateinit var pushHandler: PushHandler + @AppCoroutineScope @Inject lateinit var coroutineScope: CoroutineScope override fun onCreate() { diff --git a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt index 9cb7e8e60f7..b19aa985fed 100644 --- a/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt +++ b/libraries/pushproviders/unifiedpush/src/main/kotlin/io/element/android/libraries/pushproviders/unifiedpush/VectorUnifiedPushMessagingReceiver.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import io.element.android.libraries.architecture.bindings import io.element.android.libraries.core.log.logger.LoggerTag +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.pushproviders.api.PushHandler import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult @@ -34,6 +35,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() { @Inject lateinit var unifiedPushGatewayUrlResolver: UnifiedPushGatewayUrlResolver @Inject lateinit var newGatewayHandler: UnifiedPushNewGatewayHandler @Inject lateinit var endpointRegistrationHandler: EndpointRegistrationHandler + @AppCoroutineScope @Inject lateinit var coroutineScope: CoroutineScope override fun onReceive(context: Context, intent: Intent) { diff --git a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserver.kt b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserver.kt index e35768ed6cc..71fc9b6a980 100644 --- a/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserver.kt +++ b/libraries/session-storage/impl/src/main/kotlin/io/element/android/libraries/sessionstorage/impl/observer/DefaultSessionObserver.kt @@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.sessionstorage.api.SessionStore import io.element.android.libraries.sessionstorage.api.observer.SessionListener import io.element.android.libraries.sessionstorage.api.observer.SessionObserver @@ -28,6 +29,7 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) class DefaultSessionObserver @Inject constructor( private val sessionStore: SessionStore, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val dispatchers: CoroutineDispatchers, ) : SessionObserver { diff --git a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt index 5ee74860aab..31d52d22492 100644 --- a/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt +++ b/services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt @@ -14,6 +14,7 @@ import im.vector.app.features.analytics.plan.SuperProperties import im.vector.app.features.analytics.plan.UserProperties import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.sessionstorage.api.observer.SessionListener import io.element.android.libraries.sessionstorage.api.observer.SessionObserver import io.element.android.services.analytics.api.AnalyticsService @@ -34,6 +35,7 @@ class DefaultAnalyticsService @Inject constructor( private val analyticsProviders: Set<@JvmSuppressWildcards AnalyticsProvider>, private val analyticsStore: AnalyticsStore, // private val lateInitUserPropertiesFactory: LateInitUserPropertiesFactory, + @AppCoroutineScope private val coroutineScope: CoroutineScope, private val sessionObserver: SessionObserver, ) : AnalyticsService, SessionListener { diff --git a/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt b/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt index f173812fed0..204ab66495b 100644 --- a/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt +++ b/services/appnavstate/impl/src/main/kotlin/io/element/android/services/appnavstate/impl/DefaultAppNavigationStateService.kt @@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.ContributesBinding import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.SingleIn +import io.element.android.libraries.di.annotations.AppCoroutineScope 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.SpaceId @@ -36,7 +37,8 @@ private val loggerTag = LoggerTag("Navigation") @SingleIn(AppScope::class) class DefaultAppNavigationStateService @Inject constructor( private val appForegroundStateService: AppForegroundStateService, - private val coroutineScope: CoroutineScope, + @AppCoroutineScope + coroutineScope: CoroutineScope, ) : AppNavigationStateService { private val state = MutableStateFlow( AppNavigationState(