exception handling
This commit is contained in:
parent
42c21b0ce7
commit
c0b94141a3
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="deploymentTargetDropDown">
|
|
||||||
<runningDeviceTargetSelectedWithDropDown>
|
|
||||||
<Target>
|
|
||||||
<type value="RUNNING_DEVICE_TARGET" />
|
|
||||||
<deviceKey>
|
|
||||||
<Key>
|
|
||||||
<type value="SERIAL_NUMBER" />
|
|
||||||
<value value="KFRSEQ6DTWWWQOE6" />
|
|
||||||
</Key>
|
|
||||||
</deviceKey>
|
|
||||||
</Target>
|
|
||||||
</runningDeviceTargetSelectedWithDropDown>
|
|
||||||
<timeTargetWasSelectedWithDropDown value="2023-12-17T14:14:18.887820Z" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,5 +1,6 @@
|
|||||||
package com.example.myapplication
|
package com.example.myapplication
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
@ -20,6 +21,7 @@ class MainComposeActivity : ComponentActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
application.deleteDatabase("pmy-db")
|
application.deleteDatabase("pmy-db")
|
||||||
|
appContext = applicationContext
|
||||||
setContent {
|
setContent {
|
||||||
PmudemoTheme(darkTheme = isDarkTheme.value) {
|
PmudemoTheme(darkTheme = isDarkTheme.value) {
|
||||||
LaunchedEffect(key1 = true) {
|
LaunchedEffect(key1 = true) {
|
||||||
@ -40,4 +42,7 @@ class MainComposeActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
companion object {
|
||||||
|
lateinit var appContext: Context
|
||||||
|
}
|
||||||
}
|
}
|
@ -15,21 +15,17 @@ fun Authenticator(
|
|||||||
viewModel: AuthenticatorViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: AuthenticatorViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val login = dataStoreManager.getLogin().collectAsState(initial = "").value
|
val login = dataStoreManager.getLogin().collectAsState(initial = "").value
|
||||||
|
|
||||||
|
LiveStore.user.value = viewModel.authUiState.user
|
||||||
|
|
||||||
fun synchronize() {
|
fun synchronize() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
if (login == "") {
|
if (login == "") {
|
||||||
LiveStore.user.value = null
|
LiveStore.user.value = null
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
val overlap = viewModel.findUserByLogin(login)
|
viewModel.findUserByLogin(login)
|
||||||
if (overlap == null) {
|
|
||||||
dataStoreManager.setLogin("")
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
LiveStore.user.value = overlap
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,27 @@
|
|||||||
package com.example.myapplication.composeui
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import com.example.myapplication.database.entities.model.User
|
import com.example.myapplication.database.entities.model.User
|
||||||
import com.example.myapplication.database.entities.repository.UserRepository
|
import com.example.myapplication.database.entities.repository.UserRepository
|
||||||
|
|
||||||
class AuthenticatorViewModel(
|
class AuthenticatorViewModel(
|
||||||
private val userRepository: UserRepository
|
private val userRepository: UserRepository
|
||||||
) : MyViewModel() {
|
) : MyViewModel() {
|
||||||
suspend fun findUserByLogin(login: String): User? {
|
var authUiState by mutableStateOf(AuthenticatorUiState())
|
||||||
var user: User? = null
|
private set
|
||||||
|
|
||||||
|
suspend fun findUserByLogin(login: String) {
|
||||||
runInScope(
|
runInScope(
|
||||||
actionSuccess = {
|
actionSuccess = {
|
||||||
user = userRepository.getUser(login)
|
authUiState = AuthenticatorUiState(userRepository.getUser(login))
|
||||||
|
},
|
||||||
|
actionError = {
|
||||||
|
authUiState = AuthenticatorUiState()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return user
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class AuthenticatorUiState(val user: User? = null)
|
@ -60,7 +60,6 @@ fun Cart(
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.refreshState()
|
viewModel.refreshState()
|
||||||
}
|
}
|
||||||
|
|
||||||
Cart(
|
Cart(
|
||||||
cartUiState = cartUiState,
|
cartUiState = cartUiState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -3,7 +3,6 @@ package com.example.myapplication.composeui
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.database.entities.model.Order
|
import com.example.myapplication.database.entities.model.Order
|
||||||
import com.example.myapplication.database.entities.model.OrderSessionCrossRef
|
import com.example.myapplication.database.entities.model.OrderSessionCrossRef
|
||||||
@ -21,15 +20,21 @@ class CartViewModel(
|
|||||||
private val orderRepository: OrderRepository,
|
private val orderRepository: OrderRepository,
|
||||||
private val orderSessionRepository: OrderSessionRepository,
|
private val orderSessionRepository: OrderSessionRepository,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
private var isLoading: Boolean = false
|
private var isLoading: Boolean = false
|
||||||
var cartUiState by mutableStateOf(CartUiState())
|
var cartUiState by mutableStateOf(CartUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
suspend fun refreshState() {
|
suspend fun refreshState() {
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: 0
|
val userId: Int = LiveStore.user.value?.uid ?: 0
|
||||||
val cart = userRepository.getCartByUser(userId)
|
runInScope(
|
||||||
cartUiState = CartUiState(cart)
|
actionSuccess = {
|
||||||
|
val cart = userRepository.getCartByUser(userId)
|
||||||
|
cartUiState = CartUiState(cart)
|
||||||
|
}, actionError = {
|
||||||
|
cartUiState = CartUiState()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addToOrder(sessions: List<SessionFromCart>) {
|
suspend fun addToOrder(sessions: List<SessionFromCart>) {
|
||||||
@ -39,38 +44,61 @@ class CartViewModel(
|
|||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
if (sessions.isEmpty())
|
if (sessions.isEmpty())
|
||||||
return
|
return
|
||||||
val orderId = orderRepository.insertOrder(Order(0, userId, LocalDateTime.now()))
|
runInScope(
|
||||||
sessions.forEach { session ->
|
actionSuccess = {
|
||||||
orderSessionRepository.insertOrderSession(
|
val orderId = orderRepository.insertOrder(Order(0, userId, LocalDateTime.now()))
|
||||||
OrderSessionCrossRef(
|
sessions.forEach { session ->
|
||||||
orderId.toInt(),
|
orderSessionRepository.insertOrderSession(
|
||||||
session.uid,
|
OrderSessionCrossRef(
|
||||||
session.price,
|
orderId.toInt(),
|
||||||
session.count
|
session.uid,
|
||||||
)
|
session.price,
|
||||||
)
|
session.count
|
||||||
}
|
)
|
||||||
userSessionRepository.deleteUserSessions(userId)
|
)
|
||||||
refreshState()
|
}
|
||||||
|
userSessionRepository.deleteUserSessions(userId)
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun removeFromCart(session: Session, count: Int = 0) {
|
suspend fun removeFromCart(session: Session, count: Int = 0) {
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
userSessionRepository.deleteUserSession(UserSessionCrossRef(userId, session.uid, count))
|
runInScope(
|
||||||
refreshState()
|
actionSuccess = {
|
||||||
|
userSessionRepository.deleteUserSession(
|
||||||
|
UserSessionCrossRef(
|
||||||
|
userId,
|
||||||
|
session.uid,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
)
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateFromCart(session: Session, count: Int, availableCount: Int): Boolean {
|
suspend fun updateFromCart(session: Session, count: Int, availableCount: Int) {
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return false
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
removeFromCart(session, count)
|
removeFromCart(session, count)
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
if (count > availableCount)
|
if (count > availableCount)
|
||||||
return false
|
return
|
||||||
userSessionRepository.updateUserSession(UserSessionCrossRef(userId, session.uid, count))
|
runInScope(
|
||||||
refreshState()
|
actionSuccess = {
|
||||||
return true
|
userSessionRepository.updateUserSession(
|
||||||
|
UserSessionCrossRef(
|
||||||
|
userId,
|
||||||
|
session.uid,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
)
|
||||||
|
refreshState()
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.myapplication.api.ApiStatus
|
||||||
import com.example.myapplication.api.session.ReportRemote
|
import com.example.myapplication.api.session.ReportRemote
|
||||||
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -39,57 +40,68 @@ fun Report(
|
|||||||
val dateStateStart = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
val dateStateStart = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
||||||
val dateStateEnd = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
val dateStateEnd = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
when (viewModel.apiStatus) {
|
||||||
.verticalScroll(rememberScrollState())
|
ApiStatus.DONE -> {
|
||||||
.fillMaxWidth()
|
Column(
|
||||||
.padding(all = 10.dp),
|
modifier = Modifier
|
||||||
verticalArrangement = Arrangement.Center,
|
.verticalScroll(rememberScrollState())
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
.fillMaxWidth()
|
||||||
)
|
.padding(all = 10.dp),
|
||||||
{
|
verticalArrangement = Arrangement.Center,
|
||||||
Text(
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
text = "Начало периода",
|
|
||||||
style = MaterialTheme.typography.headlineLarge
|
|
||||||
)
|
|
||||||
DatePicker(state = dateStateStart)
|
|
||||||
val selectedDateStart = dateStateStart.selectedDateMillis
|
|
||||||
if (selectedDateStart != null) {
|
|
||||||
viewModel.onUpdate(
|
|
||||||
viewModel.reportUiState.reportDetails.copy(
|
|
||||||
startDate =
|
|
||||||
Date(selectedDateStart)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
} else {
|
{
|
||||||
viewModel.onUpdate(viewModel.reportUiState.reportDetails.copy(startDate = Date(0)))
|
Text(
|
||||||
}
|
text = "Начало периода",
|
||||||
Text(
|
style = MaterialTheme.typography.headlineLarge
|
||||||
text = "Конец периода",
|
|
||||||
style = MaterialTheme.typography.headlineLarge
|
|
||||||
)
|
|
||||||
DatePicker(state = dateStateEnd)
|
|
||||||
val selectedDateEnd = dateStateEnd.selectedDateMillis
|
|
||||||
if (selectedDateEnd != null) {
|
|
||||||
viewModel.onUpdate(
|
|
||||||
viewModel.reportUiState.reportDetails.copy(
|
|
||||||
endDate =
|
|
||||||
Date(selectedDateEnd)
|
|
||||||
)
|
)
|
||||||
)
|
DatePicker(state = dateStateStart)
|
||||||
} else {
|
val selectedDateStart = dateStateStart.selectedDateMillis
|
||||||
viewModel.onUpdate(viewModel.reportUiState.reportDetails.copy(endDate = Date(0)))
|
if (selectedDateStart != null) {
|
||||||
|
viewModel.onUpdate(
|
||||||
|
viewModel.reportUiState.reportDetails.copy(
|
||||||
|
startDate =
|
||||||
|
Date(selectedDateStart)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
viewModel.onUpdate(viewModel.reportUiState.reportDetails.copy(startDate = Date(0)))
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "Конец периода",
|
||||||
|
style = MaterialTheme.typography.headlineLarge
|
||||||
|
)
|
||||||
|
DatePicker(state = dateStateEnd)
|
||||||
|
val selectedDateEnd = dateStateEnd.selectedDateMillis
|
||||||
|
if (selectedDateEnd != null) {
|
||||||
|
viewModel.onUpdate(
|
||||||
|
viewModel.reportUiState.reportDetails.copy(
|
||||||
|
endDate =
|
||||||
|
Date(selectedDateEnd)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
viewModel.onUpdate(viewModel.reportUiState.reportDetails.copy(endDate = Date(0)))
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = { coroutineScope.launch { viewModel.getReport() } },
|
||||||
|
enabled = viewModel.reportUiState.isEntryValid,
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(text = "Получить отчет")
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
CardScreen(reportData = viewModel.reportResultUiState.report)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Button(
|
|
||||||
onClick = { coroutineScope.launch { viewModel.getReport() } },
|
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||||
enabled = viewModel.reportUiState.isEntryValid,
|
else -> ErrorPlaceholder(
|
||||||
shape = MaterialTheme.shapes.small,
|
message = viewModel.apiError,
|
||||||
modifier = Modifier.fillMaxWidth()
|
onBack = { }
|
||||||
) {
|
)
|
||||||
Text(text = "Получить отчет")
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
CardScreen(reportData = viewModel.reportResultUiState.report)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,11 @@ package com.example.myapplication.composeui
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.example.myapplication.api.session.ReportRemote
|
import com.example.myapplication.api.session.ReportRemote
|
||||||
import com.example.myapplication.api.session.RestSessionRepository
|
import com.example.myapplication.api.session.RestSessionRepository
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class ReportViewModel(private val serialRepository: RestSessionRepository) : ViewModel() {
|
class ReportViewModel(private val serialRepository: RestSessionRepository) : MyViewModel() {
|
||||||
var reportUiState by mutableStateOf(ReportUiState())
|
var reportUiState by mutableStateOf(ReportUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -32,11 +31,17 @@ class ReportViewModel(private val serialRepository: RestSessionRepository) : Vie
|
|||||||
|
|
||||||
suspend fun getReport() {
|
suspend fun getReport() {
|
||||||
if (validateInput()) {
|
if (validateInput()) {
|
||||||
val temp = serialRepository.getReport(
|
runInScope(
|
||||||
reportUiState.reportDetails.startDate,
|
actionSuccess = {
|
||||||
reportUiState.reportDetails.endDate
|
val temp = serialRepository.getReport(
|
||||||
|
reportUiState.reportDetails.startDate,
|
||||||
|
reportUiState.reportDetails.endDate
|
||||||
|
)
|
||||||
|
reportResultUiState = ReportResultUiState(temp)
|
||||||
|
}, actionError = {
|
||||||
|
reportResultUiState = ReportResultUiState()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
reportResultUiState = ReportResultUiState(temp)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,22 +93,21 @@ fun Topbar(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
|
||||||
if (currentScreen?.route == Screen.CinemaList.route) {
|
Search(
|
||||||
Search(
|
initValue = LiveStore.searchRequest.value ?: "",
|
||||||
initValue = LiveStore.searchRequest.value ?: "",
|
onDone = {
|
||||||
onDone = {
|
navController.navigate(Screen.CinemaList.route)
|
||||||
LiveStore.searchRequest.value = it
|
LiveStore.searchRequest.value = it
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.height(36.dp)
|
.height(36.dp)
|
||||||
.background(
|
.background(
|
||||||
color = MaterialTheme.colorScheme.onPrimary,
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
RoundedCornerShape(18.dp)
|
RoundedCornerShape(18.dp)
|
||||||
)
|
)
|
||||||
.padding(start = 13.dp, top = 8.dp)
|
.padding(start = 13.dp, top = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +187,7 @@ fun Navhost(
|
|||||||
Screen.OrderView.route,
|
Screen.OrderView.route,
|
||||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
) { backStackEntry ->
|
) { backStackEntry ->
|
||||||
backStackEntry.arguments?.let { OrderView(it.getInt("id")) }
|
backStackEntry.arguments?.let { OrderView(navController) }
|
||||||
}
|
}
|
||||||
composable(Screen.Report.route) { Report() }
|
composable(Screen.Report.route) { Report() }
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@ fun CinemaList(
|
|||||||
LaunchedEffect(searchPattern.value) {
|
LaunchedEffect(searchPattern.value) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {},
|
topBar = {},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
@ -99,6 +98,7 @@ fun CinemaList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CinemaList(
|
private fun CinemaList(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
@ -21,12 +21,16 @@ class CinemaListViewModel(
|
|||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
val name = "%${LiveStore.searchRequest.value}%"
|
val name = "%${LiveStore.searchRequest.value}%"
|
||||||
val pagingSource = cinemaRepository.getAllCinemas(name)
|
runInScope(actionSuccess = {
|
||||||
cinemaPagingFlow = CinemaPagingFlowState(pagingSource.cachedIn(viewModelScope))
|
val pagingSource = cinemaRepository.getAllCinemas(name)
|
||||||
|
cinemaPagingFlow = CinemaPagingFlowState(pagingSource.cachedIn(viewModelScope))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteCinema(cinema: Cinema) {
|
suspend fun deleteCinema(cinema: Cinema) {
|
||||||
cinemaRepository.deleteCinema(cinema)
|
runInScope(actionSuccess = {
|
||||||
|
cinemaRepository.deleteCinema(cinema)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,9 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
|
import com.example.myapplication.api.ApiStatus
|
||||||
|
import com.example.myapplication.composeui.ErrorPlaceholder
|
||||||
|
import com.example.myapplication.composeui.LoadingPlaceholder
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.database.entities.model.Cinema
|
import com.example.myapplication.database.entities.model.Cinema
|
||||||
import com.example.myapplication.database.entities.model.UserRole
|
import com.example.myapplication.database.entities.model.UserRole
|
||||||
@ -42,104 +45,112 @@ fun CinemaView(
|
|||||||
) {
|
) {
|
||||||
val cinemaUiState = viewModel.cinemaUiState
|
val cinemaUiState = viewModel.cinemaUiState
|
||||||
val user = LiveStore.user.observeAsState()
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.refreshState()
|
viewModel.refreshState()
|
||||||
}
|
}
|
||||||
|
when (viewModel.apiStatus) {
|
||||||
Column(
|
ApiStatus.DONE -> {
|
||||||
modifier = Modifier
|
Column(
|
||||||
.padding(16.dp)
|
|
||||||
.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
val cinema: Cinema? = cinemaUiState.cinemaWithSessions?.cinema
|
|
||||||
if (cinema != null) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(
|
.padding(16.dp)
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
.fillMaxSize(),
|
||||||
shape = RoundedCornerShape(16.dp)
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
Column(
|
val cinema: Cinema? = cinemaUiState.cinemaWithSessions?.cinema
|
||||||
modifier = Modifier
|
if (cinema != null) {
|
||||||
.fillMaxWidth()
|
Box(
|
||||||
.padding(16.dp)
|
modifier = Modifier
|
||||||
.background(color = MaterialTheme.colorScheme.secondary),
|
.background(
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
) {
|
shape = RoundedCornerShape(16.dp)
|
||||||
Row(
|
)
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Column(
|
||||||
text = "${cinema.name}, ${cinema.year}",
|
|
||||||
style = TextStyle(
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
color = MaterialTheme.colorScheme.onSecondary
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(bottom = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cinema.image != null)
|
|
||||||
Image(
|
|
||||||
bitmap = BitmapFactory.decodeByteArray(
|
|
||||||
cinema.image,
|
|
||||||
0,
|
|
||||||
cinema.image.size
|
|
||||||
).asImageBitmap(),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(200.dp)
|
.padding(16.dp)
|
||||||
.padding(4.dp)
|
.background(color = MaterialTheme.colorScheme.secondary),
|
||||||
)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${cinema.name}, ${cinema.year}",
|
||||||
|
style = TextStyle(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
if (cinema.image != null)
|
||||||
text = cinema.description,
|
Image(
|
||||||
color = MaterialTheme.colorScheme.onSecondary
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
)
|
cinema.image,
|
||||||
}
|
0,
|
||||||
}
|
cinema.image.size
|
||||||
}
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(200.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
Row(
|
Text(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
text = cinema.description,
|
||||||
) {
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
Text(
|
|
||||||
text = "Сеансы",
|
|
||||||
style = TextStyle(
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f) // Занимает доступное пространство
|
|
||||||
.padding(top = 8.dp, bottom = 8.dp)
|
|
||||||
)
|
|
||||||
if (user.value?.role == UserRole.ADMIN) {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
val route = Screen.SessionEdit.route.replace("{id}", 0.toString())
|
|
||||||
.replace(
|
|
||||||
"{cinemaId}",
|
|
||||||
cinemaUiState.cinemaWithSessions?.cinema?.uid.toString()
|
|
||||||
)
|
)
|
||||||
navController.navigate(route)
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Text(
|
||||||
imageVector = Icons.Filled.Add,
|
text = "Сеансы",
|
||||||
contentDescription = "Добавить сеанс",
|
style = TextStyle(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f) // Занимает доступное пространство
|
||||||
|
.padding(top = 8.dp, bottom = 8.dp)
|
||||||
)
|
)
|
||||||
|
if (user.value?.role == UserRole.ADMIN) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val route = Screen.SessionEdit.route.replace("{id}", 0.toString())
|
||||||
|
.replace(
|
||||||
|
"{cinemaId}",
|
||||||
|
cinemaUiState.cinemaWithSessions?.cinema?.uid.toString()
|
||||||
|
)
|
||||||
|
navController.navigate(route)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Add,
|
||||||
|
contentDescription = "Добавить сеанс",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cinemaUiState.cinemaWithSessions != null) {
|
||||||
|
SessionList(viewModel, navController)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cinemaUiState.cinemaWithSessions != null) {
|
|
||||||
SessionList(viewModel, navController)
|
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||||
}
|
else -> ErrorPlaceholder(
|
||||||
|
message = viewModel.apiError,
|
||||||
|
onBack = { navController.popBackStack() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import com.example.myapplication.composeui.MyViewModel
|
||||||
import com.example.myapplication.database.entities.model.CinemaWithSessions
|
import com.example.myapplication.database.entities.model.CinemaWithSessions
|
||||||
import com.example.myapplication.database.entities.repository.CinemaRepository
|
import com.example.myapplication.database.entities.repository.CinemaRepository
|
||||||
|
|
||||||
class CinemaViewModel(
|
class CinemaViewModel(
|
||||||
savedStateHandle: SavedStateHandle, private val cinemaRepository: CinemaRepository
|
savedStateHandle: SavedStateHandle, private val cinemaRepository: CinemaRepository
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
private val cinemaUid: Int = checkNotNull(savedStateHandle["id"])
|
private val cinemaUid: Int = checkNotNull(savedStateHandle["id"])
|
||||||
|
|
||||||
var cinemaUiState by mutableStateOf(CinemaUiState())
|
var cinemaUiState by mutableStateOf(CinemaUiState())
|
||||||
@ -18,7 +18,11 @@ class CinemaViewModel(
|
|||||||
|
|
||||||
suspend fun refreshState() {
|
suspend fun refreshState() {
|
||||||
if (cinemaUid > 0) {
|
if (cinemaUid > 0) {
|
||||||
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
runInScope(actionSuccess = {
|
||||||
|
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
||||||
|
}, actionError = {
|
||||||
|
cinemaUiState = CinemaUiState()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
|
import com.example.myapplication.composeui.MyViewModel
|
||||||
import com.example.myapplication.database.entities.model.Order
|
import com.example.myapplication.database.entities.model.Order
|
||||||
import com.example.myapplication.database.entities.repository.OrderRepository
|
import com.example.myapplication.database.entities.repository.OrderRepository
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -9,10 +9,12 @@ import kotlinx.coroutines.flow.emptyFlow
|
|||||||
|
|
||||||
class OrderListViewModel(
|
class OrderListViewModel(
|
||||||
private val orderRepository: OrderRepository
|
private val orderRepository: OrderRepository
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
var orderListUiState: Flow<PagingData<Order>> = emptyFlow()
|
var orderListUiState: Flow<PagingData<Order>> = emptyFlow()
|
||||||
|
|
||||||
fun refreshState(userId: Int = 0) {
|
fun refreshState(userId: Int = 0) {
|
||||||
orderListUiState = orderRepository.getAllOrders(userId)
|
runInScope(actionSuccess = {
|
||||||
|
orderListUiState = orderRepository.getAllOrders(userId)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@ -15,100 +14,98 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
import androidx.navigation.NavController
|
||||||
|
import com.example.myapplication.api.ApiStatus
|
||||||
|
import com.example.myapplication.composeui.ErrorPlaceholder
|
||||||
|
import com.example.myapplication.composeui.LoadingPlaceholder
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OrderView(
|
fun OrderView(
|
||||||
id: Int,
|
navController: NavController,
|
||||||
viewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val orderUiState = viewModel.orderUiState
|
||||||
val orderUiState by viewModel.orderUiState.collectAsState()
|
|
||||||
LazyColumn(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(10.dp)
|
|
||||||
) {
|
|
||||||
items(orderUiState.sessionList) { session ->
|
|
||||||
val count = remember { mutableStateOf(session.count) }
|
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
|
||||||
val formattedDate = dateFormatter.format(session.dateTime)
|
|
||||||
|
|
||||||
Text(
|
LaunchedEffect(Unit) {
|
||||||
text = formattedDate,
|
viewModel.refreshState()
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
}
|
||||||
)
|
when (viewModel.apiStatus) {
|
||||||
Box(
|
ApiStatus.DONE -> {
|
||||||
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
.clip(RoundedCornerShape(16.dp))
|
|
||||||
.background(MaterialTheme.colorScheme.secondary)
|
|
||||||
) {
|
) {
|
||||||
Row(
|
items(orderUiState.sessionList) { session ->
|
||||||
modifier = Modifier
|
val count = remember { mutableIntStateOf(session.count) }
|
||||||
.fillMaxWidth()
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
.padding(8.dp),
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
|
||||||
if (session.cinema.image != null)
|
|
||||||
Image(
|
|
||||||
bitmap = BitmapFactory.decodeByteArray(
|
|
||||||
session.cinema.image,
|
|
||||||
0,
|
|
||||||
session.cinema.image.size
|
|
||||||
).asImageBitmap(),
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.size(90.dp)
|
|
||||||
.padding(4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
Text(
|
||||||
|
text = formattedDate,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.fillMaxWidth()
|
||||||
.padding(start = 8.dp),
|
.padding(10.dp)
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(MaterialTheme.colorScheme.secondary)
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
modifier = Modifier
|
||||||
"Цена: ${session.frozenPrice}\n" +
|
.fillMaxWidth()
|
||||||
"Количество: ${count.value}",
|
.padding(8.dp),
|
||||||
color = MaterialTheme.colorScheme.onSecondary
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
)
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
if (session.cinema.image != null)
|
||||||
|
Image(
|
||||||
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
|
session.cinema.image,
|
||||||
|
0,
|
||||||
|
session.cinema.image.size
|
||||||
|
).asImageBitmap(),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(90.dp)
|
||||||
|
.padding(4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(start = 8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
||||||
|
"Цена: ${session.frozenPrice}\n" +
|
||||||
|
"Количество: $count",
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||||
|
else -> ErrorPlaceholder(
|
||||||
|
message = viewModel.apiError,
|
||||||
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
onBack = { navController.popBackStack() }
|
||||||
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
)
|
||||||
@Composable
|
|
||||||
fun OrderViewPreview() {
|
|
||||||
PmudemoTheme {
|
|
||||||
Surface(
|
|
||||||
color = MaterialTheme.colorScheme.background
|
|
||||||
) {
|
|
||||||
OrderView(id = 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,31 +1,29 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
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.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import com.example.myapplication.composeui.MyViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.example.myapplication.database.AppContainer
|
|
||||||
import com.example.myapplication.database.entities.model.SessionFromOrder
|
import com.example.myapplication.database.entities.model.SessionFromOrder
|
||||||
import com.example.myapplication.database.entities.repository.OrderRepository
|
import com.example.myapplication.database.entities.repository.OrderRepository
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.flow
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
|
|
||||||
class OrderViewModel(
|
class OrderViewModel(
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
private val orderRepository: OrderRepository
|
private val orderRepository: OrderRepository
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
private val orderUid: Int = checkNotNull(savedStateHandle["id"])
|
private val orderUid: Int = checkNotNull(savedStateHandle["id"])
|
||||||
|
|
||||||
val orderUiState: StateFlow<OrderUiState> =
|
var orderUiState by mutableStateOf(OrderUiState())
|
||||||
flow { emit(orderRepository.getOrder(orderUid)) }.map {
|
private set
|
||||||
OrderUiState(it)
|
|
||||||
}.stateIn(
|
suspend fun refreshState() {
|
||||||
scope = viewModelScope,
|
runInScope(actionSuccess = {
|
||||||
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppContainer.TIMEOUT),
|
orderUiState = OrderUiState(orderRepository.getOrder(orderUid))
|
||||||
initialValue = OrderUiState()
|
}, actionError = {
|
||||||
)
|
orderUiState = OrderUiState()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class OrderUiState(val sessionList: List<SessionFromOrder> = listOf())
|
data class OrderUiState(val sessionList: List<SessionFromOrder> = listOf())
|
@ -1,7 +1,7 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
|
import com.example.myapplication.composeui.MyViewModel
|
||||||
import com.example.myapplication.database.entities.model.Session
|
import com.example.myapplication.database.entities.model.Session
|
||||||
import com.example.myapplication.database.entities.model.SessionFromCinema
|
import com.example.myapplication.database.entities.model.SessionFromCinema
|
||||||
import com.example.myapplication.database.entities.model.UserSessionCrossRef
|
import com.example.myapplication.database.entities.model.UserSessionCrossRef
|
||||||
@ -11,25 +11,35 @@ import com.example.myapplication.database.entities.repository.UserSessionReposit
|
|||||||
class SessionListViewModel(
|
class SessionListViewModel(
|
||||||
private val sessionRepository: SessionRepository,
|
private val sessionRepository: SessionRepository,
|
||||||
private val userSessionRepository: UserSessionRepository
|
private val userSessionRepository: UserSessionRepository
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
suspend fun deleteSession(session: SessionFromCinema) {
|
suspend fun deleteSession(session: SessionFromCinema) {
|
||||||
sessionRepository.deleteSession(
|
runInScope(actionSuccess = {
|
||||||
Session(
|
sessionRepository.deleteSession(
|
||||||
uid = session.uid,
|
Session(
|
||||||
dateTime = session.dateTime,
|
uid = session.uid,
|
||||||
price = session.price,
|
dateTime = session.dateTime,
|
||||||
maxCount = 0,
|
price = session.price,
|
||||||
cinemaId = 0
|
maxCount = 0,
|
||||||
|
cinemaId = 0
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addSessionInCart(sessionId: Int, count: Int = 1) {
|
suspend fun addSessionInCart(sessionId: Int, count: Int = 1) {
|
||||||
try {
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
runInScope(actionSuccess = {
|
||||||
userSessionRepository.insertUserSession(UserSessionCrossRef(userId, sessionId, count))
|
try {
|
||||||
} catch (_: Exception) {
|
userSessionRepository.insertUserSession(
|
||||||
|
UserSessionCrossRef(
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
count
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,6 +34,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.datastore.DataStoreManager
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -47,11 +48,15 @@ fun UserProfile(
|
|||||||
var isRegistration by remember { mutableStateOf(false) }
|
var isRegistration by remember { mutableStateOf(false) }
|
||||||
val coroutine = rememberCoroutineScope()
|
val coroutine = rememberCoroutineScope()
|
||||||
val errorStringId: Int? = viewModel.userUiState.errorId
|
val errorStringId: Int? = viewModel.userUiState.errorId
|
||||||
val errorMessage = if (errorStringId == null) "" else stringResource(errorStringId)
|
val errorMessage =
|
||||||
|
if (errorStringId == null || errorStringId == 0) "" else stringResource(errorStringId)
|
||||||
val user = LiveStore.user.observeAsState()
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
|
if (errorStringId == 0) {
|
||||||
|
navController.navigate(Screen.CinemaList.route)
|
||||||
|
}
|
||||||
if (user.value != null) {
|
if (user.value != null) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -151,7 +156,7 @@ fun UserProfile(
|
|||||||
|
|
||||||
if (isRegistration) {
|
if (isRegistration) {
|
||||||
Button(
|
Button(
|
||||||
onClick = { coroutine.launch { isRegistration = !viewModel.signUp() } },
|
onClick = { coroutine.launch { viewModel.signUp() } },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
@ -169,13 +174,7 @@ fun UserProfile(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = { coroutine.launch { viewModel.signIn(dataStoreManager) } },
|
||||||
coroutine.launch {
|
|
||||||
if (viewModel.signIn(dataStoreManager)) {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import com.example.myapplication.MainComposeActivity
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.composeui.MyViewModel
|
||||||
import com.example.myapplication.database.entities.model.User
|
import com.example.myapplication.database.entities.model.User
|
||||||
import com.example.myapplication.database.entities.repository.UserRepository
|
import com.example.myapplication.database.entities.repository.UserRepository
|
||||||
import com.example.myapplication.datastore.DataStoreManager
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
|
||||||
class UserProfileViewModel(
|
class UserProfileViewModel(
|
||||||
private val userRepository: UserRepository
|
private val userRepository: UserRepository
|
||||||
) : ViewModel() {
|
) : MyViewModel() {
|
||||||
var userUiState by mutableStateOf(UserUiState())
|
var userUiState by mutableStateOf(UserUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -22,43 +24,62 @@ class UserProfileViewModel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun signIn(dataStoreManager: DataStoreManager): Boolean {
|
suspend fun signIn(dataStoreManager: DataStoreManager) {
|
||||||
userUiState.details.passwordConfirm = userUiState.details.password
|
userUiState.details.passwordConfirm = userUiState.details.password
|
||||||
var errorId: Int? = validateInput(userUiState.details)
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
if (errorId == null) {
|
runInScope(
|
||||||
val overlap = userRepository.getUser(userUiState.details.login)
|
actionSuccess = {
|
||||||
if (overlap == null || userUiState.details.password != overlap.password) {
|
if (errorId == null) {
|
||||||
errorId = R.string.err_04
|
val overlap: User? = userRepository.getUser(userUiState.details.login)
|
||||||
}
|
if (overlap == null || userUiState.details.password != overlap.password) {
|
||||||
}
|
errorId = R.string.err_04
|
||||||
userUiState = UserUiState(
|
} else {
|
||||||
details = userUiState.details,
|
dataStoreManager.setLogin(userUiState.details.login)
|
||||||
errorId = errorId
|
errorId = 0
|
||||||
)
|
}
|
||||||
if (errorId == null) {
|
}
|
||||||
dataStoreManager.setLogin(userUiState.details.login)
|
userUiState = UserUiState(
|
||||||
return true
|
details = userUiState.details,
|
||||||
}
|
errorId = errorId
|
||||||
return false
|
)
|
||||||
|
}, actionError = {
|
||||||
|
errorId = R.string.err_06
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
errorId = errorId
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun signUp(): Boolean {
|
suspend fun signUp() {
|
||||||
var errorId: Int? = validateInput(userUiState.details)
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
if (errorId == null) {
|
runInScope(actionSuccess = {
|
||||||
val overlap = userRepository.getUser(userUiState.details.login)
|
if (errorId == null) {
|
||||||
if (overlap != null) {
|
val overlap = userRepository.getUser(userUiState.details.login)
|
||||||
errorId = R.string.err_03
|
if (overlap != null) {
|
||||||
|
errorId = R.string.err_03
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
userUiState = UserUiState(
|
||||||
userUiState = UserUiState(
|
details = userUiState.details,
|
||||||
details = userUiState.details,
|
errorId = errorId
|
||||||
errorId = errorId
|
)
|
||||||
)
|
if (errorId == null) {
|
||||||
if (errorId == null) {
|
userRepository.insertUser(userUiState.details.toUser())
|
||||||
userRepository.insertUser(userUiState.details.toUser())
|
val toast = Toast.makeText(
|
||||||
return true
|
MainComposeActivity.appContext,
|
||||||
}
|
"Вы зарегистрированы",
|
||||||
return false
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
toast.show()
|
||||||
|
}
|
||||||
|
}, actionError = {
|
||||||
|
errorId = R.string.err_06
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
errorId = errorId
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateInput(details: UserDetails = userUiState.details): Int? {
|
private fun validateInput(details: UserDetails = userUiState.details): Int? {
|
||||||
|
@ -22,6 +22,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.api.ApiStatus
|
||||||
|
import com.example.myapplication.composeui.ErrorPlaceholder
|
||||||
|
import com.example.myapplication.composeui.LoadingPlaceholder
|
||||||
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -32,17 +35,25 @@ fun CinemaEdit(
|
|||||||
viewModel: CinemaEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: CinemaEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
when (viewModel.apiStatus) {
|
||||||
CinemaEdit(
|
ApiStatus.DONE -> {
|
||||||
cinemaUiState = viewModel.cinemaUiState,
|
CinemaEdit(
|
||||||
onClick = {
|
cinemaUiState = viewModel.cinemaUiState,
|
||||||
coroutineScope.launch {
|
onClick = {
|
||||||
viewModel.saveCinema()
|
coroutineScope.launch {
|
||||||
navController.popBackStack()
|
viewModel.saveCinema()
|
||||||
}
|
navController.popBackStack()
|
||||||
},
|
}
|
||||||
onUpdate = viewModel::updateUiState,
|
},
|
||||||
)
|
onUpdate = viewModel::updateUiState,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||||
|
else -> ErrorPlaceholder(
|
||||||
|
message = viewModel.apiError,
|
||||||
|
onBack = { navController.popBackStack() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -24,6 +24,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.api.ApiStatus
|
||||||
|
import com.example.myapplication.composeui.ErrorPlaceholder
|
||||||
|
import com.example.myapplication.composeui.LoadingPlaceholder
|
||||||
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.threeten.bp.Instant
|
import org.threeten.bp.Instant
|
||||||
@ -39,16 +42,26 @@ fun SessionEdit(
|
|||||||
viewModel: SessionEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: SessionEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
SessionEdit(
|
when (viewModel.apiStatus) {
|
||||||
sessionUiState = viewModel.sessionUiState,
|
ApiStatus.DONE -> {
|
||||||
onClick = {
|
SessionEdit(
|
||||||
coroutineScope.launch {
|
sessionUiState = viewModel.sessionUiState,
|
||||||
viewModel.saveSession()
|
onClick = {
|
||||||
navController.popBackStack()
|
coroutineScope.launch {
|
||||||
}
|
viewModel.saveSession()
|
||||||
},
|
navController.popBackStack()
|
||||||
onUpdate = viewModel::updateUiState
|
}
|
||||||
)
|
},
|
||||||
|
onUpdate = viewModel::updateUiState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiStatus.LOADING -> LoadingPlaceholder()
|
||||||
|
else -> ErrorPlaceholder(
|
||||||
|
message = viewModel.apiError,
|
||||||
|
onBack = { navController.popBackStack() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Long.toLocalDate(): org.threeten.bp.LocalDate {
|
fun Long.toLocalDate(): org.threeten.bp.LocalDate {
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<string name="err_03">Логин занят</string>
|
<string name="err_03">Логин занят</string>
|
||||||
<string name="err_04">Неверный логин или пароль</string>
|
<string name="err_04">Неверный логин или пароль</string>
|
||||||
<string name="err_05">Не совпадают пароли</string>
|
<string name="err_05">Не совпадают пароли</string>
|
||||||
|
<string name="err_06">Ошибка сети</string>
|
||||||
<string name="back">Назад</string>
|
<string name="back">Назад</string>
|
||||||
<string name="loading">Загрузка…</string>
|
<string name="loading">Загрузка…</string>
|
||||||
</resources>
|
</resources>
|
74809
server/data.json
74809
server/data.json
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user