Compare commits

..

No commits in common. "6ee5e225ef89375770f4ccd38fc71a8a5a975df3" and "a8f9a69d58e669c5f034348c7ab99ac9ba77d28b" have entirely different histories.

28 changed files with 273 additions and 1903 deletions

View file

@ -4,7 +4,9 @@ plugins {
android { android {
namespace = "com.campusaula.edbole.kanban_clone_android" namespace = "com.campusaula.edbole.kanban_clone_android"
compileSdk = 36 compileSdk {
version = release(36)
}
defaultConfig { defaultConfig {
applicationId = "com.campusaula.edbole.KanbanCloneAndroid" applicationId = "com.campusaula.edbole.KanbanCloneAndroid"
@ -42,6 +44,7 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
implementation("androidx.lifecycle:lifecycle-runtime-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:okhttp:4.11.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0") implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("com.squareup.retrofit2:retrofit:2.9.0") implementation("com.squareup.retrofit2:retrofit:2.9.0")

View file

@ -18,18 +18,6 @@
<activity <activity
android:name=".ui.CreateProjectActivity" android:name=".ui.CreateProjectActivity"
android:exported="false" /> android:exported="false" />
<activity
android:name=".ui.ProjectEditActivity"
android:exported="false" />
<activity
android:name=".ui.CollaboratorAddActivity"
android:exported="false" />
<activity
android:name=".ui.TaskAddActivity"
android:exported="false" />
<activity
android:name=".ui.TaskEditActivity"
android:exported="false" />
<activity <activity
android:name=".ui.ProjectDetailActivity" android:name=".ui.ProjectDetailActivity"
android:exported="false" /> android:exported="false" />

View file

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

View file

@ -40,18 +40,6 @@ interface ApiService {
@GET("projects/{project_id}/users/") @GET("projects/{project_id}/users/")
suspend fun getProjectUsers(@Path("project_id") projectId: Int): Response<List<UserBase>> suspend fun getProjectUsers(@Path("project_id") projectId: Int): Response<List<UserBase>>
@POST("projects/{project_id}/users/")
suspend fun addProjectCollaborator(
@Path("project_id") projectId: Int,
@Body email: Map<String, String>
): Response<Unit>
@DELETE("projects/{project_id}/users/{user_id}/")
suspend fun removeProjectCollaborator(
@Path("project_id") projectId: Int,
@Path("user_id") userId: Int
): Response<Unit>
@POST("projects/") @POST("projects/")
suspend fun createProject(@Body projectCreate: ProjectCreate): Response<ProjectBase> suspend fun createProject(@Body projectCreate: ProjectCreate): Response<ProjectBase>
@ -69,17 +57,4 @@ interface ApiService {
@POST("projects/{project_id}/tasks/") @POST("projects/{project_id}/tasks/")
suspend fun createTask(@Path("project_id") projectId: Int, @Body taskBase: TaskBase): Response<TaskBase> suspend fun createTask(@Path("project_id") projectId: Int, @Body taskBase: TaskBase): Response<TaskBase>
@PUT("projects/{project_id}/tasks/{task_id}/")
suspend fun updateProjectTask(
@Path("project_id") projectId: Int,
@Path("task_id") taskId: Int,
@Body taskUpdate: TaskUpdate
): Response<Unit>
@DELETE("projects/{project_id}/tasks/{task_id}/")
suspend fun deleteProjectTask(
@Path("project_id") projectId: Int,
@Path("task_id") taskId: Int
): Response<Unit>
} }

View file

@ -1,126 +0,0 @@
package com.campusaula.edbole.kanban_clone_android.ui
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.util.Patterns
import android.widget.Button
import android.widget.EditText
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.network.ApiService
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.launch
class CollaboratorAddActivity : AppCompatActivity() {
private lateinit var api: ApiService
private lateinit var returnActionButton: FloatingActionButton
private lateinit var collaboratorEmailInput: EditText
private lateinit var addCollaboratorButton: Button
private var projectId: Int = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_collaborator_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)
collaboratorEmailInput = findViewById(R.id.collaboratorEmailInput)
addCollaboratorButton = findViewById(R.id.addCollaboratorButton)
// Set up button listeners
returnActionButton.setOnClickListener {
finish()
val intent = Intent(this@CollaboratorAddActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
}
addCollaboratorButton.setOnClickListener {
addCollaborator()
}
}
private fun addCollaborator() {
val user_email = collaboratorEmailInput.text.toString().trim()
// Validate email
if (user_email.isEmpty()) {
Toast.makeText(this, "Email cannot be empty", Toast.LENGTH_SHORT).show()
return
}
if (!Patterns.EMAIL_ADDRESS.matcher(user_email).matches()) {
Toast.makeText(this, "Please enter a valid email address", Toast.LENGTH_SHORT).show()
return
}
lifecycleScope.launch {
try {
Log.d("CollaboratorAddActivity", "Adding collaborator: $user_email")
val emailBody = mapOf("user_email" to user_email)
val response = api.addProjectCollaborator(projectId, emailBody)
if (response.isSuccessful) {
Log.d("CollaboratorAddActivity", "Collaborator added successfully")
Toast.makeText(
this@CollaboratorAddActivity,
"Collaborator added successfully",
Toast.LENGTH_SHORT
).show()
setResult(RESULT_OK)
finish()
// Reopen ProjectDetailActivity to show the new collaborator
val intent = Intent(this@CollaboratorAddActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
} else {
val errorBody = response.errorBody()?.string()
Log.e("CollaboratorAddActivity", "Error adding collaborator: $errorBody")
Toast.makeText(
this@CollaboratorAddActivity,
"Error adding collaborator: ${response.code()}",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Log.e("CollaboratorAddActivity", "Exception adding collaborator: ${e.message}")
Toast.makeText(
this@CollaboratorAddActivity,
"Failed to add collaborator: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}

View file

@ -3,8 +3,9 @@ package com.campusaula.edbole.kanban_clone_android.ui
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.AutoCompleteTextView
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.MultiAutoCompleteTextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -24,8 +25,8 @@ class CreateProjectActivity : AppCompatActivity() {
private lateinit var api: ApiService private lateinit var api: ApiService
private lateinit var returnActionButton : FloatingActionButton private lateinit var returnActionButton : FloatingActionButton
private lateinit var newProjectName : EditText private lateinit var newProjectName : AutoCompleteTextView
private lateinit var newProjectDescription : EditText private lateinit var newProjectDescription : AutoCompleteTextView
private lateinit var newProjectCreateButton : Button private lateinit var newProjectCreateButton : Button
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -41,63 +42,47 @@ class CreateProjectActivity : AppCompatActivity() {
api = RetrofitInstance.getRetrofit(applicationContext).create(ApiService::class.java) api = RetrofitInstance.getRetrofit(applicationContext).create(ApiService::class.java)
returnActionButton = findViewById(R.id.returnActionButton) returnActionButton = findViewById(R.id.returnActionButton)
returnActionButton.setOnClickListener { returnActionButton.setOnClickListener { finish() }
finish()
val intent = Intent(this@CreateProjectActivity, MainActivity::class.java)
startActivity(intent)
}
newProjectName = findViewById(R.id.newProjectName) newProjectName = findViewById(R.id.newProjectName)
newProjectDescription = findViewById(R.id.newProjectDescription) newProjectDescription = findViewById(R.id.newProjectDescription)
newProjectCreateButton = findViewById(R.id.newProjectCreateButton) newProjectCreateButton = findViewById(R.id.newProjectCreateButton)
newProjectCreateButton.setOnClickListener { newProjectCreateButton.setOnClickListener {
val projectName = newProjectName.text.toString().trim() val projectName = newProjectName.text.toString()
val projectDescription = newProjectDescription.text.toString().trim() val projectDescription = newProjectDescription.text.toString()
if (projectName.isEmpty()) { if (projectName.isEmpty() || projectDescription.isEmpty()) {
Toast.makeText(this, "Project name cannot be empty", Toast.LENGTH_SHORT).show() Toast
.makeText(this, "Please fill in all fields", Toast.LENGTH_SHORT)
.show()
return@setOnClickListener return@setOnClickListener
} }
lifecycleScope.launch { lifecycleScope.launch {
try {
Log.d("CreateProjectActivity", "Creating project: $projectName")
val projectCreate = ProjectCreate(projectName, projectDescription)
val response = api.createProject(projectCreate)
if (response.isSuccessful) { val projectCreate : ProjectCreate = ProjectCreate(projectName, projectDescription)
Log.d("CreateProjectActivity", "Project created successfully: ${response.body()}") val response = api.createProject(projectCreate)
Toast.makeText(
this@CreateProjectActivity,
"Project created successfully",
Toast.LENGTH_SHORT
).show()
finish()
// Volver a MainActivity para ver el nuevo proyecto if (response.isSuccessful){
val intent = Intent(this@CreateProjectActivity, MainActivity::class.java) Toast
startActivity(intent) .makeText(this@CreateProjectActivity, "Project created successfully", Toast.LENGTH_SHORT)
} else { .show()
val errorBody = response.errorBody()?.string() Log.d("CreateProjectActivity", "Created project: ${response.body()}")
Log.e("CreateProjectActivity", "Error creating project: $errorBody") startActivity(Intent(this@CreateProjectActivity, MainActivity::class.java))
Toast.makeText( } else {
this@CreateProjectActivity, Log.e("CreateProjectActivity", "Error creating project: ${response.code()} - ${response.message()}")
"Error creating project: ${response.code()}", Toast
Toast.LENGTH_SHORT .makeText(this@CreateProjectActivity, "Error creating project", Toast.LENGTH_SHORT)
).show() .show()
}
} catch (e: Exception) {
Log.e("CreateProjectActivity", "Exception creating project: ${e.message}")
Toast.makeText(
this@CreateProjectActivity,
"Failed to create project: ${e.message}",
Toast.LENGTH_SHORT
).show()
} }
} }
} }
} }
} }

View file

@ -15,7 +15,6 @@ import com.campusaula.edbole.kanban_clone_android.R
import com.campusaula.edbole.kanban_clone_android.kanban.Project 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.ApiService
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance 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 com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -82,9 +81,8 @@ class MainActivity : AppCompatActivity() {
if (logoutResponse.isSuccessful) { if (logoutResponse.isSuccessful) {
// Clear cookies for the API host // Clear cookies for the API host
RetrofitInstance.clearCookiesForHost( RetrofitInstance.clearCookiesForHost(
"10.0.2.2" "10.0.2.2:8000"
) )
// Navigate back to the login screen // Navigate back to the login screen
val intent = val intent =
Intent(this@MainActivity, LoginActivity::class.java) Intent(this@MainActivity, LoginActivity::class.java)

View file

@ -0,0 +1,41 @@
package com.campusaula.edbole.kanban_clone_android.ui
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.campusaula.edbole.kanban_clone_android.kanban.User
class ProjectCollaboratorAdapter(
private var collaborators: List<User>
) : RecyclerView.Adapter<ProjectCollaboratorAdapter.ViewHolder>() {
fun submitList(newList: List<User>) {
collaborators = newList.toMutableList()
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_collaborator, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(collaborators[position])
}
override fun getItemCount(): Int = collaborators.size
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val collaboratorNameText: TextView = itemView.findViewById(R.id.collaboratorNameText)
private val removeCollaboratorButton: Button = itemView.findViewById(R.id.removeCollaboratorButton)
fun bind(collaborator: User) {
collaboratorNameText.text = collaborator.name
}
}
}
}

View file

@ -18,8 +18,6 @@ import com.campusaula.edbole.kanban_clone_android.kanban.Task
import com.campusaula.edbole.kanban_clone_android.kanban.TaskStatus 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.ApiService
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
import com.campusaula.edbole.kanban_clone_android.ui.adapters.ProjectCollaboratorAdapter
import com.campusaula.edbole.kanban_clone_android.ui.adapters.ProjectTaskAdapter
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -30,14 +28,9 @@ class ProjectDetailActivity : AppCompatActivity() {
private lateinit var returnActionButton: FloatingActionButton private lateinit var returnActionButton: FloatingActionButton
private lateinit var addTaskButton: Button private lateinit var addTaskButton: Button
private lateinit var addCollaboratorButton: Button private lateinit var addCollaboratorButton: Button
private lateinit var editProjectButton: Button
private lateinit var deleteProjectButton: Button
private lateinit var taskListRecycler: RecyclerView
private lateinit var collaboratorListRecycler: RecyclerView private lateinit var collaboratorListRecycler: RecyclerView
private lateinit var collaboratorListAdapter: ProjectCollaboratorAdapter // private lateinit var collaboratorListAdapter: CollaboratorListAdapter
private lateinit var taskListAdapter: ProjectTaskAdapter
private lateinit var projectTitleText : TextView private lateinit var projectTitleText : TextView
private lateinit var projectDescriptionText : TextView private lateinit var projectDescriptionText : TextView
@ -66,52 +59,23 @@ class ProjectDetailActivity : AppCompatActivity() {
returnActionButton.setOnClickListener { finish() } returnActionButton.setOnClickListener { finish() }
addTaskButton = findViewById(R.id.addTaskButton) addTaskButton = findViewById(R.id.addTaskButton)
addTaskButton.setOnClickListener { // addTaskButton.setOnClickListener {
val intent = Intent(this, TaskAddActivity::class.java) // val intent: Intent = Intent(this, CreateTaskActivity::class.java)
intent.putExtra("project_id", projectId) // intent.putExtra("project_id", projectId)
startActivity(intent) // startActivity(intent)
finish() // }
}
addCollaboratorButton = findViewById(R.id.addCollaboratorButton) addCollaboratorButton = findViewById(R.id.addCollaboratorButton)
addCollaboratorButton.setOnClickListener { // addCollaboratorButton.setOnClickListener {
val intent = Intent(this, CollaboratorAddActivity::class.java) // val intent: Intent = Intent(this, AddCollaboratorActivity::class.java)
intent.putExtra("project_id", projectId) // intent.putExtra("project_id", projectId)
startActivity(intent) // startActivity(intent)
finish() // }
}
taskListRecycler = findViewById(R.id.taskListRecycler)
taskListRecycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
taskListAdapter = ProjectTaskAdapter(emptyList(), api, projectId, {
updateCompletionRate()
}, {
finish()
})
taskListRecycler.adapter = taskListAdapter
collaboratorListRecycler = findViewById(R.id.collaboratorListRecycler) collaboratorListRecycler = findViewById(R.id.collaboratorListRecycler)
// collaboratorListAdapter =
collaboratorListRecycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this) collaboratorListRecycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
collaboratorListAdapter = ProjectCollaboratorAdapter(emptyList(), api, projectId) {
updateCollaboratorList()
}
collaboratorListRecycler.adapter = collaboratorListAdapter
// Danger Zone buttons
editProjectButton = findViewById(R.id.editProjectButton)
editProjectButton.setOnClickListener {
val intent = Intent(this, ProjectEditActivity::class.java)
intent.putExtra("project_id", projectId)
intent.putExtra("project_name", projectTitleText.text.toString())
intent.putExtra("project_description", projectDescriptionText.text.toString())
startActivity(intent)
finish()
}
deleteProjectButton = findViewById(R.id.deleteProjectButton)
deleteProjectButton.setOnClickListener {
deleteProject(projectId)
}
if (projectId > 0) { if (projectId > 0) {
Log.d("ProjectDetailActivity", "Received project ID: $projectId") Log.d("ProjectDetailActivity", "Received project ID: $projectId")
@ -130,22 +94,16 @@ class ProjectDetailActivity : AppCompatActivity() {
projectDescriptionText.text = project.description projectDescriptionText.text = project.description
var percentageFinished = 0.0; var percentageFinished = 0.0;
val collaborators = project.users
val tasks: List<Task> = project.tasks val tasks: List<Task> = project.tasks
val totalTasks: Int = tasks.size val totalTasks: Int = tasks.size
val perTaskPercentage = if (totalTasks > 0) (1.0 / totalTasks)*100 else 0.0
var completedTasks = 0
for (task in tasks) { for (task in tasks) {
if (task.status == TaskStatus.COMPLETED) { if (task.status == TaskStatus.COMPLETED) {
completedTasks++ percentageFinished += perTaskPercentage
} }
} }
completedPercentageText.text = "Completed: ${"%.2f".format(percentageFinished * 100)}%"
percentageFinished = if (totalTasks > 0) (completedTasks.toDouble() / totalTasks.toDouble()) * 100 else 0.0
completedPercentageText.text = "Completed: ${"%.2f".format(percentageFinished)}%"
taskListAdapter.submitList(tasks.toMutableList())
collaboratorListAdapter.submitList(collaborators.toMutableList())
} else { } else {
@ -166,90 +124,4 @@ class ProjectDetailActivity : AppCompatActivity() {
} }
private fun updateCompletionRate() {
lifecycleScope.launch {
try {
val projectId = intent.getIntExtra("project_id", -1)
val projectResponse = api.getProjectById(projectId)
if (projectResponse.isSuccessful && projectResponse.body() != null) {
val project = projectResponse.body()!!
val tasks: List<Task> = project.tasks
val totalTasks: Int = tasks.size
var completedTasks = 0
for (task in tasks) {
if (task.status == TaskStatus.COMPLETED) {
completedTasks++
}
}
val percentageFinished = if (totalTasks > 0) (completedTasks.toDouble() / totalTasks.toDouble()) * 100 else 0.0
completedPercentageText.text = "Completed: ${"%.2f".format(percentageFinished)}%"
// Actualizar la lista de tareas también
taskListAdapter.submitList(tasks.toMutableList())
}
} catch (e: Exception) {
Log.e("ProjectDetailActivity", "Error updating completion rate", e)
}
}
}
private fun updateCollaboratorList() {
lifecycleScope.launch {
try {
val projectId = intent.getIntExtra("project_id", -1)
val projectResponse = api.getProjectById(projectId)
if (projectResponse.isSuccessful && projectResponse.body() != null) {
val project = projectResponse.body()!!
val collaborators = project.users
collaboratorListAdapter.submitList(collaborators.toMutableList())
}
} catch (e: Exception) {
Log.e("ProjectDetailActivity", "Error updating collaborator list", e)
}
}
}
private fun deleteProject(projectId: Int) {
lifecycleScope.launch {
try {
Log.d("ProjectDetailActivity", "Deleting project: $projectId")
val response = api.deleteProject(projectId)
if (response.isSuccessful) {
Log.d("ProjectDetailActivity", "Project deleted successfully")
android.widget.Toast.makeText(
this@ProjectDetailActivity,
"Project deleted successfully",
android.widget.Toast.LENGTH_SHORT
).show()
finish()
// Volver a MainActivity
val intent = Intent(this@ProjectDetailActivity, MainActivity::class.java)
startActivity(intent)
} else {
val errorBody = response.errorBody()?.string()
Log.e("ProjectDetailActivity", "Error deleting project: $errorBody")
android.widget.Toast.makeText(
this@ProjectDetailActivity,
"Error deleting project: ${response.code()}",
android.widget.Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Log.e("ProjectDetailActivity", "Exception deleting project: ${e.message}")
android.widget.Toast.makeText(
this@ProjectDetailActivity,
"Failed to delete project: ${e.message}",
android.widget.Toast.LENGTH_SHORT
).show()
}
}
}
} }

View file

@ -1,134 +0,0 @@
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.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.ProjectCreate
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 ProjectEditActivity : AppCompatActivity() {
private lateinit var api: ApiService
private lateinit var returnActionButton: FloatingActionButton
private lateinit var projectNameInput: EditText
private lateinit var projectDescriptionInput: EditText
private lateinit var saveProjectButton: Button
private var projectId: Int = -1
private var currentName: String = ""
private var currentDescription: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_project_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 project data from intent
projectId = intent.getIntExtra("project_id", -1)
currentName = intent.getStringExtra("project_name") ?: ""
currentDescription = intent.getStringExtra("project_description") ?: ""
if (projectId == -1) {
Toast.makeText(this, "Error: Invalid project ID", Toast.LENGTH_SHORT).show()
finish()
return
}
// Initialize views
returnActionButton = findViewById(R.id.returnActionButton)
projectNameInput = findViewById(R.id.projectNameInput)
projectDescriptionInput = findViewById(R.id.projectDescriptionInput)
saveProjectButton = findViewById(R.id.saveProjectButton)
// Populate fields with current project data
projectNameInput.setText(currentName)
projectDescriptionInput.setText(currentDescription)
// Set up button listeners
returnActionButton.setOnClickListener {
finish()
val intent = Intent(this@ProjectEditActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
}
saveProjectButton.setOnClickListener {
saveProject()
}
}
private fun saveProject() {
val newName = projectNameInput.text.toString().trim()
val newDescription = projectDescriptionInput.text.toString().trim()
if (newName.isEmpty()) {
Toast.makeText(this, "Project name cannot be empty", Toast.LENGTH_SHORT).show()
return
}
lifecycleScope.launch {
try {
Log.d("ProjectEditActivity", "Updating project: $projectId")
val projectCreate = ProjectCreate(
name = newName,
description = newDescription
)
val response = api.updateProject(projectId, projectCreate)
if (response.isSuccessful) {
Log.d("ProjectEditActivity", "Project updated successfully")
Toast.makeText(
this@ProjectEditActivity,
"Project updated successfully",
Toast.LENGTH_SHORT
).show()
setResult(RESULT_OK)
finish()
// Reopen ProjectDetailActivity to show the updated project
val intent = Intent(this@ProjectEditActivity, ProjectDetailActivity::class.java)
intent.putExtra("project_id", projectId)
startActivity(intent)
} else {
val errorBody = response.errorBody()?.string()
Log.e("ProjectEditActivity", "Error updating project: $errorBody")
Toast.makeText(
this@ProjectEditActivity,
"Error updating project: ${response.code()}",
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Log.e("ProjectEditActivity", "Exception updating project: ${e.message}")
Toast.makeText(
this@ProjectEditActivity,
"Failed to update project: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}

View file

@ -1,4 +1,4 @@
package com.campusaula.edbole.kanban_clone_android.ui.adapters package com.campusaula.edbole.kanban_clone_android.ui
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View

View file

@ -1,136 +0,0 @@
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()
}
}
}
}

View file

@ -1,189 +0,0 @@
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

@ -1,101 +0,0 @@
package com.campusaula.edbole.kanban_clone_android.ui.adapters
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.campusaula.edbole.kanban_clone_android.R
import com.campusaula.edbole.kanban_clone_android.kanban.User
import com.campusaula.edbole.kanban_clone_android.network.ApiService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ProjectCollaboratorAdapter(
private var collaborators: List<User>,
private val apiService: ApiService,
private val projectId: Int,
private val onCollaboratorRemoved: () -> Unit = {}
) : RecyclerView.Adapter<ProjectCollaboratorAdapter.ViewHolder>() {
private val adapterScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
fun submitList(newList: List<User>) {
collaborators = newList.toMutableList()
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_collaborator, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(collaborators[position])
}
override fun getItemCount(): Int = collaborators.size
fun onDestroy() {
adapterScope.cancel("Adapter destroyed")
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val collaboratorNameText: TextView = itemView.findViewById(R.id.collaboratorNameText)
private val collaboratorEmailText: TextView = itemView.findViewById(R.id.collaboratorEmailText)
private val removeCollaboratorButton: Button = itemView.findViewById(R.id.removeCollaboratorButton)
fun bind(collaborator: User) {
collaboratorNameText.text = collaborator.name
collaboratorEmailText.text = collaborator.email
removeCollaboratorButton.setOnClickListener {
adapterScope.launch {
try {
Log.d("ProjectCollaboratorAdapter", "Removing collaborator: ${collaborator.id}")
val response = apiService.removeProjectCollaborator(projectId, collaborator.id)
if (response.isSuccessful) {
Log.d("ProjectCollaboratorAdapter", "Collaborator removed successfully: ${collaborator.id}")
withContext(Dispatchers.Main) {
Toast.makeText(
itemView.context,
"Collaborator removed: ${collaborator.name}",
Toast.LENGTH_SHORT
).show()
onCollaboratorRemoved()
}
} else {
val errorBody = response.errorBody()?.string()
Log.e("ProjectCollaboratorAdapter", "Error removing collaborator: $errorBody")
withContext(Dispatchers.Main) {
Toast.makeText(
itemView.context,
"Error removing collaborator: ${response.code()}",
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
Log.e("ProjectCollaboratorAdapter", "Exception removing collaborator: ${e.message}")
withContext(Dispatchers.Main) {
Toast.makeText(
itemView.context,
"Failed to remove collaborator: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}
}
}
}

View file

@ -1,140 +0,0 @@
package com.campusaula.edbole.kanban_clone_android.ui.adapters
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.Button
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.campusaula.edbole.kanban_clone_android.R
import com.campusaula.edbole.kanban_clone_android.kanban.Task
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.ui.TaskEditActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ProjectTaskAdapter(
private var tasks: List<Task>,
private val apiService: ApiService,
private val projectId: Int,
private val onTaskUpdated: () -> Unit = {},
private val onEditTask: () -> Unit = {}
) : RecyclerView.Adapter<ProjectTaskAdapter.ViewHolder>() {
private val adapterScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_task, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(tasks[position])
}
override fun getItemCount(): Int = tasks.size
fun submitList(newList: List<Task>) {
tasks = newList
notifyDataSetChanged()
}
// Cancelar el CoroutineScope cuando el adaptador ya no sea necesario
fun onDestroy() {
adapterScope.cancel()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val taskTitleText: TextView = itemView.findViewById(R.id.taskTitleText)
private val taskDescriptionText: TextView = itemView.findViewById(R.id.taskDescriptionText)
private val editTaskButton: Button = itemView.findViewById(R.id.editTaskButton)
private val taskStatusPicker: Spinner = itemView.findViewById(R.id.taskStatusDropdown)
fun bind(task: Task) {
taskTitleText.text = task.title
taskDescriptionText.text = task.description
editTaskButton.setOnClickListener {
val intent = Intent(itemView.context, TaskEditActivity::class.java)
intent.putExtra("project_id", projectId)
intent.putExtra("task_id", task.id)
intent.putExtra("task_title", task.title)
intent.putExtra("task_description", task.description)
intent.putExtra("task_status", task.status.name)
itemView.context.startActivity(intent)
onEditTask() // Cerrar la actividad
}
taskStatusPicker.setSelection(TaskStatus.entries.indexOf(task.status))
taskStatusPicker.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
val selectedStatus: TaskStatus = TaskStatus.entries[position]
task.status = selectedStatus
adapterScope.launch {
try {
Log.d("ProjectTaskAdapter", "Sending PUT request for task: ${task.id}")
Log.d("ProjectTaskAdapter", "Project ID: $projectId")
Log.d("ProjectTaskAdapter", "TaskUpdate data: ${TaskUpdate(null, null, task.status)}")
val response = apiService.updateProjectTask(
projectId,
task.id,
TaskUpdate(null, null, task.status)
)
if (response.isSuccessful) {
Log.d("ProjectTaskAdapter", "Task updated successfully: ${task.id}")
withContext(Dispatchers.Main) {
onTaskUpdated()
notifyDataSetChanged()
}
} else {
val errorBody = response.errorBody()?.string()
Log.e("ProjectTaskAdapter", "Error response: $errorBody")
withContext(Dispatchers.Main) {
Toast.makeText(
itemView.context,
"Error updating task: ${response.code()} - $errorBody",
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
Log.e("ProjectTaskAdapter", "Exception updating task: ${e.message}")
withContext(Dispatchers.Main) {
Toast.makeText(
itemView.context,
"Failed to update task: ${e.message}",
Toast.LENGTH_SHORT
).show()
}
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// No action needed
}
}
}
}
}

View file

@ -1,71 +0,0 @@
<?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.CollaboratorAddActivity">
<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="Add Collaborator"
android:textSize="@dimen/text_size_title"
android:textStyle="bold"
android:padding="@dimen/padding_standard"
android:layout_marginTop="@dimen/margin_tiny" />
<TextView
android:id="@+id/collaboratorEmailLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Email Address:"
android:textSize="@dimen/text_size_subtitle"
android:textStyle="bold"
android:layout_marginTop="@dimen/margin_medium"
android:paddingLeft="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<EditText
android:id="@+id/collaboratorEmailInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter collaborator email"
android:inputType="textEmailAddress"
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/addCollaboratorButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add Collaborator"
android:backgroundTint="@color/primary_green"
android:layout_marginTop="@dimen/margin_large"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -16,83 +16,80 @@
app:srcCompat="@android:drawable/ic_menu_revert" app:srcCompat="@android:drawable/ic_menu_revert"
android:id="@+id/returnActionButton" android:id="@+id/returnActionButton"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="@dimen/fab_margin_bottom" android:layout_marginBottom="16dp"
android:layout_marginEnd="@dimen/fab_margin_end" android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<LinearLayout <TextView
android:text="Create a new project..."
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:id="@+id/activityTitle"
android:paddingBottom="@dimen/bottom_padding_for_fab"> app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent"
android:padding="12dp"
android:textSize="24dp"
android:layout_marginTop="4dp" />
<TextView <MultiAutoCompleteTextView
android:text="Create a new project..." android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="500dp"
android:layout_height="wrap_content" android:id="@+id/newProjectDescription"
android:id="@+id/activityTitle" app:layout_constraintStart_toStartOf="parent"
android:padding="@dimen/padding_standard" app:layout_constraintHorizontal_bias="0.0"
android:textSize="@dimen/text_size_title" app:layout_constraintEnd_toEndOf="parent"
android:textStyle="bold" app:layout_constraintTop_toBottomOf="@+id/newProjectDescriptionLabel"
android:layout_marginTop="@dimen/margin_tiny" /> android:hint="This is my new super-special project that will change the world!!!"
android:textAlignment="textStart"
android:gravity="start|top"
android:padding="12dp" />
<TextView <AutoCompleteTextView
android:text="Project name:" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:id="@+id/newProjectName"
android:id="@+id/newProjectNameLabel" app:layout_constraintTop_toBottomOf="@+id/newProjectNameLabel"
android:textSize="@dimen/text_size_subtitle" app:layout_constraintStart_toStartOf="parent"
android:textStyle="bold" app:layout_constraintHorizontal_bias="0.0"
android:layout_marginTop="@dimen/margin_medium" app:layout_constraintEnd_toEndOf="parent"
android:paddingLeft="@dimen/padding_standard" android:hint="My new project!"
android:paddingRight="@dimen/padding_standard" /> android:padding="12dp" />
<EditText <TextView
android:layout_width="match_parent" android:text="Project name:"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:id="@+id/newProjectName" android:layout_height="wrap_content"
android:hint="My new project!" android:id="@+id/newProjectNameLabel"
android:inputType="text" tools:layout_editor_absoluteX="0dp"
android:padding="@dimen/padding_standard" android:labelFor="@id/activityTitle"
android:layout_marginLeft="@dimen/margin_standard" app:layout_constraintTop_toBottomOf="@+id/activityTitle"
android:layout_marginRight="@dimen/margin_standard" android:layout_marginTop="16dp" />
android:layout_marginTop="@dimen/margin_small" />
<TextView <TextView
android:text="Project description:" android:text="Project description:"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/newProjectDescriptionLabel" android:id="@+id/newProjectDescriptionLabel"
android:textSize="@dimen/text_size_subtitle" app:layout_constraintStart_toStartOf="parent"
android:textStyle="bold" app:layout_constraintHorizontal_bias="0.0"
android:layout_marginTop="@dimen/margin_medium" app:layout_constraintEnd_toEndOf="parent"
android:paddingLeft="@dimen/padding_standard" app:layout_constraintTop_toBottomOf="@+id/newProjectName"
android:paddingRight="@dimen/padding_standard" /> android:layout_marginTop="20dp" />
<EditText <Button
android:layout_width="match_parent" android:text="Create new project"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:id="@+id/newProjectDescription" android:layout_height="wrap_content"
android:hint="This is my new super-special project that will change the world!!!" android:id="@+id/newProjectCreateButton"
android:inputType="textMultiLine" app:layout_constraintStart_toStartOf="parent"
android:minLines="3" app:layout_constraintHorizontal_bias="0.5"
android:maxLines="5" app:layout_constraintEnd_toEndOf="parent"
android:gravity="start|top" android:layout_marginTop="15dp"
android:padding="@dimen/padding_standard" app:layout_constraintTop_toBottomOf="@+id/newProjectDescription"
android:layout_marginLeft="@dimen/margin_standard" android:padding="20dp"
android:layout_marginRight="@dimen/margin_standard" android:layout_margin="12dp" />
android:layout_marginTop="@dimen/margin_small" />
<Button
android:text="Create new project"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/newProjectCreateButton"
android:backgroundTint="@color/primary_green"
android:layout_marginTop="@dimen/margin_large"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -35,7 +35,7 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:layout_editor_absoluteX="0dp" tools:layout_editor_absoluteX="1dp"
app:layout_constraintTop_toBottomOf="@+id/logoutButton" app:layout_constraintTop_toBottomOf="@+id/logoutButton"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:id="@+id/projectsRecyclerView" /> android:id="@+id/projectsRecyclerView" />

View file

@ -14,180 +14,120 @@
app:srcCompat="@android:drawable/ic_menu_revert" app:srcCompat="@android:drawable/ic_menu_revert"
android:id="@+id/returnActionButton" android:id="@+id/returnActionButton"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="@dimen/fab_margin_bottom" android:layout_marginBottom="16dp"
android:layout_marginEnd="@dimen/fab_margin_end" android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<ScrollView <TextView
android:text="Project Name"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="wrap_content"
android:id="@+id/projectTitleText"
android:padding="12dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="4dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent"
android:textSize="24sp" />
<LinearLayout <TextView
android:text="Completed: 100%"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/completedPercentageText"
app:layout_constraintTop_toBottomOf="@+id/projectTitleText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
android:paddingRight="12dp"
android:paddingLeft="12dp"
android:layout_marginTop="16dp"
android:textSize="18dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/projectDescriptionText"
app:layout_constraintTop_toBottomOf="@+id/projectDescriptionLabel"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
android:text="Project description"
android:padding="12dp"
android:gravity="start|top" />
<TextView
android:text="Project description:"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/projectDescriptionLabel"
tools:layout_editor_absoluteX="0dp"
app:layout_constraintTop_toBottomOf="@+id/completedPercentageText"
android:layout_marginTop="16dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:labelFor="@id/projectDescriptionText"
android:textSize="18dp" />
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/projectDescriptionText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="24dp"
android:id="@+id/taskLinearLayout">
<TextView
android:text="Tasks:"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:id="@+id/taskListTitle"
android:gravity="start|top"> android:paddingLeft="12dp"
android:textSize="18dp" />
<TextView <Button
android:text="Project Name" android:text="Add a task..."
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/projectTitleText" android:id="@+id/addTaskButton"
android:padding="@dimen/padding_standard" android:layout_marginLeft="12dp"
android:layout_marginTop="@dimen/margin_tiny" android:layout_marginRight="12dp" />
android:textSize="24sp" /> </LinearLayout>
<TextView <LinearLayout
android:text="Project description:" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/projectDescriptionLabel" tools:layout_editor_absoluteX="0dp"
android:layout_marginTop="@dimen/margin_medium" android:id="@+id/collaboratorsLinearLayout"
android:paddingLeft="@dimen/padding_standard" android:gravity="top|center_vertical"
android:paddingRight="@dimen/padding_standard" app:layout_constraintTop_toBottomOf="@+id/taskLinearLayout"
android:labelFor="@id/projectDescriptionText" android:layout_marginTop="24dp">
android:textSize="@dimen/text_size_title"
android:textStyle="bold" />
<TextView <TextView
android:layout_width="match_parent" android:text="Collaborators:"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:id="@+id/projectDescriptionText" android:layout_height="wrap_content"
android:text="Project description" android:id="@+id/collaboratorListTitle"
android:padding="@dimen/padding_standard" android:paddingLeft="12dp"
android:gravity="start|top" /> android:textSize="18dp" />
<TextView <androidx.recyclerview.widget.RecyclerView
android:text="Completed: 100%" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:id="@+id/collaboratorListRecycler" />
android:id="@+id/completedPercentageText"
android:paddingRight="@dimen/padding_standard"
android:paddingLeft="@dimen/padding_standard"
android:layout_marginTop="@dimen/margin_medium"
android:textSize="@dimen/text_size_subtitle" />
<LinearLayout <Button
android:orientation="vertical" android:text="Add a new collaborator..."
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_large" android:id="@+id/addCollaboratorButton"
android:id="@+id/taskLinearLayout"> android:layout_marginLeft="12dp"
android:layout_marginRight="12dp" />
<TextView </LinearLayout>
android:text="Tasks:"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/taskListTitle"
android:paddingLeft="@dimen/padding_standard"
android:textSize="@dimen/text_size_title"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/taskListRecycler"
android:padding="8dp"
android:scrollbars="none"
android:isScrollContainer="false" />
<Button
android:text="Add a task..."
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addTaskButton"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:backgroundTint="@color/primary_green" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/collaboratorsLinearLayout"
android:gravity="top|center_vertical"
android:layout_marginTop="@dimen/margin_large">
<TextView
android:text="Collaborators:"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/collaboratorListTitle"
android:paddingLeft="@dimen/padding_standard"
android:textSize="@dimen/text_size_title"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/collaboratorListRecycler"
android:padding="8dp"
android:scrollbars="none"
android:isScrollContainer="false" />
<Button
android:text="Add a new collaborator..."
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addCollaboratorButton"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:backgroundTint="@color/primary_green" />
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/dangerZoneLinearLayout"
android:layout_marginTop="@dimen/margin_xlarge"
android:paddingBottom="16dp">
<TextView
android:text="Danger Zone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/dangerZoneTitle"
android:paddingLeft="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard"
android:textSize="@dimen/text_size_title"
android:textStyle="bold"
android:textColor="@color/danger_red" />
<TextView
android:text="These actions cannot be undone. Proceed with caution."
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/dangerZoneWarning"
android:paddingLeft="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard"
android:layout_marginTop="@dimen/margin_small"
android:textSize="@dimen/text_size_body"
android:textColor="@color/text_secondary" />
<Button
android:text="Edit Project"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/editProjectButton"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:layout_marginTop="@dimen/margin_medium"
android:backgroundTint="@color/warning_orange" />
<Button
android:text="Delete Project"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/deleteProjectButton"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard"
android:layout_marginTop="@dimen/margin_small"
android:backgroundTint="@color/danger_red" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,97 +0,0 @@
<?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.ProjectEditActivity">
<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 Project"
android:textSize="@dimen/text_size_title"
android:textStyle="bold"
android:padding="@dimen/padding_standard"
android:layout_marginTop="@dimen/margin_tiny" />
<TextView
android:id="@+id/projectNameLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Project Name:"
android:textSize="@dimen/text_size_subtitle"
android:textStyle="bold"
android:layout_marginTop="@dimen/margin_medium"
android:paddingLeft="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<EditText
android:id="@+id/projectNameInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter project name"
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/projectDescriptionLabel"
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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<EditText
android:id="@+id/projectDescriptionInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter project 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" />
<Button
android:id="@+id/saveProjectButton"
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" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,117 +0,0 @@
<?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.TaskAddActivity">
<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="Add New 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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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/createTaskButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Create Task"
android:backgroundTint="@color/primary_green"
android:layout_marginTop="@dimen/margin_large"
android:layout_marginLeft="@dimen/margin_standard"
android:layout_marginRight="@dimen/margin_standard" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,127 +0,0 @@
<?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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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="@dimen/padding_standard"
android:paddingRight="@dimen/padding_standard" />
<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>

View file

@ -1,53 +0,0 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal|end"
android:layout_margin="8dp"
android:id="@+id/linearLayout">
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="4dp">
<TextView
android:id="@+id/collaboratorNameText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Collaborator Name"
android:textSize="18dp"
android:textStyle="bold" />
<TextView
android:text="example@email.com"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/collaboratorEmailText"
android:textStyle="italic" />
</LinearLayout>
<Button
android:id="@+id/removeCollaboratorButton"
android:layout_width="50dp"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.Icon"
app:icon="@android:drawable/ic_delete"
android:backgroundTint="@color/transparent_red"
app:iconTint="@color/danger_red"
android:layout_marginEnd="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.333" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,79 +0,0 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start|top"
android:layout_margin="4dp"
android:id="@+id/linearLayout2">
<LinearLayout
android:orientation="vertical"
android:layout_width="331dp"
android:layout_height="50dp"
android:id="@+id/linearLayout3"
tools:layout_editor_absoluteY="4dp"
tools:layout_editor_absoluteX="4dp">
<TextView
android:id="@+id/taskTitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Task Title"
android:textSize="20dp"
android:textStyle="bold"
android:paddingBottom="4dp" />
<TextView
android:id="@+id/taskDescriptionText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Task Description"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/taskStatusLinearLayout"
app:layout_constraintTop_toBottomOf="@+id/linearLayout3"
app:layout_constraintStart_toStartOf="parent"
android:layout_margin="4dp">
<TextView
android:text="STATUS:"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/taskStatusLabel"
android:textStyle="bold"
android:textAlignment="textStart"
android:gravity="start|center_vertical" />
<Spinner
android:id="@+id/taskStatusDropdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/task_status_options"
android:layout_marginStart="16dp"
android:spinnerMode="dropdown"
android:dropDownWidth="wrap_content" />
</LinearLayout>
<Button
android:layout_width="50dp"
android:layout_height="wrap_content"
android:id="@+id/editTaskButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.5"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:icon="@android:drawable/ic_menu_edit"
style="@style/Widget.Material3.Button.IconButton"
app:iconTint="#0C0808" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="task_status_options">
<item>Pending</item>
<item>In progress</item>
<item>Completed</item>
<item>Stashed</item>
<item>Failed</item>
</string-array>
</resources>

View file

@ -2,15 +2,4 @@
<resources> <resources>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<!-- Primary Colors -->
<color name="primary_green">#469E29</color>
<color name="danger_red">#FF0000</color>
<color name="warning_orange">#FF9800</color>
<!-- Text Colors -->
<color name="text_secondary">#666666</color>
<!-- Background Colors -->
<color name="transparent_red">#24FF5757</color>
</resources> </resources>

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Paddings -->
<dimen name="padding_standard">12dp</dimen>
<dimen name="padding_small">8dp</dimen>
<!-- Margins -->
<dimen name="margin_standard">12dp</dimen>
<dimen name="margin_medium">16dp</dimen>
<dimen name="margin_large">24dp</dimen>
<dimen name="margin_xlarge">32dp</dimen>
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_tiny">4dp</dimen>
<!-- FAB Margins -->
<dimen name="fab_margin_bottom">17dp</dimen>
<dimen name="fab_margin_end">18dp</dimen>
<!-- Bottom Padding for FAB -->
<dimen name="bottom_padding_for_fab">80dp</dimen>
<!-- Text Sizes -->
<dimen name="text_size_title">24sp</dimen>
<dimen name="text_size_subtitle">18sp</dimen>
<dimen name="text_size_body">14sp</dimen>
</resources>