Implemented auth with login state saved

This commit is contained in:
2025-11-30 19:13:55 +03:00
parent 0bd59b81e3
commit e572d2dd1e
7 changed files with 60 additions and 10 deletions

View File

@@ -48,4 +48,5 @@ dependencies {
implementation("io.ktor:ktor-client-content-negotiation:$ktor") implementation("io.ktor:ktor-client-content-negotiation:$ktor")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor") implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
implementation("androidx.datastore:datastore-preferences:1.2.0")
} }

View File

@@ -1,16 +1,18 @@
package ru.myitschool.work.data.repo package ru.myitschool.work.data.repo
import android.util.Log import kotlinx.coroutines.flow.Flow
import ru.myitschool.work.data.source.LocalDataSource
import ru.myitschool.work.data.source.NetworkDataSource import ru.myitschool.work.data.source.NetworkDataSource
object AuthRepository { object AuthRepository {
suspend fun clearCode() {
LocalDataSource.setCode("")
}
private var codeCache: String? = null val isCodePresentFlow: Flow<Boolean> = LocalDataSource.isCodePresentFlow
suspend fun checkAndSave(text: String): Result<Boolean> { suspend fun checkAndSave(text: String): Result<Boolean> {
return NetworkDataSource.checkAuth(text).onSuccess { success -> return NetworkDataSource.checkAuth(text).onSuccess { success ->
if (success) { if (success) {
codeCache = text LocalDataSource.setCode(text)
} }
} }
} }

View File

@@ -0,0 +1,31 @@
package ru.myitschool.work.data.source
import android.content.Context
import android.util.Log
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import ru.myitschool.work.App
object LocalDataSource {
private val Context.dataStore by preferencesDataStore("user_data")
object Keys {
val CODE = stringPreferencesKey("Username")
}
private val appContext get() = App.context
suspend fun getCode(): String {
return appContext.dataStore.data.map { it[Keys.CODE] ?: "" }.first()
}
suspend fun setCode(code: String) {
appContext.dataStore.edit { it[Keys.CODE] = code }
}
val isCodePresentFlow: Flow<Boolean> = appContext.dataStore.data.map { it[Keys.CODE] != "" }
}

View File

@@ -1,6 +1,7 @@
package ru.myitschool.work.domain.auth package ru.myitschool.work.domain.auth
import ru.myitschool.work.data.repo.AuthRepository import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.App
class CheckAndSaveAuthCodeUseCase( class CheckAndSaveAuthCodeUseCase(
private val repository: AuthRepository private val repository: AuthRepository

View File

@@ -7,19 +7,27 @@ import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking
import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.ui.screen.AppNavHost import ru.myitschool.work.ui.screen.AppNavHost
import ru.myitschool.work.ui.theme.WorkTheme import ru.myitschool.work.ui.theme.WorkTheme
class RootActivity : ComponentActivity() { class RootActivity() : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
actionBar?.hide() actionBar?.hide()
setContent { setContent {
WorkTheme { WorkTheme {
val codePresence by AuthRepository.isCodePresentFlow.collectAsState(false)
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
AppNavHost( AppNavHost(
codePresence = codePresence,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding)

View File

@@ -5,12 +5,16 @@ import androidx.compose.animation.ExitTransition
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
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
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.ui.nav.AuthScreenDestination import ru.myitschool.work.ui.nav.AuthScreenDestination
import ru.myitschool.work.ui.nav.BookScreenDestination import ru.myitschool.work.ui.nav.BookScreenDestination
import ru.myitschool.work.ui.nav.MainScreenDestination import ru.myitschool.work.ui.nav.MainScreenDestination
@@ -19,14 +23,15 @@ import ru.myitschool.work.ui.screen.auth.AuthScreen
@Composable @Composable
fun AppNavHost( fun AppNavHost(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
navController: NavHostController = rememberNavController() navController: NavHostController = rememberNavController(),
codePresence: Boolean
) { ) {
NavHost( NavHost(
modifier = modifier, modifier = modifier,
enterTransition = { EnterTransition.None }, enterTransition = { EnterTransition.None },
exitTransition = { ExitTransition.None }, exitTransition = { ExitTransition.None },
navController = navController, navController = navController,
startDestination = AuthScreenDestination, startDestination = if (codePresence) MainScreenDestination else AuthScreenDestination,
) { ) {
composable<AuthScreenDestination> { composable<AuthScreenDestination> {
AuthScreen(navController = navController) AuthScreen(navController = navController)
@@ -36,6 +41,8 @@ fun AppNavHost(
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Text(text = "MAIN") Text(text = "MAIN")
// LaunchedEffect(Unit) { AuthRepository.clearCode() }
} }
} }
composable<BookScreenDestination> { composable<BookScreenDestination> {

View File

@@ -14,7 +14,7 @@ import kotlinx.coroutines.launch
import ru.myitschool.work.data.repo.AuthRepository import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase
class AuthViewModel : ViewModel() { class AuthViewModel() : ViewModel() {
private val checkAndSaveAuthCodeUseCase by lazy { CheckAndSaveAuthCodeUseCase(AuthRepository) } private val checkAndSaveAuthCodeUseCase by lazy { CheckAndSaveAuthCodeUseCase(AuthRepository) }
private val _uiState = MutableStateFlow<AuthState>(AuthState.Data) private val _uiState = MutableStateFlow<AuthState>(AuthState.Data)
val uiState: StateFlow<AuthState> = _uiState.asStateFlow() val uiState: StateFlow<AuthState> = _uiState.asStateFlow()