feat: Create/edit logic for new categories
This commit is contained in:
parent
df18f13972
commit
ae2efe89f2
|
@ -1,17 +1,48 @@
|
||||||
package com.p_vacho.neat_calendar.activities
|
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.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
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.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 {
|
enum class CategoryMode {
|
||||||
CREATE, EDIT
|
CREATE, EDIT
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateCategoryActivity : AppCompatActivity() {
|
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?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
@ -21,5 +52,107 @@ class CreateCategoryActivity : AppCompatActivity() {
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
insets
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,6 +44,7 @@
|
||||||
<string name="remove_category">Remove the category</string>
|
<string name="remove_category">Remove the category</string>
|
||||||
<string name="add_category">Add category</string>
|
<string name="add_category">Add category</string>
|
||||||
<string name="update_event">Update Event</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="leave_invited_event">Leave invited event</string>
|
||||||
<string name="open_app_settings">Open Settings</string>
|
<string name="open_app_settings">Open Settings</string>
|
||||||
<string name="open_notifications">Open Notifications</string>
|
<string name="open_notifications">Open Notifications</string>
|
||||||
|
@ -97,4 +98,6 @@
|
||||||
<string name="event_owner_section">Event owner:</string>
|
<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="no_invited_categories_placeholder">You can\'t see categories for invited events</string>
|
||||||
<string name="edit_category">Edit category</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>
|
</resources>
|
Loading…
Reference in a new issue