0

Trying to grasp Kotlin Jetpack Compose and do basic CRUD Operations on a simple TodoList App. Each TodoItem is a data class and the id's of each will be unique. Am I approaching this all wrong? I'm stuck at the part trying to get the updated state to render inside ListArea with a removed TodoItem or updated TodoItem. Any help is greatly appreciated, I've been stuck on this for more than two days.

data class TodoItem(
    val id: String = "",
    val todoName: String = "",
    val todoCompleted: Boolean = false
)


class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        TodoListACTAppTheme {
            // A surface container using the 'background' color from the theme
            Surface(
                modifier = Modifier.fillMaxSize(),
                color = MaterialTheme.colors.background
            ) {
                MainTodoListApp()
                }
            }
        }
    }
}



@Composable
fun MainTodoListApp() {

    var item1 = TodoItem( id = "aaa", todoName = "Alpha", todoCompleted = false)
    var item2 = TodoItem( id = "bbb", todoName = "Bravo", todoCompleted = true)
    var item3 = TodoItem( id = "ccc", todoName = "Charlie", todoCompleted = false)

    val todosListState = remember {
        mutableStateListOf<TodoItem>(item1, item2, item3)
    }

    fun addNewTodo(todoName: String) {
        println("Add Todo $todoName")

        val currentTS = System.currentTimeMillis().toString()

        var item4 = TodoItem( id = currentTS, todoName = todoName, todoCompleted = false)

        todosListState.add(item4) // This works

    }

    fun completeTodo(todoId: String) {
        // STUCK HERE trying to toggle todoCompleted to it's opposite
        // Update State with List with toggeled value
        println("Complete Todo $todoId")

        var newArray = todosListState.map {
                it -> if (it.id == todoId)
            TodoItem(id = it.id, todoName = it.todoName, todoCompleted = !it.todoCompleted)
        else TodoItem(id = it.id, todoName = it.todoName, todoCompleted = it.todoCompleted)
        }

        //todosListState = newArray THIS DOES NOT WORK

        println("New Array ${newArray}")

    }

    fun deleteTodo(todoId: String) {
        // STUCK HERE trying to remove class object from List
        // Pass down state with new List with removed objects
        println("delete Todo $todoId")
        //var newArray = todoItems.filter { p -> p.id != todoId }
        println("delete  Array ${newArray}")
        // THIS does not work

    }

    Column () {
        ListArea(todosListState,
            onAddTodo = { x -> addNewTodo(x)},
            completeTodo = { x -> completeTodo(x)},
            deleteTodo = { x -> deleteTodo(x)},
            newTodoName.value,
            {newName -> newTodoName.value = newName},)
    }

}


@Composable
fun ListArea(
    todoList: List<TodoItem>,
    onAddTodo: (String) -> Unit,
    completeTodo: (String) -> Unit,
    deleteTodo: (String) -> Unit,
    textFieldValue: String,
    textFieldUpdate: (newName: String) -> Unit,
) {
    Column() {
        Text(text = "List Area of App")

        var newNameStateContent = remember { mutableStateOf("") }

        Row(
            horizontalArrangement = Arrangement.SpaceEvenly,
            modifier = Modifier
                .fillMaxWidth()) {

            TextField(value = newNameStateContent.value,
                onValueChange = { newInput -> newNameStateContent.value = newInput }, label = {
                    Text(text = "New Todo")
                }, singleLine = true)

            Spacer(Modifier.weight(1.0f))
            Button(onClick = {
                onAddTodo(newNameStateContent.value)

            }) {
                Text(text = "Submit")
            }

        }

        todoList.forEach { item ->
            TodoItemRow(todo = item,
                completeTodo = { x -> completeTodo(x)},
                deleteTodo = { x -> deleteTodo(x)})
        }

    }
}

@Composable
fun TodoItemRow(todo: TodoItem, completeTodo: (String) -> Unit, deleteTodo: (String) -> Unit) {

    Column {
        Row(modifier = Modifier
            .fillMaxWidth()
            .padding(10.dp),) {
            Button(onClick = { completeTodo(todo.id) } ) {
                Text(text = todo.todoName)
            }
            Spacer(Modifier.weight(1.0f))
            Button(onClick = { deleteTodo(todo.id) } ) {
                Text(text = "X")
            }
        }
        Divider()
    }
}
Clay_F
  • 561
  • 1
  • 6
  • 17
  • 1
    To delete an item, use todosListState.remove(todosListState.indexOf{it.id==todoId}). To update item, you can change val todosListState = ... to var todosListState = same. Then you will be able to assign: todosListState = newArray. Or you can look at this answer: https://stackoverflow.com/questions/68046535/lazycolumn-and-mutable-list-how-to-update – bylazy Feb 09 '22 at 06:11
  • 1
    Functions inside composables!! This is not at all recommended, use `viewmodel` for better approach or put the functions outside the composable in a separate file or so – RaBaKa 78 Feb 09 '22 at 06:17

0 Answers0