Implement deleting dish, use popup menu for edit and delete
This commit is contained in:
parent
9c364b2493
commit
59683ea176
@ -19,7 +19,7 @@ class ApiRequestException(message: String, cause: Throwable?) : Exception(messag
|
||||
class HttpResponse(val body: String, val code: Int)
|
||||
|
||||
fun request(ctx: Context, method: String, path: String, data: String?, autoRefresh: Boolean = true): HttpResponse {
|
||||
val url = URL(BuildConfig.API_LOCALHOST_URL + path)
|
||||
val url = URL(BuildConfig.API_BASE_URL + path)
|
||||
|
||||
val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE)
|
||||
val authToken = prefs.getString("auth-token", null)
|
||||
@ -67,7 +67,7 @@ fun request(ctx: Context, method: String, path: String, data: String?, autoRefre
|
||||
class HttpErrorResponse(val message: String)
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
val json = Json { explicitNulls = false }
|
||||
val json = Json { explicitNulls = false } // Treat missing values as null when decoding
|
||||
|
||||
inline fun <reified Req, reified Res> requestJson(ctx: Context, method: String, path: String, data: Req?): Res {
|
||||
val requestJson =
|
||||
|
@ -32,3 +32,6 @@ fun getRecipeDetails(ctx: Context, id: Int): Recipe {
|
||||
return requestJson<Unit, Recipe>(ctx, "GET", "/api/Recipe/get/$id", null)
|
||||
}
|
||||
|
||||
fun deleteRecipe(ctx: Context, id: Int) {
|
||||
requestJson<Recipe, Boolean>(ctx, "DELETE", "/api/Recipe/delete/$id", null)
|
||||
}
|
||||
|
@ -9,11 +9,7 @@ import android.widget.TextView
|
||||
import tech.mercantec.easyeat.R
|
||||
import tech.mercantec.easyeat.models.DishListItem
|
||||
|
||||
class DishAdapter(
|
||||
context: Context,
|
||||
private val dishes: List<DishListItem>,
|
||||
private val onDishClick: (DishListItem) -> Unit
|
||||
) : ArrayAdapter<DishListItem>(context, 0, dishes) {
|
||||
class DishAdapter(context: Context, private val dishes: List<DishListItem>) : ArrayAdapter<DishListItem>(context, 0, dishes) {
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val dish = getItem(position)
|
||||
@ -25,10 +21,6 @@ class DishAdapter(
|
||||
nameTextView.text = dish?.name
|
||||
descriptionTextView.text = dish?.description
|
||||
|
||||
view.setOnClickListener {
|
||||
dish?.let { onDishClick(it) }
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ import tech.mercantec.easyeat.helpers.AddRecipeToShoppingList
|
||||
import tech.mercantec.easyeat.models.Ingredient
|
||||
import tech.mercantec.easyeat.models.Recipe
|
||||
|
||||
private lateinit var editRecipeLauncher: ActivityResultLauncher<Intent>
|
||||
|
||||
class DishDetailsActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -40,12 +38,6 @@ class DishDetailsActivity : AppCompatActivity() {
|
||||
return
|
||||
}
|
||||
|
||||
editRecipeLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
loadRecipe(dishId)
|
||||
}
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.addDishToShoppingList).setOnClickListener {
|
||||
val progressDialog = ProgressDialog(this)
|
||||
progressDialog.setMessage("Loading...")
|
||||
@ -82,7 +74,6 @@ class DishDetailsActivity : AppCompatActivity() {
|
||||
val ingredientsContainer = findViewById<LinearLayout>(R.id.ingredients)
|
||||
val multiplierEditText = findViewById<EditText>(R.id.ingredient_multiplier)
|
||||
val instructionsLayout = findViewById<LinearLayout>(R.id.instructions)
|
||||
val editRecipeBtn: Button = findViewById(R.id.editRecipeBtn)
|
||||
|
||||
thread {
|
||||
val recipe: Recipe
|
||||
@ -151,13 +142,6 @@ class DishDetailsActivity : AppCompatActivity() {
|
||||
displayIngredients(recipe.ingredients, multiplier)
|
||||
}
|
||||
}
|
||||
|
||||
editRecipeBtn.setOnClickListener {
|
||||
val jsonRecipe = Json.encodeToString(recipe)
|
||||
val intent = Intent(this, EditDishActivity::class.java)
|
||||
intent.putExtra("recipe_json", jsonRecipe)
|
||||
editRecipeLauncher.launch(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.mercantec.easyeat.ui.dishes
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@ -11,11 +12,15 @@ import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tech.mercantec.easyeat.R
|
||||
import tech.mercantec.easyeat.databinding.FragmentDishesBinding
|
||||
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||
import tech.mercantec.easyeat.helpers.GetAllRecipesResponse
|
||||
import tech.mercantec.easyeat.helpers.deleteRecipe
|
||||
import tech.mercantec.easyeat.helpers.getAllRecipes
|
||||
import tech.mercantec.easyeat.helpers.getRecipeDetails
|
||||
import tech.mercantec.easyeat.models.DishListItem
|
||||
import tech.mercantec.easyeat.models.Recipe
|
||||
import kotlin.concurrent.thread
|
||||
@ -23,7 +28,7 @@ import kotlin.concurrent.thread
|
||||
class DishesFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentDishesBinding? = null
|
||||
private lateinit var createDishLauncher: ActivityResultLauncher<Intent>
|
||||
private lateinit var launcher: ActivityResultLauncher<Intent>
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
@ -36,6 +41,79 @@ class DishesFragment : Fragment() {
|
||||
|
||||
loadRecipes()
|
||||
|
||||
// Show details on click
|
||||
binding.dishesList.setOnItemClickListener { parent, view, position, id ->
|
||||
val item = parent.getItemAtPosition(position) as DishListItem
|
||||
|
||||
val intent = Intent(requireContext(), DishDetailsActivity::class.java)
|
||||
intent.putExtra("dish_id", item.id)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
// Show context menu when long clicking shopping item
|
||||
binding.dishesList.setOnItemLongClickListener { parent, view, position, id ->
|
||||
val item = parent.getItemAtPosition(position) as DishListItem
|
||||
|
||||
val popup = PopupMenu(requireActivity(), view)
|
||||
popup.apply {
|
||||
menuInflater.inflate(R.menu.dish_context_menu, menu)
|
||||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
// Open edit dish activity when editing
|
||||
R.id.edit_dish -> {
|
||||
thread {
|
||||
// Get full recipe details
|
||||
val recipe: Recipe
|
||||
try {
|
||||
recipe = getRecipeDetails(requireContext(), item.id)
|
||||
} catch (e: ApiRequestException) {
|
||||
activity?.runOnUiThread {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
return@thread
|
||||
}
|
||||
|
||||
val intent = Intent(activity, EditDishActivity::class.java)
|
||||
intent.putExtra("recipe_json", Json.encodeToString(recipe))
|
||||
launcher.launch(intent)
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
R.id.remove_dish -> {
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle("Delete dish")
|
||||
.setMessage("Are you sure you want to delete this dish?")
|
||||
.setPositiveButton(R.string.delete_label) { _, _ ->
|
||||
(parent.adapter as DishAdapter).remove(item)
|
||||
|
||||
thread {
|
||||
try {
|
||||
deleteRecipe(requireContext(), item.id)
|
||||
} catch (e: ApiRequestException) {
|
||||
activity?.runOnUiThread {
|
||||
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel_label, null)
|
||||
.show()
|
||||
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
show()
|
||||
}
|
||||
|
||||
return@setOnItemLongClickListener true
|
||||
}
|
||||
|
||||
binding.addDish.setOnClickListener {
|
||||
val popup = PopupMenu(requireActivity(), it)
|
||||
|
||||
@ -46,13 +124,13 @@ class DishesFragment : Fragment() {
|
||||
when (it.itemId) {
|
||||
R.id.create_manually -> {
|
||||
val intent = Intent(requireContext(), CreateDishActivity::class.java)
|
||||
createDishLauncher.launch(intent)
|
||||
launcher.launch(intent)
|
||||
|
||||
true
|
||||
}
|
||||
R.id.create_with_ai -> {
|
||||
val intent = Intent(requireContext(), GenerateRecipeActivity::class.java)
|
||||
createDishLauncher.launch(intent)
|
||||
launcher.launch(intent)
|
||||
|
||||
true
|
||||
}
|
||||
@ -98,12 +176,7 @@ class DishesFragment : Fragment() {
|
||||
|
||||
binding.dishesList.emptyView = binding.emptyDishesList
|
||||
|
||||
val adapter = DishAdapter(requireContext(), dishes) { selectedDish ->
|
||||
// Open details activity
|
||||
val intent = Intent(requireContext(), DishDetailsActivity::class.java)
|
||||
intent.putExtra("dish_id", selectedDish.id)
|
||||
startActivity(intent)
|
||||
}
|
||||
val adapter = DishAdapter(requireContext(), dishes)
|
||||
binding.dishesList.adapter = adapter
|
||||
}
|
||||
}
|
||||
@ -112,7 +185,7 @@ class DishesFragment : Fragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
createDishLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
loadRecipes()
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
package tech.mercantec.easyeat.ui.dishes
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.Html.FROM_HTML_MODE_LEGACY
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import kotlinx.serialization.json.Json
|
||||
import tech.mercantec.easyeat.R
|
||||
import tech.mercantec.easyeat.models.Recipe
|
||||
|
||||
class RecipeFragment : Fragment() {
|
||||
private var recipe: Recipe? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
arguments?.let { args ->
|
||||
recipe = args.getString("RECIPE")?.let { Json.decodeFromString<Recipe>(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
val binding = inflater.inflate(R.layout.fragment_recipe, container, false)
|
||||
|
||||
recipe?.let { recipe ->
|
||||
binding.findViewById<TextView>(R.id.title).text = recipe.name
|
||||
|
||||
binding.findViewById<TextView>(R.id.ingredients).text =
|
||||
Html.fromHtml(
|
||||
"<ul>" +
|
||||
recipe.ingredients.map { "<li>${it.amount} ${it.unit} ${it.name}</li>" } +
|
||||
"</ul>",
|
||||
FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
|
||||
binding.findViewById<TextView>(R.id.directions).text =
|
||||
Html.fromHtml(
|
||||
"<ul>" +
|
||||
recipe.directions.map { "<li>${it}</li>" } +
|
||||
"</ul>",
|
||||
FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
}
|
||||
|
||||
return binding
|
||||
}
|
||||
}
|
@ -9,15 +9,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="30sp"
|
||||
android:orientation="vertical">
|
||||
<Button
|
||||
android:id="@+id/editRecipeBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:backgroundTint="@color/cyan"
|
||||
android:text="@string/edit_recipe"
|
||||
android:tint="@android:color/white"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dishDetailName"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -29,7 +29,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:text="@string/empty_dishes_list"
|
||||
/>
|
||||
/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_dish"
|
||||
|
@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:padding="30dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:textSize="24sp"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/ingredients_label"
|
||||
style="@style/HighContrastText"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ingredients"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/directions_label"
|
||||
style="@style/HighContrastText"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/directions"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
11
app/app/src/main/res/menu/dish_context_menu.xml
Normal file
11
app/app/src/main/res/menu/dish_context_menu.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/edit_dish"
|
||||
android:title="@string/edit_label"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/remove_dish"
|
||||
android:title="@string/delete_label"
|
||||
/>
|
||||
</menu>
|
@ -56,7 +56,6 @@
|
||||
<string name="instructions_label">Instructions</string>
|
||||
<string name="increment_multiplier_desc">Increment portion count</string>
|
||||
<string name="decrement_multiplier_desc">Decrement portion size</string>
|
||||
<string name="edit_recipe">Edit Recipe</string>
|
||||
<string name="empty_dishes_list">You have not created any dishes yet</string>
|
||||
<string name="allergies_label">Allergies</string>
|
||||
<string name="allergies_hint">Lactose, Gluten</string>
|
||||
|
Loading…
Reference in New Issue
Block a user