From 4772c0ef2639fcb2043e9e59dcd832e9383c176b Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Tue, 13 May 2025 12:41:10 +0200
Subject: [PATCH 01/10] Create recipe fragment

---
 .../easyeat/ui/dishes/RecipeFragment.kt       | 54 +++++++++++++++++++
 .../src/main/res/layout/fragment_recipe.xml   | 48 +++++++++++++++++
 app/app/src/main/res/values-night/styles.xml  |  6 +++
 app/app/src/main/res/values/strings.xml       |  2 +
 app/app/src/main/res/values/styles.xml        |  6 +++
 5 files changed, 116 insertions(+)
 create mode 100644 app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/RecipeFragment.kt
 create mode 100644 app/app/src/main/res/layout/fragment_recipe.xml
 create mode 100644 app/app/src/main/res/values-night/styles.xml
 create mode 100644 app/app/src/main/res/values/styles.xml

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/RecipeFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/RecipeFragment.kt
new file mode 100644
index 0000000..2639315
--- /dev/null
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/RecipeFragment.kt
@@ -0,0 +1,54 @@
+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
+    }
+}
\ No newline at end of file
diff --git a/app/app/src/main/res/layout/fragment_recipe.xml b/app/app/src/main/res/layout/fragment_recipe.xml
new file mode 100644
index 0000000..8b66e2d
--- /dev/null
+++ b/app/app/src/main/res/layout/fragment_recipe.xml
@@ -0,0 +1,48 @@
+<?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>
diff --git a/app/app/src/main/res/values-night/styles.xml b/app/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..4aa21da
--- /dev/null
+++ b/app/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="HighContrastText" parent="TextAppearance.AppCompat">
+        <item name="android:textColor">@color/white</item>
+    </style>
+</resources>
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index e7d5584..367630e 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -47,6 +47,8 @@
     <string name="ai_generate_recipe_title">Generate recipe with AI</string>
     <string name="dish_title_label">Name of dish</string>
     <string name="generate_recipe_label">Generate</string>
+    <string name="ingredients_label">Ingredients</string>
+    <string name="directions_label">Directions</string>
     <string-array name="units">
         <item></item>
         <item>g</item>
diff --git a/app/app/src/main/res/values/styles.xml b/app/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..560b559
--- /dev/null
+++ b/app/app/src/main/res/values/styles.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="HighContrastText" parent="TextAppearance.AppCompat">
+        <item name="android:textColor">@color/black</item>
+    </style>
+</resources>

From 1c085a4262c0445bfbe6859a572793e38e1f93b3 Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Tue, 13 May 2025 12:59:18 +0200
Subject: [PATCH 02/10] Finish generating recipe, refactor directions property
 and request helpers

---
 app/app/src/main/AndroidManifest.xml          |  2 +-
 .../tech/mercantec/easyeat/helpers/auth.kt    | 32 ++-----------------
 .../tech/mercantec/easyeat/helpers/dishes.kt  | 19 +++++++++++
 .../mercantec/easyeat/models/CreateRecipe.kt  | 24 --------------
 .../tech/mercantec/easyeat/models/recipe.kt   |  5 ++-
 .../easyeat/ui/dishes/CreateDishActivity.kt   | 18 ++++-------
 .../easyeat/ui/dishes/DishesFragment.kt       |  6 ++--
 ...IActivity.kt => GenerateRecipeActivity.kt} | 28 ++++++++--------
 .../easyeat/ui/dishes/InstructionsAdapter.kt  |  9 +++---
 ..._form.xml => activity_generate_recipe.xml} |  0
 10 files changed, 52 insertions(+), 91 deletions(-)
 delete mode 100644 app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
 rename app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/{CreateDishAIActivity.kt => GenerateRecipeActivity.kt} (66%)
 rename app/app/src/main/res/layout/{create_dish_ai_form.xml => activity_generate_recipe.xml} (100%)

diff --git a/app/app/src/main/AndroidManifest.xml b/app/app/src/main/AndroidManifest.xml
index 10e464a..e1e0150 100644
--- a/app/app/src/main/AndroidManifest.xml
+++ b/app/app/src/main/AndroidManifest.xml
@@ -45,7 +45,7 @@
             android:exported="false" />
 
         <activity
-            android:name=".ui.dishes.CreateDishAIActivity"
+            android:name=".ui.dishes.GenerateRecipeActivity"
             android:exported="false" />
 
         <activity
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
index 6ce46f1..ff8a3f2 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
@@ -3,11 +3,6 @@ package tech.mercantec.easyeat.helpers
 import android.content.Context
 import android.util.Log
 import kotlinx.serialization.Serializable
-import tech.mercantec.easyeat.models.CreateDirection
-import tech.mercantec.easyeat.models.CreateIngredient
-import tech.mercantec.easyeat.models.CreateRecipe
-import tech.mercantec.easyeat.models.Direction
-import tech.mercantec.easyeat.models.Ingredient
 
 @Serializable
 data class LoginRequest(val emailUsr: String, val password: String)
@@ -20,7 +15,7 @@ fun login(ctx: Context, email: String, password: String) {
 
     val response = requestJson<LoginRequest, LoginResponse>(ctx, "POST", "/api/User/login", request)
 
-    with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
+    with(ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
         putInt("user-id", response.id)
         putString("username", response.userName)
         putString("auth-token", response.token)
@@ -30,7 +25,7 @@ fun login(ctx: Context, email: String, password: String) {
 }
 
 fun logout(ctx: Context) {
-    with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
+    with(ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
         remove("user-id")
         remove("username")
         remove("auth-token")
@@ -114,26 +109,3 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
 
     return requestJson<ChangePasswordRequest, Unit>(ctx, "PUT", "/api/User/change-password", request)
 }
-
-@Serializable
-data class CreateRecipeRequest(val name: String, val description: String, val directions: List<CreateDirection>, val  ingredients: List<CreateIngredient>)
-
-fun createRecipe(ctx: Context, recipe: CreateRecipe) {
-    val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients)
-
-    requestJson<CreateRecipeRequest, Boolean>(ctx, "POST", "/api/recipe/create", request)
-}
-
-@Serializable
-data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
-
-fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
-    return requestJson<Unit, List<GetAllRecipesResponse>>(ctx, "GET", "/api/Recipe/getall", null)
-}
-
-@Serializable
-data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List<Direction>, val ingredients: List<Ingredient>)
-
-fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
-    return requestJson<Unit, RecipeDetailsResponse>(ctx, "GET", "/api/Recipe/get/$id", null)
-}
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
index e0aa866..4a7a599 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
@@ -2,6 +2,7 @@ package tech.mercantec.easyeat.helpers
 
 import android.content.Context
 import kotlinx.serialization.Serializable
+import tech.mercantec.easyeat.models.Ingredient
 import tech.mercantec.easyeat.models.Recipe
 
 @Serializable
@@ -10,3 +11,21 @@ data class GenerateRecipeRequest(val dish: String, val language: String, val num
 fun generateRecipeWithAI(ctx: Context, title: String, language: String): Recipe {
     return requestJson<GenerateRecipeRequest, Recipe>(ctx, "POST", "/api/Recipe/chatbot", GenerateRecipeRequest(title, language, 1, arrayOf()))
 }
+
+fun createRecipe(ctx: Context, recipe: Recipe) {
+    requestJson<Recipe, Boolean>(ctx, "POST", "/api/recipe/create", recipe)
+}
+
+@Serializable
+data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
+
+fun getAllRecipes(ctx: Context): List<GetAllRecipesResponse> {
+    return requestJson<Unit, List<GetAllRecipesResponse>>(ctx, "GET", "/api/Recipe/getall", null)
+}
+
+@Serializable
+data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List<String>, val ingredients: List<Ingredient>)
+
+fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
+    return requestJson<Unit, RecipeDetailsResponse>(ctx, "GET", "/api/Recipe/get/$id", null)
+}
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt b/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
deleted file mode 100644
index 782f449..0000000
--- a/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package tech.mercantec.easyeat.models
-
-import kotlinx.serialization.Serializable
-
-@Serializable
-data class CreateRecipe(
-    val name: String,
-    val description: String,
-    val directions: List<CreateDirection>,
-    val ingredients: List<CreateIngredient>
-)
-
-@Serializable
-data class CreateDirection(
-    val instructions: String
-)
-
-
-@Serializable
-data class CreateIngredient(
-    val amount: Double?,
-    val unit: String?,
-    val name: String
-)
\ No newline at end of file
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/models/recipe.kt b/app/app/src/main/java/tech/mercantec/easyeat/models/recipe.kt
index 86e5796..2ee35ed 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/models/recipe.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/models/recipe.kt
@@ -2,10 +2,9 @@ package tech.mercantec.easyeat.models
 
 import kotlinx.serialization.Serializable
 
-
 @Serializable
 data class Recipe(
-    val id: Int,
+    val id: Int? = null,
     val name: String,
     val description: String,
     val directions: List<String>,
@@ -14,7 +13,7 @@ data class Recipe(
 
 @Serializable
 data class Ingredient(
-    val id: Int,
+    val id: Int? = null,
     val amount: Double?,
     val unit: String?,
     val name: String
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
index 2ece5a7..b5cf99f 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
@@ -2,9 +2,7 @@ package tech.mercantec.easyeat.ui.dishes
 
 import android.app.Activity
 import android.app.ProgressDialog
-import android.content.Context
 import android.os.Bundle
-import android.util.Log
 import android.view.LayoutInflater
 import android.widget.ArrayAdapter
 import android.widget.Button
@@ -14,15 +12,11 @@ import android.widget.LinearLayout
 import android.widget.Spinner
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.ContentProviderCompat.requireContext
 import tech.mercantec.easyeat.R
 import tech.mercantec.easyeat.helpers.ApiRequestException
-import tech.mercantec.easyeat.helpers.changePassword
 import tech.mercantec.easyeat.helpers.createRecipe
-import tech.mercantec.easyeat.helpers.request
-import tech.mercantec.easyeat.models.CreateDirection
-import tech.mercantec.easyeat.models.CreateIngredient
-import tech.mercantec.easyeat.models.CreateRecipe
+import tech.mercantec.easyeat.models.Ingredient
+import tech.mercantec.easyeat.models.Recipe
 import kotlin.concurrent.thread
 
 class CreateDishActivity : AppCompatActivity() {
@@ -53,7 +47,7 @@ class CreateDishActivity : AppCompatActivity() {
                 .map { line -> line.trim() }
                 .filter { it.isNotEmpty() }
 
-            val recipe = CreateRecipe(
+            val recipe = Recipe(
                 name = findViewById<EditText>(R.id.dishName).text.toString().trim(),
                 description = findViewById<EditText>(R.id.dishDescription).text.toString().trim(),
                 directions = directions,
@@ -107,8 +101,8 @@ class CreateDishActivity : AppCompatActivity() {
         ingredientContainer.addView(ingredientRow)
     }
 
-    private fun collectIngredients(): List<CreateIngredient> {
-        val ingredients = mutableListOf<CreateIngredient>()
+    private fun collectIngredients(): List<Ingredient> {
+        val ingredients = mutableListOf<Ingredient>()
 
         for (i in 0 until ingredientContainer.childCount) {
             val ingredientView = ingredientContainer.getChildAt(i)
@@ -125,7 +119,7 @@ class CreateDishActivity : AppCompatActivity() {
 
             // Optional: Only add non-empty rows
             if (element.isNotEmpty() && amount.isNotEmpty()) {
-                ingredients.add(CreateIngredient(name = element, amount = amount.toDouble(), unit = unit))
+                ingredients.add(Ingredient(name = element, amount = amount.toDouble(), unit = unit))
             }
         }
 
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
index 4e1a301..93e06c7 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
@@ -15,7 +15,7 @@ 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.getAllRecipies
+import tech.mercantec.easyeat.helpers.getAllRecipes
 import tech.mercantec.easyeat.models.DishListItem
 import kotlin.concurrent.thread
 
@@ -52,7 +52,7 @@ class DishesFragment : Fragment() {
             }
 
             dialogView.findViewById<Button>(R.id.createAIBtn).setOnClickListener {
-                val intent = Intent(requireContext(), CreateDishAIActivity::class.java)
+                val intent = Intent(requireContext(), GenerateRecipeActivity::class.java)
                 createDishLauncher.launch(intent)
                 dialog.dismiss()
             }
@@ -68,7 +68,7 @@ class DishesFragment : Fragment() {
         thread {
             val recipes: List<GetAllRecipesResponse>
             try {
-                recipes = getAllRecipies(requireContext())
+                recipes = getAllRecipes(requireContext())
             } catch (e: ApiRequestException) {
                 activity?.runOnUiThread {
                     Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show()
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
similarity index 66%
rename from app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt
rename to app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
index fcf4bdc..140f74f 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
@@ -4,20 +4,19 @@ import android.app.ProgressDialog
 import android.os.Bundle
 import android.widget.Button
 import android.widget.EditText
-import android.widget.LinearLayout
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
 import tech.mercantec.easyeat.R
 import tech.mercantec.easyeat.helpers.ApiRequestException
-import tech.mercantec.easyeat.helpers.GenerateRecipeResponse
+import tech.mercantec.easyeat.helpers.createRecipe
 import tech.mercantec.easyeat.helpers.generateRecipeWithAI
 import java.util.Locale
 import kotlin.concurrent.thread
 
-class CreateDishAIActivity : AppCompatActivity() {
+class GenerateRecipeActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setContentView(R.layout.create_dish_ai_form)
+        setContentView(R.layout.activity_generate_recipe)
 
         findViewById<Button>(R.id.generate).setOnClickListener {
             val name = findViewById<EditText>(R.id.dish_title).text.toString()
@@ -27,21 +26,24 @@ class CreateDishAIActivity : AppCompatActivity() {
             progressDialog.show()
 
             thread {
-                val response: GenerateRecipeResponse
                 try {
-                    response = generateRecipeWithAI(this, name, Locale.getDefault().displayLanguage)
+                    val recipe = generateRecipeWithAI(this, name, Locale.getDefault().displayLanguage)
+
+                    runOnUiThread {
+                        progressDialog.setMessage("Saving...")
+                    }
+
+                    createRecipe(this, recipe)
+
+                    finish()
                 } catch (e: ApiRequestException) {
                     runOnUiThread {
                         Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
                     }
-
-                    return@thread
                 } finally {
-                    progressDialog.hide()
-                }
-
-                runOnUiThread {
-                    Toast.makeText(this, response.toString(), Toast.LENGTH_LONG).show()
+                    runOnUiThread {
+                        progressDialog.hide()
+                    }
                 }
             }
         }
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
index e0a2fee..0dc738e 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
@@ -7,19 +7,18 @@ import android.view.ViewGroup
 import android.widget.ArrayAdapter
 import android.widget.TextView
 import tech.mercantec.easyeat.R
-import tech.mercantec.easyeat.models.Direction
 
-class InstructionsAdapter (context: Context, instructions: List<Direction>)
-    : ArrayAdapter<Direction>(context, 0, instructions) {
+class InstructionsAdapter (context: Context, instructions: List<String>)
+    : ArrayAdapter<String>(context, R.layout.activity_dish_details_instructions_list_item, instructions) {
 
     override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
-        val ingredient = getItem(position)
+        val instruction = getItem(position)
         val view = convertView ?: LayoutInflater.from(context)
             .inflate(R.layout.activity_dish_details_instructions_list_item, parent, false)
 
         val nameView = view.findViewById<TextView>(R.id.instructionText)
 
-        nameView.text = ingredient?.instruktions ?: ""
+        nameView.text = instruction
 
         return view
     }
diff --git a/app/app/src/main/res/layout/create_dish_ai_form.xml b/app/app/src/main/res/layout/activity_generate_recipe.xml
similarity index 100%
rename from app/app/src/main/res/layout/create_dish_ai_form.xml
rename to app/app/src/main/res/layout/activity_generate_recipe.xml

From dbb25a394dda588aa0d469c95ae8e09aecb6d869 Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Tue, 13 May 2025 14:56:34 +0200
Subject: [PATCH 03/10] Use popup menu for creating dish

---
 .../easyeat/ui/dishes/DishesFragment.kt       | 41 ++++++++++---------
 .../ui/shopping_list/ShoppingListFragment.kt  |  3 ++
 .../res/layout/create_dish_modal_dialog.xml   | 36 ----------------
 .../src/main/res/menu/create_dish_menu.xml    | 11 +++++
 app/app/src/main/res/values-night/themes.xml  |  1 +
 app/app/src/main/res/values/strings.xml       |  4 +-
 6 files changed, 39 insertions(+), 57 deletions(-)
 delete mode 100644 app/app/src/main/res/layout/create_dish_modal_dialog.xml
 create mode 100644 app/app/src/main/res/menu/create_dish_menu.xml

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
index 93e06c7..70ab3fd 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
@@ -6,7 +6,7 @@ import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
-import android.widget.Button
+import android.widget.PopupMenu
 import android.widget.Toast
 import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts
@@ -36,28 +36,31 @@ class DishesFragment : Fragment() {
         loadRecipes()
 
         binding.addDish.setOnClickListener {
-            val dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.create_dish_modal_dialog, null)
+            val popup = PopupMenu(requireActivity(), it)
 
-            val dialog = android.app.AlertDialog.Builder(requireContext())
-                .setView(dialogView)
-                .setCancelable(true) // tap outside to dismiss
-                .create()
+            popup.apply {
+                menuInflater.inflate(R.menu.create_dish_menu, menu)
 
-            dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
+                setOnMenuItemClickListener {
+                    when (it.itemId) {
+                        R.id.create_manually -> {
+                            val intent = Intent(requireContext(), CreateDishActivity::class.java)
+                            createDishLauncher.launch(intent)
 
-            dialogView.findViewById<Button>(R.id.createManualBtn).setOnClickListener {
-                val intent = Intent(requireContext(), CreateDishActivity::class.java)
-                createDishLauncher.launch(intent)
-                dialog.dismiss()
+                            true
+                        }
+                        R.id.create_with_ai -> {
+                            val intent = Intent(requireContext(), GenerateRecipeActivity::class.java)
+                            createDishLauncher.launch(intent)
+
+                            true
+                        }
+                        else -> false
+                    }
+                }
+
+                show()
             }
-
-            dialogView.findViewById<Button>(R.id.createAIBtn).setOnClickListener {
-                val intent = Intent(requireContext(), GenerateRecipeActivity::class.java)
-                createDishLauncher.launch(intent)
-                dialog.dismiss()
-            }
-
-            dialog.show()
         }
 
 
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
index 7267253..4c5f49f 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
@@ -86,7 +86,9 @@ class ShoppingListFragment : Fragment() {
 
             val popup = PopupMenu(requireActivity(), view)
             popup.apply {
+
                 menuInflater.inflate(R.menu.shopping_item_context_menu, menu)
+
                 setOnMenuItemClickListener {
                     when (it.itemId) {
                         R.id.remove_shopping_item -> {
@@ -107,6 +109,7 @@ class ShoppingListFragment : Fragment() {
                         else -> false
                     }
                 }
+
                 show()
             }
 
diff --git a/app/app/src/main/res/layout/create_dish_modal_dialog.xml b/app/app/src/main/res/layout/create_dish_modal_dialog.xml
deleted file mode 100644
index 0433bb6..0000000
--- a/app/app/src/main/res/layout/create_dish_modal_dialog.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/dialog_root"
-    android:layout_width="250dp"
-    android:layout_height="400dp"
-    android:orientation="vertical"
-    android:background="@drawable/rounded_background"
-    android:padding="0dp"
-    android:gravity="center">
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="40dp"
-        android:text="@string/create_dish"
-        android:textAlignment="center"
-        android:textSize="30sp"/>
-
-    <Button
-        android:id="@+id/createManualBtn"
-        android:layout_width="200dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:text="@string/manually" />
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:background="#CCCCCC" />
-
-    <Button
-        android:id="@+id/createAIBtn"
-        android:layout_width="200dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:text="@string/search_for_dishes" />
-</LinearLayout>
diff --git a/app/app/src/main/res/menu/create_dish_menu.xml b/app/app/src/main/res/menu/create_dish_menu.xml
new file mode 100644
index 0000000..65cb3bf
--- /dev/null
+++ b/app/app/src/main/res/menu/create_dish_menu.xml
@@ -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/create_manually"
+        android:title="@string/create_manually_label"
+    />
+    <item
+        android:id="@+id/create_with_ai"
+        android:title="@string/create_ai_label"
+    />
+</menu>
diff --git a/app/app/src/main/res/values-night/themes.xml b/app/app/src/main/res/values-night/themes.xml
index 91d3f75..d17ff6d 100644
--- a/app/app/src/main/res/values-night/themes.xml
+++ b/app/app/src/main/res/values-night/themes.xml
@@ -8,5 +8,6 @@
         <item name="colorSurface">@color/dark_cyan</item>
         <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
         <item name="android:colorBackground">@color/black</item>
+        <item name="android:windowBackground">@color/black</item>
     </style>
 </resources>
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index 367630e..9953f76 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -41,14 +41,14 @@
     <string name="checked_desc">Checked</string>
     <string name="delete_label">Delete</string>
     <string name="empty_shopping_list">Your shopping list is empty</string>
-    <string name="search_for_dishes">Search For Dishes</string>
-    <string name="manually">Manually</string>
     <string name="create_dish">Create Dish</string>
     <string name="ai_generate_recipe_title">Generate recipe with AI</string>
     <string name="dish_title_label">Name of dish</string>
     <string name="generate_recipe_label">Generate</string>
     <string name="ingredients_label">Ingredients</string>
     <string name="directions_label">Directions</string>
+    <string name="create_manually_label">Create manually</string>
+    <string name="create_ai_label">Generate recipe using AI</string>
     <string-array name="units">
         <item></item>
         <item>g</item>

From 00cc8101f1b9d551302627e5f17b0138893260de Mon Sep 17 00:00:00 2001
From: LilleBRG <lillebrgmc@gmail.com>
Date: Tue, 13 May 2025 15:11:57 +0200
Subject: [PATCH 04/10] need to merge but trying to add recipe to shoppinglist

---
 .../tech/mercantec/easyeat/helpers/auth.kt    |  15 ++-
 .../mercantec/easyeat/models/CreateRecipe.kt  |   8 +-
 .../easyeat/ui/dishes/CreateDishAIActivity.kt |   4 +-
 .../easyeat/ui/dishes/CreateDishActivity.kt   |   1 -
 .../easyeat/ui/dishes/DishDetailsActivity.kt  | 116 ++++++++++++++++--
 .../easyeat/ui/dishes/InstructionsAdapter.kt  |   7 +-
 .../activity_create_dish_ingredient_row.xml   |   4 +-
 .../main/res/layout/activity_dish_details.xml |  54 ++++++--
 app/app/src/main/res/values/strings.xml       |   1 +
 9 files changed, 174 insertions(+), 36 deletions(-)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
index 6ce46f1..f152195 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
@@ -3,10 +3,8 @@ package tech.mercantec.easyeat.helpers
 import android.content.Context
 import android.util.Log
 import kotlinx.serialization.Serializable
-import tech.mercantec.easyeat.models.CreateDirection
 import tech.mercantec.easyeat.models.CreateIngredient
 import tech.mercantec.easyeat.models.CreateRecipe
-import tech.mercantec.easyeat.models.Direction
 import tech.mercantec.easyeat.models.Ingredient
 
 @Serializable
@@ -116,7 +114,7 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
 }
 
 @Serializable
-data class CreateRecipeRequest(val name: String, val description: String, val directions: List<CreateDirection>, val  ingredients: List<CreateIngredient>)
+data class CreateRecipeRequest(val name: String, val description: String, val directions: List<String>, val  ingredients: List<CreateIngredient>)
 
 fun createRecipe(ctx: Context, recipe: CreateRecipe) {
     val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients)
@@ -132,8 +130,17 @@ fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
 }
 
 @Serializable
-data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List<Direction>, val ingredients: List<Ingredient>)
+data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List<String>, val ingredients: List<Ingredient>)
 
 fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
     return requestJson<Unit, RecipeDetailsResponse>(ctx, "GET", "/api/Recipe/get/$id", null)
 }
+
+@Serializable
+data class ShoppingListAddRecipeRequest(val id: Int, val multiplier: Int)
+
+fun AddRecipeToShoppingList(ctx: Context, id: Int, multiplier: Int) {
+    val request = ShoppingListAddRecipeRequest(id, multiplier)
+
+    return requestJson<ShoppingListAddRecipeRequest, Unit>(ctx, "ADD", "/api/ShoppingList/recipeadd", request)
+}
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt b/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
index 782f449..e7661bb 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/models/CreateRecipe.kt
@@ -6,16 +6,10 @@ import kotlinx.serialization.Serializable
 data class CreateRecipe(
     val name: String,
     val description: String,
-    val directions: List<CreateDirection>,
+    val directions: List<String>,
     val ingredients: List<CreateIngredient>
 )
 
-@Serializable
-data class CreateDirection(
-    val instructions: String
-)
-
-
 @Serializable
 data class CreateIngredient(
     val amount: Double?,
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt
index fcf4bdc..6b46c5e 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishAIActivity.kt
@@ -9,8 +9,8 @@ import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
 import tech.mercantec.easyeat.R
 import tech.mercantec.easyeat.helpers.ApiRequestException
-import tech.mercantec.easyeat.helpers.GenerateRecipeResponse
 import tech.mercantec.easyeat.helpers.generateRecipeWithAI
+import tech.mercantec.easyeat.models.Recipe
 import java.util.Locale
 import kotlin.concurrent.thread
 
@@ -27,7 +27,7 @@ class CreateDishAIActivity : AppCompatActivity() {
             progressDialog.show()
 
             thread {
-                val response: GenerateRecipeResponse
+                val response: Recipe
                 try {
                     response = generateRecipeWithAI(this, name, Locale.getDefault().displayLanguage)
                 } catch (e: ApiRequestException) {
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
index 2ece5a7..e5b72a9 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
@@ -20,7 +20,6 @@ import tech.mercantec.easyeat.helpers.ApiRequestException
 import tech.mercantec.easyeat.helpers.changePassword
 import tech.mercantec.easyeat.helpers.createRecipe
 import tech.mercantec.easyeat.helpers.request
-import tech.mercantec.easyeat.models.CreateDirection
 import tech.mercantec.easyeat.models.CreateIngredient
 import tech.mercantec.easyeat.models.CreateRecipe
 import kotlin.concurrent.thread
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index 3f41774..a87bc46 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -1,7 +1,12 @@
 package tech.mercantec.easyeat.ui.dishes
 
+import android.app.Activity
+import android.app.ProgressDialog
 import android.os.Bundle
 import android.util.Log
+import android.view.View
+import android.widget.Button
+import android.widget.LinearLayout
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
 import tech.mercantec.easyeat.R
@@ -9,14 +14,22 @@ import tech.mercantec.easyeat.helpers.ApiRequestException
 import tech.mercantec.easyeat.helpers.RecipeDetailsResponse
 import tech.mercantec.easyeat.helpers.getRecipeDetails
 import kotlin.concurrent.thread
-import android.widget.ListView
+import android.widget.EditText
 import android.widget.TextView
+import androidx.core.widget.doAfterTextChanged
+import tech.mercantec.easyeat.helpers.AddRecipeToShoppingList
+import tech.mercantec.easyeat.helpers.createRecipe
+import tech.mercantec.easyeat.models.CreateRecipe
+import tech.mercantec.easyeat.models.Ingredient
 
 class DishDetailsActivity : AppCompatActivity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_dish_details)
 
+        val ingredientsContainer = findViewById<LinearLayout>(R.id.dishDetailIngredients)
+        val multiplierEditText = findViewById<EditText>(R.id.ingredientMultiplier)
+
         val dishId = intent.getIntExtra("dish_id", -1)
         if (dishId == -1) {
             Toast.makeText(this, "No dish ID provided", Toast.LENGTH_SHORT).show()
@@ -24,6 +37,8 @@ class DishDetailsActivity : AppCompatActivity() {
             return
         }
 
+
+
         thread {
             val recipe: RecipeDetailsResponse
             try {
@@ -35,20 +50,101 @@ class DishDetailsActivity : AppCompatActivity() {
                 return@thread
             }
             Log.i("DISH", recipe.ingredients.toString())
+            val ingredientsLayout = findViewById<LinearLayout>(R.id.dishDetailIngredients)
+            val instructionsLayout = findViewById<LinearLayout>(R.id.dishDetailInstructions)
+
+// Example data: recipe.ingredients and recipe.directions
             runOnUiThread {
-                // Set title and description
                 findViewById<TextView>(R.id.dishDetailName).text = recipe.name
                 findViewById<TextView>(R.id.dishDetailDescription).text = recipe.description
+                // Populate Ingredients
+                recipe.ingredients.forEach { ingredient ->
+                    val textView = TextView(this).apply {
+                        text = "${ingredient.name} ${ingredient.amount ?: ""} ${ingredient.unit ?: ""}"
+                        textSize = 18f
+                    }
+                    textView.textAlignment = View.TEXT_ALIGNMENT_CENTER
+                    ingredientsLayout.addView(textView)
+                }
 
-                // Set up the ingredient list
-                val ingredientListView = findViewById<ListView>(R.id.dishDetailIngredients)
-                val ingredientAdapter = IngredientAdapter(this, recipe.ingredients)
-                ingredientListView.adapter = ingredientAdapter
-
-                val instructionsListView = findViewById<ListView>(R.id.dishDetailInstructions)
-                val instructionsAdapter = InstructionsAdapter(this, recipe.directions)
-                instructionsListView.adapter = instructionsAdapter
+                // Populate Instructions (if directions are strings)
+                recipe.directions.forEachIndexed { index, direction ->
+                    val textView = TextView(this).apply {
+                        text = "${index + 1}. $direction"
+                        textSize = 18f
+                    }
+                    textView.textAlignment = View.TEXT_ALIGNMENT_CENTER
+                    instructionsLayout.addView(textView)
+                }
             }
+
+            fun displayIngredients(ingredients: List<Ingredient>, multiplier: Int, container: LinearLayout) {
+                container.removeAllViews() // clear previous views
+
+                for (ingredient in ingredients) {
+                    val row = TextView(this)
+                    val amount = (ingredient.amount ?: 0.0) * multiplier
+                    row.text = "${ingredient.name}: ${"%.2f".format(amount)} ${ingredient.unit ?: ""}"
+                    row.textSize = 18f
+                    row.setPadding(0, 8, 0, 8)
+                    row.textAlignment = View.TEXT_ALIGNMENT_CENTER
+                    container.addView(row)
+                }
+            }
+
+            runOnUiThread {
+                val nameView = findViewById<TextView>(R.id.dishDetailName)
+                val descView = findViewById<TextView>(R.id.dishDetailDescription)
+
+                nameView.text = recipe.name
+                descView.text = recipe.description
+
+                // Default multiplier
+                var multiplier = 1
+
+                // Initial display
+                displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
+
+                // Listen for user input changes
+                multiplierEditText.doAfterTextChanged {
+                    multiplier = it.toString().toIntOrNull() ?: 1
+                    displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
+                }
+
+                // You can do the same for directions if needed
+            }
+
+            val saveButton: Button = findViewById(R.id.saveDishButton)
+            saveButton.setOnClickListener {
+
+
+                val progressDialog = ProgressDialog(this)
+                progressDialog.setMessage("Loading...")
+                progressDialog.show()
+                thread {
+                    try {
+                        AddRecipeToShoppingList(this, dishId, multiplierEditText.text.toString().toIntOrNull() ?: 1)
+                    } catch (e: ApiRequestException) {
+                        runOnUiThread {
+                            Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
+                        }
+
+                        return@thread
+                    } finally {
+                        runOnUiThread {
+                            progressDialog.hide()
+                        }
+                    }
+
+                    runOnUiThread {
+                        Toast.makeText(this, "Password changed successfully", Toast.LENGTH_LONG).show()
+                    }
+
+                    setResult(Activity.RESULT_OK)
+                    finish()
+                }
+            }
+
         }
     }
 }
\ No newline at end of file
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
index e0a2fee..161f58c 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/InstructionsAdapter.kt
@@ -7,10 +7,9 @@ import android.view.ViewGroup
 import android.widget.ArrayAdapter
 import android.widget.TextView
 import tech.mercantec.easyeat.R
-import tech.mercantec.easyeat.models.Direction
 
-class InstructionsAdapter (context: Context, instructions: List<Direction>)
-    : ArrayAdapter<Direction>(context, 0, instructions) {
+class InstructionsAdapter (context: Context, instructions: List<String>)
+    : ArrayAdapter<String>(context, 0, instructions) {
 
     override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
         val ingredient = getItem(position)
@@ -19,7 +18,7 @@ class InstructionsAdapter (context: Context, instructions: List<Direction>)
 
         val nameView = view.findViewById<TextView>(R.id.instructionText)
 
-        nameView.text = ingredient?.instruktions ?: ""
+        nameView.text = ingredient?: ""
 
         return view
     }
diff --git a/app/app/src/main/res/layout/activity_create_dish_ingredient_row.xml b/app/app/src/main/res/layout/activity_create_dish_ingredient_row.xml
index c9d590b..6d2a736 100644
--- a/app/app/src/main/res/layout/activity_create_dish_ingredient_row.xml
+++ b/app/app/src/main/res/layout/activity_create_dish_ingredient_row.xml
@@ -43,7 +43,9 @@
                 <EditText
                     android:id="@+id/ingredientAmountEditText"
                     android:layout_width="173dp"
-                    android:layout_height="48dp" />
+                    android:layout_height="48dp"
+                    android:inputType="numberDecimal"
+                    />
             </LinearLayout>
 
             <!-- Measurement field -->
diff --git a/app/app/src/main/res/layout/activity_dish_details.xml b/app/app/src/main/res/layout/activity_dish_details.xml
index 584e952..d431ab4 100644
--- a/app/app/src/main/res/layout/activity_dish_details.xml
+++ b/app/app/src/main/res/layout/activity_dish_details.xml
@@ -19,13 +19,16 @@
             android:textSize="30sp"
             android:textAlignment="center"
             android:layout_marginBottom="10dp"
-            android:textStyle="bold" />
+            android:textStyle="bold"
+            android:layout_marginHorizontal="10sp"/>
+        />
         <TextView
             android:id="@+id/dishDetailDescription"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:textSize="20sp"
-            android:textAlignment="center" />
+            android:textAlignment="center"
+            android:layout_marginHorizontal="10sp"/>
         <TextView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
@@ -34,11 +37,37 @@
             android:textAlignment="center"
             android:textStyle="bold"
             android:text="Ingredients"/>
-        <ListView
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="horizontal">
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:textSize="18sp"
+                android:layout_marginLeft="10sp"
+                android:text="Food for how many people?"
+                android:layout_weight="0.7"/>
+            <EditText
+                android:id="@+id/ingredientMultiplier"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:ems="10"
+                android:inputType="number"
+                android:layout_weight="1"
+                android:layout_marginRight="10sp"/>
+        </LinearLayout>
+
+
+        <LinearLayout
             android:id="@+id/dishDetailIngredients"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            />
+            android:orientation="vertical"
+            android:layout_marginHorizontal="10sp">
+
+        </LinearLayout>
+
 
         <TextView
             android:layout_width="match_parent"
@@ -49,10 +78,21 @@
             android:textStyle="bold"
             android:text="Instructions"/>
 
-        <ListView
+        <LinearLayout
             android:id="@+id/dishDetailInstructions"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            />
+            android:orientation="vertical"
+            android:layout_marginHorizontal="10sp"/>
+
+        <Button
+            android:id="@+id/add_dish"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_margin="16dp"
+            android:backgroundTint="@color/cyan"
+            android:text="@string/add_ingredients_to_shopping_list"
+            android:tint="@android:color/white"/>
     </LinearLayout>
-</ScrollView>
\ No newline at end of file
+</ScrollView>
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index e7d5584..737af97 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -47,6 +47,7 @@
     <string name="ai_generate_recipe_title">Generate recipe with AI</string>
     <string name="dish_title_label">Name of dish</string>
     <string name="generate_recipe_label">Generate</string>
+    <string name="add_ingredients_to_shopping_list">Add ingredients to Shopping List</string>
     <string-array name="units">
         <item></item>
         <item>g</item>

From 1e01d1ee9070757327561472cdbf423dc563726d Mon Sep 17 00:00:00 2001
From: LilleBRG <lillebrgmc@gmail.com>
Date: Tue, 13 May 2025 15:24:25 +0200
Subject: [PATCH 05/10] fixed errors in merge

---
 .../tech/mercantec/easyeat/helpers/auth.kt    | 20 +------------------
 .../tech/mercantec/easyeat/helpers/dishes.kt  |  3 ++-
 .../easyeat/ui/dishes/DishDetailsActivity.kt  |  2 --
 3 files changed, 3 insertions(+), 22 deletions(-)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
index fb5c664..bb8cdce 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
@@ -3,9 +3,8 @@ package tech.mercantec.easyeat.helpers
 import android.content.Context
 import android.util.Log
 import kotlinx.serialization.Serializable
-import tech.mercantec.easyeat.models.CreateIngredient
-import tech.mercantec.easyeat.models.CreateRecipe
 import tech.mercantec.easyeat.models.Ingredient
+import tech.mercantec.easyeat.models.Recipe
 
 @Serializable
 data class LoginRequest(val emailUsr: String, val password: String)
@@ -113,28 +112,11 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
     return requestJson<ChangePasswordRequest, Unit>(ctx, "PUT", "/api/User/change-password", request)
 }
 
-@Serializable
-data class CreateRecipeRequest(val name: String, val description: String, val directions: List<String>, val  ingredients: List<CreateIngredient>)
 
-fun createRecipe(ctx: Context, recipe: CreateRecipe) {
-    val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients)
 
-    requestJson<CreateRecipeRequest, Boolean>(ctx, "POST", "/api/recipe/create", request)
-}
 
-@Serializable
-data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
 
-fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
-    return requestJson<Unit, List<GetAllRecipesResponse>>(ctx, "GET", "/api/Recipe/getall", null)
-}
 
-@Serializable
-data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List<String>, val ingredients: List<Ingredient>)
-
-fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
-    return requestJson<Unit, RecipeDetailsResponse>(ctx, "GET", "/api/Recipe/get/$id", null)
-}
 
 @Serializable
 data class ShoppingListAddRecipeRequest(val id: Int, val multiplier: Int)
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
index 4a7a599..146e876 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
@@ -19,7 +19,7 @@ fun createRecipe(ctx: Context, recipe: Recipe) {
 @Serializable
 data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
 
-fun getAllRecipes(ctx: Context): List<GetAllRecipesResponse> {
+fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
     return requestJson<Unit, List<GetAllRecipesResponse>>(ctx, "GET", "/api/Recipe/getall", null)
 }
 
@@ -29,3 +29,4 @@ data class RecipeDetailsResponse(val id: Int, val name: String, val description:
 fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
     return requestJson<Unit, RecipeDetailsResponse>(ctx, "GET", "/api/Recipe/get/$id", null)
 }
+
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index a87bc46..5c5f1f6 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -18,8 +18,6 @@ import android.widget.EditText
 import android.widget.TextView
 import androidx.core.widget.doAfterTextChanged
 import tech.mercantec.easyeat.helpers.AddRecipeToShoppingList
-import tech.mercantec.easyeat.helpers.createRecipe
-import tech.mercantec.easyeat.models.CreateRecipe
 import tech.mercantec.easyeat.models.Ingredient
 
 class DishDetailsActivity : AppCompatActivity() {

From 2c22f8d8e134bf83d824ab2e1a5b57f77d2278f6 Mon Sep 17 00:00:00 2001
From: LilleBRG <lillebrgmc@gmail.com>
Date: Tue, 13 May 2025 15:38:11 +0200
Subject: [PATCH 06/10] more fixes idk

---
 app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt   | 2 +-
 app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt | 2 +-
 .../tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt     | 3 ---
 .../tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt    | 2 +-
 .../java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt    | 1 +
 .../tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt | 2 +-
 app/app/src/main/res/layout/activity_dish_details.xml          | 2 +-
 7 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
index bb8cdce..5362641 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
@@ -124,5 +124,5 @@ data class ShoppingListAddRecipeRequest(val id: Int, val multiplier: Int)
 fun AddRecipeToShoppingList(ctx: Context, id: Int, multiplier: Int) {
     val request = ShoppingListAddRecipeRequest(id, multiplier)
 
-    return requestJson<ShoppingListAddRecipeRequest, Unit>(ctx, "ADD", "/api/ShoppingList/recipeadd", request)
+    return requestJson<ShoppingListAddRecipeRequest, Unit>(ctx, "POST", "/api/ShoppingList/recipeadd", request)
 }
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
index 146e876..bcaba3a 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/dishes.kt
@@ -19,7 +19,7 @@ fun createRecipe(ctx: Context, recipe: Recipe) {
 @Serializable
 data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
 
-fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
+fun getAllRecipes(ctx: Context): List<GetAllRecipesResponse> {
     return requestJson<Unit, List<GetAllRecipesResponse>>(ctx, "GET", "/api/Recipe/getall", null)
 }
 
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
index 7743358..b5cf99f 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/CreateDishActivity.kt
@@ -15,9 +15,6 @@ import androidx.appcompat.app.AppCompatActivity
 import tech.mercantec.easyeat.R
 import tech.mercantec.easyeat.helpers.ApiRequestException
 import tech.mercantec.easyeat.helpers.createRecipe
-import tech.mercantec.easyeat.helpers.request
-import tech.mercantec.easyeat.models.CreateIngredient
-import tech.mercantec.easyeat.models.CreateRecipe
 import tech.mercantec.easyeat.models.Ingredient
 import tech.mercantec.easyeat.models.Recipe
 import kotlin.concurrent.thread
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index 5c5f1f6..bfa9630 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -112,7 +112,7 @@ class DishDetailsActivity : AppCompatActivity() {
                 // You can do the same for directions if needed
             }
 
-            val saveButton: Button = findViewById(R.id.saveDishButton)
+            val saveButton: Button = findViewById(R.id.addDishToShoppingList)
             saveButton.setOnClickListener {
 
 
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
index 70ab3fd..b80f99a 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
@@ -17,6 +17,7 @@ import tech.mercantec.easyeat.helpers.ApiRequestException
 import tech.mercantec.easyeat.helpers.GetAllRecipesResponse
 import tech.mercantec.easyeat.helpers.getAllRecipes
 import tech.mercantec.easyeat.models.DishListItem
+import tech.mercantec.easyeat.models.Recipe
 import kotlin.concurrent.thread
 
 class DishesFragment : Fragment() {
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
index 94523f1..b4fc843 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/GenerateRecipeActivity.kt
@@ -27,7 +27,7 @@ class GenerateRecipeActivity : AppCompatActivity() {
             progressDialog.show()
 
             thread {
-                val response: GenerateRecipeResponse
+//                val response: GenerateRecipeResponse
                 try {
                     val recipe = generateRecipeWithAI(this, name, Locale.getDefault().displayLanguage)
 
diff --git a/app/app/src/main/res/layout/activity_dish_details.xml b/app/app/src/main/res/layout/activity_dish_details.xml
index d431ab4..088988f 100644
--- a/app/app/src/main/res/layout/activity_dish_details.xml
+++ b/app/app/src/main/res/layout/activity_dish_details.xml
@@ -86,7 +86,7 @@
             android:layout_marginHorizontal="10sp"/>
 
         <Button
-            android:id="@+id/add_dish"
+            android:id="@+id/addDishToShoppingList"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center"

From b04f385bdb0c90fed6be3a4391fe764ce4c1a106 Mon Sep 17 00:00:00 2001
From: LilleBRG <lillebrgmc@gmail.com>
Date: Tue, 13 May 2025 15:52:41 +0200
Subject: [PATCH 07/10] very close to add to shopping list wrks

---
 .../src/main/java/tech/mercantec/easyeat/helpers/auth.kt    | 6 ------
 .../tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt | 4 +++-
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
index 5362641..0ef3061 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
@@ -112,12 +112,6 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
     return requestJson<ChangePasswordRequest, Unit>(ctx, "PUT", "/api/User/change-password", request)
 }
 
-
-
-
-
-
-
 @Serializable
 data class ShoppingListAddRecipeRequest(val id: Int, val multiplier: Int)
 
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index bfa9630..f89f414 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -121,7 +121,9 @@ class DishDetailsActivity : AppCompatActivity() {
                 progressDialog.show()
                 thread {
                     try {
-                        AddRecipeToShoppingList(this, dishId, multiplierEditText.text.toString().toIntOrNull() ?: 1)
+                        val multiplierEditText = findViewById<EditText>(R.id.ingredientMultiplier)
+                        val multiplierText = multiplierEditText.text.toString()
+                        AddRecipeToShoppingList(this, dishId, multiplierText.toIntOrNull() ?: 1)
                     } catch (e: ApiRequestException) {
                         runOnUiThread {
                             Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()

From 7a25b0708beca0a5240edd65f8ca6456e4c41934 Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Tue, 13 May 2025 21:15:06 +0200
Subject: [PATCH 08/10] Implement editing shopping items

---
 .../easyeat/helpers/shopping_list.kt          |  11 +-
 .../easyeat/models/ShoppingListItem.kt        |   8 +-
 .../ui/shopping_list/ShoppingListFragment.kt  | 154 ++++++++++++------
 .../src/main/res/drawable/ic_delete_24px.xml  |  10 --
 ...list.xml => dialog_edit_shopping_item.xml} |   0
 .../res/menu/shopping_item_context_menu.xml   |   5 +-
 app/app/src/main/res/values/strings.xml       |   2 +
 7 files changed, 120 insertions(+), 70 deletions(-)
 delete mode 100644 app/app/src/main/res/drawable/ic_delete_24px.xml
 rename app/app/src/main/res/layout/{dialog_add_to_shopping_list.xml => dialog_edit_shopping_item.xml} (100%)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/helpers/shopping_list.kt b/app/app/src/main/java/tech/mercantec/easyeat/helpers/shopping_list.kt
index a9adbc8..e6af1db 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/helpers/shopping_list.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/helpers/shopping_list.kt
@@ -8,13 +8,12 @@ fun getShoppingList(ctx: Context): Array<ShoppingListItem> {
     return requestJson<Unit, Array<ShoppingListItem>>(ctx, "GET", "/api/ShoppingList/get", null)
 }
 
-@Serializable
-data class AddShoppingItemRequest(val name: String, val amount: Double?, val unit: String?, val checked: Boolean)
+fun addShoppingItem(ctx: Context, item: ShoppingListItem): ShoppingListItem {
+    return requestJson<ShoppingListItem, ShoppingListItem>(ctx, "POST", "/api/ShoppingList/add", item)
+}
 
-fun addShoppingItem(ctx: Context, name: String, amount: Double?, unit: String?): ShoppingListItem {
-    val request = AddShoppingItemRequest(name, amount, unit, false)
-
-    return requestJson<AddShoppingItemRequest, ShoppingListItem>(ctx, "POST", "/api/ShoppingList/add", request)
+fun editShoppingItem(ctx: Context, old: ShoppingListItem, new: ShoppingListItem) {
+    requestJson<ShoppingListItem, Boolean>(ctx, "PUT", "/api/ShoppingList/update?itemId=${old.id}", new)
 }
 
 fun toggleShoppingItemChecked(ctx: Context, item: ShoppingListItem) {
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/models/ShoppingListItem.kt b/app/app/src/main/java/tech/mercantec/easyeat/models/ShoppingListItem.kt
index a97a6a7..f9d5711 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/models/ShoppingListItem.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/models/ShoppingListItem.kt
@@ -3,4 +3,10 @@ package tech.mercantec.easyeat.models
 import kotlinx.serialization.Serializable
 
 @Serializable
-data class ShoppingListItem(val id: Int, var name: String, var amount: Double?, var unit: String?, var checked: Boolean)
+data class ShoppingListItem(
+    var id: Int? = null,
+    var name: String,
+    var amount: Double?,
+    var unit: String?,
+    var checked: Boolean = false,
+)
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
index 4c5f49f..2523ed8 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
@@ -9,6 +9,7 @@ import android.widget.ArrayAdapter
 import android.widget.EditText
 import android.widget.PopupMenu
 import android.widget.Spinner
+import android.widget.TextView
 import android.widget.Toast
 import androidx.fragment.app.Fragment
 import tech.mercantec.easyeat.R
@@ -16,6 +17,7 @@ import tech.mercantec.easyeat.databinding.FragmentShoppingListBinding
 import tech.mercantec.easyeat.helpers.ApiRequestException
 import tech.mercantec.easyeat.helpers.addShoppingItem
 import tech.mercantec.easyeat.helpers.deleteShoppingItem
+import tech.mercantec.easyeat.helpers.editShoppingItem
 import tech.mercantec.easyeat.helpers.getShoppingList
 import tech.mercantec.easyeat.helpers.toggleShoppingItemChecked
 import tech.mercantec.easyeat.models.ShoppingListItem
@@ -86,11 +88,36 @@ class ShoppingListFragment : Fragment() {
 
             val popup = PopupMenu(requireActivity(), view)
             popup.apply {
-
                 menuInflater.inflate(R.menu.shopping_item_context_menu, menu)
 
                 setOnMenuItemClickListener {
                     when (it.itemId) {
+                        R.id.edit_shopping_item -> {
+                            showEditDialog(item) { dialog, newItem ->
+                                thread {
+                                    try {
+                                        editShoppingItem(requireContext(), item, newItem)
+                                    } catch (e: ApiRequestException) {
+                                        activity?.runOnUiThread {
+                                            Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
+                                        }
+
+                                        return@thread
+                                    } finally {
+                                        dialog.dismiss()
+                                    }
+
+                                    activity?.runOnUiThread {
+                                        val adapter = binding.shoppingList.adapter as ShoppingItemAdapter
+
+                                        adapter.remove(item)
+                                        adapter.insert(newItem, position)
+                                    }
+                                }
+                            }
+
+                            true
+                        }
                         R.id.remove_shopping_item -> {
                             (parent.adapter as ShoppingItemAdapter).remove(item)
 
@@ -119,65 +146,88 @@ class ShoppingListFragment : Fragment() {
 
         // Show new item dialog when clicking add
         binding.addToShoppingList.setOnClickListener {
-            val view = requireActivity().layoutInflater.inflate(R.layout.dialog_add_to_shopping_list, null)
-
-            val dialog = AlertDialog.Builder(activity)
-                .setView(view)
-                .setPositiveButton(R.string.add_label) { dialog, id ->
-                    val dialog = dialog as AlertDialog
-
-                    val amount = view.findViewById<EditText>(R.id.amount).text.toString().toDouble()
-                    val unit = view.findViewById<Spinner>(R.id.unit_selector).selectedItem.toString().ifEmpty { null }
-                    val name = view.findViewById<EditText>(R.id.name).text.toString()
-
-                    dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
-                    dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false
-
-                    thread {
-                        val item: ShoppingListItem
-                        try {
-                            item = addShoppingItem(requireContext(), name, amount, unit)
-                        } catch (e: ApiRequestException) {
-                            activity?.runOnUiThread {
-                                Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
-                            }
-
-                            return@thread
-                        } finally {
-                            activity?.runOnUiThread {
-                                dialog.dismiss()
-                            }
+            showEditDialog(null) { dialog, item ->
+                thread {
+                    val newItem: ShoppingListItem
+                    try {
+                        newItem = addShoppingItem(requireContext(), item)
+                    } catch (e: ApiRequestException) {
+                        activity?.runOnUiThread {
+                            Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
                         }
 
+                        return@thread
+                    } finally {
                         activity?.runOnUiThread {
-                            val adapter = binding.shoppingList.adapter as ShoppingItemAdapter
-
-                            for (i in 0 ..< adapter.count) {
-                                if (adapter.getItem(i)?.id == item.id) {
-                                    adapter.remove(adapter.getItem(i))
-                                    adapter.insert(item, i)
-
-                                    return@runOnUiThread
-                                }
-                            }
-
-                            adapter.insert(item, adapter.count)
+                            dialog.dismiss()
                         }
                     }
+
+                    activity?.runOnUiThread {
+                        val adapter = binding.shoppingList.adapter as ShoppingItemAdapter
+
+                        for (i in 0..<adapter.count) {
+                            if (adapter.getItem(i)?.id == newItem.id) {
+                                adapter.remove(adapter.getItem(i))
+                                adapter.insert(newItem, i)
+
+                                return@runOnUiThread
+                            }
+                        }
+
+                        adapter.insert(newItem, adapter.count)
+                    }
                 }
-                .setNegativeButton(R.string.cancel_label) { dialog, _ ->
-                    dialog.cancel()
-                }
-                .create()
-
-            dialog.show()
-
-            val adapter = ArrayAdapter.createFromResource(requireContext(), R.array.units, android.R.layout.simple_spinner_item)
-            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
-
-            dialog.findViewById<Spinner>(R.id.unit_selector).adapter = adapter
+            }
         }
 
         return binding.root
     }
+
+    private fun showEditDialog(item: ShoppingListItem?, onSave: (dialog: AlertDialog, item: ShoppingListItem) -> Unit) {
+        val view = requireActivity().layoutInflater.inflate(R.layout.dialog_edit_shopping_item, null)
+
+        val dialog = AlertDialog.Builder(activity)
+            .setView(view)
+            .setPositiveButton(R.string.add_label) { dialog, id ->
+                val dialog = dialog as AlertDialog
+
+                val amount = view.findViewById<EditText>(R.id.amount).text.toString().toDouble()
+                val unit = view.findViewById<Spinner>(R.id.unit_selector).selectedItem.toString()
+                    .ifEmpty { null }
+                val name = view.findViewById<EditText>(R.id.name).text.toString()
+
+                onSave(dialog, ShoppingListItem(item?.id, name, amount, unit, item?.checked ?: false))
+
+                dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
+                dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false
+
+
+            }
+            .setNegativeButton(R.string.cancel_label) { dialog, _ ->
+                dialog.cancel()
+            }
+            .create()
+
+        dialog.show()
+
+        val adapter = ArrayAdapter.createFromResource(
+            requireContext(),
+            R.array.units,
+            android.R.layout.simple_spinner_item
+        )
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+
+        dialog.findViewById<Spinner>(R.id.unit_selector).adapter = adapter
+
+        // Pre-fill dialog inputs with current item if applicable
+        item?.let { item ->
+            view.findViewById<EditText>(R.id.amount).setText(item.amount?.toBigDecimal()?.stripTrailingZeros().toString(), TextView.BufferType.EDITABLE)
+            view.findViewById<Spinner>(R.id.unit_selector).setSelection(adapter.getPosition(item.unit))
+            view.findViewById<EditText>(R.id.name).setText(item.name, TextView.BufferType.EDITABLE)
+
+            view.findViewById<TextView>(R.id.title).text = resources.getString(R.string.edit_shopping_item_label)
+            dialog.getButton(AlertDialog.BUTTON_POSITIVE).text = resources.getString(R.string.save_label)
+        }
+    }
 }
\ No newline at end of file
diff --git a/app/app/src/main/res/drawable/ic_delete_24px.xml b/app/app/src/main/res/drawable/ic_delete_24px.xml
deleted file mode 100644
index d1ed443..0000000
--- a/app/app/src/main/res/drawable/ic_delete_24px.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="960"
-    android:viewportHeight="960"
-    android:tint="?attr/colorControlNormal">
-  <path
-      android:fillColor="@android:color/white"
-      android:pathData="M280,840Q247,840 223.5,816.5Q200,793 200,760L200,240L160,240L160,160L360,160L360,120L600,120L600,160L800,160L800,240L760,240L760,760Q760,793 736.5,816.5Q713,840 680,840L280,840ZM360,680L440,680L440,320L360,320L360,680ZM520,680L600,680L600,320L520,320L520,680Z"/>
-</vector>
diff --git a/app/app/src/main/res/layout/dialog_add_to_shopping_list.xml b/app/app/src/main/res/layout/dialog_edit_shopping_item.xml
similarity index 100%
rename from app/app/src/main/res/layout/dialog_add_to_shopping_list.xml
rename to app/app/src/main/res/layout/dialog_edit_shopping_item.xml
diff --git a/app/app/src/main/res/menu/shopping_item_context_menu.xml b/app/app/src/main/res/menu/shopping_item_context_menu.xml
index 48be440..14f1008 100644
--- a/app/app/src/main/res/menu/shopping_item_context_menu.xml
+++ b/app/app/src/main/res/menu/shopping_item_context_menu.xml
@@ -1,8 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/edit_shopping_item"
+        android:title="@string/edit_label"
+    />
     <item
         android:id="@+id/remove_shopping_item"
-        android:icon="@drawable/ic_delete_24px"
         android:title="@string/delete_label"
     />
 </menu>
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index a337f1a..bc68bda 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -32,6 +32,7 @@
     <string name="Instructions">Instructions</string>
     <string name="cancel_label">Cancel</string>
     <string name="add_shopping_item_label">Add shopping item</string>
+    <string name="edit_shopping_item_label">Edit shopping item</string>
     <string name="ingredient_amount_label">Amount</string>
     <string name="ingredient_amount_hint">500</string>
     <string name="ingredient_name_label">Name</string>
@@ -40,6 +41,7 @@
     <string name="logout_label">Log out</string>
     <string name="checked_desc">Checked</string>
     <string name="delete_label">Delete</string>
+    <string name="edit_label">Edit</string>
     <string name="empty_shopping_list">Your shopping list is empty</string>
     <string name="create_dish">Create Dish</string>
     <string name="ai_generate_recipe_title">Generate recipe with AI</string>

From 48b362254241e5fb92282edec01675d3c027b353 Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Tue, 13 May 2025 22:09:50 +0200
Subject: [PATCH 09/10] Redesign dish details page

---
 .../easyeat/ui/dishes/DishDetailsActivity.kt  | 21 ++---
 .../main/res/layout/activity_dish_details.xml | 89 ++++++++++---------
 app/app/src/main/res/values/strings.xml       |  2 +
 3 files changed, 53 insertions(+), 59 deletions(-)

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index f89f414..518d6ab 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -3,8 +3,10 @@ package tech.mercantec.easyeat.ui.dishes
 import android.app.Activity
 import android.app.ProgressDialog
 import android.os.Bundle
+import android.text.Html
 import android.util.Log
 import android.view.View
+import android.view.ViewGroup
 import android.widget.Button
 import android.widget.LinearLayout
 import android.widget.Toast
@@ -25,7 +27,7 @@ class DishDetailsActivity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_dish_details)
 
-        val ingredientsContainer = findViewById<LinearLayout>(R.id.dishDetailIngredients)
+        val ingredientsContainer = findViewById<LinearLayout>(R.id.ingredients)
         val multiplierEditText = findViewById<EditText>(R.id.ingredientMultiplier)
 
         val dishId = intent.getIntExtra("dish_id", -1)
@@ -48,30 +50,20 @@ class DishDetailsActivity : AppCompatActivity() {
                 return@thread
             }
             Log.i("DISH", recipe.ingredients.toString())
-            val ingredientsLayout = findViewById<LinearLayout>(R.id.dishDetailIngredients)
-            val instructionsLayout = findViewById<LinearLayout>(R.id.dishDetailInstructions)
+            val instructionsLayout = findViewById<LinearLayout>(R.id.instructions)
 
 // Example data: recipe.ingredients and recipe.directions
             runOnUiThread {
                 findViewById<TextView>(R.id.dishDetailName).text = recipe.name
                 findViewById<TextView>(R.id.dishDetailDescription).text = recipe.description
-                // Populate Ingredients
-                recipe.ingredients.forEach { ingredient ->
-                    val textView = TextView(this).apply {
-                        text = "${ingredient.name} ${ingredient.amount ?: ""} ${ingredient.unit ?: ""}"
-                        textSize = 18f
-                    }
-                    textView.textAlignment = View.TEXT_ALIGNMENT_CENTER
-                    ingredientsLayout.addView(textView)
-                }
 
                 // Populate Instructions (if directions are strings)
                 recipe.directions.forEachIndexed { index, direction ->
                     val textView = TextView(this).apply {
                         text = "${index + 1}. $direction"
                         textSize = 18f
+                        setPadding(0, 8, 0, 8)
                     }
-                    textView.textAlignment = View.TEXT_ALIGNMENT_CENTER
                     instructionsLayout.addView(textView)
                 }
             }
@@ -82,10 +74,9 @@ class DishDetailsActivity : AppCompatActivity() {
                 for (ingredient in ingredients) {
                     val row = TextView(this)
                     val amount = (ingredient.amount ?: 0.0) * multiplier
-                    row.text = "${ingredient.name}: ${"%.2f".format(amount)} ${ingredient.unit ?: ""}"
+                    row.text = Html.fromHtml("&#8226; ${ingredient.name}: ${"%.2f".format(amount)} ${ingredient.unit ?: ""}", Html.FROM_HTML_MODE_LEGACY)
                     row.textSize = 18f
                     row.setPadding(0, 8, 0, 8)
-                    row.textAlignment = View.TEXT_ALIGNMENT_CENTER
                     container.addView(row)
                 }
             }
diff --git a/app/app/src/main/res/layout/activity_dish_details.xml b/app/app/src/main/res/layout/activity_dish_details.xml
index 088988f..e50eb50 100644
--- a/app/app/src/main/res/layout/activity_dish_details.xml
+++ b/app/app/src/main/res/layout/activity_dish_details.xml
@@ -1,89 +1,89 @@
 <?xml version="1.0" encoding="utf-8"?>
 <ScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="409dp"
-    android:layout_height="729dp"
-    tools:layout_editor_absoluteX="1dp"
-    tools:layout_editor_absoluteY="1dp">
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        >
+        android:padding="30sp"
+        android:orientation="vertical">
+
         <TextView
             android:id="@+id/dishDetailName"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:textSize="30sp"
-            android:textAlignment="center"
             android:layout_marginBottom="10dp"
             android:textStyle="bold"
-            android:layout_marginHorizontal="10sp"/>
+            style="@style/HighContrastText"
         />
+
         <TextView
             android:id="@+id/dishDetailDescription"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:textSize="20sp"
-            android:textAlignment="center"
-            android:layout_marginHorizontal="10sp"/>
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginVertical="20dp"
-            android:textSize="25sp"
-            android:textAlignment="center"
-            android:textStyle="bold"
-            android:text="Ingredients"/>
+        />
+
         <LinearLayout
+            android:layout_marginTop="20dp"
+            android:layout_marginHorizontal="10dp"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="horizontal">
+
             <TextView
-                android:layout_width="match_parent"
+                android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:textSize="18sp"
-                android:layout_marginLeft="10sp"
-                android:text="Food for how many people?"
-                android:layout_weight="0.7"/>
+                android:textSize="16sp"
+                android:paddingTop="8dp"
+                android:text="@string/portions_label"
+            />
+
             <EditText
                 android:id="@+id/ingredientMultiplier"
-                android:layout_width="match_parent"
+                android:layout_marginStart="20dp"
+                android:layout_width="50dp"
                 android:layout_height="wrap_content"
-                android:ems="10"
                 android:inputType="number"
-                android:layout_weight="1"
-                android:layout_marginRight="10sp"/>
-        </LinearLayout>
-
-
-        <LinearLayout
-            android:id="@+id/dishDetailIngredients"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical"
-            android:layout_marginHorizontal="10sp">
+            />
 
         </LinearLayout>
 
-
         <TextView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_marginVertical="20dp"
-            android:textSize="25sp"
-            android:textAlignment="center"
             android:textStyle="bold"
-            android:text="Instructions"/>
+            android:textSize="18sp"
+            android:text="@string/ingredients_label"
+            style="@style/HighContrastText"
+        />
 
         <LinearLayout
-            android:id="@+id/dishDetailInstructions"
+            android:id="@+id/ingredients"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical" />
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginVertical="20dp"
+            android:textStyle="bold"
+            android:textSize="18sp"
+            android:text="@string/instructions_label"
+            style="@style/HighContrastText"
+        />
+
+        <LinearLayout
+            android:id="@+id/instructions"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
-            android:layout_marginHorizontal="10sp"/>
+        />
 
         <Button
             android:id="@+id/addDishToShoppingList"
@@ -93,6 +93,7 @@
             android:layout_margin="16dp"
             android:backgroundTint="@color/cyan"
             android:text="@string/add_ingredients_to_shopping_list"
-            android:tint="@android:color/white"/>
+            android:tint="@android:color/white"
+        />
     </LinearLayout>
 </ScrollView>
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index bc68bda..d527807 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -52,6 +52,8 @@
     <string name="directions_label">Directions</string>
     <string name="create_manually_label">Create manually</string>
     <string name="create_ai_label">Generate recipe using AI</string>
+    <string name="portions_label">Portions</string>
+    <string name="instructions_label">Instructions</string>
     <string-array name="units">
         <item></item>
         <item>g</item>

From 6e72f549cfde95b496a4023426c181af9123f36a Mon Sep 17 00:00:00 2001
From: Reimar <mail@reim.ar>
Date: Wed, 14 May 2025 08:40:36 +0200
Subject: [PATCH 10/10] Add buttons for incrementing/decrementing portion size,
 fix decimal numbers

---
 .../easyeat/ui/dishes/DishDetailsActivity.kt  | 29 ++++++++++++++-----
 .../ui/shopping_list/ShoppingListFragment.kt  |  2 +-
 .../res/drawable/ic_arrow_drop_down_24px.xml  | 10 +++++++
 .../res/drawable/ic_arrow_drop_up_24px.xml    | 10 +++++++
 .../main/res/layout/activity_dish_details.xml | 28 +++++++++++++++++-
 .../src/main/res/layout/activity_register.xml |  2 +-
 app/app/src/main/res/values/strings.xml       |  2 ++
 7 files changed, 73 insertions(+), 10 deletions(-)
 create mode 100644 app/app/src/main/res/drawable/ic_arrow_drop_down_24px.xml
 create mode 100644 app/app/src/main/res/drawable/ic_arrow_drop_up_24px.xml

diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index 518d6ab..e25238e 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
@@ -17,6 +17,7 @@ import tech.mercantec.easyeat.helpers.RecipeDetailsResponse
 import tech.mercantec.easyeat.helpers.getRecipeDetails
 import kotlin.concurrent.thread
 import android.widget.EditText
+import android.widget.ImageButton
 import android.widget.TextView
 import androidx.core.widget.doAfterTextChanged
 import tech.mercantec.easyeat.helpers.AddRecipeToShoppingList
@@ -28,7 +29,7 @@ class DishDetailsActivity : AppCompatActivity() {
         setContentView(R.layout.activity_dish_details)
 
         val ingredientsContainer = findViewById<LinearLayout>(R.id.ingredients)
-        val multiplierEditText = findViewById<EditText>(R.id.ingredientMultiplier)
+        val multiplierEditText = findViewById<EditText>(R.id.ingredient_multiplier)
 
         val dishId = intent.getIntExtra("dish_id", -1)
         if (dishId == -1) {
@@ -37,8 +38,6 @@ class DishDetailsActivity : AppCompatActivity() {
             return
         }
 
-
-
         thread {
             val recipe: RecipeDetailsResponse
             try {
@@ -74,7 +73,9 @@ class DishDetailsActivity : AppCompatActivity() {
                 for (ingredient in ingredients) {
                     val row = TextView(this)
                     val amount = (ingredient.amount ?: 0.0) * multiplier
-                    row.text = Html.fromHtml("&#8226; ${ingredient.name}: ${"%.2f".format(amount)} ${ingredient.unit ?: ""}", Html.FROM_HTML_MODE_LEGACY)
+                    val amountStr = amount.toBigDecimal().stripTrailingZeros().toPlainString()
+
+                    row.text = Html.fromHtml("&#8226; ${ingredient.name}: $amountStr ${ingredient.unit ?: ""}", Html.FROM_HTML_MODE_LEGACY)
                     row.textSize = 18f
                     row.setPadding(0, 8, 0, 8)
                     container.addView(row)
@@ -100,19 +101,33 @@ class DishDetailsActivity : AppCompatActivity() {
                     displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
                 }
 
+                findViewById<ImageButton>(R.id.increment_multiplier).setOnClickListener {
+                    multiplier++
+                    multiplierEditText.setText(multiplier.toString(), TextView.BufferType.EDITABLE)
+
+                    displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
+                }
+
+                findViewById<ImageButton>(R.id.decrement_multiplier).setOnClickListener {
+                    if (multiplier <= 1) return@setOnClickListener
+
+                    multiplier--
+                    multiplierEditText.setText(multiplier.toString(), TextView.BufferType.EDITABLE)
+
+                    displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
+                }
+
                 // You can do the same for directions if needed
             }
 
             val saveButton: Button = findViewById(R.id.addDishToShoppingList)
             saveButton.setOnClickListener {
-
-
                 val progressDialog = ProgressDialog(this)
                 progressDialog.setMessage("Loading...")
                 progressDialog.show()
                 thread {
                     try {
-                        val multiplierEditText = findViewById<EditText>(R.id.ingredientMultiplier)
+                        val multiplierEditText = findViewById<EditText>(R.id.ingredient_multiplier)
                         val multiplierText = multiplierEditText.text.toString()
                         AddRecipeToShoppingList(this, dishId, multiplierText.toIntOrNull() ?: 1)
                     } catch (e: ApiRequestException) {
diff --git a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
index 2523ed8..1ece23e 100644
--- a/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
+++ b/app/app/src/main/java/tech/mercantec/easyeat/ui/shopping_list/ShoppingListFragment.kt
@@ -222,7 +222,7 @@ class ShoppingListFragment : Fragment() {
 
         // Pre-fill dialog inputs with current item if applicable
         item?.let { item ->
-            view.findViewById<EditText>(R.id.amount).setText(item.amount?.toBigDecimal()?.stripTrailingZeros().toString(), TextView.BufferType.EDITABLE)
+            view.findViewById<EditText>(R.id.amount).setText(item.amount?.toBigDecimal()?.stripTrailingZeros()?.toPlainString(), TextView.BufferType.EDITABLE)
             view.findViewById<Spinner>(R.id.unit_selector).setSelection(adapter.getPosition(item.unit))
             view.findViewById<EditText>(R.id.name).setText(item.name, TextView.BufferType.EDITABLE)
 
diff --git a/app/app/src/main/res/drawable/ic_arrow_drop_down_24px.xml b/app/app/src/main/res/drawable/ic_arrow_drop_down_24px.xml
new file mode 100644
index 0000000..dfea22c
--- /dev/null
+++ b/app/app/src/main/res/drawable/ic_arrow_drop_down_24px.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M480,600L280,400L680,400L480,600Z"/>
+</vector>
diff --git a/app/app/src/main/res/drawable/ic_arrow_drop_up_24px.xml b/app/app/src/main/res/drawable/ic_arrow_drop_up_24px.xml
new file mode 100644
index 0000000..05735c6
--- /dev/null
+++ b/app/app/src/main/res/drawable/ic_arrow_drop_up_24px.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M280,560L480,360L680,560L280,560Z"/>
+</vector>
diff --git a/app/app/src/main/res/layout/activity_dish_details.xml b/app/app/src/main/res/layout/activity_dish_details.xml
index e50eb50..a2b134b 100644
--- a/app/app/src/main/res/layout/activity_dish_details.xml
+++ b/app/app/src/main/res/layout/activity_dish_details.xml
@@ -39,15 +39,41 @@
                 android:layout_height="match_parent"
                 android:textSize="16sp"
                 android:paddingTop="8dp"
+                android:labelFor="@id/ingredient_multiplier"
                 android:text="@string/portions_label"
             />
 
             <EditText
-                android:id="@+id/ingredientMultiplier"
+                android:id="@+id/ingredient_multiplier"
                 android:layout_marginStart="20dp"
                 android:layout_width="50dp"
                 android:layout_height="wrap_content"
+                android:importantForAutofill="no"
                 android:inputType="number"
+                android:text="1"
+            />
+
+            <ImageButton
+                android:id="@+id/decrement_multiplier"
+                android:layout_marginStart="20dp"
+                android:layout_width="32dp"
+                android:layout_height="40dp"
+                android:scaleType="fitXY"
+                android:src="@drawable/ic_arrow_drop_down_24px"
+                android:contentDescription="@string/decrement_multiplier_desc"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
+            />
+
+
+            <ImageButton
+                android:id="@+id/increment_multiplier"
+                android:layout_marginStart="5dp"
+                android:layout_width="32dp"
+                android:layout_height="40dp"
+                android:scaleType="fitXY"
+                android:src="@drawable/ic_arrow_drop_up_24px"
+                android:contentDescription="@string/increment_multiplier_desc"
+                android:background="?android:attr/selectableItemBackgroundBorderless"
             />
 
         </LinearLayout>
diff --git a/app/app/src/main/res/layout/activity_register.xml b/app/app/src/main/res/layout/activity_register.xml
index 54e8968..5b3daf1 100644
--- a/app/app/src/main/res/layout/activity_register.xml
+++ b/app/app/src/main/res/layout/activity_register.xml
@@ -52,7 +52,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/password_label"
-        />
+    />
 
     <EditText
         android:id="@+id/password"
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index d527807..32c8a1f 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -54,6 +54,8 @@
     <string name="create_ai_label">Generate recipe using AI</string>
     <string name="portions_label">Portions</string>
     <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-array name="units">
         <item></item>
         <item>g</item>