Merge pull request #7514 from element-hq/misc/renameModule

Rename module and ensure that naming convention is followed
This commit is contained in:
Benoit Marty
2026-08-24 12:54:16 +02:00
committed by GitHub
57 changed files with 269 additions and 193 deletions
@@ -14,16 +14,16 @@ import kotlin.reflect.KClass
* Adds Node to the specified component graph. * Adds Node to the specified component graph.
* Equivalent to the following declaration: * Equivalent to the following declaration:
* *
* ```
* @BindingContainer * @BindingContainer
* @ContributesTo(Scope::class) * @ContributesTo(Scope::class)
* abstract class YourNodeModule { * interface YourNodeBindingContainer {
* @Binds * @Binds
* @IntoMap * @IntoMap
* @NodeKey(YourNode::class) * @NodeKey(YourNode::class)
* abstract fun bindYourNodeFactory(factory: YourNode.Factory): AssistedNodeFactory<*> * fun bindYourNodeAssistedFactory(factory: YourNodeAssistedFactory): AssistedNodeFactory<*>
* } * }
* ```
*/ */
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
annotation class ContributesNode( annotation class ContributesNode(
@@ -38,7 +38,7 @@ import java.io.File
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object AppModule { object AppBindingContainer {
@Provides @Provides
@BaseDirectory @BaseDirectory
fun providesBaseDirectory(@ApplicationContext context: Context): File { fun providesBaseDirectory(@ApplicationContext context: Context): File {
@@ -111,7 +111,7 @@ object AppModule {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun provideSnackbarDispatcher(): SnackbarDispatcher { fun providesSnackbarDispatcher(): SnackbarDispatcher {
return SnackbarDispatcher() return SnackbarDispatcher()
} }
} }
@@ -61,32 +61,32 @@ class ContributesNodeProcessor(
if (config.enableLogging) { if (config.enableLogging) {
logger.warn("Processing ${ksClass.qualifiedName?.asString()}") logger.warn("Processing ${ksClass.qualifiedName?.asString()}")
} }
generateModule(ksClass) generateBindingContainer(ksClass)
generateFactory(ksClass) generateFactory(ksClass)
} }
return invalidSymbols return invalidSymbols
} }
private fun generateModule(ksClass: KSClassDeclaration) { private fun generateBindingContainer(ksClass: KSClassDeclaration) {
val annotation = ksClass.annotations.find { it.shortName.asString() == "ContributesNode" }!! val annotation = ksClass.annotations.find { it.shortName.asString() == "ContributesNode" }!!
val scope = annotation.arguments.find { it.name?.asString() == "scope" }!!.value as KSType val scope = annotation.arguments.find { it.name?.asString() == "scope" }!!.value as KSType
val modulePackage = ksClass.packageName.asString() val bindingContainerPackage = ksClass.packageName.asString()
val moduleClassName = "${ksClass.simpleName.asString()}_Module" val bindingContainerClassName = "${ksClass.simpleName.asString()}BindingContainer"
val nodeClassName = ClassName.bestGuess(ksClass.qualifiedName!!.asString()) val nodeClassName = ClassName.bestGuess(ksClass.qualifiedName!!.asString())
val content = FileSpec.builder( val content = FileSpec.builder(
packageName = modulePackage, packageName = bindingContainerPackage,
fileName = moduleClassName, fileName = bindingContainerClassName,
) )
.addType( .addType(
TypeSpec.interfaceBuilder(moduleClassName) TypeSpec.interfaceBuilder(bindingContainerClassName)
.addAnnotation(AnnotationSpec.builder(Origin::class).addMember(CLASS_PLACEHOLDER, nodeClassName).build()) .addAnnotation(AnnotationSpec.builder(Origin::class).addMember(CLASS_PLACEHOLDER, nodeClassName).build())
.addAnnotation(BindingContainer::class) .addAnnotation(BindingContainer::class)
.addAnnotation(AnnotationSpec.builder(ContributesTo::class).addMember(CLASS_PLACEHOLDER, scope.toTypeName()).build()) .addAnnotation(AnnotationSpec.builder(ContributesTo::class).addMember(CLASS_PLACEHOLDER, scope.toTypeName()).build())
.addFunction( .addFunction(
FunSpec.builder("bind${ksClass.simpleName.asString()}Factory") FunSpec.builder("bind${ksClass.simpleName.asString()}AssistedFactory")
.addModifiers(KModifier.ABSTRACT) .addModifiers(KModifier.ABSTRACT)
.addParameter("factory", ClassName(modulePackage, "${ksClass.simpleName.asString()}_AssistedFactory")) .addParameter("factory", ClassName(bindingContainerPackage, "${ksClass.simpleName.asString()}AssistedFactory"))
.returns(ClassName.bestGuess(assistedNodeFactoryFqName.asString()).parameterizedBy(STAR)) .returns(ClassName.bestGuess(assistedNodeFactoryFqName.asString()).parameterizedBy(STAR))
.addAnnotation(Binds::class) .addAnnotation(Binds::class)
.addAnnotation(IntoMap::class) .addAnnotation(IntoMap::class)
@@ -114,7 +114,7 @@ class ContributesNodeProcessor(
@OptIn(KspExperimental::class) @OptIn(KspExperimental::class)
private fun generateFactory(ksClass: KSClassDeclaration) { private fun generateFactory(ksClass: KSClassDeclaration) {
val generatedPackage = ksClass.packageName.asString() val generatedPackage = ksClass.packageName.asString()
val assistedFactoryClassName = "${ksClass.simpleName.asString()}_AssistedFactory" val assistedFactoryClassName = "${ksClass.simpleName.asString()}AssistedFactory"
val constructor = ksClass.getConstructors().first { it.parameters.isNotEmpty() } val constructor = ksClass.getConstructors().first { it.parameters.isNotEmpty() }
val assistedParameters = constructor.parameters.filter { it.isAnnotationPresent(Assisted::class) } val assistedParameters = constructor.parameters.filter { it.isAnnotationPresent(Assisted::class) }
if (assistedParameters.size != 2) { if (assistedParameters.size != 2) {
@@ -18,7 +18,7 @@ import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
interface AnalyticsModule { interface AnalyticsBindingContainer {
@Binds @Binds
fun bindAnalyticsPreferencesPresenter(presenter: AnalyticsPreferencesPresenter): Presenter<AnalyticsPreferencesState> fun bindAnalyticsPreferencesPresenter(presenter: AnalyticsPreferencesPresenter): Presenter<AnalyticsPreferencesState>
} }
@@ -21,7 +21,7 @@ import kotlinx.coroutines.CoroutineScope
@BindingContainer @BindingContainer
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
object ContentScannerModule { object ContentScannerBindingContainer {
@Provides @Provides
@SingleIn(RoomScope::class) @SingleIn(RoomScope::class)
fun providesContentScannerService( fun providesContentScannerService(
@@ -15,16 +15,16 @@ import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
class ContentScannerModuleTest { class ContentScannerBindingContainerTest {
@Test @Test
fun `ContentScannerModule provides NoopContentScannerService when ContentScanner is null`() = runTest { fun `ContentScannerBindingContainer provides NoopContentScannerService when ContentScanner is null`() = runTest {
// Given // Given
val contentScanner: ContentScanner? = null val contentScanner: ContentScanner? = null
val sessionCoroutineScope = backgroundScope val sessionCoroutineScope = backgroundScope
val coroutineDispatchers = testCoroutineDispatchers() val coroutineDispatchers = testCoroutineDispatchers()
// When // When
val contentScannerService = ContentScannerModule.providesContentScannerService( val contentScannerService = ContentScannerBindingContainer.providesContentScannerService(
contentScanner = contentScanner, contentScanner = contentScanner,
coroutineScope = sessionCoroutineScope, coroutineScope = sessionCoroutineScope,
coroutineDispatchers = coroutineDispatchers, coroutineDispatchers = coroutineDispatchers,
@@ -35,14 +35,14 @@ class ContentScannerModuleTest {
} }
@Test @Test
fun `ContentScannerModule provides DefaultContentScannerService when ContentScanner is not null`() = runTest { fun `ContentScannerBindingContainer provides DefaultContentScannerService when ContentScanner is not null`() = runTest {
// Given // Given
val contentScanner: ContentScanner? = FakeContentScanner() val contentScanner: ContentScanner? = FakeContentScanner()
val sessionCoroutineScope = backgroundScope val sessionCoroutineScope = backgroundScope
val coroutineDispatchers = testCoroutineDispatchers() val coroutineDispatchers = testCoroutineDispatchers()
// When // When
val contentScannerService = ContentScannerModule.providesContentScannerService( val contentScannerService = ContentScannerBindingContainer.providesContentScannerService(
contentScanner = contentScanner, contentScanner = contentScanner,
coroutineScope = sessionCoroutineScope, coroutineScope = sessionCoroutineScope,
coroutineDispatchers = coroutineDispatchers, coroutineDispatchers = coroutineDispatchers,
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.SessionScope
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
@BindingContainer @BindingContainer
interface FtueModule { interface FtueBindingContainer {
@Binds @Binds
fun bindChooseSelfVerificationMethodPresenter(presenter: ChooseSelfVerificationModePresenter): Presenter<ChooseSelfVerificationModeState> fun bindChooseSelfVerificationModePresenter(presenter: ChooseSelfVerificationModePresenter): Presenter<ChooseSelfVerificationModeState>
} }
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.SessionScope
@BindingContainer @BindingContainer
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
interface HomeSpacesModule { interface HomeSpacesBindingContainer {
@Binds @Binds
fun bindHomeSpacesPresenter(presenter: HomeSpacesPresenter): Presenter<HomeSpacesState> fun bindHomeSpacesPresenter(presenter: HomeSpacesPresenter): Presenter<HomeSpacesState>
} }
@@ -26,15 +26,15 @@ import io.element.android.libraries.di.SessionScope
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
@BindingContainer @BindingContainer
interface RoomListModule { interface RoomListBindingContainer {
@Binds @Binds
fun bindRoomListPresenter(presenter: RoomListPresenter): Presenter<RoomListState> fun bindRoomListPresenter(presenter: RoomListPresenter): Presenter<RoomListState>
@Binds @Binds
fun bindSearchPresenter(presenter: RoomListSearchPresenter): Presenter<RoomListSearchState> fun bindRoomListSearchPresenter(presenter: RoomListSearchPresenter): Presenter<RoomListSearchState>
@Binds @Binds
fun bindFiltersPresenter(presenter: RoomListFiltersPresenter): Presenter<RoomListFiltersState> fun bindRoomListFiltersPresenter(presenter: RoomListFiltersPresenter): Presenter<RoomListFiltersState>
@Binds @Binds
fun bindSpaceFiltersPresenter(presenter: SpaceFiltersPresenter): Presenter<SpaceFiltersState> fun bindSpaceFiltersPresenter(presenter: SpaceFiltersPresenter): Presenter<SpaceFiltersState>
@@ -5,6 +5,8 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.home.impl.search package io.element.android.features.home.impl.search
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -35,6 +37,7 @@ import io.element.android.tests.testutils.test
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
@@ -22,9 +22,9 @@ import io.element.android.libraries.matrix.api.MatrixClient
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
@BindingContainer @BindingContainer
interface InviteModule { interface InviteBindingContainer {
@Binds @Binds
fun bindAcceptDeclinePresenter(presenter: AcceptDeclineInvitePresenter): Presenter<AcceptDeclineInviteState> fun bindAcceptDeclineInvitePresenter(presenter: AcceptDeclineInvitePresenter): Presenter<AcceptDeclineInviteState>
companion object { companion object {
@Provides @Provides
@@ -27,7 +27,7 @@ import java.util.Optional
@BindingContainer @BindingContainer
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
object JoinRoomModule { object JoinRoomBindingContainer {
@Provides @Provides
fun providesJoinRoomPresenterFactory( fun providesJoinRoomPresenterFactory(
client: MatrixClient, client: MatrixClient,
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.knockrequests.impl.data package io.element.android.features.knockrequests.impl.data.di
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.ContributesTo
@@ -14,16 +14,17 @@ import dev.zacsweers.metro.Provides
import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.SingleIn
import io.element.android.features.knockrequests.api.KnockRequestPermissions import io.element.android.features.knockrequests.api.KnockRequestPermissions
import io.element.android.features.knockrequests.api.knockRequestPermissions import io.element.android.features.knockrequests.api.knockRequestPermissions
import io.element.android.features.knockrequests.impl.data.KnockRequestsService
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.powerlevels.permissionsFlow import io.element.android.libraries.matrix.api.room.powerlevels.permissionsFlow
@BindingContainer @BindingContainer
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
object KnockRequestsModule { object KnockRequestsBindingContainer {
@Provides @Provides
@SingleIn(RoomScope::class) @SingleIn(RoomScope::class)
fun knockRequestsService(room: JoinedRoom): KnockRequestsService { fun providesKnockRequestsService(room: JoinedRoom): KnockRequestsService {
return KnockRequestsService( return KnockRequestsService(
knockRequestsFlow = room.knockRequestsFlow, knockRequestsFlow = room.knockRequestsFlow,
permissionsFlow = room.permissionsFlow(KnockRequestPermissions.DEFAULT) { perms -> permissionsFlow = room.permissionsFlow(KnockRequestPermissions.DEFAULT) { perms ->
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.SessionScope
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
@BindingContainer @BindingContainer
interface LeaveRoomModule { interface LeaveRoomBindingContainer {
@Binds @Binds
fun bindLeaveRoomPresenter(presenter: LeaveRoomPresenter): Presenter<LeaveRoomState> fun bindLeaveRoomPresenter(presenter: LeaveRoomPresenter): Presenter<LeaveRoomState>
} }
@@ -8,12 +8,7 @@
package io.element.android.features.lockscreen.impl package io.element.android.features.lockscreen.impl
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import kotlin.time.Duration import kotlin.time.Duration
import io.element.android.appconfig.LockScreenConfig as AppConfigLockScreenConfig
data class LockScreenConfig( data class LockScreenConfig(
val isPinMandatory: Boolean, val isPinMandatory: Boolean,
@@ -24,18 +19,3 @@ data class LockScreenConfig(
val isStrongBiometricsEnabled: Boolean, val isStrongBiometricsEnabled: Boolean,
val isWeakBiometricsEnabled: Boolean, val isWeakBiometricsEnabled: Boolean,
) )
@ContributesTo(AppScope::class)
@BindingContainer
object LockScreenConfigModule {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = AppConfigLockScreenConfig.IS_PIN_MANDATORY,
forbiddenPinCodes = AppConfigLockScreenConfig.FORBIDDEN_PIN_CODES,
pinSize = AppConfigLockScreenConfig.PIN_SIZE,
maxPinCodeAttemptsBeforeLogout = AppConfigLockScreenConfig.MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT,
gracePeriod = AppConfigLockScreenConfig.GRACE_PERIOD,
isStrongBiometricsEnabled = AppConfigLockScreenConfig.IS_STRONG_BIOMETRICS_ENABLED,
isWeakBiometricsEnabled = AppConfigLockScreenConfig.IS_WEAK_BIOMETRICS_ENABLED,
)
}
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2026 Element Creations 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.features.lockscreen.impl.di
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.features.lockscreen.impl.LockScreenConfig
@ContributesTo(AppScope::class)
@BindingContainer
object LockScreenConfigBindingContainer {
@Provides
fun providesLockScreenConfig(): LockScreenConfig = LockScreenConfig(
isPinMandatory = io.element.android.appconfig.LockScreenConfig.IS_PIN_MANDATORY,
forbiddenPinCodes = io.element.android.appconfig.LockScreenConfig.FORBIDDEN_PIN_CODES,
pinSize = io.element.android.appconfig.LockScreenConfig.PIN_SIZE,
maxPinCodeAttemptsBeforeLogout = io.element.android.appconfig.LockScreenConfig.MAX_PIN_CODE_ATTEMPTS_BEFORE_LOGOUT,
gracePeriod = io.element.android.appconfig.LockScreenConfig.GRACE_PERIOD,
isStrongBiometricsEnabled = io.element.android.appconfig.LockScreenConfig.IS_STRONG_BIOMETRICS_ENABLED,
isWeakBiometricsEnabled = io.element.android.appconfig.LockScreenConfig.IS_WEAK_BIOMETRICS_ENABLED,
)
}
@@ -20,7 +20,7 @@ import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
interface LoginModule { interface LoginBindingContainer {
@Binds @Binds
fun bindChangeServerPresenter(presenter: ChangeServerPresenter): Presenter<ChangeServerState> fun bindChangeServerPresenter(presenter: ChangeServerPresenter): Presenter<ChangeServerState>
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.SessionScope
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
@BindingContainer @BindingContainer
interface LogoutModule { interface LogoutBindingContainer {
@Binds @Binds
fun bindDirectLogoutPresenter(presenter: DirectLogoutPresenter): Presenter<DirectLogoutState> fun bindDirectLogoutPresenter(presenter: DirectLogoutPresenter): Presenter<DirectLogoutState>
} }
@@ -34,7 +34,7 @@ import io.element.android.libraries.di.RoomScope
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
@BindingContainer @BindingContainer
interface MessagesBindsModule { interface MessagesBindingContainer {
@Binds @Binds
fun bindPinnedMessagesBannerPresenter(presenter: PinnedMessagesBannerPresenter): Presenter<PinnedMessagesBannerState> fun bindPinnedMessagesBannerPresenter(presenter: PinnedMessagesBannerPresenter): Presenter<PinnedMessagesBannerState>
@@ -18,8 +18,8 @@ import io.element.android.libraries.matrix.api.timeline.Timeline
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
@BindingContainer @BindingContainer
object MessagesProvidesModule { object MessagesProvidesBindingContainer {
@Provides @Provides
@LiveTimeline @LiveTimeline
fun provideLiveTimeline(joinedRoom: JoinedRoom): Timeline = joinedRoom.liveTimeline fun providesLiveTimeline(joinedRoom: JoinedRoom): Timeline = joinedRoom.liveTimeline
} }
@@ -10,28 +10,13 @@ package io.element.android.features.messages.impl.timeline.di
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Inject import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Multibinds
import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.SingleIn
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
import kotlin.reflect.KClass import kotlin.reflect.KClass
/**
* Container that declares the [TimelineItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@BindingContainer
@ContributesTo(RoomScope::class)
interface TimelineItemPresenterFactoriesModule {
@Multibinds
fun multiBindTimelineItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>
}
/** /**
* Room level caching layer for the [TimelineItemPresenterFactory] instances. * Room level caching layer for the [TimelineItemPresenterFactory] instances.
* *
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2026 Element Creations 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.features.messages.impl.timeline.di
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Multibinds
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.libraries.di.RoomScope
import kotlin.reflect.KClass
/**
* Container that declares the [TimelineItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@BindingContainer
@ContributesTo(RoomScope::class)
interface TimelineItemPresenterFactoriesBindingContainer {
@Multibinds
fun multiBindTimelineItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>
}
@@ -12,27 +12,12 @@ import androidx.compose.runtime.Composable
import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject import dev.zacsweers.metro.AssistedInject
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.IntoMap
import io.element.android.features.messages.impl.timeline.di.TimelineItemEventContentKey
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactory import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactory
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory
import io.element.android.libraries.voiceplayer.api.VoiceMessageState import io.element.android.libraries.voiceplayer.api.VoiceMessageState
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterModule {
@Binds
@IntoMap
@TimelineItemEventContentKey(TimelineItemVoiceContent::class)
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): TimelineItemPresenterFactory<*, *>
}
@AssistedInject @AssistedInject
class VoiceMessagePresenter( class VoiceMessagePresenter(
voiceMessagePresenterFactory: VoiceMessagePresenterFactory, voiceMessagePresenterFactory: VoiceMessagePresenterFactory,
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2026 Element Creations 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.features.messages.impl.voicemessages.timeline.di
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.IntoMap
import io.element.android.features.messages.impl.timeline.di.TimelineItemEventContentKey
import io.element.android.features.messages.impl.timeline.di.TimelineItemPresenterFactory
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
import io.element.android.features.messages.impl.voicemessages.timeline.VoiceMessagePresenter
import io.element.android.libraries.di.RoomScope
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterBindingContainer {
@Binds
@IntoMap
@TimelineItemEventContentKey(TimelineItemVoiceContent::class)
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): TimelineItemPresenterFactory<*, *>
}
@@ -17,7 +17,7 @@ import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
interface DeveloperSettingsModule { interface DeveloperSettingsBindingContainer {
@Binds @Binds
fun bindAppDeveloperSettingsPresenter(presenter: AppDeveloperSettingsPresenter): Presenter<AppDeveloperSettingsState> fun bindAppDeveloperSettingsPresenter(presenter: AppDeveloperSettingsPresenter): Presenter<AppDeveloperSettingsState>
} }
@@ -5,11 +5,13 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.features.preferences.impl.userstatus package io.element.android.features.preferences.impl.userstatus.di
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.ContributesTo
import io.element.android.features.preferences.impl.userstatus.UserStatusPresenter
import io.element.android.features.preferences.impl.userstatus.UserStatusState
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
@@ -22,7 +22,7 @@ import io.element.android.libraries.architecture.Presenter
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
interface RageshakeModule { interface RageshakeBindingContainer {
@Binds @Binds
fun bindRageshakePreferencesPresenter(presenter: RageshakePreferencesPresenter): Presenter<RageshakePreferencesState> fun bindRageshakePreferencesPresenter(presenter: RageshakePreferencesPresenter): Presenter<RageshakePreferencesState>
@@ -18,9 +18,9 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
@BindingContainer @BindingContainer
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
object RoomAliasResolverModule { object RoomAliasResolverBindingContainer {
@Provides @Provides
fun providesJoinRoomPresenterFactory( fun providesRoomAliasResolverPresenterFactory(
client: MatrixClient, client: MatrixClient,
): RoomAliasResolverPresenter.Factory { ): RoomAliasResolverPresenter.Factory {
return object : RoomAliasResolverPresenter.Factory { return object : RoomAliasResolverPresenter.Factory {
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.RoomScope
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
@BindingContainer @BindingContainer
interface RoomCallModule { interface RoomCallBindingContainer {
@Binds @Binds
fun bindRoomCallStatePresenter(presenter: RoomCallStatePresenter): Presenter<RoomCallState> fun bindRoomCallStatePresenter(presenter: RoomCallStatePresenter): Presenter<RoomCallState>
} }
@@ -21,9 +21,9 @@ import io.element.android.libraries.matrix.api.room.JoinedRoom
@BindingContainer @BindingContainer
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
object RoomMemberModule { object RoomMemberBindingContainer {
@Provides @Provides
fun provideRoomMemberDetailsPresenterFactory( fun providesRoomMemberDetailsPresenterFactory(
room: JoinedRoom, room: JoinedRoom,
userProfilePresenterFactory: UserProfilePresenterFactory, userProfilePresenterFactory: UserProfilePresenterFactory,
encryptionService: EncryptionService, encryptionService: EncryptionService,
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.RoomScope
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
@BindingContainer @BindingContainer
interface RoomMemberModerationModule { interface RoomMemberModerationBindingContainer {
@Binds @Binds
fun bindRoomMemberModerationPresenter(presenter: RoomMemberModerationPresenter): Presenter<RoomMemberModerationState> fun bindRoomMemberModerationPresenter(presenter: RoomMemberModerationPresenter): Presenter<RoomMemberModerationState>
} }
@@ -22,10 +22,10 @@ import timber.log.Timber
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object CacheStoreModule { object CacheStoreBindingContainer {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun provideCacheDatabase( fun providesCacheDatabase(
@ApplicationContext context: Context, @ApplicationContext context: Context,
): CacheDatabase { ): CacheDatabase {
val name = "cache_database" val name = "cache_database"
@@ -26,6 +26,8 @@ import java.util.concurrent.ConcurrentHashMap
import javax.crypto.KeyGenerator import javax.crypto.KeyGenerator
import javax.crypto.SecretKey import javax.crypto.SecretKey
internal const val ANDROID_KEYSTORE = "AndroidKeyStore"
/** /**
* Default implementation of [SecretKeyRepository] that uses the Android Keystore to store the keys. * Default implementation of [SecretKeyRepository] that uses the Android Keystore to store the keys.
* The generated key uses AES algorithm, with a key size of 128 bits, and the GCM block mode. * The generated key uses AES algorithm, with a key size of 128 bits, and the GCM block mode.
@@ -6,19 +6,18 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.libraries.cryptography.impl package io.element.android.libraries.cryptography.impl.di
import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides import dev.zacsweers.metro.Provides
import io.element.android.libraries.cryptography.impl.ANDROID_KEYSTORE
import java.security.KeyStore import java.security.KeyStore
internal const val ANDROID_KEYSTORE = "AndroidKeyStore"
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
object CryptographyModule { object CryptographyBindingContainer {
@Provides @Provides
fun providesAndroidKeyStore(): KeyStore { fun providesAndroidKeyStore(): KeyStore {
return KeyStore.getInstance(ANDROID_KEYSTORE).apply { return KeyStore.getInstance(ANDROID_KEYSTORE).apply {
@@ -19,7 +19,7 @@ import kotlin.time.Clock
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object DateFormatterModule { object DateFormatterBindingContainer {
@Provides @Provides
fun providesClock(): Clock = Clock.System fun providesClock(): Clock = Clock.System
@@ -27,5 +27,5 @@ object DateFormatterModule {
fun providesLocale(): Locale = Locale.getDefault() fun providesLocale(): Locale = Locale.getDefault()
@Provides @Provides
fun providesTimezone(): TimezoneProvider = TimezoneProvider { TimeZone.currentSystemDefault() } fun providesTimezoneProvider(): TimezoneProvider = TimezoneProvider { TimeZone.currentSystemDefault() }
} }
@@ -18,7 +18,7 @@ import io.element.android.libraries.featureflag.impl.PreferencesFeatureFlagProvi
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object FeatureFlagModule { object FeatureFlagBindingContainer {
@JvmStatic @JvmStatic
@Provides @Provides
@ElementsIntoSet @ElementsIntoSet
@@ -18,7 +18,7 @@ import io.element.android.libraries.fullscreenintent.impl.FullScreenIntentPermis
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
@BindingContainer @BindingContainer
interface FullScreenIntentModule { interface FullScreenIntentBindingContainer {
@Binds @Binds
fun bindFullScreenIntentPermissionsPresenter(presenter: FullScreenIntentPermissionsPresenter): Presenter<FullScreenIntentPermissionsState> fun bindFullScreenIntentPermissionsPresenter(presenter: FullScreenIntentPermissionsPresenter): Presenter<FullScreenIntentPermissionsState>
} }
@@ -18,7 +18,7 @@ import kotlinx.coroutines.CoroutineScope
@BindingContainer @BindingContainer
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
object RoomModule { object RoomBindingContainer {
@RoomCoroutineScope @RoomCoroutineScope
@Provides @Provides
fun providesSessionCoroutineScope(room: BaseRoom): CoroutineScope { fun providesSessionCoroutineScope(room: BaseRoom): CoroutineScope {
@@ -34,7 +34,7 @@ import kotlinx.coroutines.CoroutineScope
@BindingContainer @BindingContainer
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
object SessionMatrixModule { object SessionMatrixBindingContainer {
@Provides @Provides
fun providesSessionId(matrixClient: MatrixClient): SessionId { fun providesSessionId(matrixClient: MatrixClient): SessionId {
return matrixClient.sessionId return matrixClient.sessionId
@@ -56,7 +56,7 @@ object SessionMatrixModule {
} }
@Provides @Provides
fun provideRoomMembershipObserver(matrixClient: MatrixClient): RoomMembershipObserver { fun providesRoomMembershipObserver(matrixClient: MatrixClient): RoomMembershipObserver {
return matrixClient.roomMembershipObserver return matrixClient.roomMembershipObserver
} }
@@ -112,7 +112,7 @@ object SessionMatrixModule {
} }
@Provides @Provides
fun providesGetUrlResolverClient(matrixClient: MatrixClient): ClientUrlContentFetcher { fun providesClientUrlContentFetcher(matrixClient: MatrixClient): ClientUrlContentFetcher {
return matrixClient return matrixClient
} }
@@ -8,16 +8,8 @@
package io.element.android.libraries.mediaplayer.impl package io.element.android.libraries.mediaplayer.impl
import android.content.Context
import androidx.media3.common.C
import androidx.media3.common.MediaItem import androidx.media3.common.MediaItem
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.annotations.ApplicationContext
/** /**
* A subset of media3 [Player] that only exposes the few methods we need making it easier to mock. * A subset of media3 [Player] that only exposes the few methods we need making it easier to mock.
@@ -44,15 +36,6 @@ interface SimplePlayer {
} }
} }
@ContributesTo(RoomScope::class)
@BindingContainer
object SimplePlayerModule {
@Provides
fun simplePlayerProvider(
@ApplicationContext context: Context,
): SimplePlayer = DefaultSimplePlayer(ExoPlayer.Builder(context).setWakeMode(C.WAKE_MODE_LOCAL).build())
}
/** /**
* Default implementation of [SimplePlayer] backed by a media3 [Player]. * Default implementation of [SimplePlayer] backed by a media3 [Player].
*/ */
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2026 Element Creations 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.mediaplayer.impl.di
import android.content.Context
import androidx.media3.common.C
import androidx.media3.exoplayer.ExoPlayer
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.mediaplayer.impl.DefaultSimplePlayer
import io.element.android.libraries.mediaplayer.impl.SimplePlayer
@ContributesTo(RoomScope::class)
@BindingContainer
object SimplePlayerBindingContainer {
@Provides
fun providesSimplePlayer(
@ApplicationContext context: Context,
): SimplePlayer = DefaultSimplePlayer(ExoPlayer.Builder(context).setWakeMode(C.WAKE_MODE_LOCAL).build())
}
@@ -10,28 +10,13 @@ package io.element.android.libraries.mediaviewer.impl.gallery.di
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Inject import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Multibinds
import dev.zacsweers.metro.SingleIn import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import kotlin.reflect.KClass import kotlin.reflect.KClass
/**
* Container that declares the [MediaItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@BindingContainer
@ContributesTo(RoomScope::class)
interface MediaItemPresenterFactoriesModule {
@Multibinds
fun multiBindMediaItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>
}
/** /**
* Room level caching layer for the [MediaItemPresenterFactory] instances. * Room level caching layer for the [MediaItemPresenterFactory] instances.
* *
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2026 Element Creations 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.mediaviewer.impl.gallery.di
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Multibinds
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import kotlin.reflect.KClass
/**
* Container that declares the [MediaItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@BindingContainer
@ContributesTo(RoomScope::class)
interface MediaItemPresenterFactoriesBindingContainer {
@Multibinds
fun multiBindMediaItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>
}
@@ -12,28 +12,13 @@ import androidx.compose.runtime.Composable
import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject import dev.zacsweers.metro.AssistedInject
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.IntoMap
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemEventContentKey
import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresenterFactory import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresenterFactory
import io.element.android.libraries.mediaviewer.impl.model.MediaItem import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory
import io.element.android.libraries.voiceplayer.api.VoiceMessageState import io.element.android.libraries.voiceplayer.api.VoiceMessageState
import kotlin.time.Duration import kotlin.time.Duration
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterModule {
@Binds
@IntoMap
@MediaItemEventContentKey(MediaItem.Voice::class)
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): MediaItemPresenterFactory<*, *>
}
@AssistedInject @AssistedInject
class VoiceMessagePresenter( class VoiceMessagePresenter(
voiceMessagePresenterFactory: VoiceMessagePresenterFactory, voiceMessagePresenterFactory: VoiceMessagePresenterFactory,
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2026 Element Creations 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.mediaviewer.impl.gallery.voice.di
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.IntoMap
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemEventContentKey
import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresenterFactory
import io.element.android.libraries.mediaviewer.impl.gallery.voice.VoiceMessagePresenter
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterBindingContainer {
@Binds
@IntoMap
@MediaItemEventContentKey(MediaItem.Voice::class)
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): MediaItemPresenterFactory<*, *>
}
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.libraries.network package io.element.android.libraries.network.di
import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
@@ -23,7 +23,7 @@ import java.util.concurrent.TimeUnit
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object NetworkModule { object NetworkBindingContainer {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun providesOkHttpClient( fun providesOkHttpClient(
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.libraries.preferences.impl.store package io.element.android.libraries.preferences.impl.store.di
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo import dev.zacsweers.metro.ContributesTo
@@ -15,11 +15,12 @@ import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
import io.element.android.libraries.preferences.impl.store.DefaultSessionPreferencesStoreFactory
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@BindingContainer @BindingContainer
@ContributesTo(SessionScope::class) @ContributesTo(SessionScope::class)
object SessionPreferencesModule { object SessionPreferencesBindingContainer {
@Provides @Provides
fun providesSessionPreferencesStore( fun providesSessionPreferencesStore(
defaultSessionPreferencesStoreFactory: DefaultSessionPreferencesStoreFactory, defaultSessionPreferencesStoreFactory: DefaultSessionPreferencesStoreFactory,
@@ -22,10 +22,10 @@ import io.element.android.libraries.push.impl.battery.BatteryOptimizationPresent
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
interface PushModule { interface PushBindingContainer {
companion object { companion object {
@Provides @Provides
fun provideNotificationCompatManager(@ApplicationContext context: Context): NotificationManagerCompat { fun providesNotificationManagerCompat(@ApplicationContext context: Context): NotificationManagerCompat {
return NotificationManagerCompat.from(context) return NotificationManagerCompat.from(context)
} }
} }
@@ -23,10 +23,10 @@ import timber.log.Timber
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object PushHistoryModule { object PushHistoryBindingContainer {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun providePushDatabase( fun providesPushDatabase(
@ApplicationContext context: Context, @ApplicationContext context: Context,
): PushDatabase { ): PushDatabase {
val name = "push_database" val name = "push_database"
@@ -23,10 +23,10 @@ import timber.log.Timber
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object SessionStorageModule { object SessionStorageBindingContainer {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun provideMatrixDatabase( fun providesSessionDatabase(
@ApplicationContext context: Context, @ApplicationContext context: Context,
): SessionDatabase { ): SessionDatabase {
val name = "session_database" val name = "session_database"
@@ -22,9 +22,9 @@ import io.element.android.opusencoder.OggOpusEncoder
@BindingContainer @BindingContainer
@ContributesTo(RoomScope::class) @ContributesTo(RoomScope::class)
object VoiceRecorderModule { object VoiceRecorderBindingContainer {
@Provides @Provides
fun provideAudioConfig(): AudioConfig { fun providesAudioConfig(): AudioConfig {
val sampleRate = SampleRate val sampleRate = SampleRate
return AudioConfig( return AudioConfig(
format = AudioFormat.Builder() format = AudioFormat.Builder()
@@ -40,7 +40,7 @@ object VoiceRecorderModule {
} }
@Provides @Provides
public fun provideVoiceFileConfig(): VoiceFileConfig = public fun providesVoiceFileConfig(): VoiceFileConfig =
VoiceFileConfig( VoiceFileConfig(
cacheSubdir = "voice_recordings", cacheSubdir = "voice_recordings",
fileExt = "ogg", fileExt = "ogg",
@@ -48,5 +48,5 @@ object VoiceRecorderModule {
) )
@Provides @Provides
fun provideOggOpusEncoder(): OggOpusEncoder = OggOpusEncoder.create() fun providesOggOpusEncoder(): OggOpusEncoder = OggOpusEncoder.create()
} }
@@ -18,7 +18,7 @@ import io.element.android.libraries.voicerecorder.api.VoiceRecorderState
import io.element.android.libraries.voicerecorder.impl.audio.Audio import io.element.android.libraries.voicerecorder.impl.audio.Audio
import io.element.android.libraries.voicerecorder.impl.audio.AudioConfig import io.element.android.libraries.voicerecorder.impl.audio.AudioConfig
import io.element.android.libraries.voicerecorder.impl.audio.SampleRate import io.element.android.libraries.voicerecorder.impl.audio.SampleRate
import io.element.android.libraries.voicerecorder.impl.di.VoiceRecorderModule import io.element.android.libraries.voicerecorder.impl.di.VoiceRecorderBindingContainer
import io.element.android.libraries.voicerecorder.test.FakeAudioLevelCalculator import io.element.android.libraries.voicerecorder.test.FakeAudioLevelCalculator
import io.element.android.libraries.voicerecorder.test.FakeAudioReaderFactory import io.element.android.libraries.voicerecorder.test.FakeAudioReaderFactory
import io.element.android.libraries.voicerecorder.test.FakeEncoder import io.element.android.libraries.voicerecorder.test.FakeEncoder
@@ -151,7 +151,7 @@ class DefaultVoiceRecorderTest {
} }
private fun TestScope.createDefaultVoiceRecorder(): DefaultVoiceRecorder { private fun TestScope.createDefaultVoiceRecorder(): DefaultVoiceRecorder {
val fileConfig = VoiceRecorderModule.provideVoiceFileConfig() val fileConfig = VoiceRecorderBindingContainer.providesVoiceFileConfig()
return DefaultVoiceRecorder( return DefaultVoiceRecorder(
dispatchers = testCoroutineDispatchers(), dispatchers = testCoroutineDispatchers(),
timeSource = timeSource, timeSource = timeSource,
@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.libraries.workmanager.impl package io.element.android.libraries.workmanager.impl.di
import android.content.Context import android.content.Context
import androidx.work.WorkManager import androidx.work.WorkManager
@@ -18,7 +18,7 @@ import io.element.android.libraries.di.annotations.ApplicationContext
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object WorkManagerModule { object WorkManagerBindingContainer {
@Provides @Provides
@SingleIn(AppScope::class) @SingleIn(AppScope::class)
fun providesWorkManager( fun providesWorkManager(
@@ -15,7 +15,7 @@ import io.element.android.libraries.di.identifiers.SentrySdkDsn
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object NoopAnalyticsModule { object NoopAnalyticsBindingContainer {
@Provides @Provides
fun provideSentrySdkDsn(): SentrySdkDsn? = null fun providesSentrySdkDsn(): SentrySdkDsn? = null
} }
@@ -17,10 +17,10 @@ import io.element.android.services.analyticsproviders.sentry.SentryConfig
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object SentryModule { object SentryBindingContainer {
@Provides @Provides
fun provideSentryDsn(): SentryDsn? = SentryConfig.DSN.takeIf { it.isNotBlank() }?.let(::SentryDsn) fun providesSentryDsn(): SentryDsn? = SentryConfig.DSN.takeIf { it.isNotBlank() }?.let(::SentryDsn)
@Provides @Provides
fun provideSentrySdkDsn(): SentrySdkDsn? = SentryConfig.SDK_DSN.takeIf { it.isNotBlank() }?.let(::SentrySdkDsn) fun providesSentrySdkDsn(): SentrySdkDsn? = SentryConfig.SDK_DSN.takeIf { it.isNotBlank() }?.let(::SentrySdkDsn)
} }
@@ -20,9 +20,9 @@ import io.element.android.services.appnavstate.impl.initializer.AppForegroundSta
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object AppNavStateModule { object AppNavStateBindingContainer {
@Provides @Provides
fun provideAppForegroundStateService( fun providesAppForegroundStateService(
@ApplicationContext context: Context @ApplicationContext context: Context
): AppForegroundStateService = ): AppForegroundStateService =
AppInitializer.getInstance(context).initializeComponent(AppForegroundStateServiceInitializer::class.java) AppInitializer.getInstance(context).initializeComponent(AppForegroundStateServiceInitializer::class.java)
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details. * Please see LICENSE files in the repository root for full details.
*/ */
package io.element.android.services.toolbox.impl.systemclock package io.element.android.services.toolbox.impl.systemclock.di
import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.BindingContainer import dev.zacsweers.metro.BindingContainer
@@ -16,9 +16,9 @@ import kotlin.time.TimeSource
@BindingContainer @BindingContainer
@ContributesTo(AppScope::class) @ContributesTo(AppScope::class)
object TimeModule { object TimeBindingContainer {
@Provides @Provides
fun timeSource(): TimeSource { fun providesTimeSource(): TimeSource {
return TimeSource.Monotonic return TimeSource.Monotonic
} }
} }