добавлен способ инжекта в 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 androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Surface
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModel
import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.navigation.AppNavHost
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 kotlin.concurrent.thread
@@ -27,6 +31,7 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
this.app = application as App
app.appComponent.inject(this)
setContent {
Surface(
@@ -9,6 +9,7 @@ enum class AuthorizationStatus {
MAINTAIN,
CREDENTIALS_LOADING,
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.GlobalUserContextDao
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.ProfileViewModel
import javax.inject.Singleton
@@ -19,13 +20,16 @@ import javax.inject.Singleton
@Component(modules = [AppModule::class])
interface AppComponent {
fun inject(viewModel: AuthorizationViewModel)
val authViewModel: AuthorizationViewModel
val profileViewModel: ProfileViewModel
val credentialsDao: CredentialsDao
val globalUserContextDao: GlobalUserContextDao
fun inject(viewModel: ProfileViewModel)
fun inject(activity: MainActivity)
fun getCredentialsDao(): CredentialsDao
fun getGlobalUserContextDao(): GlobalUserContextDao
@Component.Builder
interface Builder {
fun appModule(appModule: AppModule): Builder // add this
@@ -4,10 +4,13 @@ import android.content.Context
import androidx.room.Room
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.coroutineScope
import ru.megboyzz.dnevnik.db.AppDataBase
import ru.megboyzz.dnevnik.db.dao.CredentialsDao
import ru.megboyzz.dnevnik.db.dao.GlobalUserContextDao
import ru.megboyzz.dnevnik.entities.db.Credentials
import javax.inject.Singleton
import kotlin.coroutines.coroutineContext
@Module
class DatabaseModule {
@@ -27,5 +30,4 @@ class DatabaseModule {
@Provides
fun provideGlobalUserContextDao(dataBase: AppDataBase): GlobalUserContextDao = dataBase.globalUserContextDao()
}
@@ -1,10 +1,10 @@
package ru.megboyzz.dnevnik.navigation
import android.util.Log
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
@@ -14,7 +14,8 @@ import ru.megboyzz.dnevnik.collectAsMutableState
import ru.megboyzz.dnevnik.screens.*
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
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
sealed class BaseNavRote(open val route: String)
@@ -33,14 +34,19 @@ sealed class AppNavRoute(override val route: String): BaseNavRote(route){
@Composable
fun AppNavHost(){
Log.i("AppNavHost", "Called")
val scaffoldState = rememberScaffoldState()
val navController = rememberNavController()
val app = (LocalContext.current as MainActivity).app
val mainActivity = LocalContext.current as MainActivity
val authorizationViewModel: AuthorizationViewModel = viewModel(
factory = AuthorizationViewModelFactory(app)
)
val authorizationViewModel: AuthorizationViewModel by mainActivity.viewModels{
ViewModelFactory{
Log.i("AuthorizationViewModel", "i am created!")
mainActivity.appComponent.authViewModel
}
}
val loginStatus = authorizationViewModel.loginStatus.collectAsMutableState()
@@ -1,8 +1,9 @@
package ru.megboyzz.dnevnik.screens
import android.util.Log
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material.Button
import androidx.compose.material.CircularProgressIndicator
@@ -10,10 +11,8 @@ import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import ru.megboyzz.dnevnik.MainActivity
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.LoginScreenContent
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
//TODO Переверстать экран входа
@Composable
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()
@@ -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)
}
Box(){
LoginScreenContent(
@@ -109,8 +117,8 @@ fun LoginScreen(navController: NavController) {
val scope = rememberCoroutineScope()
var isRemoving by remember{ mutableStateOf(false) }
Button(onClick = {
val globalUserContextDao = context.appComponent.getGlobalUserContextDao()
val credentialsDao = context.appComponent.getCredentialsDao()
val globalUserContextDao = activity.appComponent.globalUserContextDao
val credentialsDao = activity.appComponent.credentialsDao
scope.launch(Dispatchers.IO) {
isRemoving = true
globalUserContextDao.deleteGlobalUserContext()
@@ -1,6 +1,7 @@
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.background
import androidx.compose.foundation.layout.*
@@ -11,20 +12,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.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.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.zIndex
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.ProfileCard
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.white
import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModel
import ru.megboyzz.dnevnik.viewmodel.ProfileViewModelFactory
import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
import ru.megboyzz.dnevnik.viewmodel.core.ViewModelFactory
@Composable
@@ -83,15 +72,27 @@ fun DrawerContent(
scaffoldState: ScaffoldState
) {
val app = (LocalContext.current as MainActivity).app
Log.i("DrawerContent", "Called")
val profileViewModel: ProfileViewModel = viewModel(
factory = ProfileViewModelFactory(app)
)
val activity = LocalContext.current as MainActivity
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 dao = LocalContext.current.appComponent.getCredentialsDao()
val credentialsDao = activity.appComponent.credentialsDao
val globalUserContextDao = activity.appComponent.globalUserContextDao
var leaveAlertIsOpened by remember {
@@ -110,11 +111,12 @@ fun DrawerContent(
onAgree = {
scope.launch(Dispatchers.IO) {
isLeavingProcess = true
dao.deleteCredentials()
credentialsDao.deleteCredentials()
globalUserContextDao.deleteGlobalUserContext()
leaveAlertIsOpened = false
this.launch(Dispatchers.Main) { navController.navigate(AppNavRoute.Login) }
scaffoldState.drawerState.close()
}
authorizationViewModel.resetAuth()
navController.navigate(AppNavRoute.Login)
},
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 javax.inject.Inject
class AuthorizationViewModel(val application: App): AndroidViewModel(application) {
class AuthorizationViewModel @Inject constructor(
private val authManager: AuthorizationManager
): ViewModel() {
val login = MutableStateFlow("")
val password = MutableStateFlow("")
val rememberMe = MutableStateFlow(false)
@Inject
lateinit var authManager: AuthorizationManager
val loginStatus = MutableStateFlow(AuthorizationStatus.CREDENTIALS_LOADING)
init {
application.appComponent.inject(this)
Log.i("AuthorizationViewModel", "AuthorizationViewModel in constructor")
viewModelScope.launch(Dispatchers.IO) {
loginStatus.emit(authManager.checkCredentials())
}
@@ -45,14 +44,12 @@ class AuthorizationViewModel(val application: App): AndroidViewModel(application
}
}
class AuthorizationViewModelFactory(private val application: App) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(AuthorizationViewModel::class.java))
return AuthorizationViewModel(application) as T
throw IllegalArgumentException("Unknown ViewModel Class")
fun resetAuth(){
viewModelScope.launch(Dispatchers.IO) {
loginStatus.emit(AuthorizationStatus.LOGOUT)
login.emit("")
password.emit("")
}
}
}
@@ -1,5 +1,6 @@
package ru.megboyzz.dnevnik.viewmodel
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@@ -16,15 +17,14 @@ import ru.megboyzz.dnevnik.viewmodel.model.UserProfileModel
import java.lang.IllegalArgumentException
import javax.inject.Inject
class ProfileViewModel(val application: App) : AndroidViewModel(application) {
class ProfileViewModel @Inject constructor(
val userContextDao: GlobalUserContextDao
) : ViewModel() {
val profile = MutableStateFlow<UserProfileModel?>(null)
@Inject
lateinit var userContextDao: GlobalUserContextDao
init{
application.appComponent.inject(this)
Log.i("ProfileViewModel", "i am created!")
viewModelScope.launch(Dispatchers.IO) {
val globalUserContext = userContextDao.getGlobalUserContext()
val convertedProfile = convertGlobalUserContextToProfile(globalUserContext)
@@ -57,13 +57,3 @@ 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 java.lang.IllegalArgumentException
class ViewModelFactory(private val application: App): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ViewModel::class.java))
return modelClass.getConstructor().newInstance(application)
throw IllegalArgumentException("Unknown ViewModel Class")
}
class ViewModelFactory<T: ViewModel>(private val create: () -> T) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T = create.invoke() as T
}
@@ -1,18 +1,20 @@
package ru.megboyzz.dnevnik.viewmodel.subscreen
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
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.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 isLoading = MutableStateFlow(true)
@@ -20,9 +22,11 @@ class LastMarksViewModel(apiUserContext: UserContext): ViewModel() {
init{
viewModelScope.launch(Dispatchers.IO) {
globalUserContextDao.globalUserContextIsExists()
}
}
}