forked from Olympic/NTO-2025-Android-TeamTask
Compare commits
2 Commits
487d228a9b
...
48f4f9fd6f
| Author | SHA1 | Date | |
|---|---|---|---|
| 48f4f9fd6f | |||
| ca1850b97a |
@@ -36,7 +36,7 @@ android {
|
||||
|
||||
dependencies {
|
||||
defaultComposeLibrary()
|
||||
implementation("androidx.datastore:datastore-preferences:1.1.7")
|
||||
implementation("androidx.datastore:datastore-preferences:1.2.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.4.0")
|
||||
implementation("androidx.navigation:navigation-compose:2.9.6")
|
||||
val coil = "3.3.0"
|
||||
|
||||
@@ -2,11 +2,21 @@ package ru.myitschool.work
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import ru.myitschool.work.data.datastore.DataStoreManager
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "datastore")
|
||||
|
||||
class App: Application() {
|
||||
|
||||
lateinit var dataStoreManager: DataStoreManager
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
context = this
|
||||
dataStoreManager = DataStoreManager(dataStore)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package ru.myitschool.work.data.datastore
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class DataStoreManager(
|
||||
private val dataStore: DataStore<Preferences>
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val USER_CODE_KEY = stringPreferencesKey("user_code")
|
||||
}
|
||||
|
||||
suspend fun saveUserCode(userCode: UserCode) {
|
||||
dataStore.edit { preferences ->
|
||||
preferences[USER_CODE_KEY] = userCode.code
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserCode(): Flow<UserCode> = dataStore.data.map { preferences ->
|
||||
UserCode(
|
||||
code = preferences[USER_CODE_KEY] ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package ru.myitschool.work.data.datastore
|
||||
|
||||
data class UserCode(
|
||||
val code: String
|
||||
)
|
||||
@@ -1,8 +1,6 @@
|
||||
package ru.myitschool.work.ui
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -17,6 +15,10 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -131,13 +133,13 @@ fun BaseText14(
|
||||
fun BaseInputText(
|
||||
placeholder: String= "",
|
||||
modifier: Modifier = Modifier,
|
||||
valueChange: (String) -> Unit,
|
||||
onValueChange: (String) -> Unit,
|
||||
value: String
|
||||
) {
|
||||
|
||||
TextField(
|
||||
value = value,
|
||||
onValueChange = valueChange,
|
||||
onValueChange = onValueChange,
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
placeholder = {
|
||||
BaseText16(
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package ru.myitschool.work.ui.nav
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data object SplashScreenDestination: AppDestination
|
||||
@@ -14,9 +14,10 @@ import androidx.navigation.compose.rememberNavController
|
||||
import ru.myitschool.work.ui.nav.AuthScreenDestination
|
||||
import ru.myitschool.work.ui.nav.BookScreenDestination
|
||||
import ru.myitschool.work.ui.nav.MainScreenDestination
|
||||
import ru.myitschool.work.ui.nav.SplashScreenDestination
|
||||
import ru.myitschool.work.ui.screen.auth.AuthScreen
|
||||
import ru.myitschool.work.ui.screen.book.BookScreen
|
||||
import ru.myitschool.work.ui.screen.main.MainScreen
|
||||
import ru.myitschool.work.ui.screen.splash.SplashScreen
|
||||
|
||||
@Composable
|
||||
fun AppNavHost(
|
||||
@@ -28,21 +29,23 @@ fun AppNavHost(
|
||||
enterTransition = { EnterTransition.None },
|
||||
exitTransition = { ExitTransition.None },
|
||||
navController = navController,
|
||||
startDestination = AuthScreenDestination,
|
||||
startDestination = SplashScreenDestination,
|
||||
) {
|
||||
composable<SplashScreenDestination> {
|
||||
SplashScreen(navController = navController)
|
||||
}
|
||||
composable<AuthScreenDestination> {
|
||||
AuthScreen(
|
||||
navController = navController)
|
||||
AuthScreen(navController = navController)
|
||||
}
|
||||
composable<MainScreenDestination> {
|
||||
MainScreen(
|
||||
navController = navController
|
||||
)
|
||||
MainScreen(navController = navController)
|
||||
}
|
||||
composable<BookScreenDestination> {
|
||||
BookScreen(
|
||||
navController = navController
|
||||
)
|
||||
Box(
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(text = "Hello")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,24 @@
|
||||
package ru.myitschool.work.ui.screen.auth
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import ru.myitschool.work.R
|
||||
@@ -46,15 +36,28 @@ import ru.myitschool.work.ui.theme.White
|
||||
@Composable
|
||||
fun AuthScreen(
|
||||
viewModel: AuthViewModel = viewModel(),
|
||||
navController: NavController
|
||||
navController: NavController,
|
||||
) {
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
viewModel.actionFlow.collect {
|
||||
navController.navigate(MainScreenDestination)
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(400.dp)
|
||||
.fillMaxHeight()
|
||||
.width(200.dp)
|
||||
.padding(20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Logo()
|
||||
|
||||
BaseText24(
|
||||
@@ -62,25 +65,45 @@ fun AuthScreen(
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
when (state) {
|
||||
is AuthState.Data -> Content(viewModel)
|
||||
is AuthState.Loading -> {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.padding(top = 40.dp)
|
||||
.size(64.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(
|
||||
viewModel: AuthViewModel
|
||||
) {
|
||||
|
||||
val isButtonEnabled by viewModel.isButtonEnabled.collectAsState()
|
||||
val errorStateValue by viewModel.errorStateValue.collectAsState()
|
||||
val textState by viewModel.textState.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 20.dp)
|
||||
) {
|
||||
|
||||
val textState by viewModel.textState.collectAsStateWithLifecycle()
|
||||
val errorState by viewModel.errorState.collectAsStateWithLifecycle()
|
||||
|
||||
BaseInputText(
|
||||
value = textState,
|
||||
placeholder = stringResource(R.string.auth_label),
|
||||
modifier = Modifier
|
||||
.testTag(TestIds.Auth.CODE_INPUT)
|
||||
.fillMaxWidth(),
|
||||
valueChange = {viewModel.updateText(it)}
|
||||
onValueChange = { viewModel.onIntent(AuthIntent.TextInput(it)) }
|
||||
)
|
||||
|
||||
if (errorState) {
|
||||
if (errorStateValue != "") {
|
||||
BaseText12(
|
||||
text = "Недействительный код сотрудника",
|
||||
text = errorStateValue,
|
||||
color = Red,
|
||||
modifier = Modifier
|
||||
.testTag(TestIds.Auth.ERROR)
|
||||
@@ -94,11 +117,9 @@ fun AuthScreen(
|
||||
}
|
||||
}
|
||||
|
||||
val isButtonEnabled by viewModel.isButtonEnabled.collectAsStateWithLifecycle()
|
||||
|
||||
BaseButton(
|
||||
text = stringResource(R.string.auth_sign_in),
|
||||
onClick = { navController.navigate(MainScreenDestination)},
|
||||
onClick = { viewModel.onIntent(AuthIntent.Send(textState)) },
|
||||
btnColor = Blue,
|
||||
enable = isButtonEnabled,
|
||||
btnContentColor = White,
|
||||
@@ -107,69 +128,3 @@ fun AuthScreen(
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//@Composable
|
||||
//fun AuthScreen(
|
||||
// viewModel: AuthViewModel = viewModel(),
|
||||
// navController: NavController
|
||||
//) {
|
||||
// val state by viewModel.uiState.collectAsState()
|
||||
//
|
||||
// LaunchedEffect(Unit) {
|
||||
// viewModel.actionFlow.collect {
|
||||
// navController.navigate(MainScreenDestination)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Column(
|
||||
// modifier = Modifier
|
||||
// .fillMaxSize()
|
||||
// .padding(all = 24.dp),
|
||||
// horizontalAlignment = Alignment.CenterHorizontally,
|
||||
// verticalArrangement = Arrangement.Center
|
||||
// ) {
|
||||
// Text(
|
||||
// text = stringResource(R.string.auth_title),
|
||||
// style = MaterialTheme.typography.headlineSmall,
|
||||
// textAlign = TextAlign.Center
|
||||
// )
|
||||
// when (val currentState = state) {
|
||||
// is AuthState.Data -> Content(viewModel, currentState)
|
||||
// is AuthState.Loading -> {
|
||||
// CircularProgressIndicator(
|
||||
// modifier = Modifier.size(64.dp)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@Composable
|
||||
//private fun Content(
|
||||
// viewModel: AuthViewModel,
|
||||
// state: AuthState.Data
|
||||
//) {
|
||||
// var inputText by remember { mutableStateOf("") }
|
||||
// Spacer(modifier = Modifier.size(16.dp))
|
||||
// TextField(
|
||||
// modifier = Modifier.testTag(TestIds.Auth.CODE_INPUT).fillMaxWidth(),
|
||||
// value = inputText,
|
||||
// onValueChange = {
|
||||
// inputText = it
|
||||
// viewModel.onIntent(AuthIntent.TextInput(it))
|
||||
// },
|
||||
// label = { Text(stringResource(R.string.auth_label)) }
|
||||
// )
|
||||
// Spacer(modifier = Modifier.size(16.dp))
|
||||
// Button(
|
||||
// modifier = Modifier.testTag(TestIds.Auth.SIGN_BUTTON).fillMaxWidth(),
|
||||
// onClick = {
|
||||
// viewModel.onIntent(AuthIntent.Send(inputText))
|
||||
// },
|
||||
// enabled = true
|
||||
// ) {
|
||||
// Text(stringResource(R.string.auth_sign_in))
|
||||
// }
|
||||
//}
|
||||
@@ -1,66 +1,62 @@
|
||||
package ru.myitschool.work.ui.screen.auth
|
||||
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.myitschool.work.App
|
||||
import ru.myitschool.work.data.datastore.UserCode
|
||||
import ru.myitschool.work.data.repo.AuthRepository
|
||||
import ru.myitschool.work.domain.auth.CheckAndSaveAuthCodeUseCase
|
||||
|
||||
class AuthViewModel : ViewModel() {
|
||||
// private val checkAndSaveAuthCodeUseCase by lazy { CheckAndSaveAuthCodeUseCase(AuthRepository) }
|
||||
// private val _uiState = MutableStateFlow<AuthState>(AuthState.Data)
|
||||
// val uiState: StateFlow<AuthState> = _uiState.asStateFlow()
|
||||
//
|
||||
// private val _actionFlow: MutableSharedFlow<Unit> = MutableSharedFlow()
|
||||
// val actionFlow: SharedFlow<Unit> = _actionFlow
|
||||
//
|
||||
// fun onIntent(intent: AuthIntent) {
|
||||
// when (intent) {
|
||||
// is AuthIntent.Send -> {
|
||||
// viewModelScope.launch(Dispatchers.Default) {
|
||||
// _uiState.update { AuthState.Loading }
|
||||
// checkAndSaveAuthCodeUseCase.invoke("9999").fold(
|
||||
// onSuccess = {
|
||||
// _actionFlow.emit(Unit)
|
||||
// },
|
||||
// onFailure = { error ->
|
||||
// error.printStackTrace()
|
||||
// _actionFlow.emit(Unit)
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// is AuthIntent.TextInput -> Unit
|
||||
// }
|
||||
// }
|
||||
class AuthViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val dataStoreManager by lazy {
|
||||
(getApplication() as App).dataStoreManager
|
||||
}
|
||||
private val checkAndSaveAuthCodeUseCase by lazy { CheckAndSaveAuthCodeUseCase(AuthRepository) }
|
||||
private val _uiState = MutableStateFlow<AuthState>(AuthState.Data)
|
||||
val uiState: StateFlow<AuthState> = _uiState.asStateFlow()
|
||||
private val _actionFlow: MutableSharedFlow<Unit> = MutableSharedFlow()
|
||||
val actionFlow: SharedFlow<Unit> = _actionFlow
|
||||
private val _errorStateValue = MutableStateFlow("")
|
||||
val errorStateValue: StateFlow<String> = _errorStateValue.asStateFlow()
|
||||
private val _isButtonEnabled = MutableStateFlow(false)
|
||||
val isButtonEnabled: StateFlow<Boolean> = _isButtonEnabled.asStateFlow()
|
||||
private val _textState = MutableStateFlow("")
|
||||
val textState: StateFlow<String> = _textState.asStateFlow()
|
||||
|
||||
private val _errorState = MutableStateFlow(false)
|
||||
val errorState: StateFlow<Boolean> = _errorState.asStateFlow()
|
||||
|
||||
fun updateText(newText: String) {
|
||||
_textState.value = newText
|
||||
_errorState.value = false
|
||||
fun onIntent(intent: AuthIntent) {
|
||||
when (intent) {
|
||||
is AuthIntent.Send -> {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
_uiState.update { AuthState.Loading }
|
||||
checkAndSaveAuthCodeUseCase.invoke(intent.text).fold(
|
||||
onSuccess = {
|
||||
dataStoreManager.saveUserCode(UserCode(code = intent.text))
|
||||
_actionFlow.emit(Unit)
|
||||
},
|
||||
onFailure = { error ->
|
||||
error.printStackTrace()
|
||||
_uiState.update { AuthState.Data }
|
||||
_errorStateValue.value = "Неизвестная ошибка"
|
||||
}
|
||||
|
||||
val isButtonEnabled: StateFlow<Boolean> =
|
||||
_textState.map { it.length == 4 && it.matches(Regex("^[a-zA-Z0-9]*\$"))}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = false
|
||||
)
|
||||
}
|
||||
}
|
||||
is AuthIntent.TextInput -> {
|
||||
_textState.value = intent.text
|
||||
_errorStateValue.value = ""
|
||||
_isButtonEnabled.value = if (intent.text.length == 4 && intent.text.matches(Regex("^[a-zA-Z0-9]*\$")))
|
||||
true else false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,14 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
@@ -23,17 +27,14 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import ru.myitschool.work.R
|
||||
import ru.myitschool.work.core.TestIds.Main
|
||||
import ru.myitschool.work.ui.BaseButton
|
||||
import ru.myitschool.work.ui.BaseNoBackgroundButton
|
||||
import ru.myitschool.work.ui.BaseText14
|
||||
import ru.myitschool.work.ui.BaseText16
|
||||
import ru.myitschool.work.ui.BaseText20
|
||||
import ru.myitschool.work.ui.BaseText24
|
||||
import ru.myitschool.work.ui.ErrorScreen
|
||||
import ru.myitschool.work.ui.nav.BookScreenDestination
|
||||
import ru.myitschool.work.ui.theme.Black
|
||||
import ru.myitschool.work.ui.theme.Blue
|
||||
import ru.myitschool.work.ui.theme.LightGray
|
||||
@@ -42,8 +43,34 @@ import ru.myitschool.work.ui.theme.White
|
||||
|
||||
@Composable
|
||||
fun MainScreen(
|
||||
navController: NavController
|
||||
navController: NavController,
|
||||
viewModel: MainViewModel = viewModel()
|
||||
) {
|
||||
|
||||
val state by viewModel.uiState.collectAsState()
|
||||
|
||||
when(state) {
|
||||
is MainState.Loading -> {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.size(64.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
is MainState.Error -> {
|
||||
|
||||
}
|
||||
is MainState.Data -> {
|
||||
Content(viewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Content(viewModel: MainViewModel) {
|
||||
Column (
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
@@ -52,10 +79,6 @@ fun MainScreen(
|
||||
.width(400.dp)
|
||||
|
||||
) {
|
||||
|
||||
val dateError = false
|
||||
|
||||
if(!dateError) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
@@ -68,13 +91,11 @@ fun MainScreen(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
|
||||
BaseNoBackgroundButton(
|
||||
text = "Обновить",
|
||||
onClick = { },
|
||||
modifier = Modifier.testTag(Main.REFRESH_BUTTON)
|
||||
)
|
||||
|
||||
BaseNoBackgroundButton(
|
||||
text = "Выйти",
|
||||
onClick = { },
|
||||
@@ -129,7 +150,7 @@ fun MainScreen(
|
||||
text = "Бронировать",
|
||||
btnColor = Blue,
|
||||
btnContentColor = White,
|
||||
onClick = { navController.navigate(BookScreenDestination)},
|
||||
onClick = {},
|
||||
modifier = Modifier
|
||||
.testTag(Main.ADD_BUTTON)
|
||||
.padding(horizontal = 10.dp, vertical = 15.dp)
|
||||
@@ -142,10 +163,6 @@ fun MainScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
ErrorScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val bookListData = listOf(
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package ru.myitschool.work.ui.screen.main
|
||||
|
||||
sealed interface MainState {
|
||||
object Data: MainState
|
||||
object Loading: MainState
|
||||
object Error: MainState
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package ru.myitschool.work.ui.screen.main
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
class MainViewModel: ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow<MainState>(MainState.Loading)
|
||||
val uiState: StateFlow<MainState> = _uiState.asStateFlow()
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package ru.myitschool.work.ui.screen.splash
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
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.Alignment
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import ru.myitschool.work.ui.nav.AuthScreenDestination
|
||||
import ru.myitschool.work.ui.nav.MainScreenDestination
|
||||
|
||||
@Composable
|
||||
fun SplashScreen(
|
||||
navController: NavController,
|
||||
viewModel: SplashViewModel = viewModel()
|
||||
) {
|
||||
|
||||
val splashState by viewModel.splashState.collectAsState()
|
||||
|
||||
LaunchedEffect(splashState) {
|
||||
when (splashState) {
|
||||
is SplashState.Authenticated -> {
|
||||
navController.navigate(MainScreenDestination)
|
||||
}
|
||||
is SplashState.UnAuthenticated -> {
|
||||
navController.navigate(AuthScreenDestination)
|
||||
}
|
||||
is SplashState.Error -> {
|
||||
navController.navigate(AuthScreenDestination)
|
||||
}
|
||||
SplashState.Loading -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(64.dp))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package ru.myitschool.work.ui.screen.splash
|
||||
|
||||
import android.os.Message
|
||||
|
||||
sealed interface SplashState {
|
||||
object Loading: SplashState
|
||||
object Authenticated: SplashState
|
||||
object UnAuthenticated: SplashState
|
||||
class Error(message: String): SplashState
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ru.myitschool.work.ui.screen.splash
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.myitschool.work.App
|
||||
|
||||
class SplashViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val dataStoreManager by lazy {
|
||||
(getApplication() as App).dataStoreManager
|
||||
}
|
||||
|
||||
private val _splashState = MutableStateFlow<SplashState>(SplashState.Loading)
|
||||
val splashState: StateFlow<SplashState> = _splashState.asStateFlow()
|
||||
|
||||
init {
|
||||
checkAuthStatus()
|
||||
}
|
||||
|
||||
private fun checkAuthStatus() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val userCode = dataStoreManager.getUserCode().first()
|
||||
|
||||
val isAuthenticated = when {
|
||||
userCode == null -> false
|
||||
userCode.code is String -> (userCode.code as String).isNotEmpty()
|
||||
userCode.code is Int -> (userCode.code as Int) != -1
|
||||
else -> false
|
||||
}
|
||||
|
||||
_splashState.value = if (isAuthenticated) {
|
||||
SplashState.Authenticated
|
||||
} else {
|
||||
SplashState.UnAuthenticated
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_splashState.value = SplashState.Error(e.message ?: "Unknown error")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user