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

@ -10,15 +10,18 @@ package io.element.android.features.messages.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.features.messages.api.MessagesEntryPoint
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.AppScope
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.NodeFactoriesBindings
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.di.SessionScope
@ContributesBinding(AppScope::class)
class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint {
@ContributesBinding(SessionScope::class)
@Inject
class DefaultMessagesEntryPoint : MessagesEntryPoint {
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): MessagesEntryPoint.NodeBuilder {
val nodeFactories = parentNode.bindings<NodeFactoriesBindings>().nodeFactories()
val plugins = ArrayList<Plugin>()
return object : MessagesEntryPoint.NodeBuilder {
@ -33,7 +36,7 @@ class DefaultMessagesEntryPoint @Inject constructor() : MessagesEntryPoint {
}
override fun build(): Node {
return parentNode.createNode<MessagesFlowNode>(buildContext, plugins)
return nodeFactories[MessagesFlowNode::class]!!.create(buildContext, plugins)
}
}
}

View file

@ -20,8 +20,8 @@ import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.Inject
import im.vector.app.features.analytics.plan.Interaction
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.call.api.CallType
@ -92,7 +92,8 @@ import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
@ContributesNode(RoomScope::class)
class MessagesFlowNode @AssistedInject constructor(
@Inject
class MessagesFlowNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val matrixClient: MatrixClient,

View file

@ -24,8 +24,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.compound.theme.ElementTheme
import io.element.android.features.knockrequests.api.banner.KnockRequestsBannerRenderer
@ -50,7 +50,7 @@ import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom
@ -74,7 +74,8 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@ContributesNode(RoomScope::class)
class MessagesNode @AssistedInject constructor(
@Inject
class MessagesNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
@ApplicationContext private val context: Context,

View file

@ -22,9 +22,9 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.lifecycle.compose.LifecycleResumeEffect
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 im.vector.app.features.analytics.plan.PinUnpinAction
import io.element.android.appconfig.MessageComposerConfig
import io.element.android.features.messages.api.timeline.HtmlConverterProvider
@ -92,7 +92,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
class MessagesPresenter @AssistedInject constructor(
@Inject
class MessagesPresenter(
@Assisted private val navigator: MessagesNavigator,
private val room: JoinedRoom,
@Assisted private val composerPresenter: Presenter<MessageComposerState>,

View file

@ -14,10 +14,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import io.element.android.features.messages.impl.UserEventPermissions
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
import io.element.android.features.messages.impl.actionlist.model.TimelineItemActionComparator
@ -61,7 +61,8 @@ interface ActionListPresenter : Presenter<ActionListState> {
}
}
class DefaultActionListPresenter @AssistedInject constructor(
@Inject
class DefaultActionListPresenter(
@Assisted
private val postProcessor: TimelineItemActionPostProcessor,
@Assisted

View file

@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
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.compound.theme.ForcedDarkElementTheme
import io.element.android.features.messages.impl.attachments.Attachment
@ -24,7 +24,8 @@ import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.mediaviewer.api.local.LocalMediaRenderer
@ContributesNode(RoomScope::class)
class AttachmentsPreviewNode @AssistedInject constructor(
@Inject
class AttachmentsPreviewNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: AttachmentsPreviewPresenter.Factory,

View file

@ -17,9 +17,9 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
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.features.messages.impl.attachments.Attachment
import io.element.android.features.messages.impl.attachments.video.MediaOptimizationSelectorPresenter
import io.element.android.libraries.androidutils.file.TemporaryUriDeleter
@ -49,7 +49,8 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import timber.log.Timber
class AttachmentsPreviewPresenter @AssistedInject constructor(
@Inject
class AttachmentsPreviewPresenter(
@Assisted private val attachment: Attachment,
@Assisted private val onDoneListener: OnDoneListener,
@Assisted private val timelineMode: Timeline.Mode,

View file

@ -14,10 +14,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeVideo
import io.element.android.libraries.di.SessionScope
@ -34,7 +34,8 @@ import kotlinx.coroutines.flow.first
import timber.log.Timber
import kotlin.math.roundToLong
class DefaultMediaOptimizationSelectorPresenter @AssistedInject constructor(
@Inject
class DefaultMediaOptimizationSelectorPresenter(
@Assisted private val localMedia: LocalMedia,
private val maxUploadSizeProvider: MaxUploadSizeProvider,
private val sessionPreferencesStore: SessionPreferencesStore,

View file

@ -11,13 +11,13 @@ import android.content.Context
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.util.Size
import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import io.element.android.libraries.core.extensions.runCatchingExceptions
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 kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
@ -30,7 +30,8 @@ interface VideoMetadataExtractor : AutoCloseable {
}
@ContributesBinding(AppScope::class)
class DefaultVideoMetadataExtractor @AssistedInject constructor(
@Inject
class DefaultVideoMetadataExtractor(
@ApplicationContext private val context: Context,
@Assisted private val uri: Uri,
) : VideoMetadataExtractor {

View file

@ -20,9 +20,10 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class IdentityChangeStatePresenter @Inject constructor(
@Inject
class IdentityChangeStatePresenter(
private val room: JoinedRoom,
private val encryptionService: EncryptionService,
) : Presenter<IdentityChangeState> {

View file

@ -9,9 +9,10 @@ package io.element.android.features.messages.impl.crypto.sendfailure
import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class VerifiedUserSendFailureFactory @Inject constructor(
@Inject
class VerifiedUserSendFailureFactory(
private val room: BaseRoom,
) {
suspend fun create(

View file

@ -22,9 +22,10 @@ import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
import kotlinx.coroutines.launch
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class ResolveVerifiedUserSendFailurePresenter @Inject constructor(
@Inject
class ResolveVerifiedUserSendFailurePresenter(
private val room: JoinedRoom,
private val verifiedUserSendFailureFactory: VerifiedUserSendFailureFactory,
) : Presenter<ResolveVerifiedUserSendFailureState> {

View file

@ -7,9 +7,9 @@
package io.element.android.features.messages.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Binds
import dagger.Module
import dev.zacsweers.metro.Binds
import dev.zacsweers.metro.BindingContainer
import dev.zacsweers.metro.ContributesTo
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeState
import io.element.android.features.messages.impl.crypto.identity.IdentityChangeStatePresenter
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailurePresenter
@ -32,7 +32,7 @@ import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
@ContributesTo(RoomScope::class)
@Module
@BindingContainer
interface MessagesBindsModule {
@Binds
fun bindPinnedMessagesBannerPresenter(presenter: PinnedMessagesBannerPresenter): Presenter<PinnedMessagesBannerState>

View file

@ -7,16 +7,16 @@
package io.element.android.features.messages.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.features.messages.impl.timeline.di.LiveTimeline
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
@ContributesTo(RoomScope::class)
@Module
@BindingContainer
object MessagesProvidesModule {
@Provides
@LiveTimeline

View file

@ -7,15 +7,16 @@
package io.element.android.features.messages.impl.draft
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.RoomId
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(RoomScope::class)
class DefaultComposerDraftService @Inject constructor(
@Inject
class DefaultComposerDraftService(
private val volatileComposerDraftStore: VolatileComposerDraftStore,
private val matrixComposerDraftStore: MatrixComposerDraftStore,
) : ComposerDraftService {

View file

@ -12,13 +12,14 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* A draft store that persists drafts in the room state.
* It can be used to store drafts that should be persisted across app restarts.
*/
class MatrixComposerDraftStore @Inject constructor(
@Inject
class MatrixComposerDraftStore(
private val client: MatrixClient,
) : ComposerDraftStore {
override suspend fun loadDraft(roomId: RoomId, threadRoot: ThreadId?): ComposerDraft? {

View file

@ -10,14 +10,15 @@ package io.element.android.features.messages.impl.draft
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* A volatile draft store that keeps drafts in memory only.
* It can be used to store drafts that should not be persisted across app restarts.
* Currently it's used to store draft message when moving to edit mode.
*/
class VolatileComposerDraftStore @Inject constructor() : ComposerDraftStore {
@Inject
class VolatileComposerDraftStore() : ComposerDraftStore {
private val drafts: MutableMap<String, ComposerDraft> = mutableMapOf()
override suspend fun loadDraft(roomId: RoomId, threadRoot: ThreadId?): ComposerDraft? {

View file

@ -17,8 +17,8 @@ import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.node.ParentNode
import com.bumble.appyx.core.plugin.Plugin
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.NodeInputs
import io.element.android.libraries.architecture.inputs
@ -31,7 +31,8 @@ import io.element.android.libraries.roomselect.api.RoomSelectMode
import kotlinx.parcelize.Parcelize
@ContributesNode(RoomScope::class)
class ForwardMessagesNode @AssistedInject constructor(
@Inject
class ForwardMessagesNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: ForwardMessagesPresenter.Factory,

View file

@ -10,9 +10,9 @@ package io.element.android.features.messages.impl.forward
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
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.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
@ -26,7 +26,8 @@ import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
class ForwardMessagesPresenter @AssistedInject constructor(
@Inject
class ForwardMessagesPresenter(
@Assisted eventId: String,
@Assisted private val timelineProvider: TimelineProvider,
@SessionCoroutineScope

View file

@ -7,20 +7,21 @@
package io.element.android.features.messages.impl.link
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.core.extensions.containsRtLOverride
import io.element.android.libraries.di.AppScope
import dev.zacsweers.metro.AppScope
import io.element.android.wysiwyg.link.Link
import java.net.URI
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface LinkChecker {
fun isSafe(link: Link): Boolean
}
@ContributesBinding(AppScope::class)
class DefaultLinkChecker @Inject constructor() : LinkChecker {
@Inject
class DefaultLinkChecker() : LinkChecker {
override fun isSafe(link: Link): Boolean {
return if (link.url.containsRtLOverride()) {
false

View file

@ -14,9 +14,10 @@ import androidx.compose.runtime.remember
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.wysiwyg.link.Link
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class LinkPresenter @Inject constructor(
@Inject
class LinkPresenter(
private val linkChecker: LinkChecker,
) : Presenter<LinkState> {
@Composable

View file

@ -10,16 +10,17 @@ package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.messages.api.MessageComposerContext
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.textcomposer.model.MessageComposerMode
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(RoomScope::class)
@ContributesBinding(RoomScope::class)
class DefaultMessageComposerContext @Inject constructor() : MessageComposerContext {
@Inject
class DefaultMessageComposerContext() : MessageComposerContext {
override var composerMode: MessageComposerMode by mutableStateOf(MessageComposerMode.Normal)
internal set
}

View file

@ -25,9 +25,9 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.media3.common.util.UnstableApi
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 im.vector.app.features.analytics.plan.Composer
import im.vector.app.features.analytics.plan.Interaction
import io.element.android.features.location.api.LocationService
@ -99,7 +99,8 @@ import timber.log.Timber
import kotlin.time.Duration.Companion.seconds
import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes
class MessageComposerPresenter @AssistedInject constructor(
@Inject
class MessageComposerPresenter(
@Assisted private val navigator: MessagesNavigator,
@Assisted private val timelineController: TimelineController,
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,

View file

@ -8,11 +8,11 @@
package io.element.android.features.messages.impl.messagecomposer
import androidx.compose.runtime.Composable
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.wysiwyg.compose.RichTextEditorState
import io.element.android.wysiwyg.compose.rememberRichTextEditorState
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface RichTextEditorStateFactory {
@Composable
@ -20,7 +20,8 @@ interface RichTextEditorStateFactory {
}
@ContributesBinding(AppScope::class)
class DefaultRichTextEditorStateFactory @Inject constructor() : RichTextEditorStateFactory {
@Inject
class DefaultRichTextEditorStateFactory() : RichTextEditorStateFactory {
@Composable
override fun remember(): RichTextEditorState {
return rememberRichTextEditorState()

View file

@ -7,14 +7,14 @@
package io.element.android.features.messages.impl.messagecomposer.suggestions
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.core.RoomAlias
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import dev.zacsweers.metro.Inject
data class RoomAliasSuggestion(
val roomAlias: RoomAlias,
@ -28,7 +28,8 @@ interface RoomAliasSuggestionsDataSource {
}
@ContributesBinding(SessionScope::class)
class DefaultRoomAliasSuggestionsDataSource @Inject constructor(
@Inject
class DefaultRoomAliasSuggestionsDataSource(
private val roomListService: RoomListService,
) : RoomAliasSuggestionsDataSource {
override fun getAllRoomAliasSuggestions(): Flow<List<RoomAliasSuggestion>> {

View file

@ -16,12 +16,13 @@ import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion
import io.element.android.libraries.textcomposer.model.Suggestion
import io.element.android.libraries.textcomposer.model.SuggestionType
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* This class is responsible for processing suggestions when `@`, `/` or `#` are type in the composer.
*/
class SuggestionsProcessor @Inject constructor() {
@Inject
class SuggestionsProcessor() {
/**
* Process the suggestion.
* @param suggestion The current suggestion input

View file

@ -11,7 +11,7 @@ import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.coroutine.mapState
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.room.CreateTimelineParams
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.sync.SyncService
@ -26,10 +26,11 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(RoomScope::class)
class PinnedEventsTimelineProvider @Inject constructor(
@Inject
class PinnedEventsTimelineProvider(
private val room: JoinedRoom,
private val syncService: SyncService,
private val dispatchers: CoroutineDispatchers,

View file

@ -12,9 +12,10 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.eventformatter.api.PinnedMessagesBannerFormatter
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import kotlinx.coroutines.withContext
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class PinnedMessagesBannerItemFactory @Inject constructor(
@Inject
class PinnedMessagesBannerItemFactory(
private val coroutineDispatchers: CoroutineDispatchers,
private val formatter: PinnedMessagesBannerFormatter,
) {

View file

@ -29,9 +29,10 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class PinnedMessagesBannerPresenter @Inject constructor(
@Inject
class PinnedMessagesBannerPresenter(
private val room: BaseRoom,
private val itemFactory: PinnedMessagesBannerItemFactory,
private val pinnedEventsTimelineProvider: PinnedEventsTimelineProvider,

View file

@ -18,8 +18,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.features.messages.impl.actionlist.ActionListPresenter
import io.element.android.features.messages.impl.timeline.di.LocalTimelineItemPresenterFactories
@ -38,7 +38,8 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.ui.strings.CommonStrings
@ContributesNode(RoomScope::class)
class PinnedMessagesListNode @AssistedInject constructor(
@Inject
class PinnedMessagesListNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: PinnedMessagesListPresenter.Factory,

View file

@ -17,9 +17,9 @@ import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
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 im.vector.app.features.analytics.plan.Interaction
import im.vector.app.features.analytics.plan.PinUnpinAction
import io.element.android.features.messages.impl.UserEventPermissions
@ -61,7 +61,8 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
class PinnedMessagesListPresenter @AssistedInject constructor(
@Inject
class PinnedMessagesListPresenter(
@Assisted private val navigator: PinnedMessagesListNavigator,
private val room: JoinedRoom,
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,

View file

@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
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.NodeInputs
import io.element.android.libraries.architecture.inputs
@ -22,7 +22,8 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
@ContributesNode(RoomScope::class)
class ReportMessageNode @AssistedInject constructor(
@Inject
class ReportMessageNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
presenterFactory: ReportMessagePresenter.Factory,

View file

@ -15,9 +15,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
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.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runUpdatingState
@ -30,7 +30,8 @@ import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
class ReportMessagePresenter @AssistedInject constructor(
@Inject
class ReportMessagePresenter(
private val room: JoinedRoom,
@Assisted private val inputs: Inputs,
private val snackbarDispatcher: SnackbarDispatcher,

View file

@ -24,8 +24,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.compound.theme.ElementTheme
import io.element.android.features.messages.impl.MessagesNavigator
@ -49,7 +49,7 @@ import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.matrix.api.analytics.toAnalyticsViewRoom
@ -73,7 +73,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
@ContributesNode(RoomScope::class)
class ThreadedMessagesNode @AssistedInject constructor(
@Inject
class ThreadedMessagesNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
@ApplicationContext private val context: Context,

View file

@ -13,11 +13,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.messages.api.timeline.HtmlConverterProvider
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import dev.zacsweers.metro.SingleIn
import io.element.android.libraries.textcomposer.ElementRichTextEditorStyle
import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
import io.element.android.wysiwyg.compose.StyledHtmlConverter
@ -25,11 +25,12 @@ import io.element.android.wysiwyg.display.MentionDisplayHandler
import io.element.android.wysiwyg.display.TextDisplay
import io.element.android.wysiwyg.utils.HtmlConverter
import uniffi.wysiwyg_composer.newMentionDetector
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(RoomScope::class)
@SingleIn(RoomScope::class)
class DefaultHtmlConverterProvider @Inject constructor(
@Inject
class DefaultHtmlConverterProvider(
private val mentionSpanProvider: MentionSpanProvider,
) : HtmlConverterProvider {
private val htmlConverter: MutableState<HtmlConverter?> = mutableStateOf(null)

View file

@ -7,21 +7,22 @@
package io.element.android.features.messages.impl.timeline
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.core.RoomId
import io.element.android.libraries.matrix.api.timeline.ReceiptType
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface MarkAsFullyRead {
operator fun invoke(roomId: RoomId)
}
@ContributesBinding(SessionScope::class)
class DefaultMarkAsFullyRead @Inject constructor(
@Inject
class DefaultMarkAsFullyRead(
private val matrixClient: MatrixClient,
) : MarkAsFullyRead {
override fun invoke(roomId: RoomId) {

View file

@ -7,10 +7,10 @@
package io.element.android.features.messages.impl.timeline
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.messages.impl.timeline.di.LiveTimeline
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.CreateTimelineParams
import io.element.android.libraries.matrix.api.room.JoinedRoom
@ -34,15 +34,17 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import java.io.Closeable
import java.util.Optional
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import dev.zacsweers.metro.binding
/**
* This controller is responsible of using the right timeline to display messages and make associated actions.
* It can be focused on the live timeline or on a detached timeline (focusing an unknown event).
*/
@SingleIn(RoomScope::class)
@ContributesBinding(RoomScope::class, boundType = TimelineProvider::class)
class TimelineController @Inject constructor(
@ContributesBinding(RoomScope::class, binding = binding<TimelineProvider>())
@Inject
class TimelineController(
private val room: JoinedRoom,
@LiveTimeline private val liveTimeline: Timeline,
) : Closeable, TimelineProvider {

View file

@ -13,9 +13,10 @@ import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemIndexer @Inject constructor() {
@Inject
class TimelineItemIndexer() {
// This is a latch to wait for the first process call
private val firstProcessLatch = CompletableDeferred<Unit>()
private val timelineEventsIndexes = mutableMapOf<EventId, Int>()

View file

@ -20,9 +20,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
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.features.messages.impl.MessagesNavigator
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureEvents
import io.element.android.features.messages.impl.crypto.sendfailure.resolve.ResolveVerifiedUserSendFailureState
@ -67,7 +67,8 @@ import timber.log.Timber
const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L
class TimelinePresenter @AssistedInject constructor(
@Inject
class TimelinePresenter(
timelineItemsFactoryCreator: TimelineItemsFactory.Creator,
private val room: JoinedRoom,
private val dispatchers: CoroutineDispatchers,

View file

@ -16,9 +16,10 @@ import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.libraries.architecture.Presenter
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.coroutines.launch
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class CustomReactionPresenter @Inject constructor(
@Inject
class CustomReactionPresenter(
private val emojibaseProvider: EmojibaseProvider
) : Presenter<CustomReactionState> {
@Composable

View file

@ -21,9 +21,10 @@ import io.element.android.libraries.matrix.api.room.roomMembers
import io.element.android.libraries.matrix.api.user.MatrixUser
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class ReactionSummaryPresenter @Inject constructor(
@Inject
class ReactionSummaryPresenter(
private val room: BaseRoom,
) : Presenter<ReactionSummaryState> {
@Composable

View file

@ -14,9 +14,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.libraries.architecture.Presenter
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class ReadReceiptBottomSheetPresenter @Inject constructor() : Presenter<ReadReceiptBottomSheetState> {
@Inject
class ReadReceiptBottomSheetPresenter() : Presenter<ReadReceiptBottomSheetState> {
@Composable
override fun present(): ReadReceiptBottomSheetState {
var selectedEvent: TimelineItem.Event? by remember { mutableStateOf(null) }

View file

@ -12,8 +12,8 @@ import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
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.NodeInputs
import io.element.android.libraries.architecture.inputs
@ -22,7 +22,8 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
@ContributesNode(RoomScope::class)
class EventDebugInfoNode @AssistedInject constructor(
@Inject
class EventDebugInfoNode(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
) : Node(buildContext, plugins = plugins) {

View file

@ -18,7 +18,7 @@ import io.element.android.libraries.voiceplayer.api.aVoiceMessageState
fun aFakeTimelineItemPresenterFactories() = TimelineItemPresenterFactories(
mapOf(
Pair(
TimelineItemVoiceContent::class.java,
TimelineItemVoiceContent::class,
TimelineItemPresenterFactory<TimelineItemVoiceContent, VoiceMessageState> { Presenter { aVoiceMessageState() } },
),
)

View file

@ -7,7 +7,7 @@
package io.element.android.features.messages.impl.timeline.di
import javax.inject.Qualifier
import dev.zacsweers.metro.Qualifier
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented

View file

@ -7,7 +7,7 @@
package io.element.android.features.messages.impl.timeline.di
import dagger.MapKey
import dev.zacsweers.metro.MapKey
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import kotlin.reflect.KClass

View file

@ -9,25 +9,26 @@ package io.element.android.features.messages.impl.timeline.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 io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.di.SingleIn
import javax.inject.Inject
import dev.zacsweers.metro.SingleIn
import kotlin.reflect.KClass
/**
* Dagger module that declares the [TimelineItemPresenterFactory] map multi binding.
*
* Its sole purpose is to support the case of an empty map multibinding.
*/
@Module
@BindingContainer
@ContributesTo(RoomScope::class)
interface TimelineItemPresenterFactoriesModule {
@Multibinds
fun multiBindTimelineItemPresenterFactories(): @JvmSuppressWildcards Map<Class<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>
fun multiBindTimelineItemPresenterFactories(): @JvmSuppressWildcards Map<KClass<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>
}
/**
@ -38,8 +39,9 @@ interface TimelineItemPresenterFactoriesModule {
* goes out of the [LazyColumn] viewport.
*/
@SingleIn(RoomScope::class)
class TimelineItemPresenterFactories @Inject constructor(
private val factories: @JvmSuppressWildcards Map<Class<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>,
@Inject
class TimelineItemPresenterFactories(
private val factories: @JvmSuppressWildcards Map<KClass<out TimelineItemEventContent>, TimelineItemPresenterFactory<*, *>>,
) {
private val presenters: MutableMap<TimelineItemEventContent, Presenter<*>> = mutableMapOf()
@ -57,7 +59,7 @@ class TimelineItemPresenterFactories @Inject constructor(
@Composable
fun <C : TimelineItemEventContent, 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 : TimelineItemEventContent, S : Any> TimelineItemPresenter
content: C
): Presenter<S> = rememberPresenter(
content = content,
contentClass = C::class.java
contentClass = C::class
)

View file

@ -7,9 +7,9 @@
package io.element.android.features.messages.impl.timeline.factories
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.features.messages.impl.timeline.diff.TimelineItemsCacheInvalidator
import io.element.android.features.messages.impl.timeline.factories.event.TimelineItemEventFactory
import io.element.android.features.messages.impl.timeline.factories.virtual.TimelineItemVirtualFactory
@ -29,7 +29,8 @@ import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
class TimelineItemsFactory @AssistedInject constructor(
@Inject
class TimelineItemsFactory(
@Assisted config: TimelineItemsFactoryConfig,
eventItemFactoryCreator: TimelineItemEventFactory.Creator,
private val dispatchers: CoroutineDispatchers,

View file

@ -26,9 +26,10 @@ import io.element.android.libraries.matrix.api.timeline.item.event.StickerConten
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.getDisambiguatedDisplayName
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentFactory @Inject constructor(
@Inject
class TimelineItemContentFactory(
private val messageFactory: TimelineItemContentMessageFactory,
private val redactedMessageFactory: TimelineItemContentRedactedFactory,
private val stickerFactory: TimelineItemContentStickerFactory,

View file

@ -10,9 +10,10 @@ package io.element.android.features.messages.impl.timeline.factories.event
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentFailedToParseMessageFactory @Inject constructor() {
@Inject
class TimelineItemContentFailedToParseMessageFactory() {
fun create(@Suppress("UNUSED_PARAMETER") failedToParseMessageLike: FailedToParseMessageLikeContent): TimelineItemEventContent {
return TimelineItemUnknownContent
}

View file

@ -10,9 +10,10 @@ package io.element.android.features.messages.impl.timeline.factories.event
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemUnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentFailedToParseStateFactory @Inject constructor() {
@Inject
class TimelineItemContentFailedToParseStateFactory() {
@Suppress("UNUSED_PARAMETER")
fun create(failedToParseState: FailedToParseStateContent): TimelineItemEventContent {
return TimelineItemUnknownContent

View file

@ -48,10 +48,11 @@ import io.element.android.libraries.matrix.ui.messages.toHtmlDocument
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
import dev.zacsweers.metro.Inject
import kotlin.time.Duration
class TimelineItemContentMessageFactory @Inject constructor(
@Inject
class TimelineItemContentMessageFactory(
private val fileSizeFormatter: FileSizeFormatter,
private val fileExtensionExtractor: FileExtensionExtractor,
private val htmlConverterProvider: HtmlConverterProvider,

View file

@ -12,9 +12,10 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.poll.api.pollcontent.PollContentStateFactory
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentPollFactory @Inject constructor(
@Inject
class TimelineItemContentPollFactory(
private val pollContentStateFactory: PollContentStateFactory,
) {
suspend fun create(

View file

@ -12,9 +12,10 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentProfileChangeFactory @Inject constructor(
@Inject
class TimelineItemContentProfileChangeFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {

View file

@ -10,9 +10,10 @@ package io.element.android.features.messages.impl.timeline.factories.event
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemRedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentRedactedFactory @Inject constructor() {
@Inject
class TimelineItemContentRedactedFactory() {
fun create(@Suppress("UNUSED_PARAMETER") content: RedactedContent): TimelineItemEventContent {
return TimelineItemRedactedContent
}

View file

@ -12,9 +12,10 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentRoomMembershipFactory @Inject constructor(
@Inject
class TimelineItemContentRoomMembershipFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {

View file

@ -12,9 +12,10 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.libraries.core.extensions.orEmpty
import io.element.android.libraries.eventformatter.api.TimelineEventFormatter
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentStateFactory @Inject constructor(
@Inject
class TimelineItemContentStateFactory(
private val timelineEventFormatter: TimelineEventFormatter,
) {
fun create(eventTimelineItem: EventTimelineItem): TimelineItemEventContent {

View file

@ -13,9 +13,10 @@ import io.element.android.libraries.androidutils.filesize.FileSizeFormatter
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractor
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentStickerFactory @Inject constructor(
@Inject
class TimelineItemContentStickerFactory(
private val fileSizeFormatter: FileSizeFormatter,
private val fileExtensionExtractor: FileExtensionExtractor
) {

View file

@ -10,9 +10,10 @@ package io.element.android.features.messages.impl.timeline.factories.event
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEncryptedContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEventContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemContentUTDFactory @Inject constructor() {
@Inject
class TimelineItemContentUTDFactory() {
fun create(content: UnableToDecryptContent): TimelineItemEventContent {
return TimelineItemEncryptedContent(content.data)
}

View file

@ -7,9 +7,9 @@
package io.element.android.features.messages.impl.timeline.factories.event
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.features.messages.impl.timeline.factories.TimelineItemsFactoryConfig
import io.element.android.features.messages.impl.timeline.groups.canBeDisplayedInBubbleBlock
import io.element.android.features.messages.impl.timeline.model.AggregatedReaction
@ -36,7 +36,8 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import java.util.Date
class TimelineItemEventFactory @AssistedInject constructor(
@Inject
class TimelineItemEventFactory(
@Assisted private val config: TimelineItemsFactoryConfig,
private val contentFactory: TimelineItemContentFactory,
private val matrixClient: MatrixClient,

View file

@ -12,9 +12,10 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline
import io.element.android.libraries.dateformatter.api.DateFormatter
import io.element.android.libraries.dateformatter.api.DateFormatterMode
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemDaySeparatorFactory @Inject constructor(
@Inject
class TimelineItemDaySeparatorFactory(
private val dateFormatter: DateFormatter,
) {
fun create(virtualItem: VirtualTimelineItem.DayDivider): TimelineItemVirtualModel {

View file

@ -16,9 +16,10 @@ import io.element.android.features.messages.impl.timeline.model.virtual.Timeline
import io.element.android.features.messages.impl.timeline.model.virtual.TimelineItemVirtualModel
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineItemVirtualFactory @Inject constructor(
@Inject
class TimelineItemVirtualFactory(
private val daySeparatorFactory: TimelineItemDaySeparatorFactory,
) {
fun create(

View file

@ -10,13 +10,14 @@ package io.element.android.features.messages.impl.timeline.groups
import androidx.annotation.VisibleForTesting
import io.element.android.features.messages.impl.timeline.model.TimelineItem
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.UniqueId
import kotlinx.collections.immutable.toImmutableList
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@SingleIn(RoomScope::class)
class TimelineItemGrouper @Inject constructor() {
@Inject
class TimelineItemGrouper() {
/**
* Keys are identifier of items in a group, only one by group will be kept.
* Values are the actual groupIds.

View file

@ -20,9 +20,10 @@ import io.element.android.libraries.matrix.api.media.MediaPreviewService
import io.element.android.libraries.matrix.api.media.isPreviewEnabled
import io.element.android.libraries.matrix.api.room.BaseRoom
import kotlinx.collections.immutable.toImmutableSet
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TimelineProtectionPresenter @Inject constructor(
@Inject
class TimelineProtectionPresenter(
private val mediaPreviewService: MediaPreviewService,
private val room: BaseRoom,
) : Presenter<TimelineProtectionState> {

View file

@ -29,9 +29,10 @@ import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
import dev.zacsweers.metro.Inject
class TypingNotificationPresenter @Inject constructor(
@Inject
class TypingNotificationPresenter(
private val room: JoinedRoom,
private val sessionPreferencesStore: SessionPreferencesStore,
) : Presenter<TypingNotificationState> {

View file

@ -13,7 +13,7 @@ import android.text.Spanned
import android.text.style.URLSpan
import android.util.Patterns
import androidx.core.text.getSpans
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.MatrixPatternType
import io.element.android.libraries.matrix.api.core.MatrixPatterns
@ -26,14 +26,15 @@ import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
import io.element.android.libraries.textcomposer.mentions.getMentionSpans
import io.element.android.wysiwyg.view.spans.CodeBlockSpan
import io.element.android.wysiwyg.view.spans.InlineCodeSpan
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface TextPillificationHelper {
fun pillify(text: CharSequence, pillifyPermalinks: Boolean = true): CharSequence
}
@ContributesBinding(RoomScope::class)
class DefaultTextPillificationHelper @Inject constructor(
@Inject
class DefaultTextPillificationHelper(
private val mentionSpanProvider: MentionSpanProvider,
private val permalinkParser: PermalinkParser,
private val permalinkBuilder: PermalinkBuilder,

View file

@ -8,7 +8,7 @@
package io.element.android.features.messages.impl.utils.messagesummary
import android.content.Context
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.messages.impl.timeline.model.TimelineItem
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemCallNotifyContent
@ -27,13 +27,14 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent
import io.element.android.libraries.core.extensions.toSafeLength
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.annotations.ApplicationContext
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.ui.strings.CommonStrings
import javax.inject.Inject
import dev.zacsweers.metro.Inject
@ContributesBinding(RoomScope::class)
class DefaultMessageSummaryFormatter @Inject constructor(
@Inject
class DefaultMessageSummaryFormatter(
@ApplicationContext private val context: Context,
) : MessageSummaryFormatter {
override fun format(event: TimelineItem.Event): String {

View file

@ -19,10 +19,10 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.core.net.toUri
import androidx.lifecycle.Lifecycle
import com.squareup.anvil.annotations.ContributesBinding
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.Inject
import im.vector.app.features.analytics.plan.Composer
import io.element.android.features.messages.api.MessageComposerContext
import io.element.android.features.messages.api.timeline.voicemessages.composer.VoiceMessageComposerEvents
@ -51,7 +51,8 @@ import java.io.File
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
class DefaultVoiceMessageComposerPresenter @AssistedInject constructor(
@Inject
class DefaultVoiceMessageComposerPresenter(
@SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope,
@Assisted private val timelineMode: Timeline.Mode,
private val voiceRecorder: VoiceRecorder,

View file

@ -21,7 +21,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
import dev.zacsweers.metro.Inject
/**
* A media player for the voice message composer.
@ -29,7 +29,8 @@ import javax.inject.Inject
* @param mediaPlayer The [MediaPlayer] to use.
* @param sessionCoroutineScope
*/
class VoiceMessageComposerPlayer @Inject constructor(
@Inject
class VoiceMessageComposerPlayer(
private val mediaPlayer: MediaPlayer,
@SessionCoroutineScope
private val sessionCoroutineScope: CoroutineScope,

View file

@ -7,21 +7,22 @@
package io.element.android.features.messages.impl.voicemessages.timeline
import com.squareup.anvil.annotations.ContributesBinding
import dev.zacsweers.metro.ContributesBinding
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.mediaplayer.api.MediaPlayer
import kotlinx.coroutines.withContext
import javax.inject.Inject
import dev.zacsweers.metro.Inject
interface RedactedVoiceMessageManager {
suspend fun onEachMatrixTimelineItem(timelineItems: List<MatrixTimelineItem>)
}
@ContributesBinding(RoomScope::class)
class DefaultRedactedVoiceMessageManager @Inject constructor(
@Inject
class DefaultRedactedVoiceMessageManager(
private val dispatchers: CoroutineDispatchers,
private val mediaPlayer: MediaPlayer,
) : RedactedVoiceMessageManager {

View file

@ -8,13 +8,13 @@
package io.element.android.features.messages.impl.voicemessages.timeline
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.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
@ -23,7 +23,7 @@ import io.element.android.libraries.di.RoomScope
import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory
import io.element.android.libraries.voiceplayer.api.VoiceMessageState
@Module
@BindingContainer
@ContributesTo(RoomScope::class)
interface VoiceMessagePresenterModule {
@Binds
@ -32,7 +32,8 @@ interface VoiceMessagePresenterModule {
fun bindVoiceMessagePresenterFactory(factory: VoiceMessagePresenter.Factory): TimelineItemPresenterFactory<*, *>
}
class VoiceMessagePresenter @AssistedInject constructor(
@Inject
class VoiceMessagePresenter(
voiceMessagePresenterFactory: VoiceMessagePresenterFactory,
@Assisted private val content: TimelineItemVoiceContent,
) : Presenter<VoiceMessageState> {