From 0ebc9f762b3acb9169ce0af33e8c7af99cf7040e Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 17 Apr 2023 01:24:41 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D0=BD=D0=B5=D0=B4=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B0=D1=83=D0=BD=D1=82=D0=B8=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/ru/megboyzz/dnevnik/App.kt | 4 +- .../java/ru/megboyzz/dnevnik/MainActivity.kt | 50 ++++---- .../main/java/ru/megboyzz/dnevnik/Utils.kt | 32 +++-- .../authorization/AuthorizationManager.kt | 110 ++++++++++++++++++ .../authorization/AuthorizationStatus.kt | 12 ++ .../dnevnik/db/converters/CookiesConverter.kt | 18 +++ .../megboyzz/dnevnik/db/dao/CredentialsDao.kt | 11 +- .../dnevnik/entities/db/Credentials.kt | 9 +- .../megboyzz/dnevnik/navigation/AppNavHost.kt | 38 ++++-- .../repository/AuthorizationRepository.kt | 4 - .../megboyzz/dnevnik/screens/LoginScreen.kt | 73 +++++++++--- .../megboyzz/dnevnik/screens/ui/Components.kt | 46 +++++--- .../dnevnik/screens/ui/LoginScreen.kt | 27 +++-- .../dnevnik/service/AuthorizationStatus.kt | 7 -- .../viewmodel/AuthorizationViewModel.kt | 28 +++-- 15 files changed, 357 insertions(+), 112 deletions(-) create mode 100644 app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationManager.kt create mode 100644 app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationStatus.kt create mode 100644 app/src/main/java/ru/megboyzz/dnevnik/db/converters/CookiesConverter.kt delete mode 100644 app/src/main/java/ru/megboyzz/dnevnik/repository/AuthorizationRepository.kt delete mode 100644 app/src/main/java/ru/megboyzz/dnevnik/service/AuthorizationStatus.kt diff --git a/app/src/main/java/ru/megboyzz/dnevnik/App.kt b/app/src/main/java/ru/megboyzz/dnevnik/App.kt index 323934c..6d05b9d 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/App.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/App.kt @@ -1,12 +1,12 @@ package ru.megboyzz.dnevnik -import android.accounts.Account import android.app.Application import androidx.room.Room import ru.megboyzz.dnevnik.db.CredentialsDataBase class App : Application() { - var database: CredentialsDataBase? = null + + lateinit var database: CredentialsDataBase private set override fun onCreate() { diff --git a/app/src/main/java/ru/megboyzz/dnevnik/MainActivity.kt b/app/src/main/java/ru/megboyzz/dnevnik/MainActivity.kt index 95370f1..3857d49 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/MainActivity.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/MainActivity.kt @@ -1,12 +1,17 @@ package ru.megboyzz.dnevnik +import android.app.Application import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Surface +import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.lifecycle.ReportFragment.Companion.reportFragment +import androidx.lifecycle.viewmodel.compose.viewModel +import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -15,37 +20,19 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import org.jsoup.Jsoup import ru.megboyzz.dnevnik.navigation.AppNavHost import ru.megboyzz.dnevnik.ui.theme.lightGray +import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel +import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModelFactory import java.io.IOException import java.net.URL class MainActivity : ComponentActivity() { + lateinit var app: App + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - val login = "kitsekaterina" - val password = "k12345" - val returnUrl = - "https://login.dnevnik.ru/oauth2?response_type=token&client_id=bb97b3e445a340b9b9cab4b9ea0dbd6f&scope=CommonInfo,ContactInfo,FriendsAndRelatives,EducationalInfo" - - val baseUrl = "https://login.dnevnik.ru/login/" - - GlobalScope.launch(Dispatchers.IO) { - val execute: org.jsoup.Connection.Response = Jsoup - .connect(baseUrl) - .method(org.jsoup.Connection.Method.POST) - .data("ReturnUrl", returnUrl) - .data("login", login) - .data("password", password) - .followRedirects(true).execute() - val url: URL = execute.url() - - val httpUrl = url.toString().toHttpUrlOrNull() - - val queryParameter = httpUrl?.queryParameter("result") - - println("$httpUrl $queryParameter") - } + this.app = application as App setContent { @@ -57,4 +44,19 @@ class MainActivity : ComponentActivity() { } } } + + @OptIn(DelicateCoroutinesApi::class) + override fun onDestroy() { + super.onDestroy() + + GlobalScope.launch(Dispatchers.IO) { + + val credentialsDao = app.database.credentialsDao() + val credentials = credentialsDao.getCredentials() + if(!credentials.rememberMe) + credentialsDao.deleteCredentials() + + } + + } } diff --git a/app/src/main/java/ru/megboyzz/dnevnik/Utils.kt b/app/src/main/java/ru/megboyzz/dnevnik/Utils.kt index 814731c..7dbdc4d 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/Utils.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/Utils.kt @@ -28,10 +28,12 @@ import com.kizitonwose.calendar.compose.CalendarState import com.kizitonwose.calendar.compose.weekcalendar.WeekCalendarLayoutInfo import com.kizitonwose.calendar.compose.weekcalendar.WeekCalendarState import com.kizitonwose.calendar.core.* +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.filterNotNull import ru.megboyzz.dnevnik.navigation.BaseNavRote import ru.megboyzz.dnevnik.ui.theme.dark import java.time.DayOfWeek +import kotlin.coroutines.* @Composable fun Int.AsPainter() = painterResource(this) @@ -201,16 +203,28 @@ fun CalendarDay.week(): Week{ } -fun WeekDay.week(): Week{ - val weekList = mutableListOf() - val dayOrder = this.date.dayOfWeek.ordinal - var mondayLocalDate = this.date.minusDays(dayOrder.toLong()) - DayOfWeek.values().forEach { - weekList.add(WeekDay(mondayLocalDate, WeekDayPosition.RangeDate)) - mondayLocalDate = mondayLocalDate.plusDays(1) - } - return Week(weekList) +private class MutableStateAdapter( + private val state: State, + private val mutate: (T) -> Unit +) : MutableState { + override var value: T + get() = state.value + set(value) { + mutate(value) + } + + override fun component1(): T = value + override fun component2(): (T) -> Unit = { value = it } } +// Flow +@Composable +fun MutableStateFlow.collectAsMutableState( + context: CoroutineContext = EmptyCoroutineContext +): MutableState = MutableStateAdapter( + state = collectAsState(context), + mutate = { value = it } +) + diff --git a/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationManager.kt b/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationManager.kt new file mode 100644 index 0000000..73a6aeb --- /dev/null +++ b/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationManager.kt @@ -0,0 +1,110 @@ +package ru.megboyzz.dnevnik.authorization + +import android.util.Log +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import org.jsoup.Connection +import org.jsoup.Jsoup +import ru.megboyzz.dnevnik.db.dao.CredentialsDao +import ru.megboyzz.dnevnik.entities.db.Credentials +import java.net.URL + + +class AuthorizationManager(private val credentialsDao: CredentialsDao) { + + private val returnUrl = + "https://login.dnevnik.ru/oauth2?response_type=token&client_id=bb97b3e445a340b9b9cab4b9ea0dbd6f&scope=CommonInfo,ContactInfo,FriendsAndRelatives,EducationalInfo" + + private val baseUrl = "https://login.dnevnik.ru/login/" + + private var credentials = Credentials(token = "", cookies = mapOf(), rememberMe = false) + + fun login( + login: String, + password: String, + rememberMe: Boolean + ): AuthorizationStatus { + + val execute = runCatching { + Jsoup + .connect(baseUrl) + .method(Connection.Method.POST) + .data("ReturnUrl", returnUrl) + .data("login", login) + .data("password", password) + .followRedirects(true) + .execute() + }.onFailure { + + Log.i("AuthorizationManager", "No internet") + return AuthorizationStatus.NO_INTERNET + } + + val response = execute.getOrNull() + + if(response != null){ + + if(response.statusCode() != 200) { + Log.i("AuthorizationManager", "Maintain") + return AuthorizationStatus.MAINTAIN + } + + val url = response.url() + + if(url.getResult() != "success") { + Log.i("AuthorizationManager", "Wrong login") + return AuthorizationStatus.WRONG_CREDENTIALS + } + + //Безопасная зона + val cookies = response.cookies() + credentials = Credentials( + token = url.getToken(), + cookies = cookies, + rememberMe = rememberMe + ) + dbUpdate() + + }else return AuthorizationStatus.NO_INTERNET //Может быть опасно + + return AuthorizationStatus.LOGGED + + } + + fun checkCredentials(): AuthorizationStatus{ + + val credentialsIsExists = credentialsDao.credentialsIsExists() + return if(credentialsIsExists) + AuthorizationStatus.LOGGED + else + AuthorizationStatus.NOTHING + + } + + fun dbUpdate(){ + credentialsDao.setCredentials(credentials) + } + + fun deleteCredentials(){ + credentialsDao.deleteCredentials() + } + + fun URL.getResult(): String{ + + val httpUrl = this.toString().toHttpUrlOrNull() ?: return "" + + return httpUrl.queryParameter("result") ?: "" + + } + + fun URL.getToken(): String{ + + val tokenRegex = "access_token=([A-Za-z0-9]+)" + val regex = Regex(tokenRegex) + val find = regex.find(this.toString()) + if(find != null) + return find.groupValues[1] + return "" + + } + +} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationStatus.kt b/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationStatus.kt new file mode 100644 index 0000000..5f4cb7a --- /dev/null +++ b/app/src/main/java/ru/megboyzz/dnevnik/authorization/AuthorizationStatus.kt @@ -0,0 +1,12 @@ +package ru.megboyzz.dnevnik.authorization + +enum class AuthorizationStatus { + + LOGGED, + LOGGING, + WRONG_CREDENTIALS, + NO_INTERNET, + MAINTAIN, + NOTHING + +} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/dnevnik/db/converters/CookiesConverter.kt b/app/src/main/java/ru/megboyzz/dnevnik/db/converters/CookiesConverter.kt new file mode 100644 index 0000000..fe13b30 --- /dev/null +++ b/app/src/main/java/ru/megboyzz/dnevnik/db/converters/CookiesConverter.kt @@ -0,0 +1,18 @@ +package ru.megboyzz.dnevnik.db.converters + +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken + +class CookiesConverter { + + private val gson = Gson() + private val mapType = object : TypeToken>() {}.type + + @TypeConverter + fun fromMap(cookies: Map): String = gson.toJson(cookies) + + @TypeConverter + fun toMap(savedCookies: String): Map = gson.fromJson(savedCookies, mapType) + +} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/dnevnik/db/dao/CredentialsDao.kt b/app/src/main/java/ru/megboyzz/dnevnik/db/dao/CredentialsDao.kt index f1b7f42..dab0cf7 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/db/dao/CredentialsDao.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/db/dao/CredentialsDao.kt @@ -1,17 +1,22 @@ package ru.megboyzz.dnevnik.db.dao import androidx.lifecycle.LiveData +import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy import androidx.room.Query import ru.megboyzz.dnevnik.entities.db.Credentials +@Dao interface CredentialsDao { - @Query("SELECT * FROM Credentials WHERE id = 1") - fun getCredentials(): LiveData - @Query("DELETE FROM Credentials WHERE id = 1") + @Query("SELECT EXISTS(SELECT * FROM Credentials WHERE id = 0)") + fun credentialsIsExists(): Boolean + @Query("SELECT * FROM Credentials WHERE id = 0") + fun getCredentials(): Credentials + + @Query("DELETE FROM Credentials WHERE id = 0") fun deleteCredentials() @Insert(onConflict = OnConflictStrategy.REPLACE) diff --git a/app/src/main/java/ru/megboyzz/dnevnik/entities/db/Credentials.kt b/app/src/main/java/ru/megboyzz/dnevnik/entities/db/Credentials.kt index 166d825..a4863eb 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/entities/db/Credentials.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/entities/db/Credentials.kt @@ -1,9 +1,16 @@ package ru.megboyzz.dnevnik.entities.db import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverters +import ru.megboyzz.dnevnik.db.converters.CookiesConverter @Entity +@TypeConverters(CookiesConverter::class) data class Credentials( + @PrimaryKey + val id: Int = 0, val token: String, - val cookies: Map + val cookies: Map, + val rememberMe: Boolean ) diff --git a/app/src/main/java/ru/megboyzz/dnevnik/navigation/AppNavHost.kt b/app/src/main/java/ru/megboyzz/dnevnik/navigation/AppNavHost.kt index 3519652..bd8f8a5 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/navigation/AppNavHost.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/navigation/AppNavHost.kt @@ -1,20 +1,23 @@ package ru.megboyzz.dnevnik.navigation -import android.window.SplashScreen -import androidx.compose.animation.* -import androidx.compose.animation.core.CubicBezierEasing -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.spring -import androidx.compose.animation.core.tween import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.unit.IntOffset import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import ru.megboyzz.dnevnik.MainActivity +import ru.megboyzz.dnevnik.authorization.AuthorizationStatus +import ru.megboyzz.dnevnik.collectAsMutableState import ru.megboyzz.dnevnik.screens.* +import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModel +import ru.megboyzz.dnevnik.viewmodel.AuthorizationViewModelFactory sealed class BaseNavRote(open val route: String) @@ -29,18 +32,33 @@ sealed class AppNavRoute(override val route: String): BaseNavRote(route){ object Settings: AppNavRoute("settings_screen") } -@OptIn(ExperimentalAnimationApi::class) @Composable fun AppNavHost(){ val scaffoldState = rememberScaffoldState() val navController = rememberNavController() + val app = (LocalContext.current as MainActivity).app + + val authorizationViewModel: AuthorizationViewModel = viewModel( + factory = AuthorizationViewModelFactory(app) + ) + + val loginStatus = authorizationViewModel.loginStatus.collectAsMutableState() + NavHost( navController = navController, - startDestination = AppNavRoute.Login.route /* сделать проверку куки файлов */ + startDestination = AppNavRoute.Splash.route ){ - composable(AppNavRoute.Splash.route) { } + composable(AppNavRoute.Splash.route) { + + if(loginStatus.value != AuthorizationStatus.LOGGED){ + navController.navigate(AppNavRoute.Login.route) + }else + navController.navigate(AppNavRoute.Marks.route) + + + } composable(AppNavRoute.Login.route) { LoginScreen(navController) } composable(AppNavRoute.Marks.route) { MarksScreen(navController, scaffoldState) } composable(AppNavRoute.Schedule.route) { ScheduleScreen(navController, scaffoldState) } diff --git a/app/src/main/java/ru/megboyzz/dnevnik/repository/AuthorizationRepository.kt b/app/src/main/java/ru/megboyzz/dnevnik/repository/AuthorizationRepository.kt deleted file mode 100644 index 9532a34..0000000 --- a/app/src/main/java/ru/megboyzz/dnevnik/repository/AuthorizationRepository.kt +++ /dev/null @@ -1,4 +0,0 @@ -package ru.megboyzz.dnevnik.repository - -class AuthorizationRepository() { -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/dnevnik/screens/LoginScreen.kt b/app/src/main/java/ru/megboyzz/dnevnik/screens/LoginScreen.kt index 295740c..a790382 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/screens/LoginScreen.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/screens/LoginScreen.kt @@ -1,35 +1,70 @@ package ru.megboyzz.dnevnik.screens -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.* +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController +import ru.megboyzz.dnevnik.MainActivity +import ru.megboyzz.dnevnik.authorization.AuthorizationStatus +import ru.megboyzz.dnevnik.collectAsMutableState 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.AuthorizationViewModelFactory //TODO Переверстать экран входа @Composable fun LoginScreen(navController: NavController) { - val login = remember { - mutableStateOf("") - } - val password = remember { - mutableStateOf("") - } - val isError = remember { - mutableStateOf(false) - } - val rememberMe = remember { - mutableStateOf(false) + val app = (LocalContext.current as MainActivity).app + + val authorizationViewModel: AuthorizationViewModel = viewModel( + factory = AuthorizationViewModelFactory(app) + ) + + val login = authorizationViewModel.login.collectAsMutableState() + + val password = authorizationViewModel.password.collectAsMutableState() + + val loginStatus = authorizationViewModel.loginStatus.collectAsMutableState() + + val rememberMe = authorizationViewModel.rememberMe.collectAsMutableState() + + var isError by remember{ + mutableStateOf(true) } + if(loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS && isError) { + AlertMessageBox( + title = "Информация", + alertText = "Неверный логин или пароль", + onClick = { isError =! isError } + ) + } + + if(loginStatus.value == AuthorizationStatus.LOGGED) + navController.navigate(AppNavRoute.Marks.route) + LoginScreenContent( - login = login, - password = password, - isError = isError, - isRememberMe = rememberMe, - onSignIn = { navController.navigate(AppNavRoute.Marks.route) }, + login = login.value, + onLoginChange = { login.value = it }, + + password = password.value, + onPasswordChange = { password.value = it }, + + isError = loginStatus.value == AuthorizationStatus.WRONG_CREDENTIALS, + onErrorChange = { }, + + isLoading = loginStatus.value == AuthorizationStatus.LOGGING, + + isRememberMe = rememberMe.value, + onRememberChange = { rememberMe.value = it }, + + onSignIn = { + if(loginStatus.value != AuthorizationStatus.LOGGED) + authorizationViewModel.login() + }, onSignUp = { /*TODO*/ }, onForgetPassword = { /* TODO */ } ) diff --git a/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/Components.kt b/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/Components.kt index 49c422c..34be277 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/Components.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/Components.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.* -import androidx.compose.ui.window.DialogProperties import ru.megboyzz.dnevnik.* import ru.megboyzz.dnevnik.R import ru.megboyzz.dnevnik.ui.theme.* @@ -102,18 +101,20 @@ fun ProfileCard( @Composable fun MainTextField( - value: MutableState, - isError: MutableState = remember { mutableStateOf(false) }, + value: String, + onChange: (String) -> Unit, + isError: Boolean, + isLoading: Boolean = false, + onErrorChanged: (Boolean) -> Unit, label: String = "", keyboardType: KeyboardType = KeyboardType.Text, - onChange: (it: String) -> Unit = { value.value = it } ) { var passwordVisible by rememberSaveable { mutableStateOf(false) } val focusRequester = FocusRequester() OutlinedTextField( - value = value.value, + value = value, onValueChange = onChange, label = { Text( @@ -126,8 +127,8 @@ fun MainTextField( textStyle = H2, colors = TextFieldDefaults.outlinedTextFieldColors( textColor = dark, - unfocusedBorderColor = if (isError.value) falseColor else mainBlue, - focusedBorderColor = if (isError.value) falseColor else mainBlue, + unfocusedBorderColor = if (isError) falseColor else mainBlue, + focusedBorderColor = if (isError) falseColor else mainBlue, focusedLabelColor = dark, unfocusedLabelColor = dark, cursorColor = dark @@ -152,42 +153,50 @@ fun MainTextField( IconButton(onClick = { passwordVisible = !passwordVisible }) { Icon(imageVector = image, "") } + } else { + if(isLoading) LoginProgress() } }, modifier = Modifier .focusRequester(focusRequester) .onFocusChanged { if (it.isFocused) - if (isError.value) isError.value = false + if (isError) onErrorChanged(false) } .fillMaxWidth(), ) } +@Composable +fun LoginProgress() { + CircularProgressIndicator( + modifier = Modifier.size(20.dp), + strokeWidth = 2.dp, + color = mainBlue + ) +} + @Composable fun MainCheckbox( - isChecked: MutableState, + isChecked: Boolean, modifier: Modifier = Modifier, size: Float = 24f, checkedColor: Color = mainBlue, uncheckedColor: Color = lightGray, checkmarkColor: Color = white, - onValueChange: () -> Unit + onValueChange: (Boolean) -> Unit ) { - val checkboxColor: Color by animateColorAsState(if (isChecked.value) checkedColor else uncheckedColor) + val checkboxColor: Color by animateColorAsState(if (isChecked) checkedColor else uncheckedColor) val density = LocalDensity.current val duration = 200 Row( modifier = modifier .toggleable( - value = isChecked.value, + value = isChecked, role = Role.Checkbox, - onValueChange = { - isChecked.value = !isChecked.value - onValueChange.invoke() - } + onValueChange = onValueChange ) ) { Card( @@ -202,7 +211,7 @@ fun MainCheckbox( contentAlignment = Alignment.Center ) { androidx.compose.animation.AnimatedVisibility( - visible = isChecked.value, + visible = isChecked, enter = slideInHorizontally( animationSpec = tween(duration) ) { @@ -618,7 +627,8 @@ fun AlertMessageBox( contentColor = white ), modifier = Modifier - .defaultMinSize(170.dp).padding(bottom = 30.dp) + .defaultMinSize(170.dp) + .padding(bottom = 30.dp) ) { Text( text = R.string.title_ok.AsString(), diff --git a/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/LoginScreen.kt b/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/LoginScreen.kt index f349e40..7bbff62 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/LoginScreen.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/screens/ui/LoginScreen.kt @@ -22,10 +22,15 @@ import ru.megboyzz.dnevnik.R @Composable fun LoginScreenContent( - login: MutableState, - password: MutableState, - isError: MutableState, - isRememberMe: MutableState, + login: String, + onLoginChange: (String) -> Unit, + password: String, + onPasswordChange: (String) -> Unit, + isLoading: Boolean, + isError: Boolean, + onErrorChange: (Boolean) -> Unit, + isRememberMe: Boolean, + onRememberChange: (Boolean) -> Unit, onSignIn: () -> Unit, onSignUp: () -> Unit, onForgetPassword: () -> Unit @@ -65,14 +70,19 @@ fun LoginScreenContent( MainTextField( value = login, label = R.string.title_login.AsString(), - isError = isError + isError = isError, + isLoading = isLoading, + onErrorChanged = onErrorChange, + onChange = onLoginChange ) SpacerHeight(15.dp) MainTextField( value = password, keyboardType = KeyboardType.Password, label = R.string.title_password.AsString(), - isError = isError + isError = isError, + onErrorChanged = onErrorChange, + onChange = onPasswordChange ) } SpacerHeight(5.dp) @@ -87,7 +97,10 @@ fun LoginScreenContent( modifier = Modifier.fillMaxHeight(), verticalAlignment = Alignment.CenterVertically ) { - MainCheckbox(isRememberMe) { } + MainCheckbox( + isChecked = isRememberMe, + onValueChange = onRememberChange + ) SpacerWidth(5.dp) Text( text = R.string.title_remember_me.AsString(), diff --git a/app/src/main/java/ru/megboyzz/dnevnik/service/AuthorizationStatus.kt b/app/src/main/java/ru/megboyzz/dnevnik/service/AuthorizationStatus.kt deleted file mode 100644 index 6a9a758..0000000 --- a/app/src/main/java/ru/megboyzz/dnevnik/service/AuthorizationStatus.kt +++ /dev/null @@ -1,7 +0,0 @@ -package ru.megboyzz.dnevnik.service - -enum class AuthorizationStatus { - WRONG_CREDENTIALS, - NO_INTERNET, - MAINTAIN -} \ No newline at end of file diff --git a/app/src/main/java/ru/megboyzz/dnevnik/viewmodel/AuthorizationViewModel.kt b/app/src/main/java/ru/megboyzz/dnevnik/viewmodel/AuthorizationViewModel.kt index 2f42a08..885a38f 100644 --- a/app/src/main/java/ru/megboyzz/dnevnik/viewmodel/AuthorizationViewModel.kt +++ b/app/src/main/java/ru/megboyzz/dnevnik/viewmodel/AuthorizationViewModel.kt @@ -1,36 +1,48 @@ package ru.megboyzz.dnevnik.viewmodel -import android.app.Application 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.authorization.AuthorizationManager +import ru.megboyzz.dnevnik.authorization.AuthorizationStatus import java.lang.IllegalArgumentException //Если есть попадание в этот вьюмодел то нам нужна авторизация -class AuthorizationViewModel(application: Application) : AndroidViewModel(application) { +class AuthorizationViewModel(application: App) : AndroidViewModel(application) { val login = MutableStateFlow("") val password = MutableStateFlow("") - val isLogged = MutableStateFlow(false) + val rememberMe = MutableStateFlow(false) + + val loginStatus = MutableStateFlow(AuthorizationStatus.NOTHING) + private val authManager = AuthorizationManager(application.database.credentialsDao()) init { - - - + viewModelScope.launch(Dispatchers.IO) { + loginStatus.emit(authManager.checkCredentials()) + } } - fun login(){ + viewModelScope.launch(Dispatchers.IO) { + loginStatus.emit(AuthorizationStatus.LOGGING) + loginStatus.emit(authManager.login(login.value, password.value, rememberMe.value)) + + } } } -class AuthorizationViewModelFactory(private val application: Application) : ViewModelProvider.Factory { +class AuthorizationViewModelFactory(private val application: App) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { if (modelClass.isAssignableFrom(AuthorizationViewModel::class.java))