регистрация и вход
This commit is contained in:
parent
167d5ccc7d
commit
28fd92559c
@ -50,6 +50,7 @@ android {
|
|||||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buildToolsVersion = "34.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -58,6 +59,9 @@ dependencies {
|
|||||||
implementation("io.github.vanpra.compose-material-dialogs:datetime:0.8.1-rc")
|
implementation("io.github.vanpra.compose-material-dialogs:datetime:0.8.1-rc")
|
||||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
|
||||||
|
|
||||||
|
// LiveData
|
||||||
|
implementation("androidx.compose.runtime:runtime-livedata:1.5.4")
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
implementation("androidx.core:core-ktx:1.9.0")
|
implementation("androidx.core:core-ktx:1.9.0")
|
||||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||||
|
11
app/src/main/java/com/example/myapplication/LiveStore.kt
Normal file
11
app/src/main/java/com/example/myapplication/LiveStore.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.myapplication
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.example.myapplication.database.entities.model.User
|
||||||
|
|
||||||
|
class LiveStore {
|
||||||
|
companion object {
|
||||||
|
val user = MutableLiveData<User?>(null)
|
||||||
|
val searchRequest = MutableLiveData("")
|
||||||
|
}
|
||||||
|
}
|
@ -3,12 +3,17 @@ package com.example.myapplication
|
|||||||
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
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import com.example.myapplication.composeui.Authenticator
|
||||||
import com.example.myapplication.composeui.navigation.MainNavbar
|
import com.example.myapplication.composeui.navigation.MainNavbar
|
||||||
import com.example.myapplication.datastore.DataStoreManager
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
import com.example.myapplication.ui.theme.PmudemoTheme
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
@ -22,14 +27,15 @@ class MainComposeActivity : ComponentActivity() {
|
|||||||
setContent {
|
setContent {
|
||||||
PmudemoTheme(darkTheme = isDarkTheme.value) {
|
PmudemoTheme(darkTheme = isDarkTheme.value) {
|
||||||
LaunchedEffect(key1 = true) {
|
LaunchedEffect(key1 = true) {
|
||||||
dataStoreManager.getSettings().collect { setting ->
|
dataStoreManager.getDarkTheme().collect { setting ->
|
||||||
isDarkTheme.value = setting.isDarkTheme
|
isDarkTheme.value = setting == "Dark"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.background
|
||||||
) {
|
) {
|
||||||
|
Authenticator(dataStoreManager)
|
||||||
MainNavbar(
|
MainNavbar(
|
||||||
isDarkTheme = isDarkTheme,
|
isDarkTheme = isDarkTheme,
|
||||||
dataStoreManager = dataStoreManager
|
dataStoreManager = dataStoreManager
|
||||||
|
@ -87,12 +87,22 @@ interface MyServerService {
|
|||||||
@Path("id") id: Int,
|
@Path("id") id: Int,
|
||||||
): UserRemote
|
): UserRemote
|
||||||
|
|
||||||
|
@GET("users?_limit=1")
|
||||||
|
suspend fun getUser(
|
||||||
|
@Query("login") login: String,
|
||||||
|
): List<UserRemote>
|
||||||
|
|
||||||
@PUT("users/{id}")
|
@PUT("users/{id}")
|
||||||
suspend fun updateUserCart(
|
suspend fun updateUserCart(
|
||||||
@Path("id") id: Int,
|
@Path("id") id: Int,
|
||||||
@Body userRemote: UserRemote,
|
@Body userRemote: UserRemote,
|
||||||
): UserRemote
|
): UserRemote
|
||||||
|
|
||||||
|
@POST("users")
|
||||||
|
suspend fun createUser(
|
||||||
|
@Body user: UserRemote,
|
||||||
|
): UserRemote
|
||||||
|
|
||||||
@GET("orders")
|
@GET("orders")
|
||||||
suspend fun getOrders(
|
suspend fun getOrders(
|
||||||
@Query("_page") page: Int,
|
@Query("_page") page: Int,
|
||||||
@ -116,7 +126,7 @@ interface MyServerService {
|
|||||||
): OrderRemote
|
): OrderRemote
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
//private const val BASE_URL = "http://192.168.154.166:8079/"
|
//private const val BASE_URL = "http://192.168.154.166:8080/"
|
||||||
private const val BASE_URL = "http://192.168.0.101:8079/"
|
private const val BASE_URL = "http://192.168.0.101:8079/"
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
|
@ -2,17 +2,23 @@ package com.example.myapplication.api.order
|
|||||||
|
|
||||||
import com.example.myapplication.api.session.SessionFromOrderRemote
|
import com.example.myapplication.api.session.SessionFromOrderRemote
|
||||||
import com.example.myapplication.database.entities.model.Order
|
import com.example.myapplication.database.entities.model.Order
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class OrderRemote(
|
data class OrderRemote(
|
||||||
val id: Int = 0, val userId: Int = 0, var sessions: List<SessionFromOrderRemote> = emptyList()
|
val id: Int = 0,
|
||||||
|
val userId: Int = 0,
|
||||||
|
@Contextual
|
||||||
|
val dateTime: LocalDateTime = LocalDateTime.now(),
|
||||||
|
var sessions: List<SessionFromOrderRemote> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun OrderRemote.toOrder(): Order = Order(
|
fun OrderRemote.toOrder(): Order = Order(
|
||||||
id, userId
|
id, userId, dateTime
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Order.toOrderRemote(): OrderRemote = OrderRemote(
|
fun Order.toOrderRemote(): OrderRemote = OrderRemote(
|
||||||
uid, userId!!, sessions = emptyList()
|
uid, userId!!, dateTime, sessions = emptyList()
|
||||||
)
|
)
|
@ -2,6 +2,8 @@ package com.example.myapplication.api.user
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.example.myapplication.api.MyServerService
|
import com.example.myapplication.api.MyServerService
|
||||||
|
import com.example.myapplication.api.cinema.toCinema
|
||||||
|
import com.example.myapplication.api.cinema.toCinemaRemote
|
||||||
import com.example.myapplication.api.session.toSessionFromCart
|
import com.example.myapplication.api.session.toSessionFromCart
|
||||||
import com.example.myapplication.database.entities.model.SessionFromCart
|
import com.example.myapplication.database.entities.model.SessionFromCart
|
||||||
import com.example.myapplication.database.entities.model.User
|
import com.example.myapplication.database.entities.model.User
|
||||||
@ -21,6 +23,10 @@ class RestUserRepository(
|
|||||||
return dbUserRepository.getAllUsers()
|
return dbUserRepository.getAllUsers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getUser(login: String): User? {
|
||||||
|
return service.getUser(login).firstOrNull()?.toUser()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getCartByUser(userId: Int): List<SessionFromCart> {
|
override suspend fun getCartByUser(userId: Int): List<SessionFromCart> {
|
||||||
val cart = service.getUserCart(userId)
|
val cart = service.getUserCart(userId)
|
||||||
dbUserSessionRepository.deleteUserSessions(userId)
|
dbUserSessionRepository.deleteUserSessions(userId)
|
||||||
@ -47,6 +53,7 @@ class RestUserRepository(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun insertUser(user: User) {
|
override suspend fun insertUser(user: User) {
|
||||||
|
service.createUser(user.toUserRemote()).toUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateUser(user: User) {
|
override suspend fun updateUser(user: User) {
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package com.example.myapplication.api.user
|
package com.example.myapplication.api.user
|
||||||
|
|
||||||
import com.example.myapplication.api.session.SessionFromCartRemote
|
import com.example.myapplication.api.session.SessionFromCartRemote
|
||||||
|
import com.example.myapplication.api.session.SessionRemote
|
||||||
|
import com.example.myapplication.database.entities.model.Session
|
||||||
|
import com.example.myapplication.database.entities.model.User
|
||||||
|
import com.example.myapplication.database.entities.model.UserRole
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -8,5 +12,20 @@ data class UserRemote(
|
|||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
val login: String = "",
|
val login: String = "",
|
||||||
val password: String = "",
|
val password: String = "",
|
||||||
|
val role: Int = -1,
|
||||||
var sessions: List<SessionFromCartRemote> = emptyList()
|
var sessions: List<SessionFromCartRemote> = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun User.toUserRemote(): UserRemote = UserRemote(
|
||||||
|
uid,
|
||||||
|
login,
|
||||||
|
password,
|
||||||
|
role = role.ordinal,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun UserRemote.toUser(): User = User(
|
||||||
|
id,
|
||||||
|
login,
|
||||||
|
password,
|
||||||
|
role = enumValues<UserRole>()[role],
|
||||||
|
)
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Authenticator(
|
||||||
|
dataStoreManager: DataStoreManager,
|
||||||
|
viewModel: AuthenticatorViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val login = dataStoreManager.getLogin().collectAsState(initial = "").value
|
||||||
|
|
||||||
|
fun synchronize() {
|
||||||
|
scope.launch {
|
||||||
|
if (login == "") {
|
||||||
|
LiveStore.user.value = null
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val overlap = viewModel.findUserByLogin(login)
|
||||||
|
if (overlap == null) {
|
||||||
|
dataStoreManager.setLogin("")
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
LiveStore.user.value = overlap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronize()
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.example.myapplication.composeui
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.myapplication.database.entities.model.User
|
||||||
|
import com.example.myapplication.database.entities.repository.UserRepository
|
||||||
|
|
||||||
|
class AuthenticatorViewModel(
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
suspend fun findUserByLogin(login: String): User? {
|
||||||
|
return userRepository.getUser(login)
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,8 @@ 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.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@ -51,14 +53,13 @@ import androidx.compose.ui.res.vectorResource
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
import com.example.myapplication.database.entities.composeui.AppViewModelProvider
|
||||||
import com.example.myapplication.database.entities.composeui.CartUiState
|
|
||||||
import com.example.myapplication.database.entities.composeui.CartViewModel
|
|
||||||
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.ui.theme.PmudemoTheme
|
import com.example.myapplication.ui.theme.PmudemoTheme
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ fun Cart(
|
|||||||
cartUiState = cartUiState,
|
cartUiState = cartUiState,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = 10.dp),
|
.padding(all = 10.dp),
|
||||||
onSwipe = { session: SessionFromCart, user: Int ->
|
onSwipe = { session: SessionFromCart ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
viewModel.removeFromCart(
|
viewModel.removeFromCart(
|
||||||
session = Session(
|
session = Session(
|
||||||
@ -86,11 +87,11 @@ fun Cart(
|
|||||||
price = session.price,
|
price = session.price,
|
||||||
maxCount = 0,
|
maxCount = 0,
|
||||||
cinemaId = session.cinemaId
|
cinemaId = session.cinemaId
|
||||||
), user = user
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChangeCount = { session: SessionFromCart, user: Int, count: Int ->
|
onChangeCount = { session: SessionFromCart, count: Int ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
viewModel.updateFromCart(
|
viewModel.updateFromCart(
|
||||||
session = Session(
|
session = Session(
|
||||||
@ -99,13 +100,13 @@ fun Cart(
|
|||||||
price = session.price,
|
price = session.price,
|
||||||
maxCount = 0,
|
maxCount = 0,
|
||||||
cinemaId = session.cinemaId
|
cinemaId = session.cinemaId
|
||||||
), userId = user, count = count, availableCount = session.availableCount
|
), count = count, availableCount = session.availableCount
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onAddToOrder = { sessions: List<SessionFromCart>, user: Int ->
|
onAddToOrder = { sessions: List<SessionFromCart> ->
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
viewModel.addToOrder(sessions = sessions, userId = user)
|
viewModel.addToOrder(sessions = sessions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -116,9 +117,9 @@ fun Cart(
|
|||||||
private fun Cart(
|
private fun Cart(
|
||||||
cartUiState: CartUiState,
|
cartUiState: CartUiState,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
onSwipe: (SessionFromCart, Int) -> Unit,
|
onSwipe: (SessionFromCart) -> Unit,
|
||||||
onChangeCount: (SessionFromCart, Int, Int) -> Unit,
|
onChangeCount: (SessionFromCart, Int) -> Unit,
|
||||||
onAddToOrder: (List<SessionFromCart>, Int) -> Unit
|
onAddToOrder: (List<SessionFromCart>) -> Unit
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@ -129,68 +130,8 @@ private fun Cart(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
|
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
|
||||||
onSwipe(session, 1)
|
onSwipe(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
SwipeToDelete(
|
|
||||||
dismissState = dismissState,
|
|
||||||
session = session,
|
|
||||||
onChangeCount = onChangeCount
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Column {
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = { onAddToOrder(cartUiState.sessionList, 1) },
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(16.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
) { Text("Купить") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
private fun SwipeToDelete(
|
|
||||||
dismissState: DismissState,
|
|
||||||
session: SessionFromCart,
|
|
||||||
onChangeCount: (SessionFromCart, Int, Int) -> Unit,
|
|
||||||
) {
|
|
||||||
SwipeToDismiss(
|
|
||||||
state = dismissState,
|
|
||||||
directions = setOf(
|
|
||||||
DismissDirection.EndToStart
|
|
||||||
),
|
|
||||||
background = {
|
|
||||||
val backgroundColor by animateColorAsState(
|
|
||||||
when (dismissState.targetValue) {
|
|
||||||
DismissValue.DismissedToStart -> Color.Red.copy(alpha = 0.8f)
|
|
||||||
else -> MaterialTheme.colorScheme.background
|
|
||||||
},
|
|
||||||
label = ""
|
|
||||||
)
|
|
||||||
val iconScale by animateFloatAsState(
|
|
||||||
targetValue = if (dismissState.targetValue == DismissValue.DismissedToStart) 1.3f else 0.5f,
|
|
||||||
label = ""
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(color = backgroundColor)
|
|
||||||
.padding(end = 16.dp),
|
|
||||||
contentAlignment = Alignment.CenterEnd
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier.scale(iconScale),
|
|
||||||
imageVector = Icons.Outlined.Delete,
|
|
||||||
contentDescription = "Delete",
|
|
||||||
tint = Color.White
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissContent = {
|
|
||||||
SessionListItem(
|
SessionListItem(
|
||||||
session = session,
|
session = session,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -201,16 +142,29 @@ private fun SwipeToDelete(
|
|||||||
onChangeCount = onChangeCount
|
onChangeCount = onChangeCount
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
|
if (user.value?.role == UserRole.USER) {
|
||||||
|
Column {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = { onAddToOrder(cartUiState.sessionList) },
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) { Text("Купить") }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SessionListItem(
|
private fun SessionListItem(
|
||||||
session: SessionFromCart,
|
session: SessionFromCart,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onChangeCount: (SessionFromCart, Int, Int) -> Unit,
|
onChangeCount: (SessionFromCart, Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
var currentCount by remember { mutableStateOf(session.count) }
|
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)
|
||||||
@ -265,7 +219,7 @@ private fun SessionListItem(
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { onChangeCount(session, 1, --currentCount) }
|
onClick = { onChangeCount(session, --currentCount) }
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = ImageVector.vectorResource(id = R.drawable.minus),
|
imageVector = ImageVector.vectorResource(id = R.drawable.minus),
|
||||||
@ -284,7 +238,6 @@ private fun SessionListItem(
|
|||||||
onClick = {
|
onClick = {
|
||||||
onChangeCount(
|
onChangeCount(
|
||||||
session,
|
session,
|
||||||
1,
|
|
||||||
if (currentCount != session.availableCount) ++currentCount else currentCount
|
if (currentCount != session.availableCount) ++currentCount else currentCount
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
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 androidx.lifecycle.ViewModel
|
||||||
|
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
|
||||||
import com.example.myapplication.database.entities.model.Session
|
import com.example.myapplication.database.entities.model.Session
|
||||||
@ -13,7 +14,7 @@ import com.example.myapplication.database.entities.repository.OrderRepository
|
|||||||
import com.example.myapplication.database.entities.repository.OrderSessionRepository
|
import com.example.myapplication.database.entities.repository.OrderSessionRepository
|
||||||
import com.example.myapplication.database.entities.repository.UserRepository
|
import com.example.myapplication.database.entities.repository.UserRepository
|
||||||
import com.example.myapplication.database.entities.repository.UserSessionRepository
|
import com.example.myapplication.database.entities.repository.UserSessionRepository
|
||||||
import kotlinx.coroutines.delay
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
class CartViewModel(
|
class CartViewModel(
|
||||||
private val userSessionRepository: UserSessionRepository,
|
private val userSessionRepository: UserSessionRepository,
|
||||||
@ -21,19 +22,20 @@ class CartViewModel(
|
|||||||
private val orderSessionRepository: OrderSessionRepository,
|
private val orderSessionRepository: OrderSessionRepository,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val userUid: Int = 1
|
|
||||||
var cartUiState by mutableStateOf(CartUiState())
|
var cartUiState by mutableStateOf(CartUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
suspend fun refreshState() {
|
suspend fun refreshState() {
|
||||||
val cart = userRepository.getCartByUser(userUid)
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
|
val cart = userRepository.getCartByUser(userId)
|
||||||
cartUiState = CartUiState(cart)
|
cartUiState = CartUiState(cart)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addToOrder(userId: Int, sessions: List<SessionFromCart>) {
|
suspend fun addToOrder(sessions: List<SessionFromCart>) {
|
||||||
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
if (sessions.isEmpty())
|
if (sessions.isEmpty())
|
||||||
return
|
return
|
||||||
val orderId = orderRepository.insertOrder(Order(0, userId))
|
val orderId = orderRepository.insertOrder(Order(0, userId, LocalDateTime.now()))
|
||||||
sessions.forEach { session ->
|
sessions.forEach { session ->
|
||||||
orderSessionRepository.insertOrderSession(
|
orderSessionRepository.insertOrderSession(
|
||||||
OrderSessionCrossRef(
|
OrderSessionCrossRef(
|
||||||
@ -48,15 +50,17 @@ class CartViewModel(
|
|||||||
refreshState()
|
refreshState()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun removeFromCart(user: Int, session: Session, count: Int = 1) {
|
suspend fun removeFromCart(session: Session, count: Int = 0) {
|
||||||
userSessionRepository.deleteUserSession(UserSessionCrossRef(user, session.uid, count))
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
|
userSessionRepository.deleteUserSession(UserSessionCrossRef(userId, session.uid, count))
|
||||||
refreshState()
|
refreshState()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateFromCart(userId: Int, session: Session, count: Int, availableCount: Int)
|
suspend fun updateFromCart(session: Session, count: Int, availableCount: Int)
|
||||||
: Boolean {
|
: Boolean {
|
||||||
|
val userId: Int = LiveStore.user.value?.uid ?: return false
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
removeFromCart(userId, session, count)
|
removeFromCart(session, count)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (count > availableCount)
|
if (count > availableCount)
|
@ -176,9 +176,9 @@ fun Navhost(
|
|||||||
modifier.padding(innerPadding)
|
modifier.padding(innerPadding)
|
||||||
) {
|
) {
|
||||||
composable(Screen.CinemaList.route) { CinemaList(navController) }
|
composable(Screen.CinemaList.route) { CinemaList(navController) }
|
||||||
composable(Screen.OrderList.route) { OrderList(navController, 1) }
|
composable(Screen.OrderList.route) { OrderList(navController) }
|
||||||
composable(Screen.Cart.route) { Cart() }
|
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 })
|
||||||
|
@ -6,6 +6,9 @@ import androidx.lifecycle.viewmodel.CreationExtras
|
|||||||
import androidx.lifecycle.viewmodel.initializer
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
import com.example.myapplication.CinemaApplication
|
import com.example.myapplication.CinemaApplication
|
||||||
|
import com.example.myapplication.composeui.Authenticator
|
||||||
|
import com.example.myapplication.composeui.AuthenticatorViewModel
|
||||||
|
import com.example.myapplication.composeui.CartViewModel
|
||||||
import com.example.myapplication.database.entities.composeui.edit.CinemaEditViewModel
|
import com.example.myapplication.database.entities.composeui.edit.CinemaEditViewModel
|
||||||
import com.example.myapplication.database.entities.composeui.edit.SessionEditViewModel
|
import com.example.myapplication.database.entities.composeui.edit.SessionEditViewModel
|
||||||
|
|
||||||
@ -57,6 +60,14 @@ object AppViewModelProvider {
|
|||||||
cinemaApplication().container.orderRestRepository,
|
cinemaApplication().container.orderRestRepository,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
initializer {
|
||||||
|
UserProfileViewModel(
|
||||||
|
cinemaApplication().container.userRestRepository,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
initializer {
|
||||||
|
AuthenticatorViewModel(cinemaApplication().container.userRestRepository)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@ -27,6 +28,7 @@ import androidx.compose.material3.Scaffold
|
|||||||
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.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
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
|
||||||
@ -36,8 +38,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.paging.compose.LazyPagingItems
|
import androidx.paging.compose.LazyPagingItems
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
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 kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -47,22 +51,25 @@ fun CinemaList(
|
|||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val cinemaPagingItems = viewModel.cinemaListUiState.collectAsLazyPagingItems()
|
val cinemaPagingItems = viewModel.cinemaListUiState.collectAsLazyPagingItems()
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {},
|
topBar = {},
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
FloatingActionButton(
|
if (user.value?.role == UserRole.ADMIN) {
|
||||||
onClick = {
|
FloatingActionButton(
|
||||||
val route = Screen.CinemaEdit.route.replace("{id}", 0.toString())
|
onClick = {
|
||||||
navController.navigate(route)
|
val route = Screen.CinemaEdit.route.replace("{id}", 0.toString())
|
||||||
},
|
navController.navigate(route)
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
},
|
||||||
) {
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
Icon(
|
) {
|
||||||
Icons.Filled.Add,
|
Icon(
|
||||||
"Добавить",
|
Icons.Filled.Add,
|
||||||
tint = MaterialTheme.colorScheme.onPrimary
|
"Добавить",
|
||||||
)
|
tint = MaterialTheme.colorScheme.onPrimary
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
@ -132,6 +139,7 @@ private fun CinemaListItem(
|
|||||||
onDeleteClick: (cinema: Cinema) -> Unit,
|
onDeleteClick: (cinema: Cinema) -> Unit,
|
||||||
onEditClick: (cinema: Int) -> Unit
|
onEditClick: (cinema: Int) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
@ -160,27 +168,29 @@ private fun CinemaListItem(
|
|||||||
color = MaterialTheme.colorScheme.onSecondary
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
)
|
)
|
||||||
|
|
||||||
// Добавляем пустое пространство для разделения текста и кнопки
|
if (user.value?.role == UserRole.ADMIN) {
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
// Добавляем пустое пространство для разделения текста и кнопки
|
||||||
IconButton(
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
onClick = { onEditClick(cinema.uid) },
|
IconButton(
|
||||||
modifier = Modifier.size(24.dp)
|
onClick = { onEditClick(cinema.uid) },
|
||||||
) {
|
modifier = Modifier.size(24.dp)
|
||||||
Icon(
|
) {
|
||||||
imageVector = Icons.Default.Edit,
|
Icon(
|
||||||
contentDescription = "Редактировать",
|
imageVector = Icons.Default.Edit,
|
||||||
tint = MaterialTheme.colorScheme.onSecondary,
|
contentDescription = "Редактировать",
|
||||||
)
|
tint = MaterialTheme.colorScheme.onSecondary,
|
||||||
}
|
)
|
||||||
IconButton(
|
}
|
||||||
onClick = { onDeleteClick(cinema) },
|
IconButton(
|
||||||
modifier = Modifier.size(24.dp)
|
onClick = { onDeleteClick(cinema) },
|
||||||
) {
|
modifier = Modifier.size(24.dp)
|
||||||
Icon(
|
) {
|
||||||
imageVector = Icons.Default.Delete,
|
Icon(
|
||||||
contentDescription = "Удалить",
|
imageVector = Icons.Default.Delete,
|
||||||
tint = MaterialTheme.colorScheme.onSecondary,
|
contentDescription = "Удалить",
|
||||||
)
|
tint = MaterialTheme.colorScheme.onSecondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
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.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.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
@ -29,8 +30,10 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
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.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
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CinemaView(
|
fun CinemaView(
|
||||||
@ -38,6 +41,7 @@ fun CinemaView(
|
|||||||
viewModel: CinemaViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
viewModel: CinemaViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
val cinemaUiState = viewModel.cinemaUiState
|
val cinemaUiState = viewModel.cinemaUiState
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
viewModel.refreshState()
|
viewModel.refreshState()
|
||||||
@ -116,21 +120,22 @@ fun CinemaView(
|
|||||||
.weight(1f) // Занимает доступное пространство
|
.weight(1f) // Занимает доступное пространство
|
||||||
.padding(top = 8.dp, bottom = 8.dp)
|
.padding(top = 8.dp, bottom = 8.dp)
|
||||||
)
|
)
|
||||||
|
if (user.value?.role == UserRole.ADMIN) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
val route = Screen.SessionEdit.route.replace("{id}", 0.toString())
|
val route = Screen.SessionEdit.route.replace("{id}", 0.toString())
|
||||||
.replace(
|
.replace(
|
||||||
"{cinemaId}",
|
"{cinemaId}",
|
||||||
cinemaUiState.cinemaWithSessions?.cinema?.uid.toString()
|
cinemaUiState.cinemaWithSessions?.cinema?.uid.toString()
|
||||||
)
|
)
|
||||||
navController.navigate(route)
|
navController.navigate(route)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Add,
|
||||||
|
contentDescription = "Добавить сеанс",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Add,
|
|
||||||
contentDescription = "Добавить сеанс",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cinemaUiState.cinemaWithSessions != null) {
|
if (cinemaUiState.cinemaWithSessions != null) {
|
||||||
|
@ -21,25 +21,6 @@ class CinemaViewModel(
|
|||||||
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// init {
|
|
||||||
// viewModelScope.launch {
|
|
||||||
// if (cinemaUid > 0) {
|
|
||||||
// cinemaUiState = CinemaUiState(cinemaRepository.getCinema(cinemaUid))
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// val cinemaUiState: mutableStateOf(CinemaUiState()) = cinemaRepository.getCinema(
|
|
||||||
// cinemaUid
|
|
||||||
// ).map
|
|
||||||
// {
|
|
||||||
// CinemaUiState(it)
|
|
||||||
// }.stateIn(
|
|
||||||
// scope = viewModelScope,
|
|
||||||
// started = SharingStarted.WhileSubscribed(stopTimeoutMillis = AppDataContainer.TIMEOUT),
|
|
||||||
// initialValue = CinemaUiState()
|
|
||||||
// )
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CinemaUiState(val cinemaWithSessions: CinemaWithSessions? = null)
|
data class CinemaUiState(val cinemaWithSessions: CinemaWithSessions? = null)
|
@ -30,14 +30,13 @@ import androidx.paging.compose.itemContentType
|
|||||||
import androidx.paging.compose.itemKey
|
import androidx.paging.compose.itemKey
|
||||||
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
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OrderList(
|
fun OrderList(
|
||||||
navController: NavController?,
|
navController: NavController?,
|
||||||
userId: Int?,
|
|
||||||
viewModel: OrderListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
viewModel: OrderListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
|
||||||
val ordersUiState = viewModel.orderListUiState.collectAsLazyPagingItems()
|
val ordersUiState = viewModel.orderListUiState.collectAsLazyPagingItems()
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -48,7 +47,9 @@ fun OrderList(
|
|||||||
key = ordersUiState.itemKey(),
|
key = ordersUiState.itemKey(),
|
||||||
contentType = ordersUiState.itemContentType()) { index ->
|
contentType = ordersUiState.itemContentType()) { index ->
|
||||||
val order = ordersUiState[index]
|
val order = ordersUiState[index]
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
|
||||||
val orderId = Screen.OrderView.route.replace("{id}", order!!.uid.toString())
|
val orderId = Screen.OrderView.route.replace("{id}", order!!.uid.toString())
|
||||||
|
val formattedDate = dateFormatter.format(order.dateTime)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -66,7 +67,7 @@ fun OrderList(
|
|||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
Text("Заказ №${order.uid}", color = MaterialTheme.colorScheme.onSecondary)
|
Text("Заказ №${order.uid}, ${formattedDate}", color = MaterialTheme.colorScheme.onSecondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +82,7 @@ fun OrderListPreview() {
|
|||||||
Surface(
|
Surface(
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.background
|
||||||
) {
|
) {
|
||||||
OrderList(navController = null, 1)
|
OrderList(navController = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.paging.PagingData
|
import androidx.paging.PagingData
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.database.AppDataContainer
|
import com.example.myapplication.database.AppDataContainer
|
||||||
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
|
||||||
@ -19,7 +20,7 @@ import kotlinx.coroutines.launch
|
|||||||
class OrderListViewModel(
|
class OrderListViewModel(
|
||||||
private val orderRepository: OrderRepository
|
private val orderRepository: OrderRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val orderListUiState: Flow<PagingData<Order>> = orderRepository.getAllOrders(1)
|
val orderListUiState: Flow<PagingData<Order>> = orderRepository.getAllOrders(LiveStore.user.value?.uid ?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class OrderListUiState(val orderList: List<Order> = listOf())
|
data class OrderListUiState(val orderList: List<Order> = listOf())
|
@ -22,6 +22,7 @@ import androidx.compose.material3.IconButton
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
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
|
||||||
@ -31,8 +32,10 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
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 androidx.navigation.NavController
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
import com.example.myapplication.R
|
import com.example.myapplication.R
|
||||||
import com.example.myapplication.composeui.navigation.Screen
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
|
import com.example.myapplication.database.entities.model.UserRole
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.threeten.bp.format.DateTimeFormatter
|
import org.threeten.bp.format.DateTimeFormatter
|
||||||
|
|
||||||
@ -44,6 +47,7 @@ fun SessionList(
|
|||||||
) {
|
) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val cinemaWithSessions = cinemaWithSessionsViewModel.cinemaUiState.cinemaWithSessions!!
|
val cinemaWithSessions = cinemaWithSessionsViewModel.cinemaUiState.cinemaWithSessions!!
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
if (cinemaWithSessions.sessions.isEmpty()) {
|
if (cinemaWithSessions.sessions.isEmpty()) {
|
||||||
@ -104,36 +108,39 @@ fun SessionList(
|
|||||||
color = MaterialTheme.colorScheme.onSecondary
|
color = MaterialTheme.colorScheme.onSecondary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (user.value?.role == UserRole.USER) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
if (session.availableCount != 0)
|
if (session.availableCount != 0)
|
||||||
viewModel.addSessionInCart(sessionId = session.uid)
|
viewModel.addSessionInCart(sessionId = session.uid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.ShoppingCart,
|
imageVector = Icons.Filled.ShoppingCart,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
tint = MaterialTheme.colorScheme.onSecondary
|
tint = MaterialTheme.colorScheme.onSecondary
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IconButton(
|
if (user.value?.role == UserRole.ADMIN) {
|
||||||
onClick = {
|
IconButton(
|
||||||
coroutineScope.launch {
|
onClick = {
|
||||||
viewModel.deleteSession(session = session)
|
coroutineScope.launch {
|
||||||
cinemaWithSessionsViewModel.refreshState()
|
viewModel.deleteSession(session = session)
|
||||||
}
|
cinemaWithSessionsViewModel.refreshState()
|
||||||
},
|
}
|
||||||
) {
|
},
|
||||||
Icon(
|
) {
|
||||||
imageVector = Icons.Default.Delete,
|
Icon(
|
||||||
contentDescription = null,
|
imageVector = Icons.Default.Delete,
|
||||||
modifier = Modifier.size(24.dp),
|
contentDescription = null,
|
||||||
tint = MaterialTheme.colorScheme.onSecondary
|
modifier = Modifier.size(24.dp),
|
||||||
)
|
tint = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.example.myapplication.database.entities.composeui
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
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
|
||||||
@ -25,7 +26,8 @@ class SessionListViewModel(
|
|||||||
|
|
||||||
suspend fun addSessionInCart(sessionId: Int, count: Int = 1) {
|
suspend fun addSessionInCart(sessionId: Int, count: Int = 1) {
|
||||||
try {
|
try {
|
||||||
userSessionRepository.insertUserSession(UserSessionCrossRef(1, sessionId, count))
|
val userId: Int = LiveStore.user.value?.uid ?: return
|
||||||
|
userSessionRepository.insertUserSession(UserSessionCrossRef(userId, sessionId, count))
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,29 +20,60 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
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.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
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.navigation.NavController
|
||||||
|
import com.example.myapplication.LiveStore
|
||||||
|
import com.example.myapplication.composeui.navigation.Screen
|
||||||
import com.example.myapplication.datastore.DataStoreManager
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
import com.example.myapplication.datastore.SettingData
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UserProfile(
|
fun UserProfile(
|
||||||
isDarkTheme: MutableState<Boolean>,
|
isDarkTheme: MutableState<Boolean>,
|
||||||
dataStoreManager: DataStoreManager
|
dataStoreManager: DataStoreManager,
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: UserProfileViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
) {
|
) {
|
||||||
var username by remember { mutableStateOf("") }
|
|
||||||
var password by remember { mutableStateOf("") }
|
|
||||||
var isRegistration by remember { mutableStateOf(false) }
|
var isRegistration by remember { mutableStateOf(false) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val coroutine = rememberCoroutineScope()
|
||||||
|
val errorStringId: Int? = viewModel.userUiState.errorId
|
||||||
|
val errorMessage = if (errorStringId == null) "" else stringResource(errorStringId)
|
||||||
|
val user = LiveStore.user.observeAsState()
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
|
Text(
|
||||||
|
text = "Текущий пользователь: " + (LiveStore.user.value?.login ?: ""),
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
enabled = user.value != null,
|
||||||
|
onClick = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
dataStoreManager.setLogin("")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
Text("Выход")
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = errorMessage,
|
||||||
|
color = Color.Red
|
||||||
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@ -54,8 +85,10 @@ fun UserProfile(
|
|||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
)
|
)
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = username,
|
value = viewModel.userUiState.details.login,
|
||||||
onValueChange = { newValue -> username = newValue },
|
onValueChange = {
|
||||||
|
viewModel.updateUiState(viewModel.userUiState.details.copy(login = it))
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.size(36.dp)
|
.size(36.dp)
|
||||||
@ -68,8 +101,10 @@ fun UserProfile(
|
|||||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||||
)
|
)
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = password,
|
value = viewModel.userUiState.details.password,
|
||||||
onValueChange = { newValue -> password = newValue },
|
onValueChange = {
|
||||||
|
viewModel.updateUiState(viewModel.userUiState.details.copy(password = it))
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.size(36.dp)
|
.size(36.dp)
|
||||||
@ -80,7 +115,12 @@ fun UserProfile(
|
|||||||
|
|
||||||
if (isRegistration) {
|
if (isRegistration) {
|
||||||
Button(
|
Button(
|
||||||
onClick = { },
|
onClick = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
val flag = viewModel.signUp()
|
||||||
|
isRegistration = !flag
|
||||||
|
}
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
@ -98,7 +138,13 @@ fun UserProfile(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Button(
|
Button(
|
||||||
onClick = { },
|
onClick = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
if (viewModel.signIn(dataStoreManager)) {
|
||||||
|
navController.navigate(Screen.CinemaList.route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
@ -133,14 +179,16 @@ fun UserProfile(
|
|||||||
.padding(5.dp)
|
.padding(5.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
val coroutine = rememberCoroutineScope()
|
|
||||||
|
|
||||||
Switch(
|
Switch(
|
||||||
checked = isDarkTheme.value,
|
checked = isDarkTheme.value,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
isDarkTheme.value = !isDarkTheme.value
|
isDarkTheme.value = !isDarkTheme.value
|
||||||
coroutine.launch {
|
coroutine.launch {
|
||||||
dataStoreManager.saveSettings(SettingData(isDarkTheme = isDarkTheme.value))
|
if (isDarkTheme.value) {
|
||||||
|
dataStoreManager.setDarkTheme("Dark")
|
||||||
|
} else {
|
||||||
|
dataStoreManager.setDarkTheme("Light")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = switchColors
|
colors = switchColors
|
||||||
@ -150,16 +198,3 @@ fun UserProfile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*@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 UserProfilePreview() {
|
|
||||||
PmudemoTheme {
|
|
||||||
Surface(
|
|
||||||
color = MaterialTheme.colorScheme.background
|
|
||||||
) {
|
|
||||||
UserProfile(navController = null, isDarkTheme = remember { mutableStateOf(true) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.example.myapplication.database.entities.composeui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.example.myapplication.R
|
||||||
|
import com.example.myapplication.database.entities.model.User
|
||||||
|
import com.example.myapplication.database.entities.repository.UserRepository
|
||||||
|
import com.example.myapplication.datastore.DataStoreManager
|
||||||
|
|
||||||
|
class UserProfileViewModel(
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
var userUiState by mutableStateOf(UserUiState())
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun updateUiState(userDetails: UserDetails) {
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userDetails,
|
||||||
|
errorId = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun signIn(dataStoreManager: DataStoreManager): Boolean {
|
||||||
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
|
if (errorId == null) {
|
||||||
|
val overlap = userRepository.getUser(userUiState.details.login)
|
||||||
|
if (overlap == null || userUiState.details.password != overlap.password) {
|
||||||
|
errorId = R.string.err_04
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
errorId = errorId
|
||||||
|
)
|
||||||
|
if (errorId == null) {
|
||||||
|
dataStoreManager.setLogin(userUiState.details.login)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun signUp(): Boolean {
|
||||||
|
var errorId: Int? = validateInput(userUiState.details)
|
||||||
|
if (errorId == null) {
|
||||||
|
val overlap = userRepository.getUser(userUiState.details.login)
|
||||||
|
if (overlap != null) {
|
||||||
|
errorId = R.string.err_03
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userUiState = UserUiState(
|
||||||
|
details = userUiState.details,
|
||||||
|
errorId = errorId
|
||||||
|
)
|
||||||
|
if (errorId == null) {
|
||||||
|
userRepository.insertUser(userUiState.details.toUser())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun validateInput(details: UserDetails = userUiState.details): Int? {
|
||||||
|
return if (details.login.isBlank()) {
|
||||||
|
R.string.err_01
|
||||||
|
} else if (details.password.isBlank()) {
|
||||||
|
R.string.err_02
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UserDetails(
|
||||||
|
val login: String = "",
|
||||||
|
val password: String = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
data class UserUiState(
|
||||||
|
val details: UserDetails = UserDetails(),
|
||||||
|
val errorId: Int? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
fun UserDetails.toUser(uid: Int = 0): User = User(
|
||||||
|
uid = uid,
|
||||||
|
login = login,
|
||||||
|
password = password,
|
||||||
|
)
|
@ -14,6 +14,9 @@ interface UserDao {
|
|||||||
@Query("select * from users order by login collate nocase asc")
|
@Query("select * from users order by login collate nocase asc")
|
||||||
fun getAll(): Flow<List<User>>
|
fun getAll(): Flow<List<User>>
|
||||||
|
|
||||||
|
@Query("select * from users where users.login=:login LIMIT 1")
|
||||||
|
suspend fun getByLogin(login: String): User?
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"SELECT sessions.*, sessions.max_count-IFNULL(SUM(orders_sessions.count), 0) as available_count, " +
|
"SELECT sessions.*, sessions.max_count-IFNULL(SUM(orders_sessions.count), 0) as available_count, " +
|
||||||
"users_sessions.count FROM sessions " +
|
"users_sessions.count FROM sessions " +
|
||||||
|
@ -4,23 +4,18 @@ import androidx.room.ColumnInfo
|
|||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.ForeignKey
|
import androidx.room.ForeignKey
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
|
import org.threeten.bp.LocalDateTime
|
||||||
|
|
||||||
@Entity(
|
@Entity(
|
||||||
tableName = "orders", foreignKeys = [
|
tableName = "orders"
|
||||||
ForeignKey(
|
|
||||||
entity = User::class,
|
|
||||||
parentColumns = ["uid"],
|
|
||||||
childColumns = ["user_id"],
|
|
||||||
onDelete = ForeignKey.RESTRICT,
|
|
||||||
onUpdate = ForeignKey.RESTRICT
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
data class Order(
|
data class Order(
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
val uid: Int,
|
val uid: Int,
|
||||||
@ColumnInfo(name = "user_id", index = true)
|
@ColumnInfo(name = "user_id", index = true)
|
||||||
val userId: Int?,
|
val userId: Int?,
|
||||||
|
@ColumnInfo(name = "date_time")
|
||||||
|
val dateTime: LocalDateTime,
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -8,7 +8,8 @@ data class User(
|
|||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
val uid: Int = 0,
|
val uid: Int = 0,
|
||||||
val login: String,
|
val login: String,
|
||||||
val password: String
|
val password: String,
|
||||||
|
val role: UserRole = UserRole.USER
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.myapplication.database.entities.model
|
||||||
|
|
||||||
|
enum class UserRole(val value: Int) {
|
||||||
|
USER(0),
|
||||||
|
ADMIN(1)
|
||||||
|
}
|
@ -8,6 +8,8 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
class OfflineUserRepository(private val userDao: UserDao) : UserRepository {
|
||||||
override fun getAllUsers(): Flow<List<User>> = userDao.getAll()
|
override fun getAllUsers(): Flow<List<User>> = userDao.getAll()
|
||||||
|
|
||||||
|
override suspend fun getUser(login: String): User? = userDao.getByLogin(login)
|
||||||
|
|
||||||
override suspend fun getCartByUser(userId: Int): List<SessionFromCart> =
|
override suspend fun getCartByUser(userId: Int): List<SessionFromCart> =
|
||||||
userDao.getCartByUid(userId)
|
userDao.getCartByUid(userId)
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
|
|
||||||
interface UserRepository {
|
interface UserRepository {
|
||||||
fun getAllUsers(): Flow<List<User>>
|
fun getAllUsers(): Flow<List<User>>
|
||||||
|
suspend fun getUser(login: String): User?
|
||||||
suspend fun getCartByUser(userId: Int): List<SessionFromCart>
|
suspend fun getCartByUser(userId: Int): List<SessionFromCart>
|
||||||
suspend fun insertUser(user: User)
|
suspend fun insertUser(user: User)
|
||||||
suspend fun updateUser(user: User)
|
suspend fun updateUser(user: User)
|
||||||
|
@ -5,21 +5,46 @@ import androidx.datastore.core.DataStore
|
|||||||
import androidx.datastore.preferences.core.Preferences
|
import androidx.datastore.preferences.core.Preferences
|
||||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||||
import androidx.datastore.preferences.core.edit
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
import androidx.datastore.preferences.preferencesDataStore
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("data_store")
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("data_store")
|
||||||
|
|
||||||
class DataStoreManager(private val context: Context) {
|
class DataStoreManager(private val context: Context) {
|
||||||
suspend fun saveSettings(settingData: SettingData) {
|
|
||||||
context.dataStore.edit { pref ->
|
companion object {
|
||||||
pref[booleanPreferencesKey("isDarkTheme")] = settingData.isDarkTheme
|
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore("Store")
|
||||||
|
val DARK_THEME = stringPreferencesKey("dark_theme")
|
||||||
|
val LOGIN = stringPreferencesKey("login")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDarkTheme(): Flow<String> {
|
||||||
|
return context.dataStore.data
|
||||||
|
.map { preferences ->
|
||||||
|
preferences[DARK_THEME] ?: "Dark"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLogin(): Flow<String> {
|
||||||
|
return context.dataStore.data
|
||||||
|
.map { preferences ->
|
||||||
|
preferences[LOGIN] ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun saveStringValue(key: Preferences.Key<String>, value: String) {
|
||||||
|
context.dataStore.edit { preferences ->
|
||||||
|
preferences[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSettings() = context.dataStore.data.map { pref ->
|
suspend fun setDarkTheme(darkTheme: String) {
|
||||||
return@map SettingData(
|
saveStringValue(DARK_THEME, darkTheme)
|
||||||
pref[booleanPreferencesKey("isDarkTheme")] ?: true
|
}
|
||||||
)
|
|
||||||
|
suspend fun setLogin(login: String) {
|
||||||
|
saveStringValue(LOGIN, login)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +0,0 @@
|
|||||||
package com.example.myapplication.datastore
|
|
||||||
|
|
||||||
data class SettingData(
|
|
||||||
val isDarkTheme: Boolean
|
|
||||||
)
|
|
@ -19,4 +19,8 @@
|
|||||||
<string name="session_cinema_not_select">Фильм не указан</string>
|
<string name="session_cinema_not_select">Фильм не указан</string>
|
||||||
<string name="size">Размер загруженного изображения: %1$dx%2$d</string>
|
<string name="size">Размер загруженного изображения: %1$dx%2$d</string>
|
||||||
<string name="not_uploaded">Загрузите изображение</string>
|
<string name="not_uploaded">Загрузите изображение</string>
|
||||||
|
<string name="err_01">Введите логин</string>
|
||||||
|
<string name="err_02">Введите пароль</string>
|
||||||
|
<string name="err_03">Логин занят</string>
|
||||||
|
<string name="err_04">Неверный логин или пароль</string>
|
||||||
</resources>
|
</resources>
|
70088
server/.~data.json
70088
server/.~data.json
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,19 @@
|
|||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"login": "login",
|
"login": "admin",
|
||||||
"password": "password",
|
"password": "admin",
|
||||||
|
"role": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"login": "qwe",
|
||||||
|
"password": "qwe",
|
||||||
|
"role": 0,
|
||||||
"sessions": [
|
"sessions": [
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 6,
|
||||||
"count": 4,
|
"count": 7,
|
||||||
"cinemaId": 2
|
"cinemaId": 2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -16,7 +23,8 @@
|
|||||||
"orders": [
|
"orders": [
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"userId": 1,
|
"userId": 2,
|
||||||
|
"dateTime": "19.12.2022 02:15",
|
||||||
"sessions": [
|
"sessions": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
@ -29,15 +37,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"userId": 1,
|
"userId": 2,
|
||||||
|
"dateTime": "13.12.2023 19:03",
|
||||||
"sessions": [
|
"sessions": [
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"dateTime": "20.12.2022 02:15",
|
|
||||||
"frozenPrice": 150,
|
|
||||||
"count": 3,
|
|
||||||
"cinemaId": 3
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"dateTime": "04.04.2004 00:00",
|
"dateTime": "04.04.2004 00:00",
|
||||||
@ -46,50 +48,6 @@
|
|||||||
"cinemaId": 2
|
"cinemaId": 2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"userId": 1,
|
|
||||||
"sessions": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"dateTime": "20.12.2022 02:15",
|
|
||||||
"frozenPrice": 150,
|
|
||||||
"count": 1,
|
|
||||||
"cinemaId": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"dateTime": "04.04.2004 00:00",
|
|
||||||
"frozenPrice": 1234,
|
|
||||||
"count": 1,
|
|
||||||
"cinemaId": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"userId": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 6,
|
|
||||||
"userId": 1,
|
|
||||||
"sessions": [
|
|
||||||
{
|
|
||||||
"id": 5,
|
|
||||||
"dateTime": "04.04.2004 00:00",
|
|
||||||
"frozenPrice": 1234,
|
|
||||||
"count": 5,
|
|
||||||
"cinemaId": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"dateTime": "22.03.2021 03:15",
|
|
||||||
"frozenPrice": 100,
|
|
||||||
"count": 5,
|
|
||||||
"cinemaId": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sessions": [
|
"sessions": [
|
||||||
@ -113,11 +71,19 @@
|
|||||||
"maxCount": 15,
|
"maxCount": 15,
|
||||||
"cinemaId": 2,
|
"cinemaId": 2,
|
||||||
"id": 5
|
"id": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"dateTime": "22.02.2022 03:15",
|
||||||
|
"price": 100,
|
||||||
|
"maxCount": 500,
|
||||||
|
"cinemaId": 2
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"cinemas": [
|
"cinemas": [
|
||||||
{
|
{
|
||||||
"name": "кино",
|
"id": 2,
|
||||||
|
"name": "кино123",
|
||||||
"description": "кино",
|
"description": "кино",
|
||||||
"image": [
|
"image": [
|
||||||
-1,
|
-1,
|
||||||
@ -39085,8 +39051,7 @@
|
|||||||
-1,
|
-1,
|
||||||
-39
|
-39
|
||||||
],
|
],
|
||||||
"year": 2010,
|
"year": 2010
|
||||||
"id": 2
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
|
Loading…
Reference in New Issue
Block a user