Start migrating Anvil KSP to Metro

This commit is contained in:
Jorge Martín 2025-08-20 15:29:50 +02:00
parent d4d57b1e21
commit b76a71ebf5
703 changed files with 3523 additions and 2820 deletions

View file

@ -11,15 +11,16 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import androidx.core.content.getSystemService
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.SingleIn
import javax.inject.Inject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class AndroidClipboardHelper @Inject constructor(
@Inject
class AndroidClipboardHelper(
@ApplicationContext private val context: Context,
) : ClipboardHelper {
private val clipboardManager = requireNotNull(context.getSystemService<ClipboardManager>())

View file

@ -9,11 +9,11 @@ package io.element.android.libraries.androidutils.file
import android.content.Context
import android.net.Uri
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import timber.log.Timber
import javax.inject.Inject
interface TemporaryUriDeleter {
/**
@ -23,7 +23,8 @@ interface TemporaryUriDeleter {
}
@ContributesBinding(AppScope::class)
class DefaultTemporaryUriDeleter @Inject constructor(
@Inject
class DefaultTemporaryUriDeleter(
@ApplicationContext private val context: Context,
) : TemporaryUriDeleter {
private val baseCacheUri = "content://${context.packageName}.fileprovider/cache"

View file

@ -10,14 +10,15 @@ package io.element.android.libraries.androidutils.filesize
import android.content.Context
import android.os.Build
import android.text.format.Formatter
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class AndroidFileSizeFormatter @Inject constructor(
@Inject
class AndroidFileSizeFormatter(
@ApplicationContext private val context: Context,
private val sdkIntProvider: BuildVersionSdkIntProvider,
) : FileSizeFormatter {

View file

@ -11,15 +11,15 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.androidutils.system.DateTimeObserver.Event
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import java.time.Instant
import javax.inject.Inject
interface DateTimeObserver {
val changes: Flow<Event>
@ -32,7 +32,8 @@ interface DateTimeObserver {
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class DefaultDateTimeObserver @Inject constructor(
@Inject
class DefaultDateTimeObserver(
@ApplicationContext context: Context
) : DateTimeObserver {
private val dateTimeReceiver = object : BroadcastReceiver() {

View file

@ -1,3 +1,5 @@
import extension.setupAnvil
/*
* Copyright 2023, 2024 New Vector Ltd.
*
@ -13,10 +15,12 @@ android {
namespace = "io.element.android.libraries.architecture"
}
setupAnvil()
dependencies {
api(projects.libraries.di)
api(projects.libraries.core)
api(libs.dagger)
api(libs.metro.runtime)
api(libs.appyx.core)
api(libs.androidx.lifecycle.runtime)
api(libs.molecule.runtime)

View file

@ -11,6 +11,11 @@ import android.content.Context
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Multibinds
import io.element.android.libraries.di.AppScope
import kotlin.reflect.KClass
inline fun <reified N : Node> Node.createNode(
buildContext: BuildContext,
@ -32,11 +37,11 @@ inline fun <reified N : Node> NodeFactoriesBindings.createNode(
buildContext: BuildContext,
plugins: List<Plugin> = emptyList()
): N {
val nodeClass = N::class.java
val nodeClass = N::class
val nodeFactoryMap = nodeFactories()
// Note to developers: If you got the error below, make sure to build again after
// clearing the cache (sometimes several times) to let Dagger generate the NodeFactory.
val nodeFactory = nodeFactoryMap[nodeClass] ?: error("Cannot find NodeFactory for ${nodeClass.name}.")
val nodeFactory = nodeFactoryMap[nodeClass] ?: error("Cannot find NodeFactory for ${nodeClass.java.name}.")
@Suppress("UNCHECKED_CAST")
val castedNodeFactory = nodeFactory as? AssistedNodeFactory<N>
@ -44,6 +49,8 @@ inline fun <reified N : Node> NodeFactoriesBindings.createNode(
return node as N
}
//@BindingContainer
interface NodeFactoriesBindings {
fun nodeFactories(): Map<Class<out Node>, AssistedNodeFactory<*>>
@Multibinds
fun nodeFactories(): Map<KClass<out Node>, AssistedNodeFactory<*>>
}

View file

@ -8,10 +8,10 @@
package io.element.android.libraries.architecture
import com.bumble.appyx.core.node.Node
import dagger.MapKey
import dev.zacsweers.metro.MapKey
import kotlin.reflect.KClass
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
@MapKey
annotation class NodeKey(val value: KClass<out Node>)

View file

@ -13,15 +13,16 @@ import android.media.AudioFocusRequest
import android.media.AudioManager
import android.os.Build
import androidx.core.content.getSystemService
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.audio.api.AudioFocus
import io.element.android.libraries.audio.api.AudioFocusRequester
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import javax.inject.Inject
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
@ContributesBinding(AppScope::class)
class DefaultAudioFocus @Inject constructor(
@Inject
class DefaultAudioFocus(
@ApplicationContext private val context: Context,
) : AudioFocus {
private val audioManager = requireNotNull(context.getSystemService<AudioManager>())

View file

@ -7,21 +7,22 @@
package io.element.android.libraries.cryptography.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.cryptography.api.AESEncryptionSpecs
import io.element.android.libraries.cryptography.api.EncryptionDecryptionService
import io.element.android.libraries.cryptography.api.EncryptionResult
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* Default implementation of [EncryptionDecryptionService] using AES encryption.
*/
@ContributesBinding(AppScope::class)
class AESEncryptionDecryptionService @Inject constructor() : EncryptionDecryptionService {
@Inject
class AESEncryptionDecryptionService() : EncryptionDecryptionService {
override fun createEncryptionCipher(key: SecretKey): Cipher {
return Cipher.getInstance(AESEncryptionSpecs.CIPHER_TRANSFORMATION).apply {
init(Cipher.ENCRYPT_MODE, key)

View file

@ -7,16 +7,16 @@
package io.element.android.libraries.cryptography.impl
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import dev.zacsweers.metro.AppScope
import java.security.KeyStore
internal const val ANDROID_KEYSTORE = "AndroidKeyStore"
@ContributesTo(AppScope::class)
@Module
@BindingContainer
object CryptographyModule {
@Provides
fun providesAndroidKeyStore(): KeyStore {

View file

@ -10,23 +10,24 @@ package io.element.android.libraries.cryptography.impl
import android.annotation.SuppressLint
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.cryptography.api.AESEncryptionSpecs
import io.element.android.libraries.cryptography.api.SecretKeyRepository
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import timber.log.Timber
import java.security.KeyStore
import java.security.KeyStoreException
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* 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.
*/
@ContributesBinding(AppScope::class)
class KeyStoreSecretKeyRepository @Inject constructor(
@Inject
class KeyStoreSecretKeyRepository(
private val keyStore: KeyStore,
) : SecretKeyRepository {
// False positive lint issue

View file

@ -7,10 +7,10 @@
package io.element.android.libraries.dateformatter.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.extensions.safeCapitalize
import io.element.android.libraries.di.AppScope
import javax.inject.Inject
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Inject
interface DateFormatterDay {
fun format(
@ -20,7 +20,8 @@ interface DateFormatterDay {
}
@ContributesBinding(AppScope::class)
class DefaultDateFormatterDay @Inject constructor(
@Inject
class DefaultDateFormatterDay(
private val localDateTimeProvider: LocalDateTimeProvider,
private val dateFormatters: DateFormatters,
) : DateFormatterDay {

View file

@ -8,9 +8,10 @@
package io.element.android.libraries.dateformatter.impl
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class DateFormatterFull @Inject constructor(
@Inject
class DateFormatterFull(
private val stringProvider: StringProvider,
private val localDateTimeProvider: LocalDateTimeProvider,
private val dateFormatters: DateFormatters,

View file

@ -9,9 +9,10 @@ package io.element.android.libraries.dateformatter.impl
import io.element.android.libraries.core.extensions.safeCapitalize
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class DateFormatterMonth @Inject constructor(
@Inject
class DateFormatterMonth(
private val stringProvider: StringProvider,
private val localDateTimeProvider: LocalDateTimeProvider,
private val dateFormatters: DateFormatters,

View file

@ -7,9 +7,10 @@
package io.element.android.libraries.dateformatter.impl
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class DateFormatterTime @Inject constructor(
@Inject
class DateFormatterTime(
private val localDateTimeProvider: LocalDateTimeProvider,
private val dateFormatters: DateFormatters,
) {

View file

@ -7,9 +7,10 @@
package io.element.android.libraries.dateformatter.impl
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class DateFormatterTimeOnly @Inject constructor(
@Inject
class DateFormatterTimeOnly(
private val localDateTimeProvider: LocalDateTimeProvider,
private val dateFormatters: DateFormatters,
) {

View file

@ -8,8 +8,8 @@
package io.element.android.libraries.dateformatter.impl
import android.text.format.DateUtils
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.SingleIn
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toInstant
import kotlinx.datetime.toJavaLocalDate
@ -17,12 +17,13 @@ import kotlinx.datetime.toJavaLocalDateTime
import timber.log.Timber
import java.time.Period
import java.util.Locale
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.math.absoluteValue
import kotlin.time.Clock
@SingleIn(AppScope::class)
class DateFormatters @Inject constructor(
@Inject
class DateFormatters(
localeChangeObserver: LocaleChangeObserver,
private val clock: Clock,
private val timeZoneProvider: TimezoneProvider,

View file

@ -7,14 +7,15 @@
package io.element.android.libraries.dateformatter.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.api.DateFormatterMode
import io.element.android.libraries.di.AppScope
import javax.inject.Inject
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultDateFormatter @Inject constructor(
@Inject
class DefaultDateFormatter(
private val dateFormatterFull: DateFormatterFull,
private val dateFormatterMonth: DateFormatterMonth,
private val dateFormatterDay: DateFormatterDay,

View file

@ -9,11 +9,12 @@ package io.element.android.libraries.dateformatter.impl
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.toLocalDateTime
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.time.Clock
import kotlin.time.Instant
class LocalDateTimeProvider @Inject constructor(
@Inject
class LocalDateTimeProvider(
private val clock: Clock,
private val timezoneProvider: TimezoneProvider,
) {

View file

@ -12,11 +12,11 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
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.SingleIn
import javax.inject.Inject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import dev.zacsweers.metro.SingleIn
import dev.zacsweers.metro.Inject
fun interface LocaleChangeObserver {
fun addListener(listener: LocaleChangeListener)
@ -28,7 +28,8 @@ interface LocaleChangeListener {
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class)
class DefaultLocaleChangeObserver @Inject constructor(
@Inject
class DefaultLocaleChangeObserver(
@ApplicationContext private val context: Context,
) : LocaleChangeObserver {
init {

View file

@ -7,16 +7,16 @@
package io.element.android.libraries.dateformatter.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.dateformatter.impl.TimezoneProvider
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import kotlinx.datetime.TimeZone
import java.util.Locale
import kotlin.time.Clock
@Module
@BindingContainer
@ContributesTo(AppScope::class)
object DateFormatterModule {
@Provides

View file

@ -7,13 +7,13 @@
package io.element.android.libraries.deeplink.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.deeplink.api.DeepLinkCreator
import io.element.android.libraries.di.AppScope
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.ThreadId
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultDeepLinkCreator @Inject constructor() : DeepLinkCreator {

View file

@ -9,17 +9,18 @@ package io.element.android.libraries.deeplink.impl
import android.content.Intent
import android.net.Uri
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.deeplink.api.DeeplinkData
import io.element.android.libraries.deeplink.api.DeeplinkParser
import io.element.android.libraries.di.AppScope
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.ThreadId
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultDeeplinkParser @Inject constructor() : DeeplinkParser {
@Inject
class DefaultDeeplinkParser: DeeplinkParser {
override fun getFromIntent(intent: Intent): DeeplinkData? {
return intent
.takeIf { it.action == Intent.ACTION_VIEW }

View file

@ -8,7 +8,8 @@
package io.element.android.libraries.deeplink.impl.usecase
import android.app.Activity
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import io.element.android.libraries.androidutils.system.startSharePlainTextIntent
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.deeplink.api.usecase.InviteFriendsUseCase
@ -18,11 +19,11 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider
import timber.log.Timber
import javax.inject.Inject
import io.element.android.libraries.androidutils.R as AndroidUtilsR
@ContributesBinding(SessionScope::class)
class DefaultInviteFriendsUseCase @Inject constructor(
@Inject
class DefaultInviteFriendsUseCase(
private val stringProvider: StringProvider,
private val matrixClient: MatrixClient,
private val buildMeta: BuildMeta,

View file

@ -12,4 +12,5 @@ plugins {
dependencies {
api(libs.inject)
api(libs.metro.runtime)
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2022-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
import dev.zacsweers.metro.Qualifier
/**
* Qualifies a [File] object which represents the application base directory.
*/
//@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Qualifier
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FIELD,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE,
)
public annotation class BaseDirectory

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.di
import javax.inject.Qualifier
import dev.zacsweers.metro.Qualifier
/**
* Qualifies a [File] object which represents the application cache directory.
@ -15,4 +15,13 @@ import javax.inject.Qualifier
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Qualifier
annotation class CacheDirectory
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FIELD,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE,
)
public annotation class CacheDirectory

View file

@ -1,15 +0,0 @@
/*
* Copyright 2022-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
import javax.inject.Scope
import kotlin.reflect.KClass
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class SingleIn(val clazz: KClass<*>)

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.di.annotations
import javax.inject.Qualifier
import dev.zacsweers.metro.Qualifier
/**
* Qualifies a [CoroutineScope] object which represents the base coroutine scope to use for the application.

View file

@ -1,13 +1,13 @@
/*
* Copyright 2022-2024 New Vector Ltd.
* Copyright 2025 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
package io.element.android.libraries.di.annotations
import javax.inject.Qualifier
import dev.zacsweers.metro.Qualifier
/**
* Qualifies a [Context] object that represents the application context.

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.di.annotations
import javax.inject.Qualifier
import dev.zacsweers.metro.Qualifier
/**
* Qualifies a [CoroutineScope] object which represents the base coroutine scope to use for an active session.

View file

@ -9,7 +9,7 @@ package io.element.android.libraries.eventformatter.impl
import androidx.annotation.StringRes
import androidx.compose.ui.text.AnnotatedString
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.eventformatter.api.PinnedMessagesBannerFormatter
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
@ -35,10 +35,11 @@ import io.element.android.libraries.matrix.api.timeline.item.event.getDisambigua
import io.element.android.libraries.matrix.ui.messages.toPlainText
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultPinnedMessagesBannerFormatter @Inject constructor(
@Inject
class DefaultPinnedMessagesBannerFormatter(
private val sp: StringProvider,
private val permalinkParser: PermalinkParser,
) : PinnedMessagesBannerFormatter {

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.eventformatter.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
import io.element.android.libraries.eventformatter.impl.mode.RenderingMode
@ -42,10 +42,11 @@ import io.element.android.libraries.matrix.api.timeline.item.event.getDisambigua
import io.element.android.libraries.matrix.ui.messages.toPlainText
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultRoomLastMessageFormatter @Inject constructor(
@Inject
class DefaultRoomLastMessageFormatter(
private val sp: StringProvider,
private val roomMembershipContentFormatter: RoomMembershipContentFormatter,
private val profileChangeContentFormatter: ProfileChangeContentFormatter,

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.eventformatter.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
@ -29,10 +29,11 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnknownConten
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultTimelineEventFormatter @Inject constructor(
@Inject
class DefaultTimelineEventFormatter(
private val sp: StringProvider,
private val buildMeta: BuildMeta,
private val roomMembershipContentFormatter: RoomMembershipContentFormatter,

View file

@ -10,9 +10,10 @@ package io.element.android.libraries.eventformatter.impl
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
import io.element.android.services.toolbox.api.strings.StringProvider
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class ProfileChangeContentFormatter @Inject constructor(
@Inject
class ProfileChangeContentFormatter(
private val sp: StringProvider,
) {
fun format(

View file

@ -12,9 +12,10 @@ import io.element.android.libraries.matrix.api.timeline.item.event.MembershipCha
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.services.toolbox.api.strings.StringProvider
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class RoomMembershipContentFormatter @Inject constructor(
@Inject
class RoomMembershipContentFormatter(
private val matrixClient: MatrixClient,
private val sp: StringProvider,
) {

View file

@ -13,9 +13,10 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.services.toolbox.api.strings.StringProvider
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class StateContentFormatter @Inject constructor(
@Inject
class StateContentFormatter(
private val sp: StringProvider,
) {
fun format(

View file

@ -7,19 +7,20 @@
package io.element.android.libraries.featureflag.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.featureflag.api.FeatureFlagService
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class DefaultFeatureFlagService @Inject constructor(
@Inject
class DefaultFeatureFlagService(
private val providers: Set<@JvmSuppressWildcards FeatureFlagProvider>,
private val buildMeta: BuildMeta,
) : FeatureFlagService {

View file

@ -9,18 +9,19 @@ package io.element.android.libraries.featureflag.impl
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import dev.zacsweers.metro.Inject
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.featureflag.api.Feature
import io.element.android.libraries.preferences.api.store.PreferenceDataStoreFactory
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import javax.inject.Inject
/**
* Note: this will be used only in the nightly and in the debug build.
*/
class PreferencesFeatureFlagProvider @Inject constructor(
@Inject
class PreferencesFeatureFlagProvider(
private val buildMeta: BuildMeta,
preferenceDataStoreFactory: PreferenceDataStoreFactory,
) : MutableFeatureFlagProvider {

View file

@ -7,15 +7,15 @@
package io.element.android.libraries.featureflag.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dagger.multibindings.ElementsIntoSet
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.featureflag.impl.FeatureFlagProvider
import io.element.android.libraries.featureflag.impl.PreferencesFeatureFlagProvider
@Module
@BindingContainer
@ContributesTo(AppScope::class)
object FeatureFlagModule {
@JvmStatic

View file

@ -19,6 +19,9 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsEvents
@ -28,9 +31,10 @@ import io.element.android.services.toolbox.api.intent.ExternalIntentLauncher
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
class FullScreenIntentPermissionsPresenter @Inject constructor(
@SingleIn(AppScope::class)
@Inject
class FullScreenIntentPermissionsPresenter(
private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider,
private val externalIntentLauncher: ExternalIntentLauncher,
private val buildMeta: BuildMeta,

View file

@ -7,16 +7,16 @@
package io.element.android.libraries.fullscreenintent.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Binds
import dagger.Module
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.ContributesTo
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
import io.element.android.libraries.fullscreenintent.impl.FullScreenIntentPermissionsPresenter
@ContributesTo(AppScope::class)
@Module
@BindingContainer
interface FullScreenIntentModule {
@Binds
fun bindFullScreenIntentPermissionsPresenter(presenter: FullScreenIntentPermissionsPresenter): Presenter<FullScreenIntentPermissionsState>

View file

@ -13,17 +13,18 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.indicator.api.IndicatorService
import io.element.android.libraries.matrix.api.encryption.BackupState
import io.element.android.libraries.matrix.api.encryption.EncryptionService
import io.element.android.libraries.matrix.api.encryption.RecoveryState
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultIndicatorService @Inject constructor(
@Inject
class DefaultIndicatorService(
private val sessionVerificationService: SessionVerificationService,
private val encryptionService: EncryptionService,
) : IndicatorService {

View file

@ -7,9 +7,10 @@
package io.element.android.libraries.matrix.api.mxc
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class MxcTools @Inject constructor() {
@Inject
class MxcTools() {
/**
* Regex to match a Matrix Content (mxc://) URI.
*

View file

@ -8,13 +8,14 @@
package io.element.android.libraries.matrix.api.user
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(SessionScope::class)
class CurrentSessionIdHolder @Inject constructor(matrixClient: MatrixClient) {
@Inject
class CurrentSessionIdHolder(matrixClient: MatrixClient) {
val current = matrixClient.sessionId
fun isCurrentSession(sessionId: SessionId?): Boolean = current == sessionId

View file

@ -7,17 +7,18 @@
package io.element.android.libraries.matrix.impl
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import org.matrix.rustcomponents.sdk.ClientBuilder
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface ClientBuilderProvider {
fun provide(): ClientBuilder
}
@ContributesBinding(AppScope::class)
class RustClientBuilderProvider @Inject constructor() : ClientBuilderProvider {
@Inject
class RustClientBuilderProvider() : ClientBuilderProvider {
override fun provide(): ClientBuilder {
return ClientBuilder()
}

View file

@ -38,11 +38,14 @@ import uniffi.matrix_sdk_crypto.CollectStrategy
import uniffi.matrix_sdk_crypto.DecryptionSettings
import uniffi.matrix_sdk_crypto.TrustRequirement
import java.io.File
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Named
import io.element.android.libraries.di.BaseDirectory
class RustMatrixClientFactory @Inject constructor(
private val baseDirectory: File,
@CacheDirectory private val cacheDirectory: File,
@Inject
class RustMatrixClientFactory(
@Named("baseDirectory") private val baseDirectory: File,
@Named("cacheDirectory") private val cacheDirectory: File,
@AppCoroutineScope
private val appCoroutineScope: CoroutineScope,
private val coroutineDispatchers: CoroutineDispatchers,

View file

@ -7,14 +7,15 @@
package io.element.android.libraries.matrix.impl
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.SdkMetadata
import org.matrix.rustcomponents.sdk.sdkGitSha
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class RustSdkMetadata @Inject constructor() : SdkMetadata {
@Inject
class RustSdkMetadata() : SdkMetadata {
override val sdkGitSha: String
get() = sdkGitSha()
}

View file

@ -11,9 +11,10 @@ import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.auth.OidcConfig
import io.element.android.libraries.matrix.api.auth.OidcRedirectUrlProvider
import org.matrix.rustcomponents.sdk.OidcConfiguration
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class OidcConfigurationProvider @Inject constructor(
@Inject
class OidcConfigurationProvider(
private val buildMeta: BuildMeta,
private val oidcRedirectUrlProvider: OidcRedirectUrlProvider,
) {

View file

@ -7,12 +7,12 @@
package io.element.android.libraries.matrix.impl.auth
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
@ -49,11 +49,12 @@ import org.matrix.rustcomponents.sdk.QrLoginProgress
import org.matrix.rustcomponents.sdk.QrLoginProgressListener
import timber.log.Timber
import uniffi.matrix_sdk.OAuthAuthorizationData
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class RustMatrixAuthenticationService @Inject constructor(
@Inject
class RustMatrixAuthenticationService(
private val sessionPathsFactory: SessionPathsFactory,
private val coroutineDispatchers: CoroutineDispatchers,
private val sessionStore: SessionStore,

View file

@ -7,16 +7,17 @@
package io.element.android.libraries.matrix.impl.auth.qrlogin
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginDataFactory
import org.matrix.rustcomponents.sdk.QrCodeData
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class RustQrCodeLoginDataFactory @Inject constructor() : MatrixQrCodeLoginDataFactory {
@Inject
class RustQrCodeLoginDataFactory() : MatrixQrCodeLoginDataFactory {
override fun parseQrCodeData(data: ByteArray): Result<MatrixQrCodeLoginData> {
return runCatchingExceptions { SdkQrCodeLoginData(QrCodeData.fromBytes(data)) }
}

View file

@ -7,15 +7,16 @@
package io.element.android.libraries.matrix.impl.certificates
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import timber.log.Timber
import java.security.KeyStore
import java.security.KeyStoreException
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultUserCertificatesProvider @Inject constructor() : UserCertificatesProvider {
@Inject
class DefaultUserCertificatesProvider() : UserCertificatesProvider {
/**
* Get additional user-installed certificates from the `AndroidCAStore` `Keystore`.
*

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.matrix.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.MatrixClient
@ -24,7 +24,7 @@ import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import kotlinx.coroutines.CoroutineScope
@Module
@BindingContainer
@ContributesTo(SessionScope::class)
object SessionMatrixModule {
@Provides

View file

@ -8,15 +8,16 @@
package io.element.android.libraries.matrix.impl.keys
import android.util.Base64
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import java.security.SecureRandom
import javax.inject.Inject
import dev.zacsweers.metro.Inject
private const val SECRET_SIZE = 256
@ContributesBinding(AppScope::class)
class DefaultPassphraseGenerator @Inject constructor() : PassphraseGenerator {
@Inject
class DefaultPassphraseGenerator() : PassphraseGenerator {
override fun generatePassphrase(): String? {
val key = ByteArray(size = SECRET_SIZE)
SecureRandom().nextBytes(key)

View file

@ -10,11 +10,14 @@ package io.element.android.libraries.matrix.impl.paths
import io.element.android.libraries.di.CacheDirectory
import java.io.File
import java.util.UUID
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Named
import io.element.android.libraries.di.BaseDirectory
class SessionPathsFactory @Inject constructor(
private val baseDirectory: File,
@CacheDirectory private val cacheDirectory: File,
@Inject
class SessionPathsFactory(
@Named("baseDirectory") private val baseDirectory: File,
@Named("cacheDirectory") private val cacheDirectory: File,
) {
fun create(): SessionPaths {
val subPath = UUID.randomUUID().toString()

View file

@ -9,18 +9,19 @@ package io.element.android.libraries.matrix.impl.permalink
import android.net.Uri
import androidx.core.net.toUri
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.appconfig.MatrixConfiguration
import io.element.android.libraries.core.extensions.replacePrefix
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.permalink.MatrixToConverter
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* Mapping of an input URI to a matrix.to compliant URI.
*/
@ContributesBinding(AppScope::class)
class DefaultMatrixToConverter @Inject constructor() : MatrixToConverter {
@Inject
class DefaultMatrixToConverter() : MatrixToConverter {
/**
* Try to convert a URL from an element web instance or from a client permalink to a matrix.to url.
* To be successfully converted, URL path should contain one of the [SUPPORTED_PATHS].

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.matrix.impl.permalink
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.core.MatrixPatterns
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.UserId
@ -17,10 +17,11 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilderError
import org.matrix.rustcomponents.sdk.matrixToRoomAliasPermalink
import org.matrix.rustcomponents.sdk.matrixToUserPermalink
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultPermalinkBuilder @Inject constructor() : PermalinkBuilder {
@Inject
class DefaultPermalinkBuilder() : PermalinkBuilder {
override fun permalinkForUser(userId: UserId): Result<String> {
if (!MatrixPatterns.isUserId(userId.value)) {
return Result.failure(PermalinkBuilderError.InvalidData)

View file

@ -8,9 +8,9 @@
package io.element.android.libraries.matrix.impl.permalink
import androidx.core.net.toUri
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
@ -22,7 +22,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import kotlinx.collections.immutable.toImmutableList
import org.matrix.rustcomponents.sdk.MatrixId
import org.matrix.rustcomponents.sdk.parseMatrixEntityFrom
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* This class turns a uri to a [PermalinkData].
@ -32,7 +32,8 @@ import javax.inject.Inject
* or matrix: permalinks (e.g. matrix:u/chagai95:matrix.org)
*/
@ContributesBinding(AppScope::class)
class DefaultPermalinkParser @Inject constructor(
@Inject
class DefaultPermalinkParser(
private val matrixToConverter: MatrixToConverter
) : PermalinkParser {
/**

View file

@ -7,16 +7,17 @@
package io.element.android.libraries.matrix.impl.platform
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.platform.InitPlatformService
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.libraries.matrix.impl.tracing.map
import org.matrix.rustcomponents.sdk.initPlatform
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class RustInitPlatformService @Inject constructor() : InitPlatformService {
@Inject
class RustInitPlatformService() : InitPlatformService {
override fun init(tracingConfiguration: TracingConfiguration) {
initPlatform(
config = tracingConfiguration.map(),

View file

@ -11,11 +11,11 @@ import android.content.Context
import android.net.ConnectivityManager
import android.provider.Settings
import androidx.core.content.getSystemService
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* Provides the proxy settings from the system.
@ -29,7 +29,8 @@ import javax.inject.Inject
* ```
*/
@ContributesBinding(AppScope::class)
class DefaultProxyProvider @Inject constructor(
@Inject
class DefaultProxyProvider(
@ApplicationContext
private val context: Context
) : ProxyProvider {

View file

@ -7,19 +7,20 @@
package io.element.android.libraries.matrix.impl.room
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.room.StateEventType
import org.matrix.rustcomponents.sdk.FilterTimelineEventType
import org.matrix.rustcomponents.sdk.TimelineEventTypeFilter
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface TimelineEventTypeFilterFactory {
fun create(listStateEventType: List<StateEventType>): TimelineEventTypeFilter
}
@ContributesBinding(AppScope::class)
class RustTimelineEventTypeFilterFactory @Inject constructor() : TimelineEventTypeFilterFactory {
@Inject
class RustTimelineEventTypeFilterFactory() : TimelineEventTypeFilterFactory {
override fun create(listStateEventType: List<StateEventType>): TimelineEventTypeFilter {
return TimelineEventTypeFilter.exclude(
listStateEventType.map { stateEventType ->

View file

@ -7,14 +7,15 @@
package io.element.android.libraries.matrix.impl.room.alias
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultRoomAliasHelper @Inject constructor() : RoomAliasHelper {
@Inject
class DefaultRoomAliasHelper() : RoomAliasHelper {
override fun roomAliasNameFromRoomDisplayName(name: String): String {
return org.matrix.rustcomponents.sdk.roomAliasNameFromRoomDisplayName(name)
}

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.matrix.impl.room.join
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.libraries.core.extensions.mapFailure
import io.element.android.libraries.di.SessionScope
@ -18,10 +18,11 @@ import io.element.android.libraries.matrix.api.exception.ErrorKind
import io.element.android.libraries.matrix.api.room.join.JoinRoom
import io.element.android.libraries.matrix.impl.analytics.toAnalyticsJoinedRoom
import io.element.android.services.analytics.api.AnalyticsService
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultJoinRoom @Inject constructor(
@Inject
class DefaultJoinRoom(
private val client: MatrixClient,
private val analyticsService: AnalyticsService,
) : JoinRoom {

View file

@ -7,14 +7,15 @@
package io.element.android.libraries.matrix.impl.server
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.server.UserServerResolver
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultUserServerResolver @Inject constructor(
@Inject
class DefaultUserServerResolver(
private val matrixClient: MatrixClient,
) : UserServerResolver {
override fun resolve(): String {

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.matrix.impl.tracing
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.tracing.LogLevel
import io.element.android.libraries.matrix.api.tracing.TracingConfiguration
import io.element.android.libraries.matrix.api.tracing.TracingService
@ -17,10 +17,11 @@ import io.element.android.libraries.matrix.api.tracing.WriteToFilesConfiguration
import org.matrix.rustcomponents.sdk.TracingFileConfiguration
import org.matrix.rustcomponents.sdk.reloadTracingFileWriter
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class RustTracingService @Inject constructor(private val buildMeta: BuildMeta) : TracingService {
@Inject
class RustTracingService(private val buildMeta: BuildMeta) : TracingService {
override fun createTimberTree(target: String): Timber.Tree {
return RustTracingTree(target = target, retrieveFromStackTrace = buildMeta.isDebuggable)
}

View file

@ -7,10 +7,10 @@
package io.element.android.libraries.matrix.impl.widget
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.widget.CallAnalyticCredentialsProvider
import io.element.android.libraries.matrix.api.widget.CallWidgetSettingsProvider
import io.element.android.libraries.matrix.api.widget.MatrixWidgetSettings
@ -21,11 +21,12 @@ import uniffi.matrix_sdk.EncryptionSystem
import uniffi.matrix_sdk.HeaderStyle
import uniffi.matrix_sdk.NotificationType
import uniffi.matrix_sdk.VirtualElementCallWidgetOptions
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import uniffi.matrix_sdk.Intent as CallIntent
@ContributesBinding(AppScope::class)
class DefaultCallWidgetSettingsProvider @Inject constructor(
@Inject
class DefaultCallWidgetSettingsProvider(
private val buildMeta: BuildMeta,
private val callAnalyticsCredentialsProvider: CallAnalyticCredentialsProvider,
private val analyticsService: AnalyticsService,

View file

@ -13,20 +13,21 @@ import coil3.ImageLoader
import coil3.gif.AnimatedImageDecoder
import coil3.gif.GifDecoder
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.matrix.api.MatrixClient
import okhttp3.OkHttpClient
import javax.inject.Inject
import javax.inject.Provider
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Provider
interface LoggedInImageLoaderFactory {
fun newImageLoader(matrixClient: MatrixClient): ImageLoader
}
@ContributesBinding(AppScope::class)
class DefaultLoggedInImageLoaderFactory @Inject constructor(
@Inject
class DefaultLoggedInImageLoaderFactory(
@ApplicationContext private val context: Context,
private val okHttpClient: Provider<OkHttpClient>,
) : LoggedInImageLoaderFactory {
@ -37,7 +38,7 @@ class DefaultLoggedInImageLoaderFactory @Inject constructor(
OkHttpNetworkFetcherFactory(
callFactory = {
// Use newBuilder, see https://coil-kt.github.io/coil/network/#using-a-custom-okhttpclient
okHttpClient.get().newBuilder().build()
okHttpClient().newBuilder().build()
}
)
)
@ -56,7 +57,8 @@ class DefaultLoggedInImageLoaderFactory @Inject constructor(
}
}
class NotLoggedInImageLoaderFactory @Inject constructor(
@Inject
class NotLoggedInImageLoaderFactory(
@ApplicationContext private val context: Context,
private val okHttpClient: Provider<OkHttpClient>,
) {
@ -67,7 +69,7 @@ class NotLoggedInImageLoaderFactory @Inject constructor(
OkHttpNetworkFetcherFactory(
callFactory = {
// Use newBuilder, see https://coil-kt.github.io/coil/network/#using-a-custom-okhttpclient
okHttpClient.get().newBuilder().build()
okHttpClient().newBuilder().build()
}
)
)

View file

@ -8,14 +8,14 @@
package io.element.android.libraries.matrix.ui.media
import coil3.ImageLoader
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface ImageLoaderHolder {
fun get(client: MatrixClient): ImageLoader
@ -24,7 +24,8 @@ interface ImageLoaderHolder {
@ContributesBinding(AppScope::class)
@SingleIn(AppScope::class)
class DefaultImageLoaderHolder @Inject constructor(
@Inject
class DefaultImageLoaderHolder(
private val loggedInImageLoaderFactory: LoggedInImageLoaderFactory,
private val sessionObserver: SessionObserver,
) : ImageLoaderHolder {

View file

@ -8,17 +8,18 @@
package io.element.android.libraries.matrix.ui.messages
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.runningFold
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(RoomScope::class)
class RoomMemberProfilesCache @Inject constructor() {
@Inject
class RoomMemberProfilesCache() {
private val cache = MutableStateFlow(mapOf<UserId, RoomMember>())
val updateFlow = cache.drop(1).runningFold(0) { acc, _ -> acc + 1 }

View file

@ -8,7 +8,7 @@
package io.element.android.libraries.matrix.ui.messages
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
@ -16,10 +16,11 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.runningFold
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(RoomScope::class)
class RoomNamesCache @Inject constructor() {
@Inject
class RoomNamesCache() {
private val cache = MutableStateFlow(mapOf<RoomIdOrAlias, String?>())
val updateFlow = cache.drop(1).runningFold(0) { acc, _ -> acc + 1 }

View file

@ -19,7 +19,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@Immutable
sealed interface LoadingRoomState {
@ -36,7 +36,8 @@ open class LoadingRoomStateProvider : PreviewParameterProvider<LoadingRoomState>
)
}
class LoadingRoomStateFlowFactory @Inject constructor(private val matrixClient: MatrixClient) {
@Inject
class LoadingRoomStateFlowFactory(private val matrixClient: MatrixClient) {
fun create(lifecycleScope: CoroutineScope, roomId: RoomId): StateFlow<LoadingRoomState> =
getJoinedRoomFlow(roomId)
.map { room ->

View file

@ -15,19 +15,20 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.core.content.FileProvider
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.mediapickers.api.ComposePickerLauncher
import io.element.android.libraries.mediapickers.api.NoOpPickerLauncher
import io.element.android.libraries.mediapickers.api.PickerLauncher
import io.element.android.libraries.mediapickers.api.PickerProvider
import io.element.android.libraries.mediapickers.api.PickerType
import java.io.File
import javax.inject.Inject
@ContributesBinding(AppScope::class)
class DefaultPickerProvider @Inject constructor(
@Inject
class DefaultPickerProvider(
@ApplicationContext private val context: Context,
) : PickerProvider {
/**

View file

@ -10,11 +10,11 @@ package io.element.android.libraries.mediaplayer.impl
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
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 dev.zacsweers.metro.SingleIn
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.mediaplayer.api.MediaPlayer
import kotlinx.coroutines.CoroutineScope
@ -28,7 +28,7 @@ import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.timeout
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.time.Duration.Companion.seconds
/**
@ -36,7 +36,8 @@ import kotlin.time.Duration.Companion.seconds
*/
@ContributesBinding(RoomScope::class)
@SingleIn(RoomScope::class)
class DefaultMediaPlayer @Inject constructor(
@Inject
class DefaultMediaPlayer(
private val player: SimplePlayer,
@SessionCoroutineScope
private val sessionCoroutineScope: CoroutineScope,

View file

@ -11,10 +11,10 @@ import android.content.Context
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Provides
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.di.RoomScope
/**
@ -42,7 +42,7 @@ interface SimplePlayer {
}
@ContributesTo(RoomScope::class)
@Module
@BindingContainer
object SimplePlayerModule {
@Provides
fun simplePlayerProvider(

View file

@ -8,12 +8,13 @@
package io.element.android.libraries.mediaupload.api
import io.element.android.libraries.matrix.api.MatrixClient
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* Provides the maximum upload size allowed by the Matrix server.
*/
class MaxUploadSizeProvider @Inject constructor(
@Inject
class MaxUploadSizeProvider(
private val matrixClient: MatrixClient,
) {
suspend fun getMaxUploadSize(): Result<Long> {

View file

@ -8,9 +8,9 @@
package io.element.android.libraries.mediaupload.api
import android.net.Uri
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import io.element.android.libraries.androidutils.hash.hash
import io.element.android.libraries.core.extensions.flatMap
import io.element.android.libraries.core.extensions.flatMapCatching
@ -25,7 +25,8 @@ import timber.log.Timber
import java.io.File
import java.util.concurrent.ConcurrentHashMap
class MediaSender @AssistedInject constructor(
@Inject
class MediaSender(
private val preProcessor: MediaPreProcessor,
private val room: JoinedRoom,
@Assisted private val timelineMode: Timeline.Mode,

View file

@ -12,7 +12,7 @@ import android.graphics.BitmapFactory
import android.media.MediaMetadataRetriever
import android.net.Uri
import androidx.exifinterface.media.ExifInterface
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.androidutils.file.TemporaryUriDeleter
import io.element.android.libraries.androidutils.file.createTmpFile
import io.element.android.libraries.androidutils.file.getFileName
@ -27,8 +27,8 @@ import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeImage
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.matrix.api.media.AudioInfo
import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.matrix.api.media.ImageInfo
@ -45,12 +45,13 @@ import timber.log.Timber
import java.io.File
import java.io.InputStream
import java.util.UUID
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
@ContributesBinding(AppScope::class)
class AndroidMediaPreProcessor @Inject constructor(
@Inject
class AndroidMediaPreProcessor(
@ApplicationContext private val context: Context,
private val thumbnailFactory: ThumbnailFactory,
private val imageCompressor: ImageCompressor,

View file

@ -7,16 +7,17 @@
package io.element.android.libraries.mediaupload.impl
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfig
import io.element.android.libraries.mediaupload.api.MediaOptimizationConfigProvider
import io.element.android.libraries.preferences.api.store.SessionPreferencesStore
import kotlinx.coroutines.flow.first
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(SessionScope::class)
class DefaultMediaOptimizationConfigProvider @Inject constructor(
@Inject
class DefaultMediaOptimizationConfigProvider(
private val sessionPreferencesStore: SessionPreferencesStore,
) : MediaOptimizationConfigProvider {
override suspend fun get(): MediaOptimizationConfig = MediaOptimizationConfig(

View file

@ -17,13 +17,14 @@ import io.element.android.libraries.androidutils.bitmap.rotateToExifMetadataOrie
import io.element.android.libraries.androidutils.file.createTmpFile
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import kotlinx.coroutines.withContext
import java.io.File
import java.io.InputStream
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class ImageCompressor @Inject constructor(
@Inject
class ImageCompressor(
@ApplicationContext private val context: Context,
private val dispatchers: CoroutineDispatchers,
) {

View file

@ -23,14 +23,14 @@ import io.element.android.libraries.androidutils.bitmap.resizeToMax
import io.element.android.libraries.androidutils.file.createTmpFile
import io.element.android.libraries.androidutils.media.runAndRelease
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.matrix.api.media.ThumbnailInfo
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
import kotlinx.coroutines.suspendCancellableCoroutine
import timber.log.Timber
import java.io.File
import java.io.IOException
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.coroutines.resume
/**
@ -50,7 +50,8 @@ private const val THUMB_MAX_HEIGHT = 600
*/
private const val VIDEO_THUMB_FRAME = 0L
class ThumbnailFactory @Inject constructor(
@Inject
class ThumbnailFactory(
@ApplicationContext private val context: Context,
private val sdkIntProvider: BuildVersionSdkIntProvider
) {

View file

@ -30,7 +30,7 @@ import androidx.media3.transformer.VideoEncoderSettings
import io.element.android.libraries.androidutils.file.createTmpFile
import io.element.android.libraries.androidutils.file.safeDelete
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.preferences.api.store.VideoCompressionPreset
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
@ -42,9 +42,10 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class VideoCompressor @Inject constructor(
@Inject
class VideoCompressor(
@ApplicationContext private val context: Context,
) {
@OptIn(UnstableApi::class)

View file

@ -10,15 +10,16 @@ package io.element.android.libraries.mediaviewer.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint
import io.element.android.libraries.mediaviewer.impl.gallery.root.MediaGalleryRootNode
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultMediaGalleryEntryPoint @Inject constructor() : MediaGalleryEntryPoint {
@Inject
class DefaultMediaGalleryEntryPoint() : MediaGalleryEntryPoint {
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): MediaGalleryEntryPoint.NodeBuilder {
val plugins = ArrayList<Plugin>()

View file

@ -10,19 +10,20 @@ package io.element.android.libraries.mediaviewer.impl
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.impl.viewer.MediaViewerNode
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultMediaViewerEntryPoint @Inject constructor() : MediaViewerEntryPoint {
@Inject
class DefaultMediaViewerEntryPoint() : MediaViewerEntryPoint {
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): MediaViewerEntryPoint.NodeBuilder {
val plugins = ArrayList<Plugin>()

View file

@ -42,9 +42,10 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class EventItemFactory @Inject constructor(
@Inject
class EventItemFactory(
private val fileSizeFormatter: FileSizeFormatter,
private val fileExtensionExtractor: FileExtensionExtractor,
private val dateFormatter: DateFormatter,

View file

@ -7,12 +7,12 @@
package io.element.android.libraries.mediaviewer.impl.datasource
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface FocusedTimelineMediaGalleryDataSourceFactory {
fun createFor(
@ -23,7 +23,8 @@ interface FocusedTimelineMediaGalleryDataSourceFactory {
}
@ContributesBinding(RoomScope::class)
class DefaultFocusedTimelineMediaGalleryDataSourceFactory @Inject constructor(
@Inject
class DefaultFocusedTimelineMediaGalleryDataSourceFactory(
private val room: JoinedRoom,
private val timelineMediaItemsFactory: TimelineMediaItemsFactory,
private val mediaItemsPostProcessor: MediaItemsPostProcessor,

View file

@ -7,10 +7,10 @@
package io.element.android.libraries.mediaviewer.impl.datasource
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
@ -27,7 +27,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface MediaGalleryDataSource {
fun start()
@ -39,7 +39,8 @@ interface MediaGalleryDataSource {
@SingleIn(RoomScope::class)
@ContributesBinding(RoomScope::class)
class TimelineMediaGalleryDataSource @Inject constructor(
@Inject
class TimelineMediaGalleryDataSource(
private val room: BaseRoom,
private val mediaTimeline: MediaTimeline,
private val timelineMediaItemsFactory: TimelineMediaItemsFactory,

View file

@ -10,9 +10,10 @@ package io.element.android.libraries.mediaviewer.impl.datasource
import io.element.android.libraries.mediaviewer.impl.model.GroupedMediaItems
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class MediaItemsPostProcessor @Inject constructor() {
@Inject
class MediaItemsPostProcessor() {
fun process(
mediaItems: List<MediaItem>,
): GroupedMediaItems {

View file

@ -7,9 +7,9 @@
package io.element.android.libraries.mediaviewer.impl.datasource
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
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.CreateTimelineParams
@ -21,7 +21,7 @@ import io.element.android.libraries.mediaviewer.impl.model.hasEvent
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface MediaTimeline {
suspend fun getTimeline(): Result<Timeline>
@ -36,7 +36,8 @@ interface MediaTimeline {
*/
@SingleIn(RoomScope::class)
@ContributesBinding(RoomScope::class)
class LiveMediaTimeline @Inject constructor(
@Inject
class LiveMediaTimeline(
private val room: JoinedRoom,
) : MediaTimeline {
private var timeline: Timeline? = null

View file

@ -21,9 +21,10 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineMediaItemsFactory @Inject constructor(
@Inject
class TimelineMediaItemsFactory(
private val dispatchers: CoroutineDispatchers,
private val virtualItemFactory: VirtualItemFactory,
private val eventItemFactory: EventItemFactory,

View file

@ -12,9 +12,10 @@ import io.element.android.libraries.dateformatter.api.DateFormatterMode
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class VirtualItemFactory @Inject constructor(
@Inject
class VirtualItemFactory(
private val dateFormatter: DateFormatter,
) {
fun create(timelineItem: MatrixTimelineItem.Virtual): MediaItem? {

View file

@ -14,8 +14,8 @@ import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.Inject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.core.EventId
@ -24,7 +24,8 @@ import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemPresent
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
@ContributesNode(RoomScope::class)
class MediaGalleryNode @AssistedInject constructor(
@Inject
class MediaGalleryNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: MediaGalleryPresenter.Factory,

View file

@ -16,9 +16,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import io.element.android.libraries.androidutils.R
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
@ -44,7 +44,8 @@ import io.element.android.libraries.mediaviewer.impl.model.mediaSource
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.launch
class MediaGalleryPresenter @AssistedInject constructor(
@Inject
class MediaGalleryPresenter(
@Assisted private val navigator: MediaGalleryNavigator,
private val room: BaseRoom,
private val mediaGalleryDataSource: MediaGalleryDataSource,

View file

@ -18,7 +18,7 @@ import io.element.android.libraries.voiceplayer.api.aVoiceMessageState
fun aFakeMediaItemPresenterFactories() = MediaItemPresenterFactories(
mapOf(
Pair(
MediaItem.Voice::class.java,
MediaItem.Voice::class,
MediaItemPresenterFactory<MediaItem.Voice, VoiceMessageState> { Presenter { aVoiceMessageState() } },
),
)

View file

@ -7,7 +7,7 @@
package io.element.android.libraries.mediaviewer.impl.gallery.di
import dagger.MapKey
import dev.zacsweers.metro.MapKey
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import kotlin.reflect.KClass

View file

@ -9,25 +9,26 @@ package io.element.android.libraries.mediaviewer.impl.gallery.di
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.multibindings.Multibinds
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.Multibinds
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
import javax.inject.Inject
import kotlin.reflect.KClass
/**
* Dagger module that declares the [MediaItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@Module
@BindingContainer
@ContributesTo(RoomScope::class)
interface MediaItemPresenterFactoriesModule {
@Multibinds
fun multiBindMediaItemPresenterFactories(): @JvmSuppressWildcards Map<Class<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>
fun multiBindMediaItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>
}
/**
@ -38,8 +39,9 @@ interface MediaItemPresenterFactoriesModule {
* goes out of the [LazyColumn] viewport.
*/
@SingleIn(RoomScope::class)
class MediaItemPresenterFactories @Inject constructor(
private val factories: @JvmSuppressWildcards Map<Class<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>,
@Inject
class MediaItemPresenterFactories(
private val factories: @JvmSuppressWildcards Map<KClass<out MediaItem.Event>, MediaItemPresenterFactory<*, *>>,
) {
private val presenters: MutableMap<MediaItem.Event, Presenter<*>> = mutableMapOf()
@ -57,7 +59,7 @@ class MediaItemPresenterFactories @Inject constructor(
@Composable
fun <C : MediaItem.Event, S : Any> rememberPresenter(
content: C,
contentClass: Class<C>,
contentClass: KClass<C>,
): Presenter<S> = remember(content) {
presenters[content]?.let {
@Suppress("UNCHECKED_CAST")
@ -86,5 +88,5 @@ inline fun <reified C : MediaItem.Event, S : Any> MediaItemPresenterFactories.re
content: C
): Presenter<S> = rememberPresenter(
content = content,
contentClass = C::class.java
contentClass = C::class
)

View file

@ -15,8 +15,8 @@ import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.Inject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.architecture.BackstackWithOverlayBox
import io.element.android.libraries.architecture.BaseFlowNode
@ -40,7 +40,8 @@ import io.element.android.libraries.mediaviewer.impl.model.thumbnailSource
import kotlinx.parcelize.Parcelize
@ContributesNode(RoomScope::class)
class MediaGalleryRootNode @AssistedInject constructor(
@Inject
class MediaGalleryRootNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val mediaViewerEntryPoint: MediaViewerEntryPoint

View file

@ -8,13 +8,13 @@
package io.element.android.libraries.mediaviewer.impl.gallery.voice
import androidx.compose.runtime.Composable
import com.squareup.anvil.annotations.ContributesTo
import dagger.Binds
import dagger.Module
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.multibindings.IntoMap
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.IntoMap
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.mediaviewer.impl.gallery.di.MediaItemEventContentKey
@ -24,7 +24,7 @@ import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory
import io.element.android.libraries.voiceplayer.api.VoiceMessageState
import kotlin.time.Duration
@Module
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterModule {
@Binds
@ -33,7 +33,8 @@ interface VoiceMessagePresenterModule {
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): MediaItemPresenterFactory<*, *>
}
class VoiceMessagePresenter @AssistedInject constructor(
@Inject
class VoiceMessagePresenter(
voiceMessagePresenterFactory: VoiceMessagePresenterFactory,
@Assisted private val item: MediaItem.Voice,
) : Presenter<VoiceMessageState> {

View file

@ -29,14 +29,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.core.content.FileProvider
import androidx.core.content.PermissionChecker
import androidx.core.net.toFile
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.androidutils.system.startInstallFromSourceIntent
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.extensions.runCatchingExceptions
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -44,10 +44,11 @@ import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class AndroidLocalMediaActions @Inject constructor(
@Inject
class AndroidLocalMediaActions(
@ApplicationContext private val context: Context,
private val coroutineDispatchers: CoroutineDispatchers,
private val buildMeta: BuildMeta,

View file

@ -10,14 +10,14 @@ package io.element.android.libraries.mediaviewer.impl.local
import android.content.Context
import android.net.Uri
import androidx.core.net.toUri
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.androidutils.file.getFileName
import io.element.android.libraries.androidutils.file.getFileSize
import io.element.android.libraries.androidutils.file.getMimeType
import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.MediaFile
import io.element.android.libraries.matrix.api.media.toFile
@ -25,10 +25,11 @@ import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class AndroidLocalMediaFactory @Inject constructor(
@Inject
class AndroidLocalMediaFactory(
@ApplicationContext private val context: Context,
private val fileSizeFormatter: FileSizeFormatter,
private val fileExtensionExtractor: FileExtensionExtractor,

View file

@ -10,19 +10,20 @@ package io.element.android.libraries.mediaviewer.impl.local
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.viewfolder.api.TextFileViewer
import io.element.android.libraries.audio.api.AudioFocus
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer
import me.saket.telephoto.zoomable.OverzoomEffect
import me.saket.telephoto.zoomable.ZoomSpec
import me.saket.telephoto.zoomable.rememberZoomableState
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(AppScope::class)
class DefaultLocalMediaRenderer @Inject constructor(
@Inject
class DefaultLocalMediaRenderer(
private val textFileViewer: TextFileViewer,
private val audioFocus: AudioFocus,
) : LocalMediaRenderer {

Some files were not shown because too many files have changed in this diff Show more