Работаем над конструктором.

This commit is contained in:
ElEgEv 2023-11-27 23:12:32 +04:00
parent bf6f3fd2e4
commit ba4be87c09
13 changed files with 237 additions and 35 deletions

View File

@ -72,18 +72,6 @@ fun ColumnItem(
number: Int, number: Int,
tanks: List<Tank> tanks: List<Tank>
) { ) {
/*
val context = LocalContext.current
val tanks = remember { mutableStateListOf<Tank>() }
LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
AppDatabase.getInstance(context).tankDao().getAll().collect() { data ->
tanks.clear()
tanks.addAll(data)
tanks.reverse()
}
}
}*/
Column( Column(
modifier = Modifier.padding(0.dp, 10.dp) modifier = Modifier.padding(0.dp, 10.dp)
) { ) {
@ -223,7 +211,10 @@ fun TankEmptyListPreview() {
Surface( Surface(
color = CustomDark color = CustomDark
) { ) {
TankList(numbers = listOf(1, 2, 3), listTanks = listOf()) TankList(
numbers = listOf(1, 2, 3),
listTanks = listOf()
)
} }
} }
} }

View File

@ -0,0 +1,96 @@
package ru.ulstu.`is`.pmu.tank.composeui.edit
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.repository.TankRepository
class TankEditViewModel(
savedStateHandle: SavedStateHandle,
private val tankRepository: TankRepository
) : ViewModel() {
var tankUiState by mutableStateOf(TankUiState())
private set
private val tankUid: Long = checkNotNull(savedStateHandle["id"])
init {
viewModelScope.launch {
if (tankUid > 0) {
tankUiState = tankRepository.getTank(tankUid)
.filterNotNull()
.first()
.toUiState(true)
}
}
}
fun updateUiState(tankDetails: TankDetails) {
tankUiState = TankUiState(
tankDetails = tankDetails,
isEntryValid = validateInput(tankDetails)
)
}
suspend fun saveTank() {
if (validateInput()) {
if (tankUid > 0) {
tankRepository.updateTank(tankUiState.tankDetails.toTank(tankUid))
} else {
tankRepository.insertTank(tankUiState.tankDetails.toTank())
}
}
}
private fun validateInput(uiState: TankDetails = tankUiState.tankDetails): Boolean {
return with(uiState) {
name.isNotBlank()
&& price > 0
&& image > 0
&& levelId!! > 0
&& nationId!! > 0
}
}
}
data class TankUiState(
val tankDetails: TankDetails = TankDetails(),
val isEntryValid: Boolean = false
)
data class TankDetails(
val name: String = "",
val price: Int = 0,
val image: Int = 0,
val levelId: Long? = 0,
val nationId: Long? = 0,
)
fun TankDetails.toTank(uid: Long = 0): Tank = Tank(
tankId = uid,
name = name,
price = price,
image = image,
levelId = levelId,
nationId = levelId
)
fun Tank.toDetails(): TankDetails = TankDetails(
name = name,
price = price,
image = image,
levelId = levelId,
nationId = nationId
)
fun Tank.toUiState(isEntryValid: Boolean = false): TankUiState = TankUiState(
tankDetails = this.toDetails(),
isEntryValid = isEntryValid
)

View File

@ -27,6 +27,13 @@ data class Level(
return true return true
} }
companion object {
val DEMO_LEVEL = Level(
0,
1
)
}
override fun hashCode(): Int { override fun hashCode(): Int {
return (uid ?: -1) as Int return (uid ?: -1) as Int
} }

View File

@ -28,6 +28,13 @@ data class Nation(
override fun hashCode(): Int { override fun hashCode(): Int {
return (uid ?: -1) as Int return (uid ?: -1) as Int
} }
companion object {
val DEMO_NATION = Nation(
0,
"СССР"
)
}
} }
fun getNations(): List<Nation> { fun getNations(): List<Nation> {

View File

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Ignore import androidx.room.Ignore
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import ru.ulstu.`is`.pmu.R
@Entity( @Entity(
tableName = "tanks" tableName = "tanks"
@ -31,6 +32,19 @@ data class Tank(
nation: Nation nation: Nation
) : this(null, name, price, image, level.uid, nation.uid) ) : this(null, name, price, image, level.uid, nation.uid)
companion object {
fun getTank(index: Long = 0): Tank {
return Tank(
index,
"Первый танк",
100000,
R.drawable.t_34_85,
1,
1
)
}
}
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false

View File

@ -23,6 +23,7 @@ import androidx.compose.runtime.Composable
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.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
@ -33,25 +34,78 @@ import androidx.compose.ui.text.font.FontWeight
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.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.R import ru.ulstu.`is`.pmu.R
import ru.ulstu.`is`.pmu.composeui.navigation.Screen import ru.ulstu.`is`.pmu.composeui.navigation.Screen
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelDropDownViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.LevelsListUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationDropDownViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.NationsListUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.TankDetails
import ru.ulstu.`is`.pmu.tank.composeui.edit.TankEditViewModel
import ru.ulstu.`is`.pmu.tank.composeui.edit.TankUiState
import ru.ulstu.`is`.pmu.tank.composeui.edit.toUiState
import ru.ulstu.`is`.pmu.tank.composeui.list.TankListViewModel
import ru.ulstu.`is`.pmu.tank.model.Level
import ru.ulstu.`is`.pmu.tank.model.Nation
import ru.ulstu.`is`.pmu.tank.model.Tank
import ru.ulstu.`is`.pmu.tank.model.getLevels import ru.ulstu.`is`.pmu.tank.model.getLevels
import ru.ulstu.`is`.pmu.tank.model.getNations import ru.ulstu.`is`.pmu.tank.model.getNations
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
import ru.ulstu.`is`.pmu.ui.theme.CustomDark import ru.ulstu.`is`.pmu.ui.theme.CustomDark
import ru.ulstu.`is`.pmu.ui.theme.CustomOrange import ru.ulstu.`is`.pmu.ui.theme.CustomOrange
import ru.ulstu.`is`.pmu.ui.theme.CustomYellow import ru.ulstu.`is`.pmu.ui.theme.CustomYellow
import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme import ru.ulstu.`is`.pmu.ui.theme.PmudemoTheme
@Composable
fun Constructor(
navController: NavController,
tankEditViewModel: TankEditViewModel = viewModel(factory = AppViewModelProvider.Factory),
levelDropDownViewModel: LevelDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory),
nationDropDownViewModel: NationDropDownViewModel = viewModel(factory = AppViewModelProvider.Factory)
){
val coroutineScope = rememberCoroutineScope()
levelDropDownViewModel.setCurrentLevel(tankEditViewModel.tankUiState.tankDetails.levelId ?: 1)
nationDropDownViewModel.setCurrentNation(tankEditViewModel.tankUiState.tankDetails.nationId ?: 1)
Constructor(
tankUiState = tankEditViewModel.tankUiState,
levelUiState = levelDropDownViewModel.levelUiState,
levelsListUiState = levelDropDownViewModel.levelsListUiState,
onLevelUpdate = levelDropDownViewModel::updateUiState,
nationUiState = nationDropDownViewModel.nationUiState,
nationsListUiState = nationDropDownViewModel.nationsListUiState,
onNationUpdate = nationDropDownViewModel::updateUiState,
onClick = {
coroutineScope.launch {
tankEditViewModel.saveTank()
navController.popBackStack()
}
},
onUpdate = tankEditViewModel::updateUiState
)
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalTextApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalTextApi::class)
@Composable @Composable
fun Constructor(navController: NavController) { private fun Constructor(
val navBackStackEntry by navController.currentBackStackEntryAsState() tankUiState: TankUiState,
val currentDestination = navBackStackEntry?.destination levelUiState: LevelUiState,
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) } levelsListUiState: LevelsListUiState,
onLevelUpdate: (Level) -> Unit,
nationUiState: NationUiState,
nationsListUiState: NationsListUiState,
onNationUpdate: (Nation) -> Unit,
onClick: () -> Unit,
onUpdate: (TankDetails) -> Unit
) {
var nationName by remember { mutableStateOf("") } var nationName by remember { mutableStateOf("") }
var price by remember { mutableStateOf("") } var price by remember { mutableStateOf("") }
@ -69,7 +123,9 @@ fun Constructor(navController: NavController) {
) { ) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow) modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){ ){
Column { Column {
Row( Row(
@ -98,7 +154,7 @@ fun Constructor(navController: NavController) {
TextField( TextField(
value = nationName, value = nationName,
placeholder = { Text(text = "Название", color = CustomDark) }, placeholder = { Text(text = "Название", color = CustomDark) },
onValueChange = { nationName = it }, onValueChange = { onUpdate(tankUiState.tankDetails.copy(name = it)) },
modifier = Modifier modifier = Modifier
.width(200.dp), .width(200.dp),
) )
@ -108,7 +164,7 @@ fun Constructor(navController: NavController) {
expanded = expandedLevels, expanded = expandedLevels,
onExpandedChange = { onExpandedChange = {
expandedLevels = !expandedLevels expandedLevels = !expandedLevels
} },
) { ) {
// textfield // textfield
TextField( TextField(
@ -136,6 +192,7 @@ fun Constructor(navController: NavController) {
text = { Text(selectionOption.level.toString()) }, text = { Text(selectionOption.level.toString()) },
onClick = { onClick = {
selectedLevel = selectionOption.level selectedLevel = selectionOption.level
onLevelUpdate(selectionOption)
expandedLevels = false expandedLevels = false
}, },
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
@ -177,6 +234,7 @@ fun Constructor(navController: NavController) {
text = { Text(selectionOption.nationName) }, text = { Text(selectionOption.nationName) },
onClick = { onClick = {
selectedNation = selectionOption.nationName selectedNation = selectionOption.nationName
onNationUpdate(selectionOption)
expandedNation = false expandedNation = false
}, },
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding, contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
@ -188,7 +246,7 @@ fun Constructor(navController: NavController) {
TextField( TextField(
value = price, value = price,
placeholder = { Text(text = "Стоимость", color = CustomDark) }, placeholder = { Text(text = "Стоимость", color = CustomDark) },
onValueChange = { price = it }, onValueChange = { onUpdate(tankUiState.tankDetails.copy(price = it.toInt())) },
modifier = Modifier modifier = Modifier
.width(200.dp), .width(200.dp),
) )
@ -196,7 +254,9 @@ fun Constructor(navController: NavController) {
} }
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp) modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){ ){
Button( Button(
modifier = Modifier modifier = Modifier
@ -208,14 +268,16 @@ fun Constructor(navController: NavController) {
), ),
onClick = { }) { onClick = { }) {
//"${student.firstName} ${student.lastName}" //"${student.firstName} ${student.lastName}"
Text(text = stringResource(id = R.string.create_account_button), fontSize = 20.sp, fontWeight = FontWeight.Bold) Text(text = stringResource(id = R.string.save_account_button), fontSize = 20.sp, fontWeight = FontWeight.Bold)
} }
} }
} }
} }
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow) modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){ ){
Column { Column {
Row( Row(
@ -246,7 +308,9 @@ fun Constructor(navController: NavController) {
} }
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp) modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){ ){
Button( Button(
modifier = Modifier modifier = Modifier
@ -265,7 +329,9 @@ fun Constructor(navController: NavController) {
} }
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow) modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){ ){
Column { Column {
Row( Row(
@ -296,7 +362,9 @@ fun Constructor(navController: NavController) {
} }
Row( Row(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp) modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){ ){
Button( Button(
modifier = Modifier modifier = Modifier
@ -320,13 +388,23 @@ fun Constructor(navController: NavController) {
@Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Light Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(name = "Dark Mode", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable @Composable
fun ConstructorPreview() { fun ConstructorEditPreview() {
PmudemoTheme { PmudemoTheme {
Surface( Surface(
color = CustomDark color = CustomDark
) { ) {
val navController = rememberNavController() val navController = rememberNavController()
Constructor(navController) Constructor(
tankUiState = Tank.getTank().toUiState(true),
levelUiState = Level.DEMO_LEVEL.toUiState(),
levelsListUiState = LevelsListUiState(listOf()),
onLevelUpdate = { },
nationUiState = Nation.DEMO_NATION.toUiState(),
nationsListUiState = NationsListUiState(listOf()),
onNationUpdate = { },
onClick = { },
onUpdate = { },
)
} }
} }
} }

View File

@ -170,15 +170,12 @@ private fun Hangar(
} }
} }
} }
index++ index++
} }
} }
Spacer(Modifier.height(20.dp)) Spacer(Modifier.height(20.dp))
} }
} }
} }
} }
@ -190,8 +187,20 @@ fun HangarPreview() {
Surface( Surface(
color = CustomDark color = CustomDark
) { ) {
val navController = rememberNavController() Hangar(tankList = listOf())
Hangar(navController) }
}
}
@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 HangarEmptyPreview() {
PmudemoTheme {
Surface(
color = CustomDark
) {
Hangar(tankList = listOf())
} }
} }
} }