Branch on viewmodel...
This commit is contained in:
parent
8620a86333
commit
eba807e37a
15 changed files with 232 additions and 115 deletions
|
|
@ -3,16 +3,6 @@ plugins {
|
||||||
alias(libs.plugins.kapt)
|
alias(libs.plugins.kapt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
|
||||||
kotlinOptions {
|
|
||||||
freeCompilerArgs += listOf(
|
|
||||||
"-opt-in=com.squareup.anvil.annotations.ExperimentalAnvilApi")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":anvilannotations"))
|
implementation(project(":anvilannotations"))
|
||||||
api(libs.anvil.compiler.api)
|
api(libs.anvil.compiler.api)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
@file:OptIn(ExperimentalAnvilApi::class)
|
||||||
|
|
||||||
|
package io.element.android.x.anvilcodegen
|
||||||
|
|
||||||
|
import com.google.auto.service.AutoService
|
||||||
|
import com.squareup.anvil.annotations.ContributesTo
|
||||||
|
import com.squareup.anvil.annotations.ExperimentalAnvilApi
|
||||||
|
import com.squareup.anvil.compiler.api.AnvilCompilationException
|
||||||
|
import com.squareup.anvil.compiler.api.AnvilContext
|
||||||
|
import com.squareup.anvil.compiler.api.CodeGenerator
|
||||||
|
import com.squareup.anvil.compiler.api.GeneratedFile
|
||||||
|
import com.squareup.anvil.compiler.api.createGeneratedFile
|
||||||
|
import com.squareup.anvil.compiler.internal.asClassName
|
||||||
|
import com.squareup.anvil.compiler.internal.buildFile
|
||||||
|
import com.squareup.anvil.compiler.internal.fqName
|
||||||
|
import com.squareup.anvil.compiler.internal.reference.ClassReference
|
||||||
|
import com.squareup.anvil.compiler.internal.reference.asClassName
|
||||||
|
import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences
|
||||||
|
import com.squareup.kotlinpoet.AnnotationSpec
|
||||||
|
import com.squareup.kotlinpoet.ClassName
|
||||||
|
import com.squareup.kotlinpoet.FileSpec
|
||||||
|
import com.squareup.kotlinpoet.FunSpec
|
||||||
|
import com.squareup.kotlinpoet.KModifier
|
||||||
|
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
|
||||||
|
import com.squareup.kotlinpoet.STAR
|
||||||
|
import com.squareup.kotlinpoet.TypeSpec
|
||||||
|
import dagger.Binds
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import dagger.multibindings.IntoMap
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an anvil plugin that allows ViewModels to use [ContributesViewModel] alone and let this plugin automatically
|
||||||
|
* handle the rest of the Dagger wiring required for constructor injection.
|
||||||
|
*/
|
||||||
|
@AutoService(CodeGenerator::class)
|
||||||
|
class ContributesViewModelCodeGenerator : CodeGenerator {
|
||||||
|
|
||||||
|
override fun isApplicable(context: AnvilContext): Boolean = true
|
||||||
|
|
||||||
|
override fun generateCode(codeGenDir: File, module: ModuleDescriptor, projectFiles: Collection<KtFile>): Collection<GeneratedFile> {
|
||||||
|
return projectFiles.classAndInnerClassReferences(module)
|
||||||
|
.filter { it.isAnnotatedWith(ContributesViewModel::class.fqName) }
|
||||||
|
.flatMap { listOf(generateModule(it, codeGenDir, module), generateAssistedFactory(it, codeGenDir, module)) }
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateModule(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile {
|
||||||
|
val generatedPackage = vmClass.packageFqName.toString()
|
||||||
|
val moduleClassName = "${vmClass.shortName}_Module"
|
||||||
|
val scope = vmClass.annotations.single { it.fqName == ContributesViewModel::class.fqName }.scope()
|
||||||
|
val content = FileSpec.buildFile(generatedPackage, moduleClassName) {
|
||||||
|
addType(
|
||||||
|
TypeSpec.classBuilder(moduleClassName)
|
||||||
|
.addModifiers(KModifier.ABSTRACT)
|
||||||
|
.addAnnotation(Module::class)
|
||||||
|
.addAnnotation(AnnotationSpec.builder(ContributesTo::class).addMember("%T::class", scope.asClassName()).build())
|
||||||
|
.addFunction(
|
||||||
|
FunSpec.builder("bind${vmClass.shortName}Factory")
|
||||||
|
.addModifiers(KModifier.ABSTRACT)
|
||||||
|
.addParameter("factory", ClassName(generatedPackage, "${vmClass.shortName}_AssistedFactory"))
|
||||||
|
.returns(assistedViewModelFactoryFqName.asClassName(module).parameterizedBy(STAR, STAR))
|
||||||
|
.addAnnotation(Binds::class)
|
||||||
|
.addAnnotation(IntoMap::class)
|
||||||
|
.addAnnotation(AnnotationSpec.Companion.builder(viewModelKeyFqName.asClassName(module)).addMember("%T::class", vmClass.asClassName()).build())
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return createGeneratedFile(codeGenDir, generatedPackage, moduleClassName, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateAssistedFactory(vmClass: ClassReference.Psi, codeGenDir: File, module: ModuleDescriptor): GeneratedFile {
|
||||||
|
val generatedPackage = vmClass.packageFqName.toString()
|
||||||
|
val assistedFactoryClassName = "${vmClass.shortName}_AssistedFactory"
|
||||||
|
val constructor = vmClass.constructors.singleOrNull { it.isAnnotatedWith(AssistedInject::class.fqName) }
|
||||||
|
val assistedParameter = constructor?.parameters?.singleOrNull { it.isAnnotatedWith(Assisted::class.fqName) }
|
||||||
|
if (constructor == null || assistedParameter == null) {
|
||||||
|
throw AnvilCompilationException(
|
||||||
|
"${vmClass.fqName} must have an @AssistedInject constructor with @Assisted initialState: S parameter",
|
||||||
|
element = vmClass.clazz,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (assistedParameter.name != "initialState") {
|
||||||
|
throw AnvilCompilationException(
|
||||||
|
"${vmClass.fqName} @Assisted parameter must be named initialState",
|
||||||
|
element = assistedParameter.parameter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val vmClassName = vmClass.asClassName()
|
||||||
|
val stateClassName = assistedParameter.type().asTypeName()
|
||||||
|
val content = FileSpec.buildFile(generatedPackage, assistedFactoryClassName) {
|
||||||
|
addType(
|
||||||
|
TypeSpec.interfaceBuilder(assistedFactoryClassName)
|
||||||
|
.addSuperinterface(assistedViewModelFactoryFqName.asClassName(module).parameterizedBy(vmClassName, stateClassName))
|
||||||
|
.addAnnotation(AssistedFactory::class)
|
||||||
|
.addFunction(
|
||||||
|
FunSpec.builder("create")
|
||||||
|
.addModifiers(KModifier.OVERRIDE, KModifier.ABSTRACT)
|
||||||
|
.addParameter("initialState", stateClassName)
|
||||||
|
.returns(vmClassName)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return createGeneratedFile(codeGenDir, generatedPackage, assistedFactoryClassName, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val assistedViewModelFactoryFqName = FqName("io.element.android.x.core.di.AssistedViewModelFactory")
|
||||||
|
private val viewModelKeyFqName = FqName("io.element.android.x.core.di.ViewModelKey")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -121,6 +121,8 @@ dependencies {
|
||||||
implementation(project(":features:roomlist"))
|
implementation(project(":features:roomlist"))
|
||||||
implementation(project(":features:messages"))
|
implementation(project(":features:messages"))
|
||||||
implementation(project(":libraries:di"))
|
implementation(project(":libraries:di"))
|
||||||
|
implementation(project(":anvilannotations"))
|
||||||
|
anvil(project(":anvilcodegen"))
|
||||||
|
|
||||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.0")
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.0")
|
||||||
implementation(libs.compose.destinations)
|
implementation(libs.compose.destinations)
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.airbnb.android.showkase.models.Showkase
|
import com.airbnb.android.showkase.models.Showkase
|
||||||
|
import com.airbnb.mvrx.compose.mavericksActivityViewModel
|
||||||
|
import com.airbnb.mvrx.compose.mavericksViewModel
|
||||||
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
|
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
|
||||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||||
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
|
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
|
||||||
|
|
@ -46,14 +48,12 @@ private const val transitionAnimationDuration = 500
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
private val viewModel: MainViewModel by viewModels()
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
setContent {
|
setContent {
|
||||||
ElementXTheme {
|
ElementXTheme {
|
||||||
MainScreen(viewModel = viewModel)
|
MainScreen(viewModel = mavericksActivityViewModel())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,41 @@
|
||||||
package io.element.android.x
|
package io.element.android.x
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import com.airbnb.mvrx.MavericksState
|
||||||
import androidx.lifecycle.viewModelScope
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
|
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||||
|
import io.element.android.x.di.AppScope
|
||||||
|
import io.element.android.x.features.messages.MessagesViewModel
|
||||||
|
import io.element.android.x.features.messages.model.MessagesViewState
|
||||||
|
import io.element.android.x.matrix.Matrix
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainViewModel : ViewModel() {
|
data class MainState(val fake: Boolean = false) : MavericksState
|
||||||
private val matrix = MatrixInstance.getInstance()
|
|
||||||
|
@ContributesViewModel(AppScope::class)
|
||||||
|
class MainViewModel @AssistedInject constructor(
|
||||||
|
private val matrix: Matrix,
|
||||||
|
@Assisted initialState: MainState
|
||||||
|
) : MavericksViewModel<MainState>(initialState) {
|
||||||
|
|
||||||
|
companion object : MavericksViewModelFactory<MainViewModel, MainState> by daggerMavericksViewModelFactory()
|
||||||
|
|
||||||
suspend fun isLoggedIn(): Boolean {
|
suspend fun isLoggedIn(): Boolean {
|
||||||
return matrix.isLoggedIn().first()
|
return matrix.isLoggedIn().first()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startSyncIfLogged(){
|
fun startSyncIfLogged() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if(!isLoggedIn()) return@launch
|
if (!isLoggedIn()) return@launch
|
||||||
matrix.activeClient().startSync()
|
matrix.activeClient().startSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopSyncIfLogged(){
|
fun stopSyncIfLogged() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (!isLoggedIn()) return@launch
|
if (!isLoggedIn()) return@launch
|
||||||
matrix.activeClient().stopSync()
|
matrix.activeClient().stopSync()
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ import android.content.Context
|
||||||
import com.squareup.anvil.annotations.MergeComponent
|
import com.squareup.anvil.annotations.MergeComponent
|
||||||
import dagger.BindsInstance
|
import dagger.BindsInstance
|
||||||
import dagger.Component
|
import dagger.Component
|
||||||
|
import io.element.android.x.core.di.DaggerMavericksBindings
|
||||||
|
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
@MergeComponent(AppScope::class)
|
@MergeComponent(AppScope::class)
|
||||||
interface AppComponent {
|
interface AppComponent: DaggerMavericksBindings {
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,22 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("io.element.android-compose-library")
|
id("io.element.android-compose-library")
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.anvil)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.x.features.login"
|
namespace = "io.element.android.x.features.login"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anvil {
|
||||||
|
generateDaggerFactories.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":anvilannotations"))
|
||||||
|
anvil(project(":anvilcodegen"))
|
||||||
|
implementation(project(":libraries:di"))
|
||||||
implementation(project(":libraries:core"))
|
implementation(project(":libraries:core"))
|
||||||
implementation(project(":libraries:matrix"))
|
implementation(project(":libraries:matrix"))
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,27 @@ package io.element.android.x.features.login
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import com.airbnb.mvrx.MavericksViewModel
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
|
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||||
|
import io.element.android.x.di.AppScope
|
||||||
|
import io.element.android.x.matrix.Matrix
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.matrix.MatrixInstance
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class LoginViewModel(initialState: LoginViewState) :
|
@ContributesViewModel(AppScope::class)
|
||||||
|
class LoginViewModel @AssistedInject constructor(
|
||||||
|
private val matrix: Matrix,
|
||||||
|
@Assisted initialState: LoginViewState) :
|
||||||
MavericksViewModel<LoginViewState>(initialState) {
|
MavericksViewModel<LoginViewState>(initialState) {
|
||||||
|
|
||||||
private val matrix = MatrixInstance.getInstance()
|
companion object : MavericksViewModelFactory<LoginViewModel, LoginViewState> by daggerMavericksViewModelFactory()
|
||||||
|
|
||||||
var formState = mutableStateOf(LoginFormState.Default)
|
var formState = mutableStateOf(LoginFormState.Default)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,22 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("io.element.android-compose-library")
|
id("io.element.android-compose-library")
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.anvil)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.x.features.messages"
|
namespace = "io.element.android.x.features.messages"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anvil {
|
||||||
|
generateDaggerFactories.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":anvilannotations"))
|
||||||
|
anvil(project(":anvilcodegen"))
|
||||||
|
implementation(project(":libraries:di"))
|
||||||
implementation(project(":libraries:core"))
|
implementation(project(":libraries:core"))
|
||||||
implementation(project(":libraries:matrix"))
|
implementation(project(":libraries:matrix"))
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,21 @@ package io.element.android.x.features.messages
|
||||||
import com.airbnb.mvrx.MavericksViewModel
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
|
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
||||||
|
import io.element.android.x.di.AppScope
|
||||||
import io.element.android.x.features.messages.model.MessagesItemAction
|
import io.element.android.x.features.messages.model.MessagesItemAction
|
||||||
import io.element.android.x.features.messages.model.MessagesItemActionsSheetState
|
import io.element.android.x.features.messages.model.MessagesItemActionsSheetState
|
||||||
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
||||||
import io.element.android.x.features.messages.model.MessagesViewState
|
import io.element.android.x.features.messages.model.MessagesViewState
|
||||||
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
|
||||||
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.matrix.Matrix
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
|
||||||
import io.element.android.x.matrix.media.MediaResolver
|
import io.element.android.x.matrix.media.MediaResolver
|
||||||
import io.element.android.x.matrix.room.MatrixRoom
|
|
||||||
import io.element.android.x.matrix.timeline.MatrixTimeline
|
import io.element.android.x.matrix.timeline.MatrixTimeline
|
||||||
import io.element.android.x.matrix.timeline.MatrixTimelineItem
|
import io.element.android.x.matrix.timeline.MatrixTimelineItem
|
||||||
import io.element.android.x.textcomposer.MessageComposerMode
|
import io.element.android.x.textcomposer.MessageComposerMode
|
||||||
|
|
@ -26,35 +28,20 @@ import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private const val PAGINATION_COUNT = 50
|
private const val PAGINATION_COUNT = 50
|
||||||
|
|
||||||
class MessagesViewModel(
|
@ContributesViewModel(AppScope::class)
|
||||||
private val client: MatrixClient,
|
class MessagesViewModel @AssistedInject constructor(
|
||||||
private val room: MatrixRoom,
|
matrix: Matrix,
|
||||||
private val timeline: MatrixTimeline,
|
@Assisted private val initialState: MessagesViewState
|
||||||
private val messageTimelineItemStateFactory: MessageTimelineItemStateFactory,
|
|
||||||
private val initialState: MessagesViewState
|
|
||||||
) :
|
) :
|
||||||
MavericksViewModel<MessagesViewState>(initialState) {
|
MavericksViewModel<MessagesViewState>(initialState) {
|
||||||
|
|
||||||
companion object : MavericksViewModelFactory<MessagesViewModel, MessagesViewState> {
|
companion object : MavericksViewModelFactory<MessagesViewModel, MessagesViewState> by daggerMavericksViewModelFactory()
|
||||||
|
|
||||||
override fun create(
|
private val client = matrix.activeClient()
|
||||||
viewModelContext: ViewModelContext,
|
private val room = client.getRoom(initialState.roomId)!!
|
||||||
state: MessagesViewState
|
private val messageTimelineItemStateFactory =
|
||||||
): MessagesViewModel? {
|
MessageTimelineItemStateFactory(client, room, Dispatchers.Default)
|
||||||
val matrix = MatrixInstance.getInstance()
|
private val timeline = room.timeline()
|
||||||
val client = matrix.activeClient()
|
|
||||||
val room = client.getRoom(state.roomId) ?: return null
|
|
||||||
val messageTimelineItemStateFactory =
|
|
||||||
MessageTimelineItemStateFactory(client, room, Dispatchers.Default)
|
|
||||||
return MessagesViewModel(
|
|
||||||
client,
|
|
||||||
room,
|
|
||||||
room.timeline(),
|
|
||||||
messageTimelineItemStateFactory,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val timelineCallback = object : MatrixTimeline.Callback {
|
private val timelineCallback = object : MatrixTimeline.Callback {
|
||||||
override fun onPushedTimelineItem(timelineItem: MatrixTimelineItem) {
|
override fun onPushedTimelineItem(timelineItem: MatrixTimelineItem) {
|
||||||
|
|
|
||||||
|
|
@ -2,32 +2,24 @@ package io.element.android.x.features.messages.textcomposer
|
||||||
|
|
||||||
import com.airbnb.mvrx.MavericksViewModel
|
import com.airbnb.mvrx.MavericksViewModel
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
import io.element.android.x.core.data.StableCharSequence
|
import io.element.android.x.core.data.StableCharSequence
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.di.AppScope
|
||||||
|
import io.element.android.x.matrix.Matrix
|
||||||
|
|
||||||
|
@ContributesViewModel(AppScope::class)
|
||||||
class MessageComposerViewModel(
|
class MessageComposerViewModel @AssistedInject constructor(
|
||||||
private val client: MatrixClient,
|
private val matrix: Matrix,
|
||||||
private val initialState: MessageComposerViewState
|
@Assisted private val initialState: MessageComposerViewState
|
||||||
) : MavericksViewModel<MessageComposerViewState>(initialState) {
|
) : MavericksViewModel<MessageComposerViewState>(initialState) {
|
||||||
|
|
||||||
companion object :
|
companion object :
|
||||||
MavericksViewModelFactory<MessageComposerViewModel, MessageComposerViewState> {
|
MavericksViewModelFactory<MessageComposerViewModel, MessageComposerViewState> by daggerMavericksViewModelFactory()
|
||||||
|
|
||||||
override fun create(
|
private val client = matrix.activeClient()
|
||||||
viewModelContext: ViewModelContext,
|
|
||||||
state: MessageComposerViewState
|
|
||||||
): MessageComposerViewModel? {
|
|
||||||
val matrix = MatrixInstance.getInstance()
|
|
||||||
val client = matrix.activeClient()
|
|
||||||
return MessageComposerViewModel(
|
|
||||||
client,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onComposerFullScreenChange() {
|
fun onComposerFullScreenChange() {
|
||||||
setState {
|
setState {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,21 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("io.element.android-compose-library")
|
id("io.element.android-compose-library")
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.anvil)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.x.features.roomlist"
|
namespace = "io.element.android.x.features.roomlist"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anvil {
|
||||||
|
generateDaggerFactories.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":anvilannotations"))
|
||||||
|
anvil(project(":anvilcodegen"))
|
||||||
|
implementation(project(":libraries:di"))
|
||||||
implementation(project(":libraries:core"))
|
implementation(project(":libraries:core"))
|
||||||
implementation(project(":libraries:matrix"))
|
implementation(project(":libraries:matrix"))
|
||||||
implementation(project(":libraries:designsystem"))
|
implementation(project(":libraries:designsystem"))
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
package io.element.android.x.features.roomlist
|
package io.element.android.x.features.roomlist
|
||||||
|
|
||||||
import com.airbnb.mvrx.*
|
import com.airbnb.mvrx.*
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.x.anvilannotations.ContributesViewModel
|
||||||
import io.element.android.x.core.data.parallelMap
|
import io.element.android.x.core.data.parallelMap
|
||||||
|
import io.element.android.x.core.di.daggerMavericksViewModelFactory
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
||||||
|
import io.element.android.x.di.AppScope
|
||||||
import io.element.android.x.features.roomlist.model.MatrixUser
|
import io.element.android.x.features.roomlist.model.MatrixUser
|
||||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
import io.element.android.x.features.roomlist.model.RoomListRoomSummary
|
||||||
import io.element.android.x.features.roomlist.model.RoomListRoomSummaryPlaceholders
|
import io.element.android.x.features.roomlist.model.RoomListRoomSummaryPlaceholders
|
||||||
import io.element.android.x.features.roomlist.model.RoomListViewState
|
import io.element.android.x.features.roomlist.model.RoomListViewState
|
||||||
|
import io.element.android.x.matrix.Matrix
|
||||||
import io.element.android.x.matrix.MatrixClient
|
import io.element.android.x.matrix.MatrixClient
|
||||||
import io.element.android.x.matrix.MatrixInstance
|
import io.element.android.x.matrix.MatrixInstance
|
||||||
import io.element.android.x.matrix.media.MediaResolver
|
import io.element.android.x.matrix.media.MediaResolver
|
||||||
|
|
@ -22,28 +28,17 @@ import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private const val extendedRangeSize = 40
|
private const val extendedRangeSize = 40
|
||||||
|
|
||||||
class RoomListViewModel(
|
@ContributesViewModel(AppScope::class)
|
||||||
private val client: MatrixClient,
|
class RoomListViewModel @AssistedInject constructor(
|
||||||
initialState: RoomListViewState
|
matrix: Matrix,
|
||||||
|
@Assisted initialState: RoomListViewState
|
||||||
) :
|
) :
|
||||||
MavericksViewModel<RoomListViewState>(initialState) {
|
MavericksViewModel<RoomListViewState>(initialState) {
|
||||||
|
|
||||||
companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> {
|
companion object : MavericksViewModelFactory<RoomListViewModel, RoomListViewState> by daggerMavericksViewModelFactory()
|
||||||
|
|
||||||
override fun create(
|
|
||||||
viewModelContext: ViewModelContext,
|
|
||||||
state: RoomListViewState
|
|
||||||
): RoomListViewModel {
|
|
||||||
val matrix = MatrixInstance.getInstance()
|
|
||||||
val client = matrix.activeClient()
|
|
||||||
return RoomListViewModel(
|
|
||||||
client,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val lastMessageFormatter = LastMessageFormatter()
|
private val lastMessageFormatter = LastMessageFormatter()
|
||||||
|
private val client = matrix.activeClient()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
handleInit()
|
handleInit()
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.x.core.di
|
package io.element.android.x.core.di
|
||||||
|
|
||||||
import com.airbnb.mvrx.MavericksState
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import com.airbnb.mvrx.ViewModelContext
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline fun <reified VM : MavericksViewModel<S>, S : MavericksState> daggerMavericksViewModelFactory() = DaggerMavericksViewModelFactory<VM, S>(VM::class.java)
|
inline fun <reified VM : MavericksViewModel<S>, S : MavericksState> daggerMavericksViewModelFactory() = DaggerMavericksViewModelFactory(VM::class.java)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [MavericksViewModelFactory] makes it easy to create instances of a ViewModel
|
* A [MavericksViewModelFactory] makes it easy to create instances of a ViewModel
|
||||||
|
|
@ -55,14 +55,6 @@ class DaggerMavericksViewModelFactory<VM : MavericksViewModel<S>, S : MavericksS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* These Anvil/Dagger bindings are used by [DaggerMavericksViewModelFactory]. The factory will find the nearest [DaggerComponentOwner]
|
|
||||||
* that implements these bindings. It will then attempt to retrieve the [AssistedViewModelFactory] for the given ViewModel class.
|
|
||||||
*
|
|
||||||
* In this example, this bindings class is implemented by [com.airbnb.mvrx.sample.anvil.feature.ExampleFeatureComponent] because
|
|
||||||
* it provides the [com.airbnb.mvrx.sample.anvil.feature.ExampleFeatureViewModel]. Any component that will generate ViewModels should
|
|
||||||
* either implement this directly or have this added via `@ContributesTo(YourScope::class)`.
|
|
||||||
*/
|
|
||||||
interface DaggerMavericksBindings {
|
interface DaggerMavericksBindings {
|
||||||
fun viewModelFactories(): Map<Class<out MavericksViewModel<*>>, AssistedViewModelFactory<*, *>>
|
fun viewModelFactories(): Map<Class<out MavericksViewModel<*>>, AssistedViewModelFactory<*, *>>
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue