From 42c21b0ce76b7265c148bcfa23ee165d1df0da52 Mon Sep 17 00:00:00 2001 From: dasha Date: Sun, 17 Dec 2023 18:16:41 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=20=D0=B8=20?= =?UTF-8?q?=D1=8D=D0=B4=D0=B8=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/deploymentTargetDropDown.xml | 17 ++++ .../example/myapplication/api/ApiStatus.kt | 3 + .../composeui/AuthenticatorViewModel.kt | 11 ++- .../myapplication/composeui/MyViewModel.kt | 48 ++++++++++ .../myapplication/composeui/NetworkUi.kt | 96 +++++++++++++++++++ .../entities/composeui/CinemaListViewModel.kt | 10 +- .../composeui/edit/CinemaEditViewModel.kt | 35 ++++--- .../composeui/edit/SessionEditViewModel.kt | 49 ++++++---- app/src/main/res/values/strings.xml | 2 + 9 files changed, 228 insertions(+), 43 deletions(-) create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 app/src/main/java/com/example/myapplication/api/ApiStatus.kt create mode 100644 app/src/main/java/com/example/myapplication/composeui/MyViewModel.kt create mode 100644 app/src/main/java/com/example/myapplication/composeui/NetworkUi.kt diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..1dc4564 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/api/ApiStatus.kt b/app/src/main/java/com/example/myapplication/api/ApiStatus.kt new file mode 100644 index 0000000..fadb629 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/api/ApiStatus.kt @@ -0,0 +1,3 @@ +package com.example.myapplication.api + +enum class ApiStatus { LOADING, ERROR, DONE } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/composeui/AuthenticatorViewModel.kt b/app/src/main/java/com/example/myapplication/composeui/AuthenticatorViewModel.kt index 7a0f1b2..c00482c 100644 --- a/app/src/main/java/com/example/myapplication/composeui/AuthenticatorViewModel.kt +++ b/app/src/main/java/com/example/myapplication/composeui/AuthenticatorViewModel.kt @@ -1,13 +1,18 @@ package com.example.myapplication.composeui -import androidx.lifecycle.ViewModel import com.example.myapplication.database.entities.model.User import com.example.myapplication.database.entities.repository.UserRepository class AuthenticatorViewModel( private val userRepository: UserRepository -) : ViewModel() { +) : MyViewModel() { suspend fun findUserByLogin(login: String): User? { - return userRepository.getUser(login) + var user: User? = null + runInScope( + actionSuccess = { + user = userRepository.getUser(login) + } + ) + return user } } \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/composeui/MyViewModel.kt b/app/src/main/java/com/example/myapplication/composeui/MyViewModel.kt new file mode 100644 index 0000000..e259171 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/composeui/MyViewModel.kt @@ -0,0 +1,48 @@ +package com.example.myapplication.composeui + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.myapplication.api.ApiStatus +import kotlinx.coroutines.launch +import retrofit2.HttpException +import java.io.IOException + +open class MyViewModel : ViewModel() { + var apiStatus by mutableStateOf(ApiStatus.DONE) + private set + + var apiError by mutableStateOf("") + private set + + fun runInScope( + actionSuccess: suspend () -> Unit, + actionError: suspend () -> Unit + ) { + viewModelScope.launch { + apiStatus = ApiStatus.LOADING + runCatching { + actionSuccess() + apiStatus = ApiStatus.DONE + apiError = "" + }.onFailure { e: Throwable -> + when (e) { + is IOException, + is HttpException -> { + actionError() + apiStatus = ApiStatus.ERROR + apiError = e.localizedMessage ?: e.toString() + } + + else -> throw e + } + } + } + } + + fun runInScope(actionSuccess: suspend () -> Unit) { + runInScope(actionSuccess, actionError = {}) + } +} diff --git a/app/src/main/java/com/example/myapplication/composeui/NetworkUi.kt b/app/src/main/java/com/example/myapplication/composeui/NetworkUi.kt new file mode 100644 index 0000000..7ceb5e1 --- /dev/null +++ b/app/src/main/java/com/example/myapplication/composeui/NetworkUi.kt @@ -0,0 +1,96 @@ +package com.example.myapplication.composeui + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.TextUnitType +import androidx.compose.ui.unit.dp +import com.example.myapplication.R +import com.example.myapplication.ui.theme.PmudemoTheme + + +@Composable +fun ErrorPlaceholder(message: String, onBack: () -> Unit) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(10.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + fontSize = TextUnit(value = 20F, type = TextUnitType.Sp), + text = message, + color = Color(0xFFFF1744) + ) + Spacer(modifier = Modifier.padding(bottom = 10.dp)) + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { onBack() } + ) { + Text(stringResource(id = R.string.back)) + } + } +} + +@Composable +fun LoadingPlaceholder() { + Column( + modifier = Modifier + .fillMaxSize() + .padding(10.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + fontSize = TextUnit(value = 25F, type = TextUnitType.Sp), + text = stringResource(id = R.string.loading) + ) + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun ErrorPlaceholderPreview() { + PmudemoTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + ErrorPlaceholder("Error", onBack = {}) + } + } +} + +@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun LoadingPlaceholderPreview() { + PmudemoTheme { + Surface( + color = MaterialTheme.colorScheme.background + ) { + LoadingPlaceholder() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/entities/composeui/CinemaListViewModel.kt b/app/src/main/java/com/example/myapplication/database/entities/composeui/CinemaListViewModel.kt index bbebe75..f322fa6 100644 --- a/app/src/main/java/com/example/myapplication/database/entities/composeui/CinemaListViewModel.kt +++ b/app/src/main/java/com/example/myapplication/database/entities/composeui/CinemaListViewModel.kt @@ -3,11 +3,11 @@ package com.example.myapplication.database.entities.composeui import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.PagingData import androidx.paging.cachedIn import com.example.myapplication.LiveStore +import com.example.myapplication.composeui.MyViewModel import com.example.myapplication.database.entities.model.Cinema import com.example.myapplication.database.entities.repository.CinemaRepository import kotlinx.coroutines.flow.Flow @@ -15,14 +15,14 @@ import kotlinx.coroutines.flow.emptyFlow class CinemaListViewModel( private val cinemaRepository: CinemaRepository -) : ViewModel() { - var cinemaPagingFlow by mutableStateOf(ProductPagingFlowState()) +) : MyViewModel() { + var cinemaPagingFlow by mutableStateOf(CinemaPagingFlowState()) private set fun refresh() { val name = "%${LiveStore.searchRequest.value}%" val pagingSource = cinemaRepository.getAllCinemas(name) - cinemaPagingFlow = ProductPagingFlowState(pagingSource.cachedIn(viewModelScope)) + cinemaPagingFlow = CinemaPagingFlowState(pagingSource.cachedIn(viewModelScope)) } suspend fun deleteCinema(cinema: Cinema) { @@ -30,6 +30,6 @@ class CinemaListViewModel( } } -data class ProductPagingFlowState( +data class CinemaPagingFlowState( val flow: Flow> = emptyFlow(), ) \ No newline at end of file diff --git a/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/CinemaEditViewModel.kt b/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/CinemaEditViewModel.kt index e1816f9..e2b173a 100644 --- a/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/CinemaEditViewModel.kt +++ b/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/CinemaEditViewModel.kt @@ -4,29 +4,32 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import com.example.myapplication.composeui.MyViewModel import com.example.myapplication.database.entities.model.Cinema import com.example.myapplication.database.entities.model.CinemaWithSessions import com.example.myapplication.database.entities.model.SessionFromCinema import com.example.myapplication.database.entities.repository.CinemaRepository -import kotlinx.coroutines.launch class CinemaEditViewModel( savedStateHandle: SavedStateHandle, private val cinemaRepository: CinemaRepository -) : ViewModel() { +) : MyViewModel() { var cinemaUiState by mutableStateOf(CinemaUiState()) private set private val cinemaUid: Int = checkNotNull(savedStateHandle["id"]) init { - viewModelScope.launch { - if (cinemaUid > 0) { - cinemaUiState = cinemaRepository.getCinema(cinemaUid) - .toUiState(true) - } + if (cinemaUid > 0) { + runInScope( + actionSuccess = { + cinemaUiState = cinemaRepository.getCinema(cinemaUid) + .toUiState(true) + }, + actionError = { + cinemaUiState = CinemaUiState() + } + ) } } @@ -39,11 +42,15 @@ class CinemaEditViewModel( suspend fun saveCinema() { if (validateInput()) { - if (cinemaUid > 0) { - cinemaRepository.updateCinema(cinemaUiState.cinemaDetails.toCinema(cinemaUid)) - } else { - cinemaRepository.insertCinema(cinemaUiState.cinemaDetails.toCinema()) - } + runInScope( + actionSuccess = { + if (cinemaUid > 0) { + cinemaRepository.updateCinema(cinemaUiState.cinemaDetails.toCinema(cinemaUid)) + } else { + cinemaRepository.insertCinema(cinemaUiState.cinemaDetails.toCinema()) + } + } + ) } } diff --git a/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/SessionEditViewModel.kt b/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/SessionEditViewModel.kt index 12737fe..97a8c6d 100644 --- a/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/SessionEditViewModel.kt +++ b/app/src/main/java/com/example/myapplication/database/entities/composeui/edit/SessionEditViewModel.kt @@ -4,17 +4,15 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.SavedStateHandle -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import com.example.myapplication.composeui.MyViewModel import com.example.myapplication.database.entities.model.Session import com.example.myapplication.database.entities.repository.SessionRepository -import kotlinx.coroutines.launch import org.threeten.bp.LocalDateTime class SessionEditViewModel( savedStateHandle: SavedStateHandle, private val sessionRepository: SessionRepository -) : ViewModel() { +) : MyViewModel() { var sessionUiState by mutableStateOf(SessionUiState()) private set @@ -22,11 +20,16 @@ class SessionEditViewModel( private val cinemaUid: Int = checkNotNull(savedStateHandle["cinemaId"]) init { - viewModelScope.launch { - if (sessionUid > 0) { - sessionUiState = sessionRepository.getSession(sessionUid) - .toUiState(true) - } + if (sessionUid > 0) { + runInScope( + actionSuccess = { + sessionUiState = sessionRepository.getSession(sessionUid) + .toUiState(true) + }, + actionError = { + sessionUiState = SessionUiState() + } + ) } } @@ -39,19 +42,23 @@ class SessionEditViewModel( suspend fun saveSession() { if (validateInput()) { - if (cinemaUid > 0) - if (sessionUid > 0) { - sessionRepository.updateSession( - sessionUiState.sessionDetails - .toSession(uid = sessionUid, cinemaUid = cinemaUid) - ) - } else { - sessionRepository.insertSession( - sessionUiState.sessionDetails.toSession( - cinemaUid = cinemaUid - ) - ) + runInScope( + actionSuccess = { + if (cinemaUid > 0) + if (sessionUid > 0) { + sessionRepository.updateSession( + sessionUiState.sessionDetails + .toSession(uid = sessionUid, cinemaUid = cinemaUid) + ) + } else { + sessionRepository.insertSession( + sessionUiState.sessionDetails.toSession( + cinemaUid = cinemaUid + ) + ) + } } + ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d1f4e96..535f57c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,4 +25,6 @@ Логин занят Неверный логин или пароль Не совпадают пароли + Назад + Загрузка… \ No newline at end of file