From e4280f049032c44eea4017063432a33c700d7aea Mon Sep 17 00:00:00 2001 From: Borgia Leiva Date: Thu, 12 Feb 2026 11:33:37 +0100 Subject: [PATCH 01/12] Added more necessary endpoints to ApiService.kt --- app/build.gradle.kts | 5 +--- .../network/ApiService.kt | 25 +++++++++++++++++++ app/src/main/res/values/arrays.xml | 10 ++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/values/arrays.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5d7a6cb..72bf4c7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,9 +4,7 @@ plugins { android { namespace = "com.campusaula.edbole.kanban_clone_android" - compileSdk { - version = release(36) - } + compileSdk = 36 defaultConfig { applicationId = "com.campusaula.edbole.KanbanCloneAndroid" @@ -44,7 +42,6 @@ dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") - // Networking: OkHttp + Retrofit implementation("com.squareup.okhttp3:okhttp:4.11.0") implementation("com.squareup.okhttp3:logging-interceptor:4.11.0") implementation("com.squareup.retrofit2:retrofit:2.9.0") diff --git a/app/src/main/java/com/campusaula/edbole/kanban_clone_android/network/ApiService.kt b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/network/ApiService.kt index 6d9184b..296b6a1 100644 --- a/app/src/main/java/com/campusaula/edbole/kanban_clone_android/network/ApiService.kt +++ b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/network/ApiService.kt @@ -40,6 +40,18 @@ interface ApiService { @GET("projects/{project_id}/users/") suspend fun getProjectUsers(@Path("project_id") projectId: Int): Response> + @POST("projects/{project_id}/users/") + suspend fun addProjectCollaborator( + @Path("project_id") projectId: Int, + @Body email: Map + ): Response + + @DELETE("projects/{project_id}/users/{user_id}/") + suspend fun removeProjectCollaborator( + @Path("project_id") projectId: Int, + @Path("user_id") userId: Int + ): Response + @POST("projects/") suspend fun createProject(@Body projectCreate: ProjectCreate): Response @@ -57,4 +69,17 @@ interface ApiService { @POST("projects/{project_id}/tasks/") suspend fun createTask(@Path("project_id") projectId: Int, @Body taskBase: TaskBase): Response + @PUT("projects/{project_id}/tasks/{task_id}/") + suspend fun updateProjectTask( + @Path("project_id") projectId: Int, + @Path("task_id") taskId: Int, + @Body taskUpdate: TaskUpdate + ): Response + + @DELETE("projects/{project_id}/tasks/{task_id}/") + suspend fun deleteProjectTask( + @Path("project_id") projectId: Int, + @Path("task_id") taskId: Int + ): Response + } diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml new file mode 100644 index 0000000..c0dda4b --- /dev/null +++ b/app/src/main/res/values/arrays.xml @@ -0,0 +1,10 @@ + + + + Pending + In progress + Completed + Stashed + Failed + + From 9e2d6b47934f21e02c7c78a9b2b3e9f3ab05a739 Mon Sep 17 00:00:00 2001 From: Borgia Leiva Date: Thu, 12 Feb 2026 11:34:15 +0100 Subject: [PATCH 02/12] Added some common-use palettes and values for layout usage --- app/src/main/res/values/colors.xml | 11 +++++++++++ app/src/main/res/values/dimens.xml | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 app/src/main/res/values/dimens.xml diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index c8524cd..4f13a53 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,4 +2,15 @@ #FF000000 #FFFFFFFF + + + #469E29 + #FF0000 + #FF9800 + + + #666666 + + + #24FF5757 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..28ce610 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,27 @@ + + + + 12dp + 8dp + + + 12dp + 16dp + 24dp + 32dp + 8dp + 4dp + + + 17dp + 18dp + + + 80dp + + + 24sp + 18sp + 14sp + + From 13ea6e4ef7ce03d1436d95b7c80f2ca69895d58c Mon Sep 17 00:00:00 2001 From: Borgia Leiva Date: Thu, 12 Feb 2026 11:35:52 +0100 Subject: [PATCH 03/12] Task creation from --- app/src/main/AndroidManifest.xml | 12 ++ .../kanban_clone_android/ui/MainActivity.kt | 1 + .../ui/TaskAddActivity.kt | 136 ++++++++++++++++++ app/src/main/res/layout/activity_task_add.xml | 117 +++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/TaskAddActivity.kt create mode 100644 app/src/main/res/layout/activity_task_add.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9bd5106..d5f2638 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,18 @@ + + + + diff --git a/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/MainActivity.kt b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/MainActivity.kt index fe71980..363fccb 100644 --- a/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/MainActivity.kt +++ b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/MainActivity.kt @@ -15,6 +15,7 @@ import com.campusaula.edbole.kanban_clone_android.R import com.campusaula.edbole.kanban_clone_android.kanban.Project import com.campusaula.edbole.kanban_clone_android.network.ApiService import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance +import com.campusaula.edbole.kanban_clone_android.ui.adapters.ProjectItemAdapter import com.google.android.material.floatingactionbutton.FloatingActionButton import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/TaskAddActivity.kt b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/TaskAddActivity.kt new file mode 100644 index 0000000..37d764c --- /dev/null +++ b/app/src/main/java/com/campusaula/edbole/kanban_clone_android/ui/TaskAddActivity.kt @@ -0,0 +1,136 @@ +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.TaskBase +import com.campusaula.edbole.kanban_clone_android.kanban.TaskStatus +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 TaskAddActivity : 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 createTaskButton: Button + + private var projectId: Int = -1 + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContentView(R.layout.activity_task_add) + 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 project ID from intent + projectId = intent.getIntExtra("project_id", -1) + + if (projectId == -1) { + Toast.makeText(this, "Error: Invalid project ID", Toast.LENGTH_SHORT).show() + finish() + return + } + + // Initialize views + returnActionButton = findViewById(R.id.returnActionButton) + taskTitleInput = findViewById(R.id.taskTitleInput) + taskDescriptionInput = findViewById(R.id.taskDescriptionInput) + taskStatusSpinner = findViewById(R.id.taskStatusSpinner) + createTaskButton = findViewById(R.id.createTaskButton) + + // Set default status to PENDING (index 0) + taskStatusSpinner.setSelection(0) + + // Set up button listeners + returnActionButton.setOnClickListener { + finish() + + val intent = Intent(this@TaskAddActivity, ProjectDetailActivity::class.java) + intent.putExtra("project_id", projectId) + startActivity(intent) + } + + createTaskButton.setOnClickListener { + createTask() + } + } + + private fun createTask() { + val title = taskTitleInput.text.toString().trim() + val description = taskDescriptionInput.text.toString().trim() + val status = TaskStatus.entries[taskStatusSpinner.selectedItemPosition] + + if (title.isEmpty()) { + Toast.makeText(this, "Title cannot be empty", Toast.LENGTH_SHORT).show() + return + } + + lifecycleScope.launch { + try { + Log.d("TaskAddActivity", "Creating task: $title") + val taskBase = TaskBase( + id = 0, // ID will be assigned by the server + title = title, + description = description, + status = status + ) + + val response = api.createTask(projectId, taskBase) + + if (response.isSuccessful) { + Log.d("TaskAddActivity", "Task created successfully") + Toast.makeText( + this@TaskAddActivity, + "Task created successfully", + Toast.LENGTH_SHORT + ).show() + setResult(RESULT_OK) + finish() + + // Reopen ProjectDetailActivity to show the new task + val intent = Intent(this@TaskAddActivity, ProjectDetailActivity::class.java) + intent.putExtra("project_id", projectId) + startActivity(intent) + } else { + val errorBody = response.errorBody()?.string() + Log.e("TaskAddActivity", "Error creating task: $errorBody") + Toast.makeText( + this@TaskAddActivity, + "Error creating task: ${response.code()}", + Toast.LENGTH_SHORT + ).show() + } + } catch (e: Exception) { + Log.e("TaskAddActivity", "Exception creating task: ${e.message}") + Toast.makeText( + this@TaskAddActivity, + "Failed to create task: ${e.message}", + Toast.LENGTH_SHORT + ).show() + } + } + } +} + diff --git a/app/src/main/res/layout/activity_task_add.xml b/app/src/main/res/layout/activity_task_add.xml new file mode 100644 index 0000000..3ceeffe --- /dev/null +++ b/app/src/main/res/layout/activity_task_add.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + +