feat: Create/edit logic for new categories

This commit is contained in:
Peter Vacho 2025-01-05 16:40:45 +01:00
parent df18f13972
commit ae2efe89f2
Signed by: school
GPG key ID: 8CFC3837052871B4
2 changed files with 137 additions and 1 deletions

View file

@ -1,17 +1,48 @@
package com.p_vacho.neat_calendar.activities
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.github.dhaval2404.colorpicker.ColorPickerDialog
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputEditText
import com.google.gson.Gson
import com.p_vacho.neat_calendar.R
import com.p_vacho.neat_calendar.api.RetrofitClient
import com.p_vacho.neat_calendar.api.models.CategoryRequest
import com.p_vacho.neat_calendar.api.models.CategoryResponse
import com.p_vacho.neat_calendar.api.models.PartialCategoryRequest
import com.p_vacho.neat_calendar.api.models.ValidationError
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.HttpException
import kotlin.properties.Delegates
enum class CategoryMode {
CREATE, EDIT
}
class CreateCategoryActivity : AppCompatActivity() {
private var selectedColor by Delegates.notNull<Int>()
private var existingCategory: CategoryResponse? = null
private lateinit var mode: CategoryMode
// UI components
private lateinit var etCategoryName: TextInputEditText
private lateinit var btnColorPicker: MaterialButton
private lateinit var btnSaveCategory: MaterialButton
private lateinit var btnCancel: MaterialButton
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
@ -21,5 +52,107 @@ class CreateCategoryActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
initializeViews()
mode = intent.getStringExtra("mode")!!.let { CategoryMode.valueOf(it) }
if (mode == CategoryMode.EDIT) {
@Suppress("DEPRECATION")
existingCategory = intent.getParcelableExtra("category")!!
etCategoryName.setText(existingCategory?.name)
selectedColor = existingCategory?.color?.toArgb() ?: ContextCompat.getColor(this, R.color.category_indicator_color)
btnSaveCategory.setText(R.string.update_category)
} else {
selectedColor = ContextCompat.getColor(this, R.color.category_indicator_color)
}
btnColorPicker.iconTint = ColorStateList.valueOf(selectedColor)
setupListeners()
}
private fun initializeViews() {
etCategoryName = findViewById(R.id.etCategoryName)
btnColorPicker = findViewById(R.id.btnColorPicker)
btnSaveCategory = findViewById(R.id.btnSaveCategory)
btnCancel = findViewById(R.id.btnCancel)
}
private fun setupListeners() {
btnColorPicker.setOnClickListener { openColorPickerDialog() }
btnSaveCategory.setOnClickListener { saveCategory() }
btnCancel.setOnClickListener { finish() }
}
private fun saveCategory() {
val categoryName = etCategoryName.text.toString().trim()
if (categoryName.isEmpty()) {
Toast.makeText(this, getString(R.string.please_enter_a_category_name), Toast.LENGTH_SHORT).show()
return
}
lifecycleScope.launch(Dispatchers.IO) {
try {
val resultCategory = if (mode == CategoryMode.CREATE) {
val request =
CategoryRequest(name = categoryName, color = Color.valueOf(selectedColor))
RetrofitClient.categoryService.createCategory(request)
} else {
val request = PartialCategoryRequest(
name = categoryName.takeIf { it != existingCategory?.name },
color = Color.valueOf(selectedColor)
.takeIf { it != existingCategory?.color }
)
RetrofitClient.categoryService.updateCategory(existingCategory!!.id, request)
}
withContext(Dispatchers.Main) { handleCategorySaved(resultCategory) }
} catch (e: HttpException) {
if (e.code() != 422) {
throw e
}
val errorBody = e.response()?.errorBody()?.string()
val validationError = Gson().fromJson(errorBody, ValidationError::class.java)
val errMsg = validationError.detail.joinToString("\n")
Log.e("CategoryCreate", "Got HTTP 422: $validationError")
withContext(Dispatchers.Main) {
Toast.makeText(
this@CreateCategoryActivity,
getString(R.string.failed_to_save_category, errMsg),
Toast.LENGTH_SHORT
).show()
}
}
}
}
private fun handleCategorySaved(category: CategoryResponse) {
Log.w("CreateCategory", "Ending")
val intent = Intent().apply {
if (mode == CategoryMode.CREATE) {
putExtra("newCategory", category)
Log.w("CreateCategory", "New")
} else {
putExtra("editedCategory", category)
Log.w("CreateCategory", "Edit")
}
}
setResult(RESULT_OK, intent)
finish()
}
private fun openColorPickerDialog() {
ColorPickerDialog
.Builder(this)
.setTitle(getString(R.string.select_color))
.setDefaultColor(selectedColor)
.setColorListener { color, _ ->
selectedColor = color
btnColorPicker.iconTint = ColorStateList.valueOf(color)
}
.show()
}
}

View file

@ -44,6 +44,7 @@
<string name="remove_category">Remove the category</string>
<string name="add_category">Add category</string>
<string name="update_event">Update Event</string>
<string name="update_category">Update Category</string>
<string name="leave_invited_event">Leave invited event</string>
<string name="open_app_settings">Open Settings</string>
<string name="open_notifications">Open Notifications</string>
@ -97,4 +98,6 @@
<string name="event_owner_section">Event owner:</string>
<string name="no_invited_categories_placeholder">You can\'t see categories for invited events</string>
<string name="edit_category">Edit category</string>
<string name="please_enter_a_category_name">Please enter a category name</string>
<string name="failed_to_save_category">Failed to save category: %1$s</string>
</resources>