Compare commits

..

2 Commits

16 changed files with 244 additions and 915 deletions

View File

@ -7,7 +7,6 @@ import androidx.paging.PagingSource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import ru.ulstu.`is`.airticketrentservice.database.dao.TicketDao import ru.ulstu.`is`.airticketrentservice.database.dao.TicketDao
import ru.ulstu.`is`.airticketrentservice.database.models.Flight
import ru.ulstu.`is`.airticketrentservice.database.models.Ticket import ru.ulstu.`is`.airticketrentservice.database.models.Ticket
class OfflineTicketRepository(private val ticketDao: TicketDao) : TicketRepository { class OfflineTicketRepository(private val ticketDao: TicketDao) : TicketRepository {
@ -27,5 +26,5 @@ class OfflineTicketRepository(private val ticketDao: TicketDao) : TicketReposito
override suspend fun getFlightsTickets(flightId: Int): List<Ticket> = ticketDao.getFlightsTickets(flightId) override suspend fun getFlightsTickets(flightId: Int): List<Ticket> = ticketDao.getFlightsTickets(flightId)
suspend fun clearTickets() = ticketDao.deleteAll() suspend fun clearTickets() = ticketDao.deleteAll()
suspend fun insertTickets(tickets: List<Ticket>) = suspend fun insertTickets(tickets: List<Ticket>) =
ticketDao.insert(*tickets.toTypedArray())[0] ticketDao.insert(*tickets.toTypedArray())
} }

View File

@ -18,6 +18,7 @@ import ru.ulstu.`is`.airticketrentservice.screen.MyRents
import ru.ulstu.`is`.airticketrentservice.screen.Profile import ru.ulstu.`is`.airticketrentservice.screen.Profile
import ru.ulstu.`is`.airticketrentservice.screen.RentEdit import ru.ulstu.`is`.airticketrentservice.screen.RentEdit
import ru.ulstu.`is`.airticketrentservice.screen.RentList import ru.ulstu.`is`.airticketrentservice.screen.RentList
import ru.ulstu.`is`.airticketrentservice.screen.RentStatusEdit
import ru.ulstu.`is`.airticketrentservice.screen.TicketEdit import ru.ulstu.`is`.airticketrentservice.screen.TicketEdit
import ru.ulstu.`is`.airticketrentservice.screen.TicketList import ru.ulstu.`is`.airticketrentservice.screen.TicketList
import ru.ulstu.`is`.airticketrentservice.screen.TicketView import ru.ulstu.`is`.airticketrentservice.screen.TicketView
@ -109,7 +110,17 @@ fun HomeNavGraph(
} }
) )
){ ){
RentEdit(navController) RentEdit()
}
composable(
route = BottomBarScreen.RentStatusEdit.route,
arguments = listOf(
navArgument("id") {
type = NavType.IntType
}
)
){
RentStatusEdit(navController)
} }
composable( composable(
route = BottomBarScreen.FlightEdit.route, route = BottomBarScreen.FlightEdit.route,

View File

@ -1,25 +1,18 @@
package ru.ulstu.`is`.airticketrentservice.navigation package ru.ulstu.`is`.airticketrentservice.navigation
import android.content.res.Configuration
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
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.getValue import androidx.compose.runtime.getValue
@ -28,21 +21,22 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDestination import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import ru.ulstu.`is`.airticketrentservice.R import ru.ulstu.`is`.airticketrentservice.R
import ru.ulstu.`is`.airticketrentservice.ui.theme.AirTicketRentServiceTheme import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
import ru.ulstu.`is`.airticketrentservice.viewModel.CurrentUserViewModel
@Composable @Composable
fun BottomBar(navController: NavHostController){ fun BottomBar(navController: NavHostController, currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)){
val screens = listOf( val screens = listOf(
BottomBarScreen.MainPage, BottomBarScreen.MainPage,
BottomBarScreen.Profile, BottomBarScreen.Profile,
@ -65,11 +59,14 @@ fun BottomBar(navController: NavHostController){
.clip(shape = RoundedCornerShape(20.dp)) .clip(shape = RoundedCornerShape(20.dp))
) { ) {
screens.forEach { screen -> screens.forEach { screen ->
AddItem( currentUserViewModel.user?.role?.let {
screen = screen, AddItem(
currentDestination = currentDestination, screen = screen,
navController = navController currentDestination = currentDestination,
) navController = navController,
userRole = it
)
}
} }
} }
} }
@ -80,34 +77,37 @@ fun BottomBar(navController: NavHostController){
fun RowScope.AddItem( fun RowScope.AddItem(
screen: BottomBarScreen, screen: BottomBarScreen,
currentDestination: NavDestination?, currentDestination: NavDestination?,
navController: NavController navController: NavController,
userRole: String
){ ){
val isAdmin = userRole == "Admin"
val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true val selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true
val background = if (selected) Color(0xFFFFFFFF) else Color.Transparent val background = if (selected) Color(0xFFFFFFFF) else Color.Transparent
if (isAdmin || screen != BottomBarScreen.Admin) {
Box(
Box( modifier = Modifier
modifier = Modifier .height(40.dp)
.height(40.dp) .clip(CircleShape)
.clip(CircleShape) .background(background)
.background(background) .clickable(onClick = {
.clickable(onClick = { navController.navigate(screen.route) {
navController.navigate(screen.route) { popUpTo(navController.graph.findStartDestination().id)
popUpTo(navController.graph.findStartDestination().id) launchSingleTop = true
launchSingleTop = true }
} })
})
) {
Row(
modifier = Modifier.padding(start = 47.dp, end = 46.dp),
verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon( Row(
imageVector = screen.icon, modifier = Modifier.padding(start = 47.dp, end = 46.dp, top = 10.dp),
contentDescription = "icon", verticalAlignment = Alignment.CenterVertically,
tint = Color.DarkGray ) {
) Icon(
imageVector = screen.icon,
contentDescription = "icon",
tint = Color.DarkGray
)
}
} }
} else {
Text(text = "Недостаточно прав", fontSize = 8.sp, modifier = Modifier.fillMaxWidth().padding(top = 10.dp))
} }
} }

View File

@ -112,6 +112,15 @@ sealed class BottomBarScreen(
return "rent-edit/$id" return "rent-edit/$id"
} }
} }
object RentStatusEdit: BottomBarScreen(
route = "rent-status-edit/{id}",
title ="",
icon = Icons.Filled.AccountCircle
) {
fun passId(id: String): String{
return "rent-status-edit/$id"
}
}
object TicketEdit: BottomBarScreen( object TicketEdit: BottomBarScreen(
route = "ticket-edit/{id}", route = "ticket-edit/{id}",
title ="", title ="",

View File

@ -1,362 +0,0 @@
package ru.ulstu.`is`.airticketrentservice.navigation
import android.annotation.SuppressLint
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationBarItemDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
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.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import androidx.navigation.navigation
import ru.ulstu.`is`.airticketrentservice.screen.RentList
import ru.ulstu.`is`.airticketrentservice.screen.UserEdit
import ru.ulstu.`is`.airticketrentservice.screen.FlightEdit
import ru.ulstu.`is`.airticketrentservice.R
import ru.ulstu.`is`.airticketrentservice.screen.Admin
import ru.ulstu.`is`.airticketrentservice.screen.FlightInfo
import ru.ulstu.`is`.airticketrentservice.screen.FlightList
import ru.ulstu.`is`.airticketrentservice.screen.FoundFlights
import ru.ulstu.`is`.airticketrentservice.screen.LoadScreen
import ru.ulstu.`is`.airticketrentservice.screen.MainPage
import ru.ulstu.`is`.airticketrentservice.screen.MyRents
import ru.ulstu.`is`.airticketrentservice.screen.Profile
import ru.ulstu.`is`.airticketrentservice.screen.RentEdit
import ru.ulstu.`is`.airticketrentservice.screen.TicketEdit
import ru.ulstu.`is`.airticketrentservice.screen.UserList
import ru.ulstu.`is`.airticketrentservice.screen.auth.Login
import ru.ulstu.`is`.airticketrentservice.screen.auth.Registration
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
import ru.ulstu.`is`.airticketrentservice.viewModel.CurrentUserViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.FlightEditViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.FlightListViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.LoginViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.RegistrationViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.RentEditViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.RentListViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.TicketEditViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.UserEditViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.UserListViewModel
//@OptIn(ExperimentalMaterial3Api::class)
//@Composable
//fun Topbar(
// navController: NavHostController,
// currentScreen: Screen?
//) {
// TopAppBar(
// colors = TopAppBarDefaults.topAppBarColors(
// containerColor = Color.Transparent,
// ),
// title = {},
// navigationIcon = {
// if (
// navController.previousBackStackEntry != null
// && (currentScreen == null || !currentScreen.showInBottomBar)
// ) {
// IconButton(onClick = { navController.navigateUp() }) {
// Icon(
// imageVector = Icons.Filled.ArrowBack,
// contentDescription = null,
// tint = colorResource(R.color.black)
// )
// }
// }
// },
// modifier = Modifier
// .padding(10.dp)
// .clip(RoundedCornerShape(20.dp))
// )
//}
//
//@Composable
//fun Navbar(
// navController: NavHostController,
// currentDestination: NavDestination?
//) {
// NavigationBar(
// Modifier
// .padding(10.dp)
// .clip(RoundedCornerShape(20.dp))) {
// Screen.bottomBarItems.forEach { screen ->
// NavigationBarItem(
// colors = NavigationBarItemDefaults.colors(colorResource(R.color.lightBlue)),
// icon = { Icon(screen.icon, contentDescription = null) },
// label = { Text(stringResource(screen.resourceId)) },
// selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
// onClick = {
// navController.navigate(screen.route) {
// popUpTo(navController.graph.findStartDestination().id) {
// saveState = true
// }
// launchSingleTop = true
// restoreState = true
// }
// }
// )
// }
// }
//}
//
//const val USERID_ARGUMENT="userId"
//@Composable
//fun RootNavGraph(
// navController: NavHostController,
// registrationViewModel: RegistrationViewModel= viewModel(factory = AppViewModelProvider.Factory),
// loginViewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory),
// currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
//) {
// NavHost(
// navController = navController,
// route = Graph.ROOT,
// startDestination = Graph.AUTHENTICATION
// ) {
// authNavGraph(navController = navController, registrationViewModel, loginViewModel, currentUserViewModel)
// composable(route=Graph.MAIN,
// arguments = listOf(navArgument(USERID_ARGUMENT){
// type= NavType.StringType
// })){
// LoadScreen(
// navController = navController,
// currentUserViewModel = currentUserViewModel
// )
// }
// }
//}
//
//fun NavGraphBuilder.authNavGraph(navController: NavHostController, registrationViewModel: RegistrationViewModel, loginViewModel: LoginViewModel, currentUserViewModel: CurrentUserViewModel){
// navigation(
// route=Graph.AUTHENTICATION,
// startDestination = AuthScreen.Login.route
// ){
// composable(route=AuthScreen.Login.route){
// Login(navController = navController, Modifier, loginViewModel, currentUserViewModel)
// }
// composable(route=AuthScreen.Registration.route){
// Registration(navController = navController, Modifier, registrationViewModel, currentUserViewModel)
// }
// }
//}
//
//sealed class AuthScreen(val route: String){
// object Login : AuthScreen(route = "login")
// object Registration : AuthScreen(route="registration")
//}
//
//@Composable
//fun HomeNavGraph(
// navController: NavHostController,
// currentUserViewModel: CurrentUserViewModel
//) {
// NavHost(
// navController = navController,
// startDestination = Screen.MainPage.route
// ) {
// composable(Screen.MainPage.route) { MainPage(navController) }
// composable(Screen.RentList.route) { RentList(navController) }
// composable(Screen.FlightList.route) { FlightList(navController) }
// composable(Screen.Profile.route) { Profile(navController, currentUserViewModel) }
// composable(Screen.UserList.route) { UserList(navController) }
//// composable(Screen.Login.route) { Login(navController) }
// composable(Screen.MyRents.route) { MyRents(navController) }
//// composable(Screen.Registration.route) { Registration(navController) }
// composable(Screen.Admin.route) { Admin(navController) }
// composable(
// Screen.FlightInfo.route,
// arguments = listOf(navArgument("id") { type = NavType.IntType })
// ) {
// FlightInfo(navController)
// }
// composable(
// Screen.FoundFlights.route,
// arguments = listOf(
// navArgument("from") { type = NavType.StringType },
// navArgument("to") { type = NavType.StringType },
// navArgument("departureDate") { type = NavType.StringType }
// )
// ) {
// FoundFlights(navController)
// }
// composable(
// Screen.UserEdit.route,
// arguments = listOf(navArgument("id") { type = NavType.IntType })
// ) {
// UserEdit(navController)
// }
// composable(
// Screen.FlightEdit.route,
// arguments = listOf(navArgument("id") { type = NavType.IntType })
// ) {
// FlightEdit(navController)
// }
// composable(
// Screen.TicketEdit.route,
// arguments = listOf(navArgument("id") { type = NavType.IntType })
// ) {
// TicketEdit(navController)
// }
//// composable(
//// Screen.MyRents.route,
//// arguments = listOf(navArgument("id") { type = NavType.IntType })
//// ) {
//// MyRents(navController)
//// }
// composable(
// Screen.RentEdit.route,
// arguments = listOf(navArgument("id") { type = NavType.IntType })
// ) {
// RentEdit(navController)
// }
// }
//}
//
//object Graph{
// const val ROOT="root_graph"
// const val AUTHENTICATION="auth_graph"
// const val MAIN="main_graph/{$USERID_ARGUMENT}"
// fun passUserId(userId: String): String{
// return "main_graph/$userId"
// }
//}
//
////@RequiresApi(Build.VERSION_CODES.O)
////@Composable
////fun Navhost(
//// navController: NavHostController,
//// innerPadding: PaddingValues, modifier:
//// Modifier = Modifier,
//// currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory),
//// loginViewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory),
//// registrationViewModel: RegistrationViewModel = viewModel(factory = AppViewModelProvider.Factory),
////) {
//// NavHost(
//// navController,
//// startDestination = Graph.AUTHENTICATION,
//// modifier.padding(innerPadding),
//// route = Graph.ROOT
//// ) {
//// authNavGraph(navController=navController,registrationViewModel,loginViewModel,currentUserViewModel)
//// composable(route=Graph.MAIN,
//// arguments = listOf(navArgument(USERID_ARGUMENT){
//// type= NavType.StringType
//// })
////// composable(Screen.RentList.route) { RentList(navController) }
////// composable(Screen.FlightList.route) { FlightList(navController) }
////// composable(Screen.Profile.route) { Profile(navController) }
////// composable(Screen.UserList.route) { UserList(navController) }
////// composable(Screen.Login.route) { Login(navController) }
////// composable(Screen.MyRents.route) { MyRents(navController) }
////// composable(Screen.Registration.route) { Registration(navController) }
////// composable(Screen.MainPage.route) { MainPage(navController) }
////// composable(Screen.Admin.route) { Admin(navController) }
////// composable(
////// Screen.TicketEdit.route,
////// arguments = listOf(navArgument("id") { type = NavType.IntType })
////// ) {
////// TicketEdit(navController)
////// }
////// composable(
////// Screen.FlightInfo.route,
////// arguments = listOf(navArgument("id") { type = NavType.IntType })
////// ) {
////// FlightInfo(navController)
////// }
////// composable(
////// Screen.FoundFlights.route,
////// arguments = listOf(
////// navArgument("from") { type = NavType.StringType },
////// navArgument("to") { type = NavType.StringType },
////// navArgument("departureDate") { type = NavType.StringType }
////// )
////// ) {
////// FoundFlights(navController)
////// }
////// composable(
////// Screen.UserEdit.route,
////// arguments = listOf(navArgument("id") { type = NavType.IntType })
////// ) {
////// UserEdit(navController)
////// }
////// composable(
////// Screen.FlightEdit.route,
////// arguments = listOf(navArgument("id") { type = NavType.IntType })
////// ) {
////// FlightEdit(navController)
////// }
//////// composable(
//////// Screen.MyRents.route,
//////// arguments = listOf(navArgument("id") { type = NavType.IntType })
//////// ) {
//////// MyRents(navController)
//////// }
////// composable(
////// Screen.RentEdit.route,
////// arguments = listOf(navArgument("id") { type = NavType.IntType })
////// ) {
////// RentEdit(navController)
////// }
//// }
////}
//
//@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
//@RequiresApi(Build.VERSION_CODES.O)
//@Composable
//fun MainNavbar() {
// val navController = rememberNavController()
// val navBackStackEntry by navController.currentBackStackEntryAsState()
// val currentDestination = navBackStackEntry?.destination
// val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
// val registrationViewModel: RegistrationViewModel= viewModel(factory = AppViewModelProvider.Factory)
// val loginViewModel: LoginViewModel = viewModel(factory = AppViewModelProvider.Factory)
// val currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
//
// Scaffold(
// topBar = {
// Topbar(navController, currentScreen)
// },
// bottomBar = {
// if (currentScreen == null || currentScreen.showInBottomBar) {
// Navbar(navController, currentDestination)
// }
// }
// ) {
// RootNavGraph(navController, registrationViewModel, loginViewModel, currentUserViewModel)
// }
//}

View File

@ -1,76 +0,0 @@
package ru.ulstu.`is`.airticketrentservice.navigation
import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.AdminPanelSettings
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Search
import androidx.compose.ui.graphics.vector.ImageVector
import ru.ulstu.`is`.airticketrentservice.R
//enum class Screen(
// val route: String,
// @StringRes val resourceId: Int,
// val icon: ImageVector = Icons.Filled.Favorite,
// val showInBottomBar: Boolean = true
//) {
// Admin(
// "admin", R.string.rent_view_title, Icons.Filled.AdminPanelSettings
// ),
// FlightEdit(
// "flight-edit/{id}", R.string.ticket_view_title, showInBottomBar = false
// ),
// FlightInfo(
// "flight-info/{id}", R.string.ticket_view_title, showInBottomBar = false
// ),
// FlightList(
// "flight-list", R.string.ticket_main_title, showInBottomBar = false
// ),
// FoundFlights(
// "found-flights/{from}-{to}-{departureDate}", R.string.ticket_main_title, showInBottomBar = false
// ),
// MainPage(
// "main", R.string.rent_view_title, Icons.Filled.Search
// ),
// MyRents(
// "my-rents", R.string.ticket_view_title, showInBottomBar = false
// ),
// Profile(
// "profile", R.string.rent_view_title, Icons.Filled.AccountCircle
// ),
// RentEdit(
// "rent-edit/{id}", R.string.ticket_view_title, showInBottomBar = false
// ),
// RentList(
// "rent-list", R.string.ticket_main_title, showInBottomBar = false
// ),
// TicketEdit(
// "ticket-edit/{id}", R.string.ticket_view_title, showInBottomBar = false
// ),
// UserEdit(
// "user-edit/{id}", R.string.ticket_view_title, showInBottomBar = false
// ),
// UserList(
// "user-list", R.string.ticket_main_title, showInBottomBar = false
// ),
// Login(
// "login", R.string.rent_view_title, showInBottomBar = false
// ),
// Registration(
// "registration", R.string.rent_view_title, showInBottomBar = false
// );
//
// companion object {
// val bottomBarItems = listOf(
// MainPage,
// Profile,
// Admin
// )
//
// fun getItem(route: String): Screen? {
// val findRoute = route.split("/").first()
// return values().find { value -> value.route.startsWith(findRoute) }
// }
// }
//}

View File

@ -1,49 +0,0 @@
package ru.ulstu.`is`.airticketrentservice.navigation
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import ru.ulstu.`is`.airticketrentservice.R
//@OptIn(ExperimentalMaterial3Api::class)
//@Composable
//fun TopBar(navController: NavHostController,
// currentScreen: BottomBarScreen?) {
// TopAppBar(
// colors = TopAppBarDefaults.topAppBarColors(
// containerColor = Color.Transparent,
// ),
// title = {},
// actions = {},
// navigationIcon = {
// if (
// navController.previousBackStackEntry != null
// && (currentScreen == null)
// ) {
// IconButton(onClick = { navController.navigateUp() }) {
// Icon(
// imageVector = Icons.Filled.ArrowBack,
// contentDescription = null,
// tint = colorResource(R.color.black)
// )
// }
// }
// },
// modifier = Modifier
// .padding(10.dp)
// .clip(RoundedCornerShape(20.dp))
// )
//}

View File

@ -229,7 +229,7 @@ fun LoadScreen(navController: NavHostController = rememberNavController(),
rentListViewModel: RentListViewModel = viewModel(factory = AppViewModelProvider.Factory) rentListViewModel: RentListViewModel = viewModel(factory = AppViewModelProvider.Factory)
){ ){
Scaffold( Scaffold(
bottomBar = {BottomBar(navController = navController) }, bottomBar = {BottomBar(navController = navController, currentUserViewModel) },
) { ) {
Modifier Modifier
.padding(it) .padding(it)

View File

@ -1,38 +1,28 @@
package ru.ulstu.`is`.airticketrentservice.screen package ru.ulstu.`is`.airticketrentservice.screen
import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize 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.foundation.lazy.LazyColumn 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.material.ExperimentalMaterialApi
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.Delete
import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.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.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DismissDirection import androidx.compose.material3.DismissDirection
import androidx.compose.material3.DismissState import androidx.compose.material3.DismissState
import androidx.compose.material3.DismissValue import androidx.compose.material3.DismissValue
import androidx.compose.material3.DismissValue.DismissedToStart
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@ -40,38 +30,29 @@ import androidx.compose.material3.SwipeToDismiss
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.rememberDismissState import androidx.compose.material3.rememberDismissState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
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.Alignment.Companion.CenterHorizontally
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.draw.scale import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.PagingData
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 kotlinx.coroutines.launch
import ru.ulstu.`is`.airticketrentservice.database.models.Rent import ru.ulstu.`is`.airticketrentservice.database.models.Rent
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
import ru.ulstu.`is`.airticketrentservice.viewModel.CurrentUserViewModel import ru.ulstu.`is`.airticketrentservice.viewModel.CurrentUserViewModel
import ru.ulstu.`is`.airticketrentservice.viewModel.RentListViewModel
import ru.ulstu.`is`.airticketrentservice.R import ru.ulstu.`is`.airticketrentservice.R
import ru.ulstu.`is`.airticketrentservice.database.models.Flight
import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen
import ru.ulstu.`is`.airticketrentservice.viewModel.UsersRentsViewModel import ru.ulstu.`is`.airticketrentservice.viewModel.UsersRentsViewModel
@ -82,9 +63,11 @@ fun MyRents(
currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory) currentUserViewModel: CurrentUserViewModel = viewModel(factory = AppViewModelProvider.Factory)
) { ) {
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
var userRentsUiState by remember { mutableStateOf(viewModel.userRentsUiState) }
val getUser by remember { mutableStateOf(currentUserViewModel.user) } SideEffect {
val userRentsUiState = viewModel.userRentsUiState userRentsUiState = viewModel.userRentsUiState
}
Log.d("RentListViewModel", "мои бронирования: ${userRentsUiState.rentList}") Log.d("RentListViewModel", "мои бронирования: ${userRentsUiState.rentList}")
Scaffold( Scaffold(
@ -101,67 +84,118 @@ fun MyRents(
onSwipe = { rent: Rent -> onSwipe = { rent: Rent ->
coroutineScope.launch { coroutineScope.launch {
viewModel.deleteRent(rent) viewModel.deleteRent(rent)
viewModel.refreshRents()
} }
} }
) )
} }
} }
@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) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun SwipeToDelete( private fun SwipeToDelete(
dismissState: DismissState, dismissState: DismissState,
rentList: MutableList<Rent>,
rent: Rent, rent: Rent,
onClick: (id: Int) -> Unit onClick: (id: Int) -> Unit
) { ) {
LaunchedEffect(dismissState.targetValue) {
if (dismissState.targetValue == DismissedToStart) {
rentList.remove(rent)
}
}
SwipeToDismiss( SwipeToDismiss(
modifier = Modifier.zIndex(1f),
state = dismissState, state = dismissState,
directions = setOf( directions = setOf(DismissDirection.EndToStart),
DismissDirection.EndToStart
),
background = { background = {
DismissBackground(dismissState) val backgroundColor by animateColorAsState(
when (dismissState.targetValue) {
DismissedToStart -> Color.Red.copy(alpha = 0.8f)
else -> Color.White
}, label = ""
)
val iconScale by animateFloatAsState(
targetValue = if (dismissState.targetValue == 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 = { dismissContent = {
RentListItem(rent = rent, RentListItem(
rent = rent,
modifier = Modifier modifier = Modifier
.padding(vertical = 7.dp) .padding(vertical = 7.dp)
.clip(shape = RoundedCornerShape(15.dp)) .clip(shape = RoundedCornerShape(15.dp))
.clickable { onClick(rent.id) }) .clickable { onClick(rent.id) }
)
} }
) )
} }
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
//@OptIn(ExperimentalMaterial3Api::class)
//@Composable
//private fun SwipeToDelete(
// dismissState: DismissState,
// rent: Rent,
// onClick: (id: Int) -> Unit
//) {
// SwipeToDismiss(
// state = dismissState,
// directions = setOf(
// DismissDirection.EndToStart
// ),
// background = {
// val backgroundColor by animateColorAsState(
// when (dismissState.targetValue) {
// DismissedToStart -> Color.Red.copy(alpha = 0.8f)
// else -> Color.White
// }, label = ""
// )
// val iconScale by animateFloatAsState(
// targetValue = if (dismissState.targetValue == 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 = {
// RentListItem(rent = rent,
// modifier = Modifier
// .padding(vertical = 7.dp)
// .clip(shape = RoundedCornerShape(15.dp))
// .clickable { onClick(rent.id) })
// }
// )
//}
@SuppressLint("MutableCollectionMutableState")
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun MyRents( private fun MyRents(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -191,6 +225,7 @@ private fun MyRents(
SwipeToDelete( SwipeToDelete(
dismissState = dismissState, dismissState = dismissState,
rentList = rentList.toMutableList(),
rent = rent, rent = rent,
onClick = onClick onClick = onClick
) )
@ -200,13 +235,15 @@ private fun MyRents(
} }
} }
@Composable @Composable
private fun RentListItem( private fun RentListItem(
modifier: Modifier = Modifier, rent: Rent modifier: Modifier = Modifier, rent: Rent
) { ) {
Card( Card(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
colors = CardDefaults.cardColors(colorResource(id = R.color.lightlightBlue))
) { ) {
Column( Column(
modifier = modifier.padding(all = 10.dp) modifier = modifier.padding(all = 10.dp)

View File

@ -170,7 +170,7 @@ fun Profile(
Button( Button(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(5.dp), .padding(top = 5.dp, bottom = 50.dp),
onClick = { onClick = {
navController.navigate(AuthScreen.Login.route) navController.navigate(AuthScreen.Login.route)
}, },
@ -179,7 +179,7 @@ fun Profile(
pressedElevation = 6.dp pressedElevation = 6.dp
), ),
shape = RoundedCornerShape(15.dp), shape = RoundedCornerShape(15.dp),
colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.lightBlue)), colors = ButtonDefaults.buttonColors(containerColor = Color.Red),
content = { content = {
Text("Выйти") Text("Выйти")
} }

View File

@ -51,93 +51,27 @@ import ru.ulstu.`is`.airticketrentservice.viewModel.UsersListUiState
@SuppressLint("UnrememberedMutableState") @SuppressLint("UnrememberedMutableState")
@Composable @Composable
fun RentEdit( fun RentEdit(
navController: NavController,
viewModel: RentEditViewModel = viewModel(factory = AppViewModelProvider.Factory), viewModel: RentEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
userViewModel: UserEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
ticketViewModel: TicketEditViewModel = viewModel(factory = AppViewModelProvider.Factory) ticketViewModel: TicketEditViewModel = viewModel(factory = AppViewModelProvider.Factory)
) { ) {
val coroutineScope = rememberCoroutineScope()
userViewModel.setCurrentUser(viewModel.rentUiState.rentDetails.userId)
ticketViewModel.setCurrentTicket(viewModel.rentUiState.rentDetails.ticketId) ticketViewModel.setCurrentTicket(viewModel.rentUiState.rentDetails.ticketId)
RentEdit( RentEdit(
rentUiState = viewModel.rentUiState, rentUiState = viewModel.rentUiState,
userUiState = userViewModel.userUiState, ticketUiState = ticketViewModel.ticketUiState
ticketUiState = ticketViewModel.ticketUiState,
onClick = {
coroutineScope.launch {
viewModel.saveRent()
navController.popBackStack()
}
},
onUpdate = viewModel::updateUiState
) )
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun RentEdit( private fun RentEdit(
rentUiState: RentUiState, rentUiState: RentUiState,
userUiState: UserUiState, ticketUiState: TicketUiState
ticketUiState: TicketUiState,
onClick: () -> Unit,
onUpdate: (RentDetails) -> Unit
) { ) {
Column( Column(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(all = 10.dp) .padding(all = 10.dp)
) { ) {
TextField(
value = rentUiState.rentDetails.userId.toString(),
onValueChange = { onUpdate(rentUiState.rentDetails.copy(userId = it.toInt())) },
modifier = Modifier.fillMaxWidth().padding(all = 5.dp),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.LightGray.copy(.2f),
unfocusedContainerColor = Color.LightGray.copy(.2f),
disabledContainerColor = Color.LightGray.copy(.2f),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
shape = RoundedCornerShape(15.dp),
label = {
Text("Номер пользователя")
}
)
TextField(
value = rentUiState.rentDetails.ticketId.toString(),
onValueChange = { onUpdate(rentUiState.rentDetails.copy(ticketId = it.toInt())) },
modifier = Modifier.fillMaxWidth().padding(all = 5.dp),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.LightGray.copy(.2f),
unfocusedContainerColor = Color.LightGray.copy(.2f),
disabledContainerColor = Color.LightGray.copy(.2f),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
shape = RoundedCornerShape(15.dp),
label = {
Text("Номер билета")
}
)
TextField(
value = "${userUiState.userDetails.surname} ${userUiState.userDetails.name} ${userUiState.userDetails.patronymic}",
onValueChange = {},
readOnly = true,
modifier = Modifier.fillMaxWidth().padding(all = 5.dp),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.LightGray.copy(.2f),
unfocusedContainerColor = Color.LightGray.copy(.2f),
disabledContainerColor = Color.LightGray.copy(.2f),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
shape = RoundedCornerShape(15.dp),
label = {
Text("Пользователь")
}
)
TextField( TextField(
value = "${ticketUiState.ticketDetails.ticket_cost}", value = "${ticketUiState.ticketDetails.ticket_cost}",
onValueChange = {}, onValueChange = {},
@ -155,7 +89,6 @@ private fun RentEdit(
Text("Стоимость билета") Text("Стоимость билета")
} }
) )
TextField( TextField(
value = "${ticketUiState.ticketDetails.passengers_count}", value = "${ticketUiState.ticketDetails.passengers_count}",
onValueChange = {}, onValueChange = {},
@ -173,108 +106,22 @@ private fun RentEdit(
Text("Количество пассажиров") Text("Количество пассажиров")
} }
) )
// TextField(
// TextField( value = rentUiState.rentDetails.status,
// value = "Ожидает подтверждения", onValueChange = {},
// onValueChange = { onUpdate(rentUiState.rentDetails.copy(status = it)) }, readOnly = true,
// readOnly = true, modifier = Modifier.fillMaxWidth().padding(all = 5.dp),
// modifier = Modifier.fillMaxWidth(), colors = TextFieldDefaults.colors(
// colors = TextFieldDefaults.colors( focusedContainerColor = Color.LightGray.copy(.2f),
// focusedContainerColor = Color.LightGray.copy(.2f), unfocusedContainerColor = Color.LightGray.copy(.2f),
// unfocusedContainerColor = Color.LightGray.copy(.2f), disabledContainerColor = Color.LightGray.copy(.2f),
// disabledContainerColor = Color.LightGray.copy(.2f), focusedIndicatorColor = Color.Transparent,
// focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent,
// unfocusedIndicatorColor = Color.Transparent,
// ),
// shape = RoundedCornerShape(15.dp),
// label = {
// Text(stringResource(id = R.string.rent_status))
// }
// )
var expanded by remember { mutableStateOf(false) }
Box(
modifier = Modifier.fillMaxWidth().padding(all = 5.dp).clip(RoundedCornerShape(15.dp))
) {
ExposedDropdownMenuBox(
modifier = Modifier.fillMaxWidth(),
expanded = expanded,
onExpandedChange = { expanded = !expanded },
)
{
TextField(
value = rentUiState.rentDetails.status,
onValueChange = {},
readOnly = true,
trailingIcon = {
TrailingIcon(expanded = expanded)
},
modifier = Modifier.menuAnchor().fillMaxWidth(),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.LightGray.copy(.2f),
unfocusedContainerColor = Color.LightGray.copy(.2f),
disabledContainerColor = Color.LightGray.copy(.2f),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
),
shape = RoundedCornerShape(15.dp),
label = {
Text(stringResource(id = R.string.rent_status))
}
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.background(Color.LightGray.copy(.2f))
.exposedDropdownSize()
.fillMaxWidth()
) {
DropdownMenuItem(
modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(15.dp)),
text = { Text("Подтверждено") },
onClick = {
onUpdate(rentUiState.rentDetails.copy(status = "Подтверждено"))
expanded = false
}
)
DropdownMenuItem(
modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(15.dp)),
text = { Text("Ожидает подтверждения") },
onClick = {
onUpdate(rentUiState.rentDetails.copy(status = "Ожидает подтверждения"))
expanded = false
}
)
DropdownMenuItem(
modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(15.dp)),
text = { Text("Отклонено") },
onClick = {
onUpdate(rentUiState.rentDetails.copy(status = "Отклонено"))
expanded = false
}
)
}
}
}
Button(
enabled = rentUiState.isEntryValid,
modifier = Modifier
.fillMaxWidth()
.padding(all = 10.dp),
onClick = onClick,
elevation = ButtonDefaults.buttonElevation(
defaultElevation = 10.dp,
pressedElevation = 6.dp
), ),
shape = RoundedCornerShape(15.dp), shape = RoundedCornerShape(15.dp),
colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.lightBlue)), label = {
content = { Text(stringResource(id = R.string.rent_status))
Text(text = stringResource(R.string.rent_save_button))
} }
) )
} }
} }

View File

@ -50,6 +50,7 @@ import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
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.tooling.preview.Preview
@ -65,6 +66,7 @@ import androidx.paging.compose.itemKey
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.ulstu.`is`.airticketrentservice.R
import ru.ulstu.`is`.airticketrentservice.database.models.Rent import ru.ulstu.`is`.airticketrentservice.database.models.Rent
import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
@ -85,17 +87,6 @@ fun RentList(
val rentListUiState = viewModel.rentListUiState.collectAsLazyPagingItems() val rentListUiState = viewModel.rentListUiState.collectAsLazyPagingItems()
Scaffold( Scaffold(
topBar = {},
floatingActionButton = {
FloatingActionButton(
onClick = {
val route = BottomBarScreen.RentEdit.passId(0.toString())
navController.navigate(route)
},
) {
Icon(Icons.Filled.Add, "Добавить")
}
}
) { innerPadding -> ) { innerPadding ->
RentList( RentList(
modifier = Modifier modifier = Modifier
@ -103,7 +94,7 @@ fun RentList(
.fillMaxSize(), .fillMaxSize(),
rentList = rentListUiState, rentList = rentListUiState,
onClick = { uid: Int -> onClick = { uid: Int ->
val route = BottomBarScreen.RentEdit.passId(uid.toString()) val route = BottomBarScreen.RentStatusEdit.passId(uid.toString())
navController.navigate(route) navController.navigate(route)
}, },
onSwipe = { rent: Rent -> onSwipe = { rent: Rent ->
@ -246,7 +237,8 @@ private fun RentListItem(
) { ) {
Card( Card(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
colors = CardDefaults.cardColors(colorResource(id = R.color.lightlightBlue))
) { ) {
Column( Column(
modifier = modifier.padding(all = 10.dp) modifier = modifier.padding(all = 10.dp)

View File

@ -1,15 +1,8 @@
package ru.ulstu.`is`.airticketrentservice.screen package ru.ulstu.`is`.airticketrentservice.screen
import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -19,53 +12,31 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
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.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.outlined.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.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DismissDirection import androidx.compose.material3.DismissDirection
import androidx.compose.material3.DismissState import androidx.compose.material3.DismissState
import androidx.compose.material3.DismissValue
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.SwipeToDismiss import androidx.compose.material3.SwipeToDismiss
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.rememberDismissState import androidx.compose.material3.rememberDismissState
import androidx.compose.runtime.Composable 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.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.colorResource
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.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.paging.PagingData
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.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.ulstu.`is`.airticketrentservice.R
import ru.ulstu.`is`.airticketrentservice.database.models.User import ru.ulstu.`is`.airticketrentservice.database.models.User
import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen import ru.ulstu.`is`.airticketrentservice.navigation.BottomBarScreen
import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider import ru.ulstu.`is`.airticketrentservice.viewModel.AppViewModelProvider
@ -97,34 +68,6 @@ fun UserList(
} }
} }
@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) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun SwipeToDelete( private fun SwipeToDelete(
@ -135,12 +78,8 @@ private fun SwipeToDelete(
SwipeToDismiss( SwipeToDismiss(
modifier = Modifier.zIndex(1f), modifier = Modifier.zIndex(1f),
state = dismissState, state = dismissState,
directions = setOf( directions = setOf(),
DismissDirection.EndToStart background = {},
),
background = {
DismissBackground(dismissState)
},
dismissContent = { dismissContent = {
UserListItem(user = user, UserListItem(user = user,
modifier = Modifier modifier = Modifier
@ -173,11 +112,6 @@ private fun UserList(
val dismissState: DismissState = rememberDismissState( val dismissState: DismissState = rememberDismissState(
positionalThreshold = { 200.dp.toPx() } positionalThreshold = { 200.dp.toPx() }
) )
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
onSwipe(user)
}
SwipeToDelete( SwipeToDelete(
dismissState = dismissState, dismissState = dismissState,
user = user, user = user,
@ -195,7 +129,8 @@ private fun UserListItem(
) { ) {
Card( Card(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
colors = CardDefaults.cardColors(colorResource(id = R.color.lightlightBlue))
) { ) {
Column( Column(
modifier = modifier.padding(all = 10.dp) modifier = modifier.padding(all = 10.dp)

View File

@ -7,8 +7,13 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import ru.ulstu.`is`.airticketrentservice.database.AppContainer
import ru.ulstu.`is`.airticketrentservice.database.AppDataContainer
import ru.ulstu.`is`.airticketrentservice.database.models.Rent import ru.ulstu.`is`.airticketrentservice.database.models.Rent
import ru.ulstu.`is`.airticketrentservice.database.repository.RentRepository import ru.ulstu.`is`.airticketrentservice.database.repository.RentRepository
import ru.ulstu.`is`.airticketrentservice.database.repository.UserRepository import ru.ulstu.`is`.airticketrentservice.database.repository.UserRepository
@ -18,7 +23,6 @@ class UsersRentsViewModel(
private val userRepository: UserRepository, private val userRepository: UserRepository,
private val rentRepository: RentRepository private val rentRepository: RentRepository
) : ViewModel() { ) : ViewModel() {
var userRentsUiState by mutableStateOf(UserRentsUiState()) var userRentsUiState by mutableStateOf(UserRentsUiState())
private set private set
@ -37,6 +41,17 @@ class UsersRentsViewModel(
} }
} }
fun refreshRents() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val rents = userRepository.getUserRents(userUid)
launch(Dispatchers.Main) {
userRentsUiState = UserRentsUiState(rents)
}
}
}
}
suspend fun deleteRent(rent: Rent) { suspend fun deleteRent(rent: Rent) {
rentRepository.deleteRent(rent) rentRepository.deleteRent(rent)
} }

View File

@ -42,12 +42,6 @@
"flightId": 9, "flightId": 9,
"id": 7 "id": 7
}, },
{
"passengers_count": 6,
"ticket_cost": 106800,
"flightId": 9,
"id": 8
},
{ {
"passengers_count": 6, "passengers_count": 6,
"ticket_cost": 106800, "ticket_cost": 106800,
@ -131,6 +125,12 @@
"ticket_cost": 10000, "ticket_cost": 10000,
"flightId": 2, "flightId": 2,
"id": 22 "id": 22
},
{
"passengers_count": 6,
"ticket_cost": 6000,
"flightId": 2,
"id": 23
} }
], ],
"flights": [ "flights": [
@ -229,16 +229,6 @@
"role": "User", "role": "User",
"id": 4 "id": 4
}, },
{
"surname": "ыщылы",
"name": "шчшчгч",
"patronymic": "шчшчшч",
"date_of_birth": "10-12-2015",
"email": "aa@mail.ru",
"password": "aaa",
"role": "User",
"id": 5
},
{ {
"surname": "фффф", "surname": "фффф",
"name": "ффф", "name": "ффф",
@ -271,29 +261,23 @@
} }
], ],
"rents": [ "rents": [
{ {
"id": 1, "id": 1,
"status": "Ожидает подтверждения", "status": "Ожидает подтверждения",
"userId": 2, "userId": 2,
"ticketId": 1 "ticketId": 1
}, },
{ {
"id": 2, "id": 2,
"status": "Подтверждено", "status": "Ожидает подтверждения",
"userId": 2, "userId": 2,
"ticketId": 2 "ticketId": 2
}, },
{ {
"id": 3,
"status": "Ожидает подтверждения", "status": "Ожидает подтверждения",
"userId": 2, "userId": 2,
"ticketId": 21, "ticketId": 3
"id": 3
},
{
"status": "Ожидает подтверждения",
"userId": 2,
"ticketId": 22,
"id": 4
} }
] ]
} }

View File

@ -42,12 +42,6 @@
"flightId": 9, "flightId": 9,
"id": 7 "id": 7
}, },
{
"passengers_count": 6,
"ticket_cost": 106800,
"flightId": 9,
"id": 8
},
{ {
"passengers_count": 6, "passengers_count": 6,
"ticket_cost": 106800, "ticket_cost": 106800,
@ -125,6 +119,18 @@
"ticket_cost": 3000, "ticket_cost": 3000,
"flightId": 2, "flightId": 2,
"id": 21 "id": 21
},
{
"passengers_count": 10,
"ticket_cost": 10000,
"flightId": 2,
"id": 22
},
{
"passengers_count": 6,
"ticket_cost": 6000,
"flightId": 2,
"id": 23
} }
], ],
"flights": [ "flights": [
@ -201,7 +207,7 @@
"date_of_birth": "7-11-2003", "date_of_birth": "7-11-2003",
"email": "usertt@mail.ru", "email": "usertt@mail.ru",
"password": "usertt", "password": "usertt",
"role": "Admin" "role": "User"
}, },
{ {
"surname": "а", "surname": "а",
@ -223,16 +229,6 @@
"role": "User", "role": "User",
"id": 4 "id": 4
}, },
{
"surname": "ыщылы",
"name": "шчшчгч",
"patronymic": "шчшчшч",
"date_of_birth": "10-12-2015",
"email": "aa@mail.ru",
"password": "aaa",
"role": "User",
"id": 5
},
{ {
"surname": "фффф", "surname": "фффф",
"name": "ффф", "name": "ффф",
@ -252,26 +248,17 @@
"password": "kkk", "password": "kkk",
"role": "User", "role": "User",
"id": 7 "id": 7
},
{
"id": 8,
"surname": "Артамонова",
"name": "Татьяна",
"patronymic": "Валерьевна",
"date_of_birth": "7-11-2003",
"email": "admin@mail.ru",
"password": "admin",
"role": "Admin"
} }
], ],
"rents": [ "rents": []
{
"id": 1,
"status": "Ожидает подтверждения",
"userId": 2,
"ticketId": 1
},
{
"id": 2,
"status": "Подтверждено",
"userId": 2,
"ticketId": 2
},
{
"status": "Ожидает подтверждения",
"userId": 2,
"ticketId": 21,
"id": 3
}
]
} }