Merge remote-tracking branch 'origin/main'

This commit is contained in:
Anthony 2024-04-27 09:55:57 +01:00
commit fe92d6a6e9
4 changed files with 128 additions and 17 deletions

View File

@ -1,10 +1,12 @@
package di
import InterfaceState
import io.anthonyberg.connector.shared.ActionTransaction
import io.anthonyberg.connector.shared.ProcedureTransaction
import io.anthonyberg.connector.shared.ProjectTransaction
import io.anthonyberg.connector.shared.database.DriverFactory
import org.koin.dsl.module
import tab.procedure.ActionsScreenModel
import tab.procedure.ProcedureScreenModel
import tab.project.ProjectsScreenModel
@ -20,6 +22,10 @@ fun commonModule() = module {
single<ProcedureTransaction> {
ProcedureTransaction(driverFactory = get<DriverFactory>())
}
single<ActionTransaction> {
ActionTransaction(driverFactory = get<DriverFactory>())
}
}
fun viewModelModule() = module {
@ -34,4 +40,8 @@ fun viewModelModule() = module {
single<ProcedureScreenModel> {
ProcedureScreenModel(db = get(), interfaceState = get())
}
single<ActionsScreenModel> {
ActionsScreenModel(db = get(), interfaceState = get())
}
}

View File

@ -10,6 +10,7 @@ import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
@ -17,6 +18,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
@ -27,18 +29,26 @@ import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
import org.koin.compose.koinInject
class Actions : Screen {
class Actions (dbActions: List<Action>) : Screen {
private val columnPadding = 24.dp
private val itemPadding = 24.dp
private var inputs = mutableStateListOf<Action>()
init {
inputs.addAll(dbActions)
}
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
val viewModel = koinInject<InterfaceState>()
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
if (viewModel.procedureId == null) {
navigator.pop()
@ -84,7 +94,7 @@ class Actions : Screen {
}
item {
footer(navigator, viewModel)
footer(navigator, viewModel, screenModel)
}
}
@ -114,7 +124,28 @@ class Actions : Screen {
Column (
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(
Modifier.fillMaxWidth(),
@ -123,7 +154,7 @@ class Actions : Screen {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(0.6f),
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") },
singleLine = true
)
@ -131,7 +162,7 @@ class Actions : Screen {
OutlinedTextField(
value = item.goal,
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") },
singleLine = true
)
@ -143,16 +174,16 @@ class Actions : Screen {
@OptIn(ExperimentalResourceApi::class)
@Composable
private fun footer(navigator: Navigator, viewModel: InterfaceState) {
private fun footer(navigator: Navigator, viewModel: InterfaceState, screenModel: ActionsScreenModel) {
Row (
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
// Add Step
// TODO add menu to choose multiple types of items
FilledTonalButton(
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
onClick = {
// TODO make this a proper data array for each item in checklist
val procedureId = viewModel.procedureId
if (procedureId != null) {
inputs += createEmptyAction(procedureId)
@ -172,7 +203,7 @@ class Actions : Screen {
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
onClick = {
// TODO make checks
// TODO save to database
screenModel.saveActions(inputs)
navigator.pop()
viewModel.procedureId = null
}
@ -191,7 +222,7 @@ class Actions : Screen {
val index = inputs.size
val action = Action(
id = index,
id = index + 1,
procedureId = procedureId,
step = index,
type = "",
@ -200,4 +231,13 @@ class Actions : Screen {
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)
}
}
}

View File

@ -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()
}

View File

@ -16,14 +16,17 @@ import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.outlined.Add
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.koin.getScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import io.anthonyberg.connector.shared.entity.Procedure
import org.koin.compose.koinInject
import tab.LoadingScreen
class ListProcedures (
private val procedures: List<Procedure>
@ -32,8 +35,20 @@ class ListProcedures (
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
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 (
floatingActionButton = {
@ -53,9 +68,9 @@ class ListProcedures (
Box(
modifier = Modifier.fillMaxWidth(0.7F),
) {
LazyColumn(state = state) {
LazyColumn(state = lazyState) {
items(procedures) { procedure ->
procedureItem(procedure, viewModel, navigator)
procedureItem(procedure, viewModel, screenModel)
}
}
VerticalScrollbar(
@ -63,7 +78,7 @@ class ListProcedures (
.align(Alignment.CenterEnd)
.fillMaxHeight(),
adapter = rememberScrollbarAdapter(
scrollState = state,
scrollState = lazyState,
),
)
}
@ -72,15 +87,14 @@ class ListProcedures (
}
@Composable
private fun procedureItem(procedure: Procedure, viewModel: InterfaceState, navigator: Navigator) {
private fun procedureItem(procedure: Procedure, viewModel: InterfaceState, screenModel: ActionsScreenModel) {
ListItem(
modifier = Modifier
.clickable(
enabled = true,
onClick = {
viewModel.procedureId = procedure.id
navigator.push(Actions())
screenModel.getActions()
}
),
overlineContent = { Text(procedure.type) },