добавлен способ инжекта в ViewModel

This commit is contained in:
2023-04-24 19:58:46 +03:00
parent 09800f9567
commit 655e8424e5
12 changed files with 107 additions and 84 deletions
@@ -3,13 +3,17 @@ package ru.megboyzz.dnevnik
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import ru.megboyzz.dnevnik.db.dao.CredentialsDao import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.navigation.AppNavHost import ru.megboyzz.dnevnik.navigation.AppNavHost
import ru.megboyzz.dnevnik.ui.theme.lightGray import ru.megboyzz.dnevnik.ui.theme.lightGray
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
import javax.inject.Inject import javax.inject.Inject
import kotlin.concurrent.thread import kotlin.concurrent.thread
@@ -27,6 +31,7 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
this.app = application as App this.app = application as App
app.appComponent.inject(this) app.appComponent.inject(this)
setContent { setContent {
Surface( Surface(
@@ -9,6 +9,7 @@ enum class AuthorizationStatus {
MAINTAIN, MAINTAIN,
CREDENTIALS_LOADING, CREDENTIALS_LOADING,
NOTHING, NOTHING,
UNKNOWN_ERROR UNKNOWN_ERROR,
LOGOUT
} }
@@ -10,6 +10,7 @@ import ru.megboyzz.dnevnik.authorization.AuthorizationManager
import ru.megboyzz.dnevnik.db.dao.CredentialsDao import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.di.modules.AppModule import ru.megboyzz.dnevnik.di.modules.AppModule
import ru.megboyzz.dnevnik.entities.db.Credentials
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel
import javax.inject.Singleton import javax.inject.Singleton
@@ -19,13 +20,16 @@ import javax.inject.Singleton
@Component(modules = [AppModule::class]) @Component(modules = [AppModule::class])
interface AppComponent { interface AppComponent {
fun inject(viewModel: AuthorizationViewModel) val authViewModel: AuthorizationViewModel
val profileViewModel: ProfileViewModel
val credentialsDao: CredentialsDao
val globalUserContextDao: GlobalUserContextDao
fun inject(viewModel: ProfileViewModel) fun inject(viewModel: ProfileViewModel)
fun inject(activity: MainActivity) fun inject(activity: MainActivity)
fun getCredentialsDao(): CredentialsDao
fun getGlobalUserContextDao(): GlobalUserContextDao
@Component.Builder @Component.Builder
interface Builder { interface Builder {
fun appModule(appModule: AppModule): Builder // add this fun appModule(appModule: AppModule): Builder // add this
@@ -4,10 +4,13 @@ import android.content.Context
import androidx.room.Room import androidx.room.Room
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import kotlinx.coroutines.coroutineScope
import ru.megboyzz.dnevnik.db.AppDataBase import ru.megboyzz.dnevnik.db.AppDataBase
import ru.megboyzz.dnevnik.db.dao.CredentialsDao import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.entities.db.Credentials
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.coroutines.coroutineContext
@Module @Module
class DatabaseModule { class DatabaseModule {
@@ -27,5 +30,4 @@ class DatabaseModule {
@Provides @Provides
fun provideGlobalUserContextDao(dataBase: AppDataBase): GlobalUserContextDao = dataBase.globalUserContextDao() fun provideGlobalUserContextDao(dataBase: AppDataBase): GlobalUserContextDao = dataBase.globalUserContextDao()
} }
@@ -1,10 +1,10 @@
package ru.megboyzz.dnevnik.navigation package ru.megboyzz.dnevnik.navigation
import android.util.Log
import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.rememberScaffoldState import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
@@ -14,7 +14,8 @@ import ru.megboyzz.dnevnik.collectAsMutableState
import ru.megboyzz.dnevnik.screens.* import ru.megboyzz.dnevnik.screens.*
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.navigate import ru.megboyzz.dnevnik.navigate
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModelFactory import androidx.activity.viewModels
import ru.megboyzz.dnevnik.appComponent
import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
sealed class BaseNavRote(open val route: String) sealed class BaseNavRote(open val route: String)
@@ -33,14 +34,19 @@ sealed class AppNavRoute(override val route: String): BaseNavRote(route){
@Composable @Composable
fun AppNavHost(){ fun AppNavHost(){
Log.i("AppNavHost", "Called")
val scaffoldState = rememberScaffoldState() val scaffoldState = rememberScaffoldState()
val navController = rememberNavController() val navController = rememberNavController()
val app = (LocalContext.current as MainActivity).app val mainActivity = LocalContext.current as MainActivity
val authorizationViewModel: AuthorizationViewModel = viewModel( val authorizationViewModel: AuthorizationViewModel by mainActivity.viewModels{
factory = AuthorizationViewModelFactory(app) ViewModelFactory{
) Log.i("AuthorizationViewModel", "i am created!")
mainActivity.appComponent.authViewModel
}
}
val loginStatus = authorizationViewModel.loginStatus.collectAsMutableState() val loginStatus = authorizationViewModel.loginStatus.collectAsMutableState()
@@ -1,8 +1,9 @@
package ru.megboyzz.dnevnik.screens package ru.megboyzz.dnevnik.screens
import android.util.Log
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.material.Button import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.CircularProgressIndicator
@@ -10,10 +11,8 @@ import androidx.compose.material.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.megboyzz.dnevnik.MainActivity import ru.megboyzz.dnevnik.MainActivity
import ru.megboyzz.dnevnik.appComponent import ru.megboyzz.dnevnik.appComponent
@@ -24,14 +23,21 @@ import ru.megboyzz.dnevnik.navigation.AppNavRoute
import ru.megboyzz.dnevnik.screens.ui.AlertMessageBox import ru.megboyzz.dnevnik.screens.ui.AlertMessageBox
import ru.megboyzz.dnevnik.screens.ui.LoginScreenContent import ru.megboyzz.dnevnik.screens.ui.LoginScreenContent
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
//TODO Переверстать экран входа //TODO Переверстать экран входа
@Composable @Composable
fun LoginScreen(navController: NavController) { fun LoginScreen(navController: NavController) {
val context = LocalContext.current Log.i("LoginScreen", "Called")
val authorizationViewModel: AuthorizationViewModel = viewModel() val activity = LocalContext.current as MainActivity
val authorizationViewModel: AuthorizationViewModel by activity.viewModels {
ViewModelFactory{
activity.appComponent.authViewModel
}
}
val login = authorizationViewModel.login.collectAsMutableState() val login = authorizationViewModel.login.collectAsMutableState()
@@ -67,8 +73,10 @@ fun LoginScreen(navController: NavController) {
) )
} }
if(loginStatus.value == AuthorizationStatus.LOGGED) if(loginStatus.value == AuthorizationStatus.LOGGED) {
Log.i("loginStatus", "logged")
navController.navigate(AppNavRoute.Marks) navController.navigate(AppNavRoute.Marks)
}
Box(){ Box(){
LoginScreenContent( LoginScreenContent(
@@ -109,8 +117,8 @@ fun LoginScreen(navController: NavController) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var isRemoving by remember{ mutableStateOf(false) } var isRemoving by remember{ mutableStateOf(false) }
Button(onClick = { Button(onClick = {
val globalUserContextDao = context.appComponent.getGlobalUserContextDao() val globalUserContextDao = activity.appComponent.globalUserContextDao
val credentialsDao = context.appComponent.getCredentialsDao() val credentialsDao = activity.appComponent.credentialsDao
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
isRemoving = true isRemoving = true
globalUserContextDao.deleteGlobalUserContext() globalUserContextDao.deleteGlobalUserContext()
@@ -1,6 +1,7 @@
package ru.megboyzz.dnevnik.screens.ui.main package ru.megboyzz.dnevnik.screens.ui.main
import android.annotation.SuppressLint import android.util.Log
import androidx.activity.viewModels
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -11,20 +12,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Outline
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@@ -38,12 +28,11 @@ import ru.megboyzz.dnevnik.screens.ui.AlmostOutlinedText
import ru.megboyzz.dnevnik.screens.ui.LeaveAlert import ru.megboyzz.dnevnik.screens.ui.LeaveAlert
import ru.megboyzz.dnevnik.screens.ui.ProfileCard import ru.megboyzz.dnevnik.screens.ui.ProfileCard
import ru.megboyzz.dnevnik.ui.theme.H2 import ru.megboyzz.dnevnik.ui.theme.H2
import ru.megboyzz.dnevnik.ui.theme.Shapes
import ru.megboyzz.dnevnik.ui.theme.mainBlue import ru.megboyzz.dnevnik.ui.theme.mainBlue
import ru.megboyzz.dnevnik.ui.theme.white import ru.megboyzz.dnevnik.ui.theme.white
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModelFactory import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
@Composable @Composable
@@ -83,15 +72,27 @@ fun DrawerContent(
scaffoldState: ScaffoldState scaffoldState: ScaffoldState
) { ) {
val app = (LocalContext.current as MainActivity).app Log.i("DrawerContent", "Called")
val profileViewModel: ProfileViewModel = viewModel( val activity = LocalContext.current as MainActivity
factory = ProfileViewModelFactory(app)
) val profileViewModel: ProfileViewModel by activity.viewModels{
ViewModelFactory{
activity.appComponent.profileViewModel
}
}
val authorizationViewModel: AuthorizationViewModel by activity.viewModels {
ViewModelFactory{
activity.appComponent.authViewModel
}
}
val profile = profileViewModel.profile.collectAsState() val profile = profileViewModel.profile.collectAsState()
val dao = LocalContext.current.appComponent.getCredentialsDao() val credentialsDao = activity.appComponent.credentialsDao
val globalUserContextDao = activity.appComponent.globalUserContextDao
var leaveAlertIsOpened by remember { var leaveAlertIsOpened by remember {
@@ -110,11 +111,12 @@ fun DrawerContent(
onAgree = { onAgree = {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
isLeavingProcess = true isLeavingProcess = true
dao.deleteCredentials() credentialsDao.deleteCredentials()
globalUserContextDao.deleteGlobalUserContext()
leaveAlertIsOpened = false leaveAlertIsOpened = false
this.launch(Dispatchers.Main) { navController.navigate(AppNavRoute.Login) }
scaffoldState.drawerState.close()
} }
authorizationViewModel.resetAuth()
navController.navigate(AppNavRoute.Login)
}, },
onCancel = { leaveAlertIsOpened = false } onCancel = { leaveAlertIsOpened = false }
) )
@@ -0,0 +1,8 @@
package ru.megboyzz.dnevnik.service
//Сервис для последних оценок
interface MarksService {
}
@@ -14,19 +14,18 @@ import ru.megboyzz.dnevnik.authorization.AuthorizationStatus
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
import javax.inject.Inject import javax.inject.Inject
class AuthorizationViewModel(val application: App): AndroidViewModel(application) { class AuthorizationViewModel @Inject constructor(
private val authManager: AuthorizationManager
): ViewModel() {
val login = MutableStateFlow("") val login = MutableStateFlow("")
val password = MutableStateFlow("") val password = MutableStateFlow("")
val rememberMe = MutableStateFlow(false) val rememberMe = MutableStateFlow(false)
@Inject
lateinit var authManager: AuthorizationManager
val loginStatus = MutableStateFlow(AuthorizationStatus.CREDENTIALS_LOADING) val loginStatus = MutableStateFlow(AuthorizationStatus.CREDENTIALS_LOADING)
init { init {
application.appComponent.inject(this) Log.i("AuthorizationViewModel", "AuthorizationViewModel in constructor")
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
loginStatus.emit(authManager.checkCredentials()) loginStatus.emit(authManager.checkCredentials())
} }
@@ -45,14 +44,12 @@ class AuthorizationViewModel(val application: App): AndroidViewModel(application
} }
} fun resetAuth(){
viewModelScope.launch(Dispatchers.IO) {
class AuthorizationViewModelFactory(private val application: App) : ViewModelProvider.Factory { loginStatus.emit(AuthorizationStatus.LOGOUT)
login.emit("")
override fun <T : ViewModel> create(modelClass: Class<T>): T { password.emit("")
if (modelClass.isAssignableFrom(AuthorizationViewModel::class.java)) }
return AuthorizationViewModel(application) as T
throw IllegalArgumentException("Unknown ViewModel Class")
} }
} }
@@ -1,5 +1,6 @@
package ru.megboyzz.dnevnik.viewmodel package ru.megboyzz.dnevnik.viewmodel
import android.util.Log
import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@@ -16,15 +17,14 @@ import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
import javax.inject.Inject import javax.inject.Inject
class ProfileViewModel(val application: App) : AndroidViewModel(application) { class ProfileViewModel @Inject constructor(
val userContextDao: GlobalUserContextDao
) : ViewModel() {
val profile = MutableStateFlow<UserProfileModel?>(null) val profile = MutableStateFlow<UserProfileModel?>(null)
@Inject
lateinit var userContextDao: GlobalUserContextDao
init{ init{
application.appComponent.inject(this) Log.i("ProfileViewModel", "i am created!")
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val globalUserContext = userContextDao.getGlobalUserContext() val globalUserContext = userContextDao.getGlobalUserContext()
val convertedProfile = convertGlobalUserContextToProfile(globalUserContext) val convertedProfile = convertGlobalUserContextToProfile(globalUserContext)
@@ -56,14 +56,4 @@ class ProfileViewModel(val application: App) : AndroidViewModel(application) {
) )
} }
}
class ProfileViewModelFactory(private val application: App) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ProfileViewModel::class.java))
return ProfileViewModel(application) as T
throw IllegalArgumentException("Unknown ViewModel Class")
}
} }
@@ -5,10 +5,6 @@ import androidx.lifecycle.ViewModelProvider
import ru.megboyzz.dnevnik.App import ru.megboyzz.dnevnik.App
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
class ViewModelFactory(private val application: App): ViewModelProvider.Factory { class ViewModelFactory<T: ViewModel>(private val create: () -> T) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T = create.invoke() as T
if (modelClass.isAssignableFrom(ViewModel::class.java))
return modelClass.getConstructor().newInstance(application)
throw IllegalArgumentException("Unknown ViewModel Class")
}
} }
@@ -1,18 +1,20 @@
package ru.megboyzz.dnevnik.viewmodel.subscreen package ru.megboyzz.dnevnik.viewmodel.subscreen
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.megboyzz.dnevnik.App import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.entities.response.UserContext import ru.megboyzz.dnevnik.entities.response.UserContext
import ru.megboyzz.dnevnik.screens.subscreens.viewmodel.model.MarkModel import ru.megboyzz.dnevnik.screens.subscreens.viewmodel.model.MarkModel
import java.lang.IllegalArgumentException import javax.inject.Inject
class LastMarksViewModel(apiUserContext: UserContext): ViewModel() { class LastMarksViewModel @Inject constructor(
globalUserContextDao: GlobalUserContextDao,
credentialsDao: CredentialsDao
): ViewModel() {
val lastMarksList = MutableStateFlow(listOf<MarkModel>()) val lastMarksList = MutableStateFlow(listOf<MarkModel>())
val isLoading = MutableStateFlow(true) val isLoading = MutableStateFlow(true)
@@ -20,9 +22,11 @@ class LastMarksViewModel(apiUserContext: UserContext): ViewModel() {
init{ init{
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
globalUserContextDao.globalUserContextIsExists()
} }
} }
} }