mirror of
https://github.com/smyalygames/checklist-tester.git
synced 2025-05-18 14:34:12 +02:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
fe92d6a6e9
@ -1,10 +1,12 @@
|
|||||||
package di
|
package di
|
||||||
|
|
||||||
import InterfaceState
|
import InterfaceState
|
||||||
|
import io.anthonyberg.connector.shared.ActionTransaction
|
||||||
import io.anthonyberg.connector.shared.ProcedureTransaction
|
import io.anthonyberg.connector.shared.ProcedureTransaction
|
||||||
import io.anthonyberg.connector.shared.ProjectTransaction
|
import io.anthonyberg.connector.shared.ProjectTransaction
|
||||||
import io.anthonyberg.connector.shared.database.DriverFactory
|
import io.anthonyberg.connector.shared.database.DriverFactory
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
import tab.procedure.ActionsScreenModel
|
||||||
import tab.procedure.ProcedureScreenModel
|
import tab.procedure.ProcedureScreenModel
|
||||||
import tab.project.ProjectsScreenModel
|
import tab.project.ProjectsScreenModel
|
||||||
|
|
||||||
@ -20,6 +22,10 @@ fun commonModule() = module {
|
|||||||
single<ProcedureTransaction> {
|
single<ProcedureTransaction> {
|
||||||
ProcedureTransaction(driverFactory = get<DriverFactory>())
|
ProcedureTransaction(driverFactory = get<DriverFactory>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single<ActionTransaction> {
|
||||||
|
ActionTransaction(driverFactory = get<DriverFactory>())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun viewModelModule() = module {
|
fun viewModelModule() = module {
|
||||||
@ -34,4 +40,8 @@ fun viewModelModule() = module {
|
|||||||
single<ProcedureScreenModel> {
|
single<ProcedureScreenModel> {
|
||||||
ProcedureScreenModel(db = get(), interfaceState = get())
|
ProcedureScreenModel(db = get(), interfaceState = get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
single<ActionsScreenModel> {
|
||||||
|
ActionsScreenModel(db = get(), interfaceState = get())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.rememberScrollbarAdapter
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
@ -17,6 +18,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.koin.getScreenModel
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
@ -27,18 +29,26 @@ import org.jetbrains.compose.resources.ExperimentalResourceApi
|
|||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.koin.compose.koinInject
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
class Actions : Screen {
|
class Actions (dbActions: List<Action>) : Screen {
|
||||||
private val columnPadding = 24.dp
|
private val columnPadding = 24.dp
|
||||||
private val itemPadding = 24.dp
|
private val itemPadding = 24.dp
|
||||||
|
|
||||||
private var inputs = mutableStateListOf<Action>()
|
private var inputs = mutableStateListOf<Action>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
inputs.addAll(dbActions)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val viewModel = koinInject<InterfaceState>()
|
val viewModel = koinInject<InterfaceState>()
|
||||||
val state = rememberLazyListState(0)
|
val state = rememberLazyListState(0)
|
||||||
|
|
||||||
|
// Sends to screen model that Actions has been loaded
|
||||||
|
val screenModel = getScreenModel<ActionsScreenModel>()
|
||||||
|
screenModel.loadedActions()
|
||||||
|
|
||||||
// Checks if a project has been selected before viewing contents
|
// Checks if a project has been selected before viewing contents
|
||||||
if (viewModel.procedureId == null) {
|
if (viewModel.procedureId == null) {
|
||||||
navigator.pop()
|
navigator.pop()
|
||||||
@ -84,7 +94,7 @@ class Actions : Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
footer(navigator, viewModel)
|
footer(navigator, viewModel, screenModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +124,28 @@ class Actions : Screen {
|
|||||||
Column (
|
Column (
|
||||||
verticalArrangement = Arrangement.spacedBy(itemPadding)
|
verticalArrangement = Arrangement.spacedBy(itemPadding)
|
||||||
) {
|
) {
|
||||||
Text(text = "Action ${item.id}")
|
Row(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(text = "Action ${item.step + 1}")
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
modifier = Modifier.size(24.dp),
|
||||||
|
onClick = {
|
||||||
|
inputs.removeAt(item.step)
|
||||||
|
updateStepOrder()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Delete,
|
||||||
|
contentDescription = "Delete Action ${item.step + 1}",
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.secondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
@ -123,7 +154,7 @@ class Actions : Screen {
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier = Modifier.fillMaxWidth(0.6f),
|
modifier = Modifier.fillMaxWidth(0.6f),
|
||||||
value = item.type,
|
value = item.type,
|
||||||
onValueChange = { inputs[item.id] = inputs[item.id].copy(type = it) },
|
onValueChange = { inputs[item.id - 1] = inputs[item.id - 1].copy(type = it) },
|
||||||
label = { Text("Dataref Name") },
|
label = { Text("Dataref Name") },
|
||||||
singleLine = true
|
singleLine = true
|
||||||
)
|
)
|
||||||
@ -131,7 +162,7 @@ class Actions : Screen {
|
|||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = item.goal,
|
value = item.goal,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onValueChange = { inputs[item.id] = inputs[item.id].copy(goal = it) },
|
onValueChange = { inputs[item.id - 1] = inputs[item.id - 1].copy(goal = it) },
|
||||||
label = { Text("Desired State") },
|
label = { Text("Desired State") },
|
||||||
singleLine = true
|
singleLine = true
|
||||||
)
|
)
|
||||||
@ -143,16 +174,16 @@ class Actions : Screen {
|
|||||||
|
|
||||||
@OptIn(ExperimentalResourceApi::class)
|
@OptIn(ExperimentalResourceApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun footer(navigator: Navigator, viewModel: InterfaceState) {
|
private fun footer(navigator: Navigator, viewModel: InterfaceState, screenModel: ActionsScreenModel) {
|
||||||
Row (
|
Row (
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
// Add Step
|
// Add Step
|
||||||
|
// TODO add menu to choose multiple types of items
|
||||||
FilledTonalButton(
|
FilledTonalButton(
|
||||||
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO make this a proper data array for each item in checklist
|
|
||||||
val procedureId = viewModel.procedureId
|
val procedureId = viewModel.procedureId
|
||||||
if (procedureId != null) {
|
if (procedureId != null) {
|
||||||
inputs += createEmptyAction(procedureId)
|
inputs += createEmptyAction(procedureId)
|
||||||
@ -172,7 +203,7 @@ class Actions : Screen {
|
|||||||
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
|
||||||
onClick = {
|
onClick = {
|
||||||
// TODO make checks
|
// TODO make checks
|
||||||
// TODO save to database
|
screenModel.saveActions(inputs)
|
||||||
navigator.pop()
|
navigator.pop()
|
||||||
viewModel.procedureId = null
|
viewModel.procedureId = null
|
||||||
}
|
}
|
||||||
@ -191,7 +222,7 @@ class Actions : Screen {
|
|||||||
val index = inputs.size
|
val index = inputs.size
|
||||||
|
|
||||||
val action = Action(
|
val action = Action(
|
||||||
id = index,
|
id = index + 1,
|
||||||
procedureId = procedureId,
|
procedureId = procedureId,
|
||||||
step = index,
|
step = index,
|
||||||
type = "",
|
type = "",
|
||||||
@ -200,4 +231,13 @@ class Actions : Screen {
|
|||||||
|
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates Action.step in the input list to be the same as the index in the list
|
||||||
|
*/
|
||||||
|
private fun updateStepOrder() {
|
||||||
|
for ((index, action) in inputs.withIndex()) {
|
||||||
|
inputs[index] = action.copy(step = index)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package tab.procedure
|
||||||
|
|
||||||
|
import InterfaceState
|
||||||
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
|
import io.anthonyberg.connector.shared.ActionTransaction
|
||||||
|
import io.anthonyberg.connector.shared.entity.Action
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ActionsScreenModel (
|
||||||
|
private val db: ActionTransaction,
|
||||||
|
private val interfaceState: InterfaceState
|
||||||
|
) : StateScreenModel<ActionsState>(ActionsState.Idle) {
|
||||||
|
fun getActions() {
|
||||||
|
screenModelScope.launch {
|
||||||
|
mutableState.value = ActionsState.Loading
|
||||||
|
|
||||||
|
val procedureId = interfaceState.procedureId ?: return@launch
|
||||||
|
|
||||||
|
val actions = db.getActions(procedureId = procedureId)
|
||||||
|
|
||||||
|
mutableState.value = ActionsState.Result(actions = actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadedActions() {
|
||||||
|
mutableState.value = ActionsState.Idle
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveActions(actions: List<Action>) {
|
||||||
|
screenModelScope.launch {
|
||||||
|
val procedureId = interfaceState.procedureId ?: return@launch
|
||||||
|
|
||||||
|
// Delete all previous items of the actions from the database
|
||||||
|
db.deleteActionByProcedure(procedureId = procedureId)
|
||||||
|
|
||||||
|
// Add the new actions to the database
|
||||||
|
db.createActionFromList(actions = actions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ActionsState {
|
||||||
|
data object Idle : ActionsState()
|
||||||
|
data object Loading : ActionsState()
|
||||||
|
data class Result(val actions: List<Action>) : ActionsState()
|
||||||
|
}
|
@ -16,14 +16,17 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
|||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.koin.getScreenModel
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import io.anthonyberg.connector.shared.entity.Procedure
|
import io.anthonyberg.connector.shared.entity.Procedure
|
||||||
import org.koin.compose.koinInject
|
import org.koin.compose.koinInject
|
||||||
|
import tab.LoadingScreen
|
||||||
|
|
||||||
class ListProcedures (
|
class ListProcedures (
|
||||||
private val procedures: List<Procedure>
|
private val procedures: List<Procedure>
|
||||||
@ -32,8 +35,20 @@ class ListProcedures (
|
|||||||
override fun Content() {
|
override fun Content() {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
val viewModel = koinInject<InterfaceState>()
|
val viewModel = koinInject<InterfaceState>()
|
||||||
|
val screenModel = getScreenModel<ActionsScreenModel>()
|
||||||
|
val state by screenModel.state.collectAsState()
|
||||||
|
|
||||||
val state = rememberLazyListState(0)
|
when (val s = state) {
|
||||||
|
is ActionsState.Idle -> { }
|
||||||
|
is ActionsState.Loading -> navigator.push(LoadingScreen("Actions"))
|
||||||
|
is ActionsState.Result -> {
|
||||||
|
navigator.pop()
|
||||||
|
navigator.push(Actions(s.actions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val lazyState = rememberLazyListState(0)
|
||||||
|
|
||||||
Scaffold (
|
Scaffold (
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
@ -53,9 +68,9 @@ class ListProcedures (
|
|||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxWidth(0.7F),
|
modifier = Modifier.fillMaxWidth(0.7F),
|
||||||
) {
|
) {
|
||||||
LazyColumn(state = state) {
|
LazyColumn(state = lazyState) {
|
||||||
items(procedures) { procedure ->
|
items(procedures) { procedure ->
|
||||||
procedureItem(procedure, viewModel, navigator)
|
procedureItem(procedure, viewModel, screenModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VerticalScrollbar(
|
VerticalScrollbar(
|
||||||
@ -63,7 +78,7 @@ class ListProcedures (
|
|||||||
.align(Alignment.CenterEnd)
|
.align(Alignment.CenterEnd)
|
||||||
.fillMaxHeight(),
|
.fillMaxHeight(),
|
||||||
adapter = rememberScrollbarAdapter(
|
adapter = rememberScrollbarAdapter(
|
||||||
scrollState = state,
|
scrollState = lazyState,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -72,15 +87,14 @@ class ListProcedures (
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun procedureItem(procedure: Procedure, viewModel: InterfaceState, navigator: Navigator) {
|
private fun procedureItem(procedure: Procedure, viewModel: InterfaceState, screenModel: ActionsScreenModel) {
|
||||||
ListItem(
|
ListItem(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
enabled = true,
|
enabled = true,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.procedureId = procedure.id
|
viewModel.procedureId = procedure.id
|
||||||
|
screenModel.getActions()
|
||||||
navigator.push(Actions())
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
overlineContent = { Text(procedure.type) },
|
overlineContent = { Text(procedure.type) },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user