Task editing form

This commit is contained in:
Marta Borgia Leiva 2026-02-12 11:36:49 +01:00
parent 13ea6e4ef7
commit 421ffd5dc9
3 changed files with 333 additions and 6 deletions

View file

@ -3,15 +3,15 @@ package com.campusaula.edbole.kanban_clone_android.kanban
import com.google.gson.annotations.SerializedName
enum class TaskStatus {
@SerializedName("PENDING")
@SerializedName("pending")
PENDING,
@SerializedName("IN_PROGRESS")
@SerializedName("in_progress")
IN_PROGRESS,
@SerializedName("COMPLETED")
@SerializedName("completed")
COMPLETED,
@SerializedName("FAILED")
@SerializedName("failed")
FAILED,
@SerializedName("STASHED")
@SerializedName("stashed")
STASHED
}
@ -19,7 +19,7 @@ class Task {
val id: Int = 0
val title: String = ""
val description: String = ""
val status: TaskStatus = TaskStatus.PENDING
var status: TaskStatus = TaskStatus.PENDING
val project: Project? = null
}
@ -36,3 +36,14 @@ data class TaskBase(
@SerializedName("status")
val status: TaskStatus
)
data class TaskUpdate(
@SerializedName("title")
val title : String?,
@SerializedName("description")
val description : String?,
@SerializedName("status")
val status: TaskStatus?
)

View file

@ -0,0 +1,189 @@
package com.campusaula.edbole.kanban_clone_android.ui
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.Spinner
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.campusaula.edbole.kanban_clone_android.R
import com.campusaula.edbole.kanban_clone_android.kanban.TaskStatus
import com.campusaula.edbole.kanban_clone_android.kanban.TaskUpdate
import com.campusaula.edbole.kanban_clone_android.network.ApiService
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.launch
class TaskEditActivity : AppCompatActivity() {
private lateinit var api: ApiService
private lateinit var returnActionButton: FloatingActionButton
private lateinit var taskTitleInput: EditText
private lateinit var taskDescriptionInput: EditText
private lateinit var taskStatusSpinner: Spinner
private lateinit var saveTaskButton: Button
private lateinit var deleteTaskButton: Button
private var projectId: Int = -1
private var taskId: Int = -1
private var currentTitle: String = ""
private var currentDescription: String = ""
private var currentStatus: TaskStatus = TaskStatus.PENDING
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_task_edit)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
api = RetrofitInstance.getRetrofit(applicationContext).create(ApiService::class.java)
// Get task and project IDs from intent
projectId = intent.getIntExtra("project_id", -1)
taskId = intent.getIntExtra("task_id", -1)
currentTitle = intent.getStringExtra("task_title") ?: ""
currentDescription = intent.getStringExtra("task_description") ?: ""
val statusString = intent.getStringExtra("task_status") ?: "PENDING"
currentStatus = TaskStatus.valueOf(statusString)
if (projectId == -1 || taskId == -1) {
Toast.makeText(this, "Error: Invalid task or project ID", Toast.LENGTH_SHORT).show()
finish()
}
// Initialize views
returnActionButton = findViewById(R.id.returnActionButton)
taskTitleInput = findViewById(R.id.taskTitleInput)
taskDescriptionInput = findViewById(R.id.taskDescriptionInput)
taskStatusSpinner = findViewById(R.id.taskStatusSpinner)
saveTaskButton = findViewById(R.id.saveTaskButton)
deleteTaskButton = findViewById(R.id.deleteTaskButton)
// Populate fields with current task data
taskTitleInput.setText(currentTitle)
taskDescriptionInput.setText(currentDescription)
taskStatusSpinner.setSelection(TaskStatus.entries.indexOf(currentStatus))
// Set up button listeners
returnActionButton.setOnClickListener {
finish()
val intent = Intent(this@TaskEditActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
}
saveTaskButton.setOnClickListener {
saveTask()
}
deleteTaskButton.setOnClickListener {
deleteTask()
}
}
private fun saveTask() {
val newTitle = taskTitleInput.text.toString().trim()
val newDescription = taskDescriptionInput.text.toString().trim()
val newStatus = TaskStatus.entries[taskStatusSpinner.selectedItemPosition]
if (newTitle.isEmpty()) {
Toast.makeText(this, "Title cannot be empty", Toast.LENGTH_SHORT).show()
return
}
lifecycleScope.launch {
try {
Log.d("TaskEditActivity", "Updating task: $taskId")
val taskUpdate = TaskUpdate(
title = if (newTitle != currentTitle) newTitle else null,
description = if (newDescription != currentDescription) newDescription else null,
status = if (newStatus != currentStatus) newStatus else null
)
val response = api.updateProjectTask(projectId, taskId, taskUpdate)
if (response.isSuccessful) {
Log.d("TaskEditActivity", "Task updated successfully")
Toast.makeText(
this@TaskEditActivity,
"Task updated successfully",
Toast.LENGTH_SHORT
).show()
setResult(RESULT_OK)
finish()
val intent = Intent(this@TaskEditActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
} else {
val errorBody = response.errorBody()?.string()
Log.e("TaskEditActivity", "Error updating task: $errorBody")
Toast.makeText(
this@TaskEditActivity,
"Error updating task: ${response.code()}",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Log.e("TaskEditActivity", "Exception updating task: ${e.message}")
Toast.makeText(
this@TaskEditActivity,
"Failed to update task: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
private fun deleteTask() {
lifecycleScope.launch {
try {
Log.d("TaskEditActivity", "Deleting task: $taskId")
val response = api.deleteProjectTask(projectId, taskId)
if (response.isSuccessful) {
Log.d("TaskEditActivity", "Task deleted successfully")
Toast.makeText(
this@TaskEditActivity,
"Task deleted successfully",
Toast.LENGTH_SHORT
).show()
setResult(RESULT_OK)
finish()
// Reopen ProjectDetailActivity after deleting the task
val intent = Intent(this@TaskEditActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
} else {
val errorBody = response.errorBody()?.string()
Log.e("TaskEditActivity", "Error deleting task: $errorBody")
Toast.makeText(
this@TaskEditActivity,
"Error deleting task: ${response.code()}",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Log.e("TaskEditActivity", "Exception deleting task: ${e.message}")
Toast.makeText(
this@TaskEditActivity,
"Failed to delete task: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}

View file

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.TaskEditActivity">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/returnActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/fab_margin_end"
android:layout_marginBottom="@dimen/fab_margin_bottom"
android:contentDescription="Return"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:srcCompat="@android:drawable/ic_menu_revert" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/bottom_padding_for_fab">
<TextView
android:id="@+id/titleLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Edit Task"
android:textSize="@dimen/text_size_title"
android:textStyle="bold"
android:padding="@dimen/padding_standard"
android:layout_marginTop="@dimen/margin_tiny" />
<TextView
android:id="@+id/taskTitleLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title:"
android:textSize="@dimen/text_size_subtitle"
android:textStyle="bold"
android:layout_marginTop="@dimen/margin_medium"
android:paddingLeft="12dp"
android:paddingRight="12dp" />
<EditText
android:id="@+id/taskTitleInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter task title"
android:inputType="text"
android:padding="@dimen/padding_standard"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:layout_marginTop="@dimen/margin_small" />
<TextView
android:id="@+id/taskDescriptionLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Description:"
android:textSize="@dimen/text_size_subtitle"
android:textStyle="bold"
android:layout_marginTop="@dimen/margin_medium"
android:paddingLeft="12dp"
android:paddingRight="12dp" />
<EditText
android:id="@+id/taskDescriptionInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter task description"
android:inputType="textMultiLine"
android:minLines="3"
android:maxLines="5"
android:padding="@dimen/padding_standard"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:layout_marginTop="@dimen/margin_small"
android:gravity="start|top" />
<TextView
android:id="@+id/taskStatusLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Status:"
android:textSize="@dimen/text_size_subtitle"
android:textStyle="bold"
android:layout_marginTop="@dimen/margin_medium"
android:paddingLeft="12dp"
android:paddingRight="12dp" />
<Spinner
android:id="@+id/taskStatusSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/task_status_options"
android:padding="@dimen/padding_standard"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:layout_marginTop="@dimen/margin_small" />
<Button
android:id="@+id/saveTaskButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save Changes"
android:backgroundTint="@color/primary_green"
android:layout_marginTop="@dimen/margin_large"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard" />
<Button
android:id="@+id/deleteTaskButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Delete Task"
android:backgroundTint="@color/danger_red"
android:layout_marginTop="@dimen/margin_medium"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>