diff --git a/app/src/main/java/com/p_vacho/neat_calendar/activities/CreateCategoryActivity.kt b/app/src/main/java/com/p_vacho/neat_calendar/activities/CreateCategoryActivity.kt index 42a5765..41dda6e 100644 --- a/app/src/main/java/com/p_vacho/neat_calendar/activities/CreateCategoryActivity.kt +++ b/app/src/main/java/com/p_vacho/neat_calendar/activities/CreateCategoryActivity.kt @@ -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() + 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() } -} \ No newline at end of file + + 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() + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ec6aa04..d5151df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,6 +44,7 @@ Remove the category Add category Update Event + Update Category Leave invited event Open Settings Open Notifications @@ -97,4 +98,6 @@ Event owner: You can\'t see categories for invited events Edit category + Please enter a category name + Failed to save category: %1$s \ No newline at end of file