Compare commits
No commits in common. "39f2cf609cd1b6aa5948472274fecea0f7637027" and "42c21b0ce76b7265c148bcfa23ee165d1df0da52" have entirely different histories.
39f2cf609c
...
42c21b0ce7
17
.idea/deploymentTargetDropDown.xml
Normal file
17
.idea/deploymentTargetDropDown.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?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,6 +1,5 @@
|
|||||||
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
|
||||||
@ -21,7 +20,6 @@ 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) {
|
||||||
@ -42,7 +40,4 @@ class MainComposeActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
companion object {
|
|
||||||
lateinit var appContext: Context
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -90,11 +90,6 @@ interface MyServerService {
|
|||||||
@Query("userId") userId: Int,
|
@Query("userId") userId: Int,
|
||||||
): List<UserSessionWithSessionRemote>
|
): List<UserSessionWithSessionRemote>
|
||||||
|
|
||||||
@GET("userssessions")
|
|
||||||
suspend fun getUserSessions(
|
|
||||||
@Query("userId") userId: Int,
|
|
||||||
): List<UserSessionRemote>
|
|
||||||
|
|
||||||
@GET("userssessions?_expand=session")
|
@GET("userssessions?_expand=session")
|
||||||
suspend fun getUsersSessions(): List<UserSessionWithSessionRemote>
|
suspend fun getUsersSessions(): List<UserSessionWithSessionRemote>
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class CinemaRemoteMediator(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val cinemas = service.getCinemas(page, state.config.pageSize).map { it.toCinema() }
|
val cinemas = service.getCinemas(page, state.config.pageSize).map { it.toCinema() }
|
||||||
val sessionsFromCinemas = cinemas.flatMap { cinema ->
|
val sessionsFromCinemas = cinemas.map { cinema ->
|
||||||
service.getCinemaWithSessions(cinema.uid).toSessions()
|
service.getCinemaWithSessions(cinema.uid).toSessions()
|
||||||
}
|
}
|
||||||
val endOfPaginationReached = cinemas.isEmpty()
|
val endOfPaginationReached = cinemas.isEmpty()
|
||||||
@ -77,7 +77,13 @@ class CinemaRemoteMediator(
|
|||||||
}
|
}
|
||||||
dbRemoteKeyRepository.createRemoteKeys(keys)
|
dbRemoteKeyRepository.createRemoteKeys(keys)
|
||||||
dbCinemaRepository.insertCinemas(cinemas)
|
dbCinemaRepository.insertCinemas(cinemas)
|
||||||
dbSessionRepository.insertSessions(sessionsFromCinemas)
|
sessionsFromCinemas.forEach {
|
||||||
|
try {
|
||||||
|
dbSessionRepository.insertSessions(it)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
|
return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
|
||||||
} catch (exception: IOException) {
|
} catch (exception: IOException) {
|
||||||
|
@ -48,18 +48,18 @@ class RestCinemaRepository(
|
|||||||
|
|
||||||
override suspend fun getCinema(uid: Int): CinemaWithSessions {
|
override suspend fun getCinema(uid: Int): CinemaWithSessions {
|
||||||
val cinemaWithSessions = service.getCinemaWithSessions(uid)
|
val cinemaWithSessions = service.getCinemaWithSessions(uid)
|
||||||
val orders = service.getOrders()
|
|
||||||
val sessions = cinemaWithSessions.sessions.map { sessionFromCinemaRemote ->
|
val sessions = cinemaWithSessions.sessions.map { sessionFromCinemaRemote ->
|
||||||
SessionFromCinema(
|
SessionFromCinema(
|
||||||
sessionFromCinemaRemote.id,
|
sessionFromCinemaRemote.id,
|
||||||
sessionFromCinemaRemote.dateTime,
|
sessionFromCinemaRemote.dateTime,
|
||||||
sessionFromCinemaRemote.price,
|
sessionFromCinemaRemote.price,
|
||||||
sessionFromCinemaRemote.maxCount - orders.flatMap
|
sessionFromCinemaRemote.maxCount - service.getOrders().flatMap
|
||||||
{ order ->
|
{ order ->
|
||||||
order.sessions.filter { session ->
|
order.sessions.filter { session ->
|
||||||
session.id == sessionFromCinemaRemote.id &&
|
session.id == sessionFromCinemaRemote.id &&
|
||||||
session.cinemaId == sessionFromCinemaRemote.cinemaId &&
|
session.cinemaId == sessionFromCinemaRemote.cinemaId &&
|
||||||
session.dateTime == sessionFromCinemaRemote.dateTime
|
session.cinema.name == cinemaWithSessions.name
|
||||||
}
|
}
|
||||||
}.sumOf { session -> session.count },
|
}.sumOf { session -> session.count },
|
||||||
uid
|
uid
|
||||||
|
@ -53,8 +53,8 @@ class OrderRemoteMediator(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val orders = service.getOrders(
|
val orders = service.getOrders(
|
||||||
userId = LiveStore.user.value?.uid ?: 0,
|
LiveStore.user.value?.uid ?: 0,
|
||||||
page = page, limit = state.config.pageSize
|
page, state.config.pageSize
|
||||||
).map { it.toOrder() }
|
).map { it.toOrder() }
|
||||||
val endOfPaginationReached = orders.isEmpty()
|
val endOfPaginationReached = orders.isEmpty()
|
||||||
database.withTransaction {
|
database.withTransaction {
|
||||||
|
@ -24,8 +24,9 @@ class RestOrderRepository(
|
|||||||
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
private val dbRemoteKeyRepository: OfflineRemoteKeyRepository,
|
||||||
private val database: AppDatabase
|
private val database: AppDatabase
|
||||||
) : OrderRepository {
|
) : OrderRepository {
|
||||||
override fun getAllOrders(): Flow<PagingData<Order>> {
|
override fun getAllOrders(userId: Int): Flow<PagingData<Order>> {
|
||||||
val pagingSourceFactory = { dbOrderRepository.getAllOrdersPagingSource() }
|
val pagingSourceFactory = { dbOrderRepository.getAllOrdersPagingSource(userId) }
|
||||||
|
|
||||||
@OptIn(ExperimentalPagingApi::class)
|
@OptIn(ExperimentalPagingApi::class)
|
||||||
return Pager(
|
return Pager(
|
||||||
config = PagingConfig(
|
config = PagingConfig(
|
||||||
|
@ -11,7 +11,7 @@ class RestOrderSessionRepository(
|
|||||||
private val dbOrderSessionRepository: OfflineOrderSessionRepository
|
private val dbOrderSessionRepository: OfflineOrderSessionRepository
|
||||||
) : OrderSessionRepository {
|
) : OrderSessionRepository {
|
||||||
override suspend fun insertOrderSession(orderSessionCrossRef: OrderSessionCrossRef) {
|
override suspend fun insertOrderSession(orderSessionCrossRef: OrderSessionCrossRef) {
|
||||||
val orderRemote = service.getOrder(orderSessionCrossRef.orderId)
|
var orderRemote = service.getOrder(orderSessionCrossRef.orderId)
|
||||||
val session = service.getSession(orderSessionCrossRef.sessionId)
|
val session = service.getSession(orderSessionCrossRef.sessionId)
|
||||||
|
|
||||||
val sessionFromOrder = SessionFromOrderRemote(
|
val sessionFromOrder = SessionFromOrderRemote(
|
||||||
@ -23,9 +23,10 @@ class RestOrderSessionRepository(
|
|||||||
session.cinema
|
session.cinema
|
||||||
)
|
)
|
||||||
|
|
||||||
orderRemote.sessions = orderRemote.sessions.toMutableList().apply {
|
val updatedSessions = orderRemote.sessions.toMutableList()
|
||||||
add(sessionFromOrder)
|
updatedSessions.add(sessionFromOrder)
|
||||||
}
|
|
||||||
|
orderRemote = orderRemote.copy(sessions = updatedSessions)
|
||||||
service.updateOrder(orderSessionCrossRef.orderId, orderRemote)
|
service.updateOrder(orderSessionCrossRef.orderId, orderRemote)
|
||||||
dbOrderSessionRepository.insertOrderSession(orderSessionCrossRef)
|
dbOrderSessionRepository.insertOrderSession(orderSessionCrossRef)
|
||||||
}
|
}
|
||||||
|
@ -37,27 +37,14 @@ class RestUserRepository(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val orders = service.getOrders()
|
return cart.map {
|
||||||
val sessions = cart.map { sessionFromCartRemote ->
|
val cinema = service.getCinema(it.session.cinemaId)
|
||||||
SessionFromCart(
|
it.toSessionFromCart(
|
||||||
uid = sessionFromCartRemote.sessionId,
|
it.session.maxCount - service.getOrders().flatMap { order ->
|
||||||
dateTime = sessionFromCartRemote.session.dateTime,
|
order.sessions.filter { session -> session.id == it.id }
|
||||||
price = sessionFromCartRemote.session.price,
|
}.sumOf { session -> session.count }, cinema.toCinema()
|
||||||
availableCount = sessionFromCartRemote.session.maxCount - orders
|
|
||||||
.flatMap
|
|
||||||
{ order ->
|
|
||||||
order.sessions.filter { session ->
|
|
||||||
session.id == sessionFromCartRemote.sessionId &&
|
|
||||||
session.cinemaId == sessionFromCartRemote.session.cinemaId &&
|
|
||||||
session.dateTime == sessionFromCartRemote.session.dateTime
|
|
||||||
}
|
|
||||||
}.sumOf { session -> session.count },
|
|
||||||
count = sessionFromCartRemote.count,
|
|
||||||
cinemaId = sessionFromCartRemote.session.cinemaId,
|
|
||||||
cinema = service.getCinema(sessionFromCartRemote.session.cinemaId).toCinema()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return sessions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun insertUser(user: User) {
|
override suspend fun insertUser(user: User) {
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.example.myapplication.api.user
|
package com.example.myapplication.api.user
|
||||||
|
|
||||||
import com.example.myapplication.api.session.SessionRemote
|
import com.example.myapplication.api.session.SessionRemote
|
||||||
|
import com.example.myapplication.database.entities.model.Cinema
|
||||||
|
import com.example.myapplication.database.entities.model.SessionFromCart
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -11,3 +13,16 @@ data class UserSessionWithSessionRemote(
|
|||||||
val count: Int = 0,
|
val count: Int = 0,
|
||||||
val session: SessionRemote,
|
val session: SessionRemote,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun UserSessionWithSessionRemote.toSessionFromCart(
|
||||||
|
availableCount: Int = 0,
|
||||||
|
cinema: Cinema
|
||||||
|
): SessionFromCart = SessionFromCart(
|
||||||
|
sessionId,
|
||||||
|
session.dateTime,
|
||||||
|
session.price,
|
||||||
|
availableCount,
|
||||||
|
count,
|
||||||
|
session.cinemaId,
|
||||||
|
cinema
|
||||||
|
)
|
@ -46,20 +46,16 @@ class RestUserSessionRepository(
|
|||||||
val userSessionRemote = service.getUserSession(
|
val userSessionRemote = service.getUserSession(
|
||||||
userSessionCrossRef.userId,
|
userSessionCrossRef.userId,
|
||||||
userSessionCrossRef.sessionId
|
userSessionCrossRef.sessionId
|
||||||
).firstOrNull() ?: return
|
).first()
|
||||||
service.deleteUserSession(userSessionRemote.id)
|
service.deleteUserSession(userSessionRemote.id)
|
||||||
dbUserSessionRepository.deleteUserSession(userSessionCrossRef)
|
dbUserSessionRepository.deleteUserSession(userSessionCrossRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteUserSessions(userId: Int) {
|
override suspend fun deleteUserSessions(userId: Int) {
|
||||||
val cart = service.getUserSessions(userId)
|
val cart = service.getUserCart(userId)
|
||||||
cart.forEach {
|
cart.forEach {
|
||||||
service.deleteUserSession(it.id)
|
service.deleteUserSession(it.id)
|
||||||
}
|
}
|
||||||
dbUserSessionRepository.deleteUserSessions(userId)
|
dbUserSessionRepository.deleteUserSessions(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteUserSessions(userSessionCrossRefs: List<UserSessionCrossRef>) {
|
|
||||||
userSessionCrossRefs.forEach { deleteUserSession(it) }
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -15,9 +15,8 @@ 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
|
|
||||||
|
|
||||||
LiveStore.user.value = viewModel.authUiState.user
|
val login = dataStoreManager.getLogin().collectAsState(initial = "").value
|
||||||
|
|
||||||
fun synchronize() {
|
fun synchronize() {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@ -25,7 +24,12 @@ fun Authenticator(
|
|||||||
LiveStore.user.value = null
|
LiveStore.user.value = null
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
viewModel.findUserByLogin(login)
|
val overlap = viewModel.findUserByLogin(login)
|
||||||
|
if (overlap == null) {
|
||||||
|
dataStoreManager.setLogin("")
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
LiveStore.user.value = overlap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,27 +1,18 @@
|
|||||||
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() {
|
||||||
var authUiState by mutableStateOf(AuthenticatorUiState())
|
suspend fun findUserByLogin(login: String): User? {
|
||||||
private set
|
var user: User? = null
|
||||||
|
|
||||||
suspend fun findUserByLogin(login: String) {
|
|
||||||
runInScope(
|
runInScope(
|
||||||
actionSuccess = {
|
actionSuccess = {
|
||||||
authUiState = AuthenticatorUiState(userRepository.getUser(login))
|
user = userRepository.getUser(login)
|
||||||
},
|
|
||||||
actionError = {
|
|
||||||
authUiState = AuthenticatorUiState()
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
return user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class AuthenticatorUiState(val user: User? = null)
|
|
@ -1,5 +1,6 @@
|
|||||||
package com.example.myapplication.composeui
|
package com.example.myapplication.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
|
||||||
@ -9,7 +10,6 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
@ -17,12 +17,16 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Delete
|
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.DismissDirection
|
||||||
|
import androidx.compose.material3.DismissState
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
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.material3.rememberDismissState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@ -33,23 +37,21 @@ import androidx.compose.ui.draw.clip
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
|
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 androidx.navigation.NavController
|
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.api.ApiStatus
|
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
|
||||||
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
import com.example.myapplication.database.entities.model.Session
|
import com.example.myapplication.database.entities.model.Session
|
||||||
import com.example.myapplication.database.entities.model.SessionFromCart
|
import com.example.myapplication.database.entities.model.SessionFromCart
|
||||||
import com.example.myapplication.database.entities.model.UserRole
|
import com.example.myapplication.database.entities.model.UserRole
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Cart(
|
fun Cart(
|
||||||
navController: NavController,
|
|
||||||
viewModel: CartViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: CartViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
@ -58,12 +60,24 @@ fun Cart(
|
|||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.refreshState()
|
viewModel.refreshState()
|
||||||
}
|
}
|
||||||
when (viewModel.apiStatus) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
Cart(
|
Cart(
|
||||||
cartUiState = cartUiState,
|
cartUiState = cartUiState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = 10.dp),
|
.padding(all = 10.dp),
|
||||||
|
onSwipe = { session: SessionFromCart ->
|
||||||
|
coroutineScope.launch {
|
||||||
|
viewModel.removeFromCart(
|
||||||
|
session = Session(
|
||||||
|
uid = session.uid,
|
||||||
|
dateTime = session.dateTime,
|
||||||
|
price = session.price,
|
||||||
|
maxCount = 0,
|
||||||
|
cinemaId = session.cinemaId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
onChangeCount = { session: SessionFromCart, count: Int ->
|
onChangeCount = { session: SessionFromCart, count: Int ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
viewModel.updateFromCart(
|
viewModel.updateFromCart(
|
||||||
@ -81,43 +95,30 @@ fun Cart(
|
|||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
viewModel.addToOrder(sessions = sessions)
|
viewModel.addToOrder(sessions = sessions)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
onDelete = { session: SessionFromCart ->
|
|
||||||
coroutineScope.launch {
|
|
||||||
viewModel.removeFromCart(
|
|
||||||
session = Session(
|
|
||||||
uid = session.uid,
|
|
||||||
dateTime = session.dateTime,
|
|
||||||
price = session.price,
|
|
||||||
maxCount = 0,
|
|
||||||
cinemaId = session.cinemaId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiStatus.LOADING -> LoadingPlaceholder()
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
else -> ErrorPlaceholder(
|
|
||||||
message = viewModel.apiError,
|
|
||||||
onBack = { navController.navigate(Screen.Report.route) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Cart(
|
private fun Cart(
|
||||||
cartUiState: CartUiState,
|
cartUiState: CartUiState,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
|
onSwipe: (SessionFromCart) -> Unit,
|
||||||
onChangeCount: (SessionFromCart, Int) -> Unit,
|
onChangeCount: (SessionFromCart, Int) -> Unit,
|
||||||
onAddToOrder: (List<SessionFromCart>) -> Unit,
|
onAddToOrder: (List<SessionFromCart>) -> Unit
|
||||||
onDelete: (SessionFromCart) -> Unit
|
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
items(cartUiState.sessionList, key = { it.uid.toString() }) { session ->
|
items(cartUiState.sessionList, key = { it.uid.toString() }) { session ->
|
||||||
|
val dismissState: DismissState = rememberDismissState(
|
||||||
|
positionalThreshold = { 200.dp.toPx() }
|
||||||
|
)
|
||||||
|
|
||||||
|
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
|
||||||
|
onSwipe(session)
|
||||||
|
}
|
||||||
SessionListItem(
|
SessionListItem(
|
||||||
session = session,
|
session = session,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -125,13 +126,9 @@ private fun Cart(
|
|||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
.clip(RoundedCornerShape(16.dp))
|
.clip(RoundedCornerShape(16.dp))
|
||||||
.background(MaterialTheme.colorScheme.secondary),
|
.background(MaterialTheme.colorScheme.secondary),
|
||||||
onChangeCount = onChangeCount,
|
onChangeCount = onChangeCount
|
||||||
onDelete = onDelete,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val user = LiveStore.user.observeAsState()
|
val user = LiveStore.user.observeAsState()
|
||||||
if (user.value?.role == UserRole.USER) {
|
if (user.value?.role == UserRole.USER) {
|
||||||
@ -141,7 +138,7 @@ private fun Cart(
|
|||||||
Button(
|
Button(
|
||||||
onClick = { onAddToOrder(cartUiState.sessionList) },
|
onClick = { onAddToOrder(cartUiState.sessionList) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(6.dp)
|
.padding(16.dp)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
) { Text("Купить") }
|
) { Text("Купить") }
|
||||||
}
|
}
|
||||||
@ -153,26 +150,27 @@ private fun SessionListItem(
|
|||||||
session: SessionFromCart,
|
session: SessionFromCart,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onChangeCount: (SessionFromCart, Int) -> Unit,
|
onChangeCount: (SessionFromCart, Int) -> Unit,
|
||||||
onDelete: (SessionFromCart) -> Unit
|
|
||||||
) {
|
) {
|
||||||
|
//var currentCount by remember { mutableIntStateOf(session.count) }
|
||||||
|
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
val formattedDate = dateFormatter.format(session.dateTime)
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = formattedDate,
|
text = formattedDate,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
)
|
)
|
||||||
Column(modifier = modifier.fillMaxWidth()) {
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
if (session.cinema.image != null) {
|
if (session.cinema.image != null)
|
||||||
Image(
|
Image(
|
||||||
bitmap = BitmapFactory.decodeByteArray(
|
bitmap = BitmapFactory.decodeByteArray(
|
||||||
session.cinema.image,
|
session.cinema.image,
|
||||||
@ -184,7 +182,6 @@ private fun SessionListItem(
|
|||||||
.size(90.dp)
|
.size(90.dp)
|
||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
@ -193,51 +190,38 @@ private fun SessionListItem(
|
|||||||
Text(
|
Text(
|
||||||
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
||||||
"Цена: ${session.price}\n" +
|
"Цена: ${session.price}\n" +
|
||||||
if (session.availableCount == 0) "Недоступно" else "${session.count}/${session.availableCount}",
|
"${session.count}/${session.availableCount}",
|
||||||
color = MaterialTheme.colorScheme.onSecondary
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = MaterialTheme.colorScheme.primary)
|
.background(
|
||||||
.fillMaxWidth(),
|
color = MaterialTheme.colorScheme.background,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
shape = RoundedCornerShape(10.dp)
|
||||||
|
) // Задаем фон для кнопок
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { onDelete(session) }
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Delete,
|
|
||||||
contentDescription = "Удалить",
|
|
||||||
tint = MaterialTheme.colorScheme.onPrimary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1F))
|
|
||||||
|
|
||||||
if (session.availableCount != 0) {
|
|
||||||
IconButton(
|
|
||||||
enabled = session.count != 1,
|
|
||||||
onClick = { onChangeCount(session, session.count - 1) }
|
onClick = { onChangeCount(session, session.count - 1) }
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.minus),
|
imageVector = ImageVector.vectorResource(id = R.drawable.minus),
|
||||||
contentDescription = "Уменьшить",
|
contentDescription = "Уменьшить",
|
||||||
tint = MaterialTheme.colorScheme.onPrimary
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.size(10.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "${session.count}",
|
text = "${session.count}",
|
||||||
color = MaterialTheme.colorScheme.onPrimary
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
)
|
)
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
enabled = session.count != session.availableCount,
|
|
||||||
onClick = {
|
onClick = {
|
||||||
onChangeCount(
|
onChangeCount(
|
||||||
session,
|
session,
|
||||||
@ -248,11 +232,26 @@ private fun SessionListItem(
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Add,
|
imageVector = Icons.Default.Add,
|
||||||
contentDescription = "Увеличить",
|
contentDescription = "Увеличить",
|
||||||
tint = MaterialTheme.colorScheme.onPrimary
|
tint = MaterialTheme.colorScheme.onBackground,
|
||||||
|
modifier = Modifier.size(10.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
@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 CartPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
Cart()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ 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.room.Transaction
|
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,37 +21,26 @@ 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,
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
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(needLoadingScreen: Boolean = true) {
|
suspend fun refreshState() {
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
val userId: Int = LiveStore.user.value?.uid ?: 0
|
||||||
runInScope(
|
val cart = userRepository.getCartByUser(userId)
|
||||||
actionSuccess = {
|
cartUiState = CartUiState(cart)
|
||||||
cartUiState = CartUiState(userRepository.getCartByUser(userId))
|
|
||||||
}, actionError = {
|
|
||||||
cartUiState = CartUiState()
|
|
||||||
},
|
|
||||||
needLoadingScreen = needLoadingScreen
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transaction
|
|
||||||
suspend fun addToOrder(sessions: List<SessionFromCart>) {
|
suspend fun addToOrder(sessions: List<SessionFromCart>) {
|
||||||
if (isLoading)
|
if (isLoading)
|
||||||
return
|
return
|
||||||
isLoading = true
|
isLoading = true
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
val cart = sessions.filter { it.availableCount != 0 }
|
if (sessions.isEmpty())
|
||||||
if (cart.isEmpty())
|
|
||||||
return
|
return
|
||||||
runInScope(
|
|
||||||
actionSuccess = {
|
|
||||||
val orderId = orderRepository.insertOrder(Order(0, userId, LocalDateTime.now()))
|
val orderId = orderRepository.insertOrder(Order(0, userId, LocalDateTime.now()))
|
||||||
cart.forEach { session ->
|
sessions.forEach { session ->
|
||||||
if (session.availableCount != 0) {
|
|
||||||
orderSessionRepository.insertOrderSession(
|
orderSessionRepository.insertOrderSession(
|
||||||
OrderSessionCrossRef(
|
OrderSessionCrossRef(
|
||||||
orderId.toInt(),
|
orderId.toInt(),
|
||||||
@ -61,53 +50,27 @@ class CartViewModel(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
userSessionRepository.deleteUserSessions(userId)
|
||||||
userSessionRepository.deleteUserSessions(cart.map {
|
|
||||||
UserSessionCrossRef(userId, it.uid, it.count)
|
|
||||||
})
|
|
||||||
refreshState()
|
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
|
||||||
runInScope(
|
userSessionRepository.deleteUserSession(UserSessionCrossRef(userId, session.uid, count))
|
||||||
actionSuccess = {
|
|
||||||
userSessionRepository.deleteUserSession(
|
|
||||||
UserSessionCrossRef(
|
|
||||||
userId,
|
|
||||||
session.uid,
|
|
||||||
count
|
|
||||||
)
|
|
||||||
)
|
|
||||||
refreshState()
|
refreshState()
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun updateFromCart(session: Session, count: Int, availableCount: Int) {
|
suspend fun updateFromCart(session: Session, count: Int, availableCount: Int): Boolean {
|
||||||
val userId: Int = LiveStore.user.value?.uid ?: return
|
val userId: Int = LiveStore.user.value?.uid ?: return false
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
removeFromCart(session, count)
|
removeFromCart(session, count)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
if (count > availableCount)
|
if (count > availableCount)
|
||||||
return
|
return false
|
||||||
runInScope(
|
userSessionRepository.updateUserSession(UserSessionCrossRef(userId, session.uid, count))
|
||||||
actionSuccess = {
|
|
||||||
userSessionRepository.updateUserSession(
|
|
||||||
UserSessionCrossRef(
|
|
||||||
userId,
|
|
||||||
session.uid,
|
|
||||||
count
|
|
||||||
)
|
|
||||||
)
|
|
||||||
refreshState()
|
refreshState()
|
||||||
},
|
return true
|
||||||
actionError = { },
|
|
||||||
needLoadingScreen = false
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,11 +19,9 @@ open class MyViewModel : ViewModel() {
|
|||||||
|
|
||||||
fun runInScope(
|
fun runInScope(
|
||||||
actionSuccess: suspend () -> Unit,
|
actionSuccess: suspend () -> Unit,
|
||||||
actionError: suspend () -> Unit,
|
actionError: suspend () -> Unit
|
||||||
needLoadingScreen: Boolean = true,
|
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
if (needLoadingScreen)
|
|
||||||
apiStatus = ApiStatus.LOADING
|
apiStatus = ApiStatus.LOADING
|
||||||
runCatching {
|
runCatching {
|
||||||
actionSuccess()
|
actionSuccess()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.example.myapplication.composeui
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@ -7,6 +8,8 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
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.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@ -14,10 +17,12 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
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.TextUnit
|
||||||
import androidx.compose.ui.unit.TextUnitType
|
import androidx.compose.ui.unit.TextUnitType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -63,3 +68,29 @@ fun LoadingPlaceholder() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,10 +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 androidx.navigation.NavController
|
|
||||||
import com.example.myapplication.api.ApiStatus
|
|
||||||
import com.example.myapplication.api.session.ReportRemote
|
import com.example.myapplication.api.session.ReportRemote
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
|
||||||
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.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
@ -37,15 +34,11 @@ import java.util.Date
|
|||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Report(
|
fun Report(
|
||||||
navController: NavController,
|
|
||||||
viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: ReportViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
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()
|
||||||
|
|
||||||
when (viewModel.apiStatus) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
@ -90,6 +83,7 @@ fun Report(
|
|||||||
Button(
|
Button(
|
||||||
onClick = { coroutineScope.launch { viewModel.getReport() } },
|
onClick = { coroutineScope.launch { viewModel.getReport() } },
|
||||||
enabled = viewModel.reportUiState.isEntryValid,
|
enabled = viewModel.reportUiState.isEntryValid,
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(text = "Получить отчет")
|
Text(text = "Получить отчет")
|
||||||
@ -99,14 +93,6 @@ fun Report(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiStatus.LOADING -> LoadingPlaceholder()
|
|
||||||
else -> ErrorPlaceholder(
|
|
||||||
message = viewModel.apiError,
|
|
||||||
onBack = { navController.navigate(Screen.Report.route) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CardScreen(reportData: List<ReportRemote>) {
|
fun CardScreen(reportData: List<ReportRemote>) {
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
|
@ -3,11 +3,12 @@ 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) : MyViewModel() {
|
class ReportViewModel(private val serialRepository: RestSessionRepository) : ViewModel() {
|
||||||
var reportUiState by mutableStateOf(ReportUiState())
|
var reportUiState by mutableStateOf(ReportUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -31,17 +32,11 @@ class ReportViewModel(private val serialRepository: RestSessionRepository) : MyV
|
|||||||
|
|
||||||
suspend fun getReport() {
|
suspend fun getReport() {
|
||||||
if (validateInput()) {
|
if (validateInput()) {
|
||||||
runInScope(
|
|
||||||
actionSuccess = {
|
|
||||||
val temp = serialRepository.getReport(
|
val temp = serialRepository.getReport(
|
||||||
reportUiState.reportDetails.startDate,
|
reportUiState.reportDetails.startDate,
|
||||||
reportUiState.reportDetails.endDate
|
reportUiState.reportDetails.endDate
|
||||||
)
|
)
|
||||||
reportResultUiState = ReportResultUiState(temp)
|
reportResultUiState = ReportResultUiState(temp)
|
||||||
}, actionError = {
|
|
||||||
reportResultUiState = ReportResultUiState()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ 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
|
||||||
@ -111,6 +111,7 @@ fun Topbar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Navbar(
|
fun Navbar(
|
||||||
@ -162,8 +163,8 @@ fun Navhost(
|
|||||||
) {
|
) {
|
||||||
composable(Screen.CinemaList.route) { CinemaList(navController) }
|
composable(Screen.CinemaList.route) { CinemaList(navController) }
|
||||||
composable(Screen.OrderList.route) { OrderList(navController) }
|
composable(Screen.OrderList.route) { OrderList(navController) }
|
||||||
composable(Screen.Cart.route) { Cart(navController) }
|
composable(Screen.Cart.route) { Cart() }
|
||||||
composable(Screen.UserProfile.route) { UserProfile(isDarkTheme, dataStore) }
|
composable(Screen.UserProfile.route) { UserProfile(isDarkTheme, dataStore, navController) }
|
||||||
composable(
|
composable(
|
||||||
Screen.CinemaEdit.route,
|
Screen.CinemaEdit.route,
|
||||||
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
arguments = listOf(navArgument("id") { type = NavType.IntType })
|
||||||
@ -187,9 +188,9 @@ 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(navController) }
|
backStackEntry.arguments?.let { OrderView(it.getInt("id")) }
|
||||||
}
|
}
|
||||||
composable(Screen.Report.route) { Report(navController) }
|
composable(Screen.Report.route) { Report() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ fun CinemaList(
|
|||||||
LaunchedEffect(searchPattern.value) {
|
LaunchedEffect(searchPattern.value) {
|
||||||
viewModel.refresh()
|
viewModel.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {},
|
topBar = {},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
@ -98,7 +99,6 @@ fun CinemaList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CinemaList(
|
private fun CinemaList(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
@ -21,16 +21,12 @@ class CinemaListViewModel(
|
|||||||
|
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
val name = "%${LiveStore.searchRequest.value}%"
|
val name = "%${LiveStore.searchRequest.value}%"
|
||||||
runInScope(actionSuccess = {
|
|
||||||
val pagingSource = cinemaRepository.getAllCinemas(name)
|
val pagingSource = cinemaRepository.getAllCinemas(name)
|
||||||
cinemaPagingFlow = CinemaPagingFlowState(pagingSource.cachedIn(viewModelScope))
|
cinemaPagingFlow = CinemaPagingFlowState(pagingSource.cachedIn(viewModelScope))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteCinema(cinema: Cinema) {
|
suspend fun deleteCinema(cinema: Cinema) {
|
||||||
runInScope(actionSuccess = {
|
|
||||||
cinemaRepository.deleteCinema(cinema)
|
cinemaRepository.deleteCinema(cinema)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,6 @@ 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
|
||||||
@ -45,11 +42,11 @@ 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) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
@ -146,11 +143,3 @@ fun CinemaView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 com.example.myapplication.composeui.MyViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
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
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
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,11 +18,7 @@ class CinemaViewModel(
|
|||||||
|
|
||||||
suspend fun refreshState() {
|
suspend fun refreshState() {
|
||||||
if (cinemaUid > 0) {
|
if (cinemaUid > 0) {
|
||||||
runInScope(actionSuccess = {
|
|
||||||
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
||||||
}, actionError = {
|
|
||||||
cinemaUiState = CinemaUiState()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Surface
|
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.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@ -24,6 +26,7 @@ import androidx.navigation.NavController
|
|||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import androidx.paging.compose.itemContentType
|
import androidx.paging.compose.itemContentType
|
||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
@ -33,8 +36,11 @@ fun OrderList(
|
|||||||
navController: NavController?,
|
navController: NavController?,
|
||||||
viewModel: OrderListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: OrderListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
val ordersUiState = viewModel.orderListUiState.collectAsLazyPagingItems()
|
val ordersUiState = viewModel.orderListUiState.collectAsLazyPagingItems()
|
||||||
|
LaunchedEffect(user.value?.uid) {
|
||||||
|
viewModel.refreshState(user.value?.uid ?: 0)
|
||||||
|
}
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
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
|
||||||
|
import kotlinx.coroutines.flow.emptyFlow
|
||||||
|
|
||||||
class OrderListViewModel(
|
class OrderListViewModel(
|
||||||
orderRepository: OrderRepository
|
private val orderRepository: OrderRepository
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
var orderListUiState: Flow<PagingData<Order>> = orderRepository.getAllOrders()
|
var orderListUiState: Flow<PagingData<Order>> = emptyFlow()
|
||||||
|
|
||||||
|
fun refreshState(userId: Int = 0) {
|
||||||
|
orderListUiState = orderRepository.getAllOrders(userId)
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
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
|
||||||
@ -14,41 +15,37 @@ 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.LaunchedEffect
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.getValue
|
||||||
|
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 androidx.navigation.NavController
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
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(
|
||||||
navController: NavController,
|
id: Int,
|
||||||
viewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: OrderViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
val orderUiState = viewModel.orderUiState
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val orderUiState by viewModel.orderUiState.collectAsState()
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
viewModel.refreshState()
|
|
||||||
}
|
|
||||||
when (viewModel.apiStatus) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
) {
|
) {
|
||||||
items(orderUiState.sessionList) { session ->
|
items(orderUiState.sessionList) { session ->
|
||||||
val count = remember { mutableIntStateOf(session.count) }
|
val count = remember { mutableStateOf(session.count) }
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
val formattedDate = dateFormatter.format(session.dateTime)
|
val formattedDate = dateFormatter.format(session.dateTime)
|
||||||
|
|
||||||
@ -92,7 +89,7 @@ fun OrderView(
|
|||||||
Text(
|
Text(
|
||||||
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
text = "${session.cinema.name}, ${session.cinema.year}\n" +
|
||||||
"Цена: ${session.frozenPrice}\n" +
|
"Цена: ${session.frozenPrice}\n" +
|
||||||
"Количество: ${count.intValue}",
|
"Количество: ${count.value}",
|
||||||
color = MaterialTheme.colorScheme.onSecondary
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -102,10 +99,16 @@ fun OrderView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApiStatus.LOADING -> LoadingPlaceholder()
|
|
||||||
else -> ErrorPlaceholder(
|
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||||
message = viewModel.apiError,
|
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||||
onBack = { navController.popBackStack() }
|
@Composable
|
||||||
)
|
fun OrderViewPreview() {
|
||||||
|
PmudemoTheme {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
OrderView(id = 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,29 +1,31 @@
|
|||||||
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 com.example.myapplication.composeui.MyViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
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
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
private val orderUid: Int = checkNotNull(savedStateHandle["id"])
|
private val orderUid: Int = checkNotNull(savedStateHandle["id"])
|
||||||
|
|
||||||
var orderUiState by mutableStateOf(OrderUiState())
|
val orderUiState: StateFlow<OrderUiState> =
|
||||||
private set
|
flow { emit(orderRepository.getOrder(orderUid)) }.map {
|
||||||
|
OrderUiState(it)
|
||||||
suspend fun refreshState() {
|
}.stateIn(
|
||||||
runInScope(actionSuccess = {
|
scope = viewModelScope,
|
||||||
orderUiState = OrderUiState(orderRepository.getOrder(orderUid))
|
started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppContainer.TIMEOUT),
|
||||||
}, actionError = {
|
initialValue = OrderUiState()
|
||||||
orderUiState = OrderUiState()
|
)
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class OrderUiState(val sessionList: List<SessionFromOrder> = listOf())
|
data class OrderUiState(val sessionList: List<SessionFromOrder> = listOf())
|
@ -113,6 +113,7 @@ fun SessionList(
|
|||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
|
if (session.availableCount != 0)
|
||||||
viewModel.addSessionInCart(sessionId = session.uid)
|
viewModel.addSessionInCart(sessionId = session.uid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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,9 +11,8 @@ 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
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
suspend fun deleteSession(session: SessionFromCinema) {
|
suspend fun deleteSession(session: SessionFromCinema) {
|
||||||
runInScope(actionSuccess = {
|
|
||||||
sessionRepository.deleteSession(
|
sessionRepository.deleteSession(
|
||||||
Session(
|
Session(
|
||||||
uid = session.uid,
|
uid = session.uid,
|
||||||
@ -23,19 +22,14 @@ class SessionListViewModel(
|
|||||||
cinemaId = 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))
|
||||||
userSessionRepository.insertUserSession(
|
} catch (_: Exception) {
|
||||||
UserSessionCrossRef(
|
|
||||||
userId,
|
}
|
||||||
sessionId,
|
|
||||||
count
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,7 +18,6 @@ import androidx.compose.material3.Switch
|
|||||||
import androidx.compose.material3.SwitchDefaults
|
import androidx.compose.material3.SwitchDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@ -33,6 +32,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
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 androidx.navigation.NavController
|
||||||
import com.example.myapplication.LiveStore
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.datastore.DataStoreManager
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -41,21 +41,15 @@ import kotlinx.coroutines.launch
|
|||||||
fun UserProfile(
|
fun UserProfile(
|
||||||
isDarkTheme: MutableState<Boolean>,
|
isDarkTheme: MutableState<Boolean>,
|
||||||
dataStoreManager: DataStoreManager,
|
dataStoreManager: DataStoreManager,
|
||||||
|
navController: NavController,
|
||||||
viewModel: UserProfileViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: UserProfileViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
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 =
|
val errorMessage = if (errorStringId == null) "" else stringResource(errorStringId)
|
||||||
if (errorStringId == null || errorStringId == 0) "" else stringResource(errorStringId)
|
|
||||||
val user = LiveStore.user.observeAsState()
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(errorStringId) {
|
|
||||||
if (errorStringId == 0) {
|
|
||||||
isRegistration = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
if (user.value != null) {
|
if (user.value != null) {
|
||||||
@ -76,7 +70,7 @@ fun UserProfile(
|
|||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 2.dp, top = 10.dp)
|
.padding(8.dp)
|
||||||
) { Text("Выход") }
|
) { Text("Выход") }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -157,10 +151,10 @@ fun UserProfile(
|
|||||||
|
|
||||||
if (isRegistration) {
|
if (isRegistration) {
|
||||||
Button(
|
Button(
|
||||||
onClick = { coroutine.launch { viewModel.signUp() } },
|
onClick = { coroutine.launch { isRegistration = !viewModel.signUp() } },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 2.dp, top = 8.dp)
|
.padding(8.dp)
|
||||||
) {
|
) {
|
||||||
Text("Регистрация")
|
Text("Регистрация")
|
||||||
}
|
}
|
||||||
@ -177,12 +171,14 @@ fun UserProfile(
|
|||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutine.launch {
|
coroutine.launch {
|
||||||
viewModel.signIn(dataStoreManager)
|
if (viewModel.signIn(dataStoreManager)) {
|
||||||
|
navController.popBackStack()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 2.dp, top = 8.dp)
|
.padding(8.dp)
|
||||||
) {
|
) {
|
||||||
Text("Вход")
|
Text("Вход")
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
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 com.example.myapplication.MainComposeActivity
|
import androidx.lifecycle.ViewModel
|
||||||
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
|
||||||
) : MyViewModel() {
|
) : ViewModel() {
|
||||||
var userUiState by mutableStateOf(UserUiState())
|
var userUiState by mutableStateOf(UserUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -25,63 +22,43 @@ class UserProfileViewModel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun signIn(dataStoreManager: DataStoreManager) {
|
suspend fun signIn(dataStoreManager: DataStoreManager): Boolean {
|
||||||
userUiState.details.passwordConfirm = userUiState.details.password
|
userUiState.details.passwordConfirm = userUiState.details.password
|
||||||
var errorId: Int? = validateInput(userUiState.details)
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
runInScope(
|
|
||||||
actionSuccess = {
|
|
||||||
if (errorId == null) {
|
if (errorId == null) {
|
||||||
val overlap: User? = userRepository.getUser(userUiState.details.login)
|
val overlap = userRepository.getUser(userUiState.details.login)
|
||||||
if (overlap == null || userUiState.details.password != overlap.password) {
|
if (overlap == null || userUiState.details.password != overlap.password) {
|
||||||
errorId = R.string.err_04
|
errorId = R.string.err_04
|
||||||
} else {
|
}
|
||||||
|
}
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
errorId = errorId
|
||||||
|
)
|
||||||
|
if (errorId == null) {
|
||||||
dataStoreManager.setLogin(userUiState.details.login)
|
dataStoreManager.setLogin(userUiState.details.login)
|
||||||
Log.d("UserProfileViewModel", "sign in success")
|
return true
|
||||||
}
|
}
|
||||||
}
|
return false
|
||||||
userUiState = UserUiState(
|
|
||||||
details = userUiState.details,
|
|
||||||
errorId = errorId
|
|
||||||
)
|
|
||||||
}, actionError = {
|
|
||||||
errorId = R.string.err_06
|
|
||||||
userUiState = UserUiState(
|
|
||||||
details = userUiState.details,
|
|
||||||
errorId = errorId
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun signUp() {
|
suspend fun signUp(): Boolean {
|
||||||
var errorId: Int? = validateInput(userUiState.details)
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
runInScope(actionSuccess = {
|
|
||||||
if (errorId == null) {
|
if (errorId == null) {
|
||||||
val overlap = userRepository.getUser(userUiState.details.login)
|
val overlap = userRepository.getUser(userUiState.details.login)
|
||||||
if (overlap != null) {
|
if (overlap != null) {
|
||||||
errorId = R.string.err_03
|
errorId = R.string.err_03
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
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,
|
|
||||||
"Вы зарегистрированы",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
toast.show()
|
|
||||||
errorId = 0
|
|
||||||
}
|
}
|
||||||
userUiState = UserUiState(
|
return false
|
||||||
details = userUiState.details,
|
|
||||||
errorId = errorId
|
|
||||||
)
|
|
||||||
}, 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,9 +22,6 @@ 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
|
||||||
@ -35,8 +32,7 @@ fun CinemaEdit(
|
|||||||
viewModel: CinemaEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: CinemaEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
when (viewModel.apiStatus) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
CinemaEdit(
|
CinemaEdit(
|
||||||
cinemaUiState = viewModel.cinemaUiState,
|
cinemaUiState = viewModel.cinemaUiState,
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -48,13 +44,6 @@ fun CinemaEdit(
|
|||||||
onUpdate = viewModel::updateUiState,
|
onUpdate = viewModel::updateUiState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ApiStatus.LOADING -> LoadingPlaceholder()
|
|
||||||
else -> ErrorPlaceholder(
|
|
||||||
message = viewModel.apiError,
|
|
||||||
onBack = { navController.popBackStack() }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun CinemaEdit(
|
private fun CinemaEdit(
|
||||||
@ -111,6 +100,7 @@ private fun CinemaEdit(
|
|||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
enabled = cinemaUiState.isEntryValid,
|
enabled = cinemaUiState.isEntryValid,
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.Save_button))
|
Text(text = stringResource(R.string.Save_button))
|
||||||
|
@ -9,6 +9,7 @@ import androidx.compose.material3.Button
|
|||||||
import androidx.compose.material3.DatePicker
|
import androidx.compose.material3.DatePicker
|
||||||
import androidx.compose.material3.DisplayMode
|
import androidx.compose.material3.DisplayMode
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TimePicker
|
import androidx.compose.material3.TimePicker
|
||||||
@ -23,9 +24,6 @@ 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
|
||||||
@ -41,8 +39,6 @@ fun SessionEdit(
|
|||||||
viewModel: SessionEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: SessionEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
when (viewModel.apiStatus) {
|
|
||||||
ApiStatus.DONE -> {
|
|
||||||
SessionEdit(
|
SessionEdit(
|
||||||
sessionUiState = viewModel.sessionUiState,
|
sessionUiState = viewModel.sessionUiState,
|
||||||
onClick = {
|
onClick = {
|
||||||
@ -55,14 +51,6 @@ fun SessionEdit(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
val instant = Instant.ofEpochMilli(this)
|
val instant = Instant.ofEpochMilli(this)
|
||||||
return instant.atZone(ZoneId.systemDefault()).toLocalDate()
|
return instant.atZone(ZoneId.systemDefault()).toLocalDate()
|
||||||
@ -152,6 +140,7 @@ private fun SessionEdit(
|
|||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
enabled = sessionUiState.isEntryValid,
|
enabled = sessionUiState.isEntryValid,
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(R.string.Save_button))
|
Text(text = stringResource(R.string.Save_button))
|
||||||
|
@ -4,7 +4,6 @@ import androidx.paging.PagingSource
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.example.myapplication.database.entities.model.Cinema
|
import com.example.myapplication.database.entities.model.Cinema
|
||||||
@ -15,7 +14,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
interface CinemaDao {
|
interface CinemaDao {
|
||||||
@Query("select * from cinemas order by name")
|
@Query("select * from cinemas order by name")
|
||||||
fun getAll(): PagingSource<Int, Cinema>
|
fun getAll(): PagingSource<Int, Cinema>
|
||||||
|
|
||||||
@Query("select * from cinemas where cinemas.name like :name order by name collate nocase asc")
|
@Query("select * from cinemas where cinemas.name like :name order by name collate nocase asc")
|
||||||
fun getAll(name: String): PagingSource<Int, Cinema>
|
fun getAll(name: String): PagingSource<Int, Cinema>
|
||||||
|
|
||||||
@ -29,7 +27,7 @@ interface CinemaDao {
|
|||||||
)
|
)
|
||||||
fun getByUid(cinemaId: Int?): Flow<Map<Cinema, List<SessionFromCinema>>>
|
fun getByUid(cinemaId: Int?): Flow<Map<Cinema, List<SessionFromCinema>>>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert
|
||||||
suspend fun insert(vararg cinema: Cinema)
|
suspend fun insert(vararg cinema: Cinema)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
@ -4,7 +4,6 @@ import androidx.paging.PagingSource
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.example.myapplication.database.entities.model.Order
|
import com.example.myapplication.database.entities.model.Order
|
||||||
@ -24,7 +23,7 @@ interface OrderDao {
|
|||||||
)
|
)
|
||||||
fun getByUid(orderId: Int?): List<SessionFromOrder>
|
fun getByUid(orderId: Int?): List<SessionFromOrder>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert
|
||||||
suspend fun insert(vararg order: Order): List<Long>
|
suspend fun insert(vararg order: Order): List<Long>
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
@ -3,7 +3,6 @@ package com.example.myapplication.database.entities.dao
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.example.myapplication.database.entities.model.Session
|
import com.example.myapplication.database.entities.model.Session
|
||||||
@ -13,7 +12,7 @@ interface SessionDao {
|
|||||||
@Query("select * from sessions where sessions.uid = :uid")
|
@Query("select * from sessions where sessions.uid = :uid")
|
||||||
suspend fun getByUid(uid: Int): Session
|
suspend fun getByUid(uid: Int): Session
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert
|
||||||
suspend fun insert(vararg session: Session)
|
suspend fun insert(vararg session: Session)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
@ -3,7 +3,6 @@ package com.example.myapplication.database.entities.dao
|
|||||||
import androidx.room.Dao
|
import androidx.room.Dao
|
||||||
import androidx.room.Delete
|
import androidx.room.Delete
|
||||||
import androidx.room.Insert
|
import androidx.room.Insert
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.example.myapplication.database.entities.model.SessionFromCart
|
import com.example.myapplication.database.entities.model.SessionFromCart
|
||||||
@ -28,7 +27,7 @@ interface UserDao {
|
|||||||
)
|
)
|
||||||
suspend fun getCartByUid(userId: Int): List<SessionFromCart>
|
suspend fun getCartByUid(userId: Int): List<SessionFromCart>
|
||||||
|
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert
|
||||||
suspend fun insert(vararg user: User)
|
suspend fun insert(vararg user: User)
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
|
@ -17,7 +17,7 @@ interface UserSessionCrossRefDao {
|
|||||||
suspend fun update(userSessionCrossRef: UserSessionCrossRef)
|
suspend fun update(userSessionCrossRef: UserSessionCrossRef)
|
||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(vararg userSessionCrossRef: UserSessionCrossRef)
|
suspend fun delete(userSessionCrossRef: UserSessionCrossRef)
|
||||||
|
|
||||||
@Query("DELETE FROM users_sessions where users_sessions.user_id = :userId")
|
@Query("DELETE FROM users_sessions where users_sessions.user_id = :userId")
|
||||||
suspend fun deleteByUserUid(userId: Int)
|
suspend fun deleteByUserUid(userId: Int)
|
||||||
|
@ -18,7 +18,7 @@ class OfflineCinemaRepository(private val cinemaDao: CinemaDao) : CinemaReposito
|
|||||||
pageSize = AppContainer.LIMIT,
|
pageSize = AppContainer.LIMIT,
|
||||||
enablePlaceholders = false
|
enablePlaceholders = false
|
||||||
),
|
),
|
||||||
pagingSourceFactory = { cinemaDao.getAll(name) }
|
pagingSourceFactory = cinemaDao::getAll
|
||||||
).flow
|
).flow
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import androidx.paging.Pager
|
|||||||
import androidx.paging.PagingConfig
|
import androidx.paging.PagingConfig
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
import androidx.paging.PagingSource
|
import androidx.paging.PagingSource
|
||||||
import com.example.myapplication.LiveStore
|
|
||||||
import com.example.myapplication.database.AppContainer
|
import com.example.myapplication.database.AppContainer
|
||||||
import com.example.myapplication.database.entities.dao.OrderDao
|
import com.example.myapplication.database.entities.dao.OrderDao
|
||||||
import com.example.myapplication.database.entities.model.Order
|
import com.example.myapplication.database.entities.model.Order
|
||||||
@ -12,21 +11,19 @@ import com.example.myapplication.database.entities.model.SessionFromOrder
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
class OfflineOrderRepository(private val orderDao: OrderDao) : OrderRepository {
|
class OfflineOrderRepository(private val orderDao: OrderDao) : OrderRepository {
|
||||||
override fun getAllOrders(): Flow<PagingData<Order>> = Pager(
|
override fun getAllOrders(userId: Int): Flow<PagingData<Order>> = Pager(
|
||||||
config = PagingConfig(
|
config = PagingConfig(
|
||||||
pageSize = AppContainer.LIMIT,
|
pageSize = AppContainer.LIMIT,
|
||||||
enablePlaceholders = false
|
enablePlaceholders = false
|
||||||
),
|
),
|
||||||
pagingSourceFactory = { orderDao.getAll(LiveStore.user.value?.uid ?: 0) }
|
pagingSourceFactory = { orderDao.getAll(userId) }
|
||||||
).flow
|
).flow
|
||||||
|
|
||||||
override suspend fun getOrder(uid: Int): List<SessionFromOrder> = orderDao.getByUid(uid)
|
override suspend fun getOrder(uid: Int): List<SessionFromOrder> = orderDao.getByUid(uid)
|
||||||
|
|
||||||
override suspend fun insertOrder(order: Order): Long = orderDao.insert(order).first()
|
override suspend fun insertOrder(order: Order): Long = orderDao.insert(order).first()
|
||||||
|
|
||||||
fun getAllOrdersPagingSource(): PagingSource<Int, Order> {
|
fun getAllOrdersPagingSource(userId: Int?): PagingSource<Int, Order> = orderDao.getAll(userId)
|
||||||
return orderDao.getAll(LiveStore.user.value?.uid ?: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun clearOrders() = orderDao.deleteAll()
|
suspend fun clearOrders() = orderDao.deleteAll()
|
||||||
|
|
||||||
|
@ -16,8 +16,5 @@ class OfflineUserSessionRepository(private val userSessionDao: UserSessionCrossR
|
|||||||
|
|
||||||
override suspend fun deleteUserSessions(userId: Int) = userSessionDao.deleteByUserUid(userId)
|
override suspend fun deleteUserSessions(userId: Int) = userSessionDao.deleteByUserUid(userId)
|
||||||
|
|
||||||
override suspend fun deleteUserSessions(userSessionCrossRefs: List<UserSessionCrossRef>) =
|
|
||||||
userSessionDao.delete(*userSessionCrossRefs.toTypedArray())
|
|
||||||
|
|
||||||
suspend fun deleteSessionsByUid(sessionId: Int) = userSessionDao.deleteBySessionUid(sessionId)
|
suspend fun deleteSessionsByUid(sessionId: Int) = userSessionDao.deleteBySessionUid(sessionId)
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ import com.example.myapplication.database.entities.model.SessionFromOrder
|
|||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface OrderRepository {
|
interface OrderRepository {
|
||||||
fun getAllOrders(): Flow<PagingData<Order>>
|
fun getAllOrders(userId: Int): Flow<PagingData<Order>>
|
||||||
suspend fun getOrder(uid: Int): List<SessionFromOrder>
|
suspend fun getOrder(uid: Int): List<SessionFromOrder>
|
||||||
suspend fun insertOrder(order: Order): Long
|
suspend fun insertOrder(order: Order): Long
|
||||||
}
|
}
|
@ -7,5 +7,4 @@ interface UserSessionRepository {
|
|||||||
suspend fun updateUserSession(userSessionCrossRef: UserSessionCrossRef)
|
suspend fun updateUserSession(userSessionCrossRef: UserSessionCrossRef)
|
||||||
suspend fun deleteUserSession(userSessionCrossRef: UserSessionCrossRef)
|
suspend fun deleteUserSession(userSessionCrossRef: UserSessionCrossRef)
|
||||||
suspend fun deleteUserSessions(userId: Int)
|
suspend fun deleteUserSessions(userId: Int)
|
||||||
suspend fun deleteUserSessions(userSessionCrossRefs: List<UserSessionCrossRef>)
|
|
||||||
}
|
}
|
@ -25,7 +25,6 @@
|
|||||||
<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>
|
309645
server/data.json
309645
server/data.json
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ module.exports = (req, res, next) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { startDate, endDate } = req.query;
|
const { startDate, endDate } = req.query;
|
||||||
const { cinemas, sessions, orders } = require('./data.json');
|
const { sessions, orders } = require('./data.json');
|
||||||
|
|
||||||
const start = new Date(startDate);
|
const start = new Date(startDate);
|
||||||
const end = new Date(endDate);
|
const end = new Date(endDate);
|
||||||
@ -42,9 +42,8 @@ module.exports = (req, res, next) => {
|
|||||||
};
|
};
|
||||||
}, { totalTicketsSold: 0, revenue: 0 });
|
}, { totalTicketsSold: 0, revenue: 0 });
|
||||||
|
|
||||||
const cinema = cinemas.find(cinema => cinema.id === session.cinemaId)
|
|
||||||
return {
|
return {
|
||||||
cinema_name: cinema ? cinema.name : "Неизвестно",
|
cinema_name: relevantOrders[0].sessions[0].cinema.name,
|
||||||
current_ticket_date_time: session.dateTime,
|
current_ticket_date_time: session.dateTime,
|
||||||
current_ticket_price: session.price,
|
current_ticket_price: session.price,
|
||||||
max_ticket_quantity: session.maxCount,
|
max_ticket_quantity: session.maxCount,
|
||||||
|
Loading…
Reference in New Issue
Block a user