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

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,
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(
modifier = Modifier.padding(0.dp, 10.dp)
) {
@ -223,7 +211,10 @@ fun TankEmptyListPreview() {
Surface(
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
}
companion object {
val DEMO_LEVEL = Level(
0,
1
)
}
override fun hashCode(): Int {
return (uid ?: -1) as Int
}

View File

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

View File

@ -4,6 +4,7 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import ru.ulstu.`is`.pmu.R
@Entity(
tableName = "tanks"
@ -31,6 +32,19 @@ data class Tank(
nation: Nation
) : 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 {
if (this === other) return true
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.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
@ -33,25 +34,78 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
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.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.launch
import ru.ulstu.`is`.pmu.R
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.getNations
import ru.ulstu.`is`.pmu.ui.AppViewModelProvider
import ru.ulstu.`is`.pmu.ui.theme.CustomDark
import ru.ulstu.`is`.pmu.ui.theme.CustomOrange
import ru.ulstu.`is`.pmu.ui.theme.CustomYellow
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)
@Composable
fun Constructor(navController: NavController) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val currentScreen = currentDestination?.route?.let { Screen.getItem(it) }
private fun Constructor(
tankUiState: TankUiState,
levelUiState: LevelUiState,
levelsListUiState: LevelsListUiState,
onLevelUpdate: (Level) -> Unit,
nationUiState: NationUiState,
nationsListUiState: NationsListUiState,
onNationUpdate: (Nation) -> Unit,
onClick: () -> Unit,
onUpdate: (TankDetails) -> Unit
) {
var nationName by remember { mutableStateOf("") }
var price by remember { mutableStateOf("") }
@ -69,7 +123,9 @@ fun Constructor(navController: NavController) {
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow)
modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){
Column {
Row(
@ -98,7 +154,7 @@ fun Constructor(navController: NavController) {
TextField(
value = nationName,
placeholder = { Text(text = "Название", color = CustomDark) },
onValueChange = { nationName = it },
onValueChange = { onUpdate(tankUiState.tankDetails.copy(name = it)) },
modifier = Modifier
.width(200.dp),
)
@ -108,7 +164,7 @@ fun Constructor(navController: NavController) {
expanded = expandedLevels,
onExpandedChange = {
expandedLevels = !expandedLevels
}
},
) {
// textfield
TextField(
@ -136,6 +192,7 @@ fun Constructor(navController: NavController) {
text = { Text(selectionOption.level.toString()) },
onClick = {
selectedLevel = selectionOption.level
onLevelUpdate(selectionOption)
expandedLevels = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
@ -177,6 +234,7 @@ fun Constructor(navController: NavController) {
text = { Text(selectionOption.nationName) },
onClick = {
selectedNation = selectionOption.nationName
onNationUpdate(selectionOption)
expandedNation = false
},
contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
@ -188,7 +246,7 @@ fun Constructor(navController: NavController) {
TextField(
value = price,
placeholder = { Text(text = "Стоимость", color = CustomDark) },
onValueChange = { price = it },
onValueChange = { onUpdate(tankUiState.tankDetails.copy(price = it.toInt())) },
modifier = Modifier
.width(200.dp),
)
@ -196,7 +254,9 @@ fun Constructor(navController: NavController) {
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp)
modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){
Button(
modifier = Modifier
@ -208,14 +268,16 @@ fun Constructor(navController: NavController) {
),
onClick = { }) {
//"${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(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow)
modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){
Column {
Row(
@ -246,7 +308,9 @@ fun Constructor(navController: NavController) {
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp)
modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){
Button(
modifier = Modifier
@ -265,7 +329,9 @@ fun Constructor(navController: NavController) {
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().background(CustomYellow)
modifier = Modifier
.fillMaxWidth()
.background(CustomYellow)
){
Column {
Row(
@ -296,7 +362,9 @@ fun Constructor(navController: NavController) {
}
Row(
horizontalArrangement = Arrangement.Center,
modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp)
modifier = Modifier
.fillMaxWidth()
.padding(10.dp, 10.dp)
){
Button(
modifier = Modifier
@ -320,13 +388,23 @@ fun Constructor(navController: 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 ConstructorPreview() {
fun ConstructorEditPreview() {
PmudemoTheme {
Surface(
color = CustomDark
) {
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++
}
}
Spacer(Modifier.height(20.dp))
}
}
}
}
@ -190,8 +187,20 @@ fun HangarPreview() {
Surface(
color = CustomDark
) {
val navController = rememberNavController()
Hangar(navController)
Hangar(tankList = listOf())
}
}
}
@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())
}
}
}