поиск и бронирования пользователя работают
This commit is contained in:
parent
a270794281
commit
51771c73c0
@ -0,0 +1,244 @@
|
|||||||
|
package ru.ulstu.`is`.airticketrentservice.screen
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.spring
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.pullrefresh.PullRefreshIndicator
|
||||||
|
import androidx.compose.material.pullrefresh.pullRefresh
|
||||||
|
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.DismissDirection
|
||||||
|
import androidx.compose.material3.DismissState
|
||||||
|
import androidx.compose.material3.DismissValue
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FloatingActionButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SwipeToDismiss
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.rememberDismissState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.colorResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.paging.compose.LazyPagingItems
|
||||||
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
|
import androidx.paging.compose.itemContentType
|
||||||
|
import androidx.paging.compose.itemKey
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.R
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.database.models.Ticket
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.FlightListViewModel
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.TicketListViewModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TicketList(
|
||||||
|
navController: NavController,
|
||||||
|
flightListViewModel: FlightListViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
|
viewModel: TicketListViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
|
) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val ticketListUiState = viewModel.ticketListUiState.collectAsLazyPagingItems()
|
||||||
|
Scaffold(
|
||||||
|
topBar = {},
|
||||||
|
floatingActionButton = {
|
||||||
|
FloatingActionButton(
|
||||||
|
onClick = {
|
||||||
|
val route = BottomBarScreen.TicketEdit.passId(0.toString())
|
||||||
|
navController.navigate(route)
|
||||||
|
},
|
||||||
|
containerColor = colorResource(R.color.lightlightBlue)
|
||||||
|
) {
|
||||||
|
Icon(Icons.Filled.Add, "Добавить")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { innerPadding ->
|
||||||
|
TicketList(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(innerPadding)
|
||||||
|
.fillMaxSize(),
|
||||||
|
ticketList = ticketListUiState,
|
||||||
|
onClick = { id: Int ->
|
||||||
|
val route = BottomBarScreen.TicketEdit.passId(id.toString())
|
||||||
|
navController.navigate(route)
|
||||||
|
},
|
||||||
|
onSwipe = { ticket: Ticket ->
|
||||||
|
coroutineScope.launch {
|
||||||
|
viewModel.deleteTicket(ticket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun DismissBackground(dismissState: DismissState) {
|
||||||
|
val color = when (dismissState.dismissDirection) {
|
||||||
|
DismissDirection.StartToEnd -> Color.Transparent
|
||||||
|
DismissDirection.EndToStart -> Color(0xFFFF1744)
|
||||||
|
null -> Color.Transparent
|
||||||
|
}
|
||||||
|
val direction = dismissState.dismissDirection
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(color)
|
||||||
|
.padding(12.dp, 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.End
|
||||||
|
) {
|
||||||
|
if (direction == DismissDirection.EndToStart) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Delete,
|
||||||
|
contentDescription = "delete",
|
||||||
|
tint = Color.White
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun SwipeToDelete(
|
||||||
|
dismissState: DismissState,
|
||||||
|
ticket: Ticket,
|
||||||
|
onClick: (id: Int) -> Unit
|
||||||
|
) {
|
||||||
|
SwipeToDismiss(
|
||||||
|
modifier = Modifier.zIndex(1f),
|
||||||
|
state = dismissState,
|
||||||
|
directions = setOf(
|
||||||
|
DismissDirection.EndToStart
|
||||||
|
),
|
||||||
|
background = {
|
||||||
|
DismissBackground(dismissState)
|
||||||
|
},
|
||||||
|
dismissContent = {
|
||||||
|
TicketListItem(ticket = ticket,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 7.dp)
|
||||||
|
.clickable { onClick(ticket.id) })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
private fun TicketList(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
ticketList: LazyPagingItems<Ticket>,
|
||||||
|
onClick: (id: Int) -> Unit,
|
||||||
|
onSwipe: (ticket: Ticket) -> Unit
|
||||||
|
) {
|
||||||
|
val refreshScope = rememberCoroutineScope()
|
||||||
|
var refreshing by remember { mutableStateOf(false) }
|
||||||
|
fun refresh() = refreshScope.launch {
|
||||||
|
refreshing = true
|
||||||
|
ticketList.refresh()
|
||||||
|
refreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
val state = rememberPullRefreshState(refreshing, ::refresh)
|
||||||
|
Box(
|
||||||
|
modifier = modifier.pullRefresh(state)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
LazyColumn(modifier = Modifier.padding(all = 10.dp)) {
|
||||||
|
items(
|
||||||
|
count = ticketList.itemCount,
|
||||||
|
key = ticketList.itemKey(),
|
||||||
|
contentType = ticketList.itemContentType()
|
||||||
|
) { index ->
|
||||||
|
val ticket = ticketList[index]
|
||||||
|
ticket?.let {
|
||||||
|
var show by remember { mutableStateOf(true) }
|
||||||
|
val dismissState = rememberDismissState(
|
||||||
|
confirmValueChange = {
|
||||||
|
if (it == DismissValue.DismissedToStart ||
|
||||||
|
it == DismissValue.DismissedToEnd
|
||||||
|
) {
|
||||||
|
show = false
|
||||||
|
true
|
||||||
|
} else false
|
||||||
|
}, positionalThreshold = { 200.dp.toPx() }
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
show, exit = fadeOut(spring())
|
||||||
|
) {
|
||||||
|
SwipeToDelete(
|
||||||
|
dismissState = dismissState,
|
||||||
|
ticket = ticket,
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(show) {
|
||||||
|
if (!show) {
|
||||||
|
delay(800)
|
||||||
|
onSwipe(ticket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PullRefreshIndicator(
|
||||||
|
refreshing, state,
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.zIndex(100f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TicketListItem(
|
||||||
|
ticket: Ticket, modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier.padding(all = 10.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Билет ${ticket.id}, Стоимость: ${ticket.ticket_cost}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
package ru.ulstu.`is`.airticketrentservice.screen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextField
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableDoubleStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.colorResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.R
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.FlightEditViewModel
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.FlightUiState
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.TicketDetails
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.TicketEditViewModel
|
||||||
|
import ru.ulstu.`is`.airticketrentservice.viewModel.TicketUiState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TicketView(
|
||||||
|
navController: NavController,
|
||||||
|
viewModel: TicketEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
|
||||||
|
flightViewModel: FlightEditViewModel = viewModel(factory = AppViewModelProvider.Factory)
|
||||||
|
) {
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
flightViewModel.setCurrentFlight(viewModel.ticketUiState.ticketDetails.flightId)
|
||||||
|
val totalCost by remember { mutableDoubleStateOf(flightViewModel.flightUiState.flightDetails.one_ticket_cost * viewModel.ticketUiState.ticketDetails.passengers_count.toDouble()) }
|
||||||
|
TicketEdit(
|
||||||
|
ticketUiState = viewModel.ticketUiState,
|
||||||
|
flightUiState = flightViewModel.flightUiState,
|
||||||
|
onClick = {
|
||||||
|
coroutineScope.launch {
|
||||||
|
viewModel.saveTicket()
|
||||||
|
navController.navigate(BottomBarScreen.RentEdit.passId(0.toString()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUpdate = viewModel::updateUiState,
|
||||||
|
totalCost = totalCost
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun TicketEdit(
|
||||||
|
ticketUiState: TicketUiState,
|
||||||
|
flightUiState: FlightUiState,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onUpdate: (TicketDetails) -> Unit,
|
||||||
|
totalCost: Double
|
||||||
|
) {
|
||||||
|
//ticketUiState.ticketDetails.ticket_cost = totalCost
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(all = 10.dp)
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(vertical = 32.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = flightUiState.flightDetails.direction_from,
|
||||||
|
onValueChange = {},
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text(stringResource(id = R.string.ticket_from)) },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = flightUiState.flightDetails.direction_to,
|
||||||
|
onValueChange = {},
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text(stringResource(id = R.string.ticket_to)) },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = flightUiState.flightDetails.departure_date,
|
||||||
|
onValueChange = {},
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text(stringResource(id = R.string.ticket_arrivalDate)) },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = flightUiState.flightDetails.arrival_date,
|
||||||
|
onValueChange = {},
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text(stringResource(id = R.string.ticket_departureDate)) },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = totalCost.toString(),
|
||||||
|
onValueChange = { onUpdate(ticketUiState.ticketDetails.copy(ticket_cost = it.toDouble())) },
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text("Стоимость билета") },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = ticketUiState.ticketDetails.passengers_count.toString(),
|
||||||
|
onValueChange = { onUpdate(ticketUiState.ticketDetails.copy(passengers_count = it.toInt())) },
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text("Количество пассажиров") },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
value = totalCost.toString(),
|
||||||
|
onValueChange = {},
|
||||||
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
|
containerColor = Color.LightGray.copy(.2f),
|
||||||
|
unfocusedIndicatorColor = Color.Transparent,
|
||||||
|
focusedIndicatorColor = Color.Transparent
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
label = { Text("Стоимость за всех пассажиров") },
|
||||||
|
singleLine = true,
|
||||||
|
readOnly = true
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
enabled = ticketUiState.isEntryValid,
|
||||||
|
elevation = ButtonDefaults.buttonElevation(
|
||||||
|
defaultElevation = 10.dp,
|
||||||
|
pressedElevation = 6.dp
|
||||||
|
),
|
||||||
|
shape = RoundedCornerShape(15.dp),
|
||||||
|
colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.lightBlue)),
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text(text = "Забронировать")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user