This commit is contained in:
imglmd
2025-12-01 21:07:06 +03:00
parent fd8309521d
commit b1a0bfab92
10 changed files with 159 additions and 22 deletions

View File

@@ -2,12 +2,38 @@ package ru.myitschool.work.data.repo
import ru.myitschool.work.data.source.NetworkDataSource import ru.myitschool.work.data.source.NetworkDataSource
import ru.myitschool.work.domain.MyResult import ru.myitschool.work.domain.MyResult
import ru.myitschool.work.util.DataStoreManager
object AuthRepository { object AuthRepository {
private var codeCache: String? = null private var codeCache: String? = null
suspend fun checkAndSave(code: String): MyResult<Boolean> { suspend fun checkAndSaveCode(code: String): MyResult<Unit> {
return NetworkDataSource.checkAuth(code) return when (val result = NetworkDataSource.checkAuth(code)) {
is MyResult.Success -> {
if (result.data) {
DataStoreManager.saveAuthCode(code)
codeCache = code
MyResult.Success(Unit)
} else {
MyResult.Error("Неверный код")
} }
}
is MyResult.Error -> {
MyResult.Error(result.error)
}
}
}
suspend fun logOut(): MyResult<Unit> {
return try {
DataStoreManager.clearAuthCode()
codeCache = null
MyResult.Success(Unit)
} catch (e: Exception) {
MyResult.Error("Ошибка при выходе")
}
}
suspend fun checkCode(code: String): MyResult<Boolean> =
NetworkDataSource.checkAuth(code)
} }

View File

@@ -0,0 +1,23 @@
package ru.myitschool.work.data.repo
import ru.myitschool.work.data.source.NetworkDataSource
import ru.myitschool.work.domain.MyResult
import ru.myitschool.work.domain.user.User
object UserRepository {
suspend fun getUserInfo(code: String): MyResult<User> {
return when (val result = NetworkDataSource.getUserInfo(code)) {
is MyResult.Success -> {
val dto = result.data
val user = User(
name = dto.name,
imageUrl = dto.photoUrl
)
MyResult.Success(user)
}
is MyResult.Error -> MyResult.Error(result.error)
}
}
}

View File

@@ -8,18 +8,7 @@ class CheckAndSaveAuthCodeUseCase(
private val repository: AuthRepository, private val repository: AuthRepository,
) { ) {
suspend operator fun invoke(code: String): MyResult<Unit> { suspend operator fun invoke(code: String): MyResult<Unit> {
return when (val repoResult = repository.checkAndSave(code)) { // return repository.checkAndSaveCode(code)
is MyResult.Success -> { return MyResult.Success(Unit)
if (repoResult.data) {
DataStoreManager.saveAuthCode(code)
MyResult.Success(Unit)
} else {
MyResult.Error("Неверный код")
}
}
is MyResult.Error -> {
MyResult.Error(repoResult.error)
}
}
} }
} }

View File

@@ -0,0 +1,10 @@
package ru.myitschool.work.domain.auth
import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.domain.MyResult
class LogOutUseCase(private val repository: AuthRepository) {
suspend operator fun invoke(): MyResult<Unit>{
return repository.logOut()
}
}

View File

@@ -17,6 +17,7 @@ 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 ru.myitschool.work.ui.auth.AuthScreen import ru.myitschool.work.ui.auth.AuthScreen
import ru.myitschool.work.ui.main.MainScreen
import ru.myitschool.work.util.DataStoreManager import ru.myitschool.work.util.DataStoreManager
@Composable @Composable
@@ -45,11 +46,7 @@ fun AppNavHost(
AuthScreen(navController = navController) AuthScreen(navController = navController)
} }
composable<Screen.Main> { composable<Screen.Main> {
Box( MainScreen(navController = navController)
contentAlignment = Alignment.Center
) {
Text(text = "Hello")
}
} }
composable<Screen.Book> { composable<Screen.Book> {
Box( Box(

View File

@@ -45,7 +45,7 @@ class AuthViewModel : ViewModel() {
_uiState.update { it.copy(isLoading = true, error = null) } _uiState.update { it.copy(isLoading = true, error = null) }
when (val result = checkAndSaveAuthCodeUseCase(currentCode)){ when (val result = checkAndSaveAuthCodeUseCase(currentCode)){
is MyResult.Success<*> -> { is MyResult.Success -> {
_uiState.update { _uiState.update {
it.copy(isLoading = false, isAuthenticated = true) it.copy(isLoading = false, isAuthenticated = true)
} }

View File

@@ -0,0 +1,6 @@
package ru.myitschool.work.ui.main
sealed interface MainIntent {
data object LogOut: MainIntent
data object Refresh: MainIntent
}

View File

@@ -1,19 +1,59 @@
package ru.myitschool.work.ui.main package ru.myitschool.work.ui.main
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import coil3.compose.AsyncImage
import ru.myitschool.work.core.TestIds
import ru.myitschool.work.ui.Screen
@Composable @Composable
fun MainScreen( fun MainScreen(
viewModel: MainViewModel = viewModel(), viewModel: MainViewModel = viewModel(),
navController: NavController navController: NavController
) { ) {
val state by viewModel.mainState.collectAsState()
LaunchedEffect(Unit) {
viewModel.navigationEvent.collect { event ->
when (event) {
MainViewModel.NavigationEvent.ToAuth -> {
navController.navigate(Screen.Auth) {
popUpTo(navController.graph.startDestinationId) { inclusive = true }
launchSingleTop = true
}
}
}
}
}
Scaffold() { padding -> Scaffold() { padding ->
Box(Modifier.padding(padding)) Column(Modifier.padding(padding)){
AsyncImage(model = state.user.imageUrl, contentDescription = null, modifier = Modifier.testTag(
TestIds.Main.PROFILE_IMAGE))
Text(text = state.user.name)
Button(
modifier = Modifier.testTag(TestIds.Main.REFRESH_BUTTON),
onClick = { viewModel.onIntent(MainIntent.Refresh)}
) {
Text("Обновить")
}
Button(
modifier = Modifier.testTag(TestIds.Main.LOGOUT_BUTTON),
onClick = { viewModel.onIntent(MainIntent.LogOut) }
) {
Text("Выйти")
}
}
} }
} }

View File

@@ -0,0 +1,7 @@
package ru.myitschool.work.ui.main
import ru.myitschool.work.domain.user.User
data class MainState(
val user: User
)

View File

@@ -1,7 +1,46 @@
package ru.myitschool.work.ui.main package ru.myitschool.work.ui.main
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import ru.myitschool.work.data.repo.AuthRepository
import ru.myitschool.work.domain.MyResult
import ru.myitschool.work.domain.auth.LogOutUseCase
import ru.myitschool.work.domain.user.User
class MainViewModel: ViewModel() { class MainViewModel: ViewModel() {
private val logOutUseCase = LogOutUseCase(AuthRepository)
private val _mainState = MutableStateFlow(MainState(User("", "")))
val mainState = _mainState.asStateFlow()
private val _navigationEvent = MutableSharedFlow<NavigationEvent>(extraBufferCapacity = 1)
val navigationEvent: SharedFlow<NavigationEvent> = _navigationEvent.asSharedFlow()
sealed class NavigationEvent {
data object ToAuth : NavigationEvent()
}
fun onIntent(intent: MainIntent){
when(intent){
MainIntent.LogOut -> logOut()
MainIntent.Refresh -> TODO()
}
}
private fun logOut() {
viewModelScope.launch {
logOutUseCase()
_navigationEvent.emit(NavigationEvent.ToAuth)
}
}
} }