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" />
(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 +27,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")
@@ -116,24 +113,10 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
}
@Serializable
-data class CreateRecipeRequest(val name: String, val description: String, val directions: List, val ingredients: List)
+data class ShoppingListAddRecipeRequest(val id: Int, val multiplier: Int)
-fun createRecipe(ctx: Context, recipe: CreateRecipe) {
- val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients)
+fun AddRecipeToShoppingList(ctx: Context, id: Int, multiplier: Int) {
+ val request = ShoppingListAddRecipeRequest(id, multiplier)
- requestJson(ctx, "POST", "/api/recipe/create", request)
-}
-
-@Serializable
-data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
-
-fun getAllRecipies(ctx: Context): List {
- return requestJson>(ctx, "GET", "/api/Recipe/getall", null)
-}
-
-@Serializable
-data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List, val ingredients: List)
-
-fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
- return requestJson(ctx, "GET", "/api/Recipe/get/$id", null)
+ return requestJson(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 e0aa866..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
@@ -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,22 @@ data class GenerateRecipeRequest(val dish: String, val language: String, val num
fun generateRecipeWithAI(ctx: Context, title: String, language: String): Recipe {
return requestJson(ctx, "POST", "/api/Recipe/chatbot", GenerateRecipeRequest(title, language, 1, arrayOf()))
}
+
+fun createRecipe(ctx: Context, recipe: Recipe) {
+ requestJson(ctx, "POST", "/api/recipe/create", recipe)
+}
+
+@Serializable
+data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
+
+fun getAllRecipes(ctx: Context): List {
+ return requestJson>(ctx, "GET", "/api/Recipe/getall", null)
+}
+
+@Serializable
+data class RecipeDetailsResponse(val id: Int, val name: String, val description: String, val directions: List, val ingredients: List)
+
+fun getRecipeDetails(ctx: Context, id: Int): RecipeDetailsResponse {
+ return requestJson(ctx, "GET", "/api/Recipe/get/$id", null)
+}
+
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 {
return requestJson>(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(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(ctx, "POST", "/api/ShoppingList/add", request)
+fun editShoppingItem(ctx: Context, old: ShoppingListItem, new: ShoppingListItem) {
+ requestJson(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/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,
- val ingredients: List
-)
-
-@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/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/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,
@@ -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(R.id.dishName).text.toString().trim(),
description = findViewById(R.id.dishDescription).text.toString().trim(),
directions = directions,
@@ -107,8 +101,8 @@ class CreateDishActivity : AppCompatActivity() {
ingredientContainer.addView(ingredientRow)
}
- private fun collectIngredients(): List {
- val ingredients = mutableListOf()
+ private fun collectIngredients(): List {
+ val ingredients = mutableListOf()
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/DishDetailsActivity.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishDetailsActivity.kt
index 3f41774..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
@@ -1,7 +1,14 @@
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
import androidx.appcompat.app.AppCompatActivity
import tech.mercantec.easyeat.R
@@ -9,14 +16,21 @@ 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.ImageButton
import android.widget.TextView
+import androidx.core.widget.doAfterTextChanged
+import tech.mercantec.easyeat.helpers.AddRecipeToShoppingList
+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(R.id.ingredients)
+ val multiplierEditText = findViewById(R.id.ingredient_multiplier)
+
val dishId = intent.getIntExtra("dish_id", -1)
if (dishId == -1) {
Toast.makeText(this, "No dish ID provided", Toast.LENGTH_SHORT).show()
@@ -35,20 +49,108 @@ class DishDetailsActivity : AppCompatActivity() {
return@thread
}
Log.i("DISH", recipe.ingredients.toString())
+ val instructionsLayout = findViewById(R.id.instructions)
+
+// Example data: recipe.ingredients and recipe.directions
runOnUiThread {
- // Set title and description
findViewById(R.id.dishDetailName).text = recipe.name
findViewById(R.id.dishDetailDescription).text = recipe.description
- // Set up the ingredient list
- val ingredientListView = findViewById(R.id.dishDetailIngredients)
- val ingredientAdapter = IngredientAdapter(this, recipe.ingredients)
- ingredientListView.adapter = ingredientAdapter
-
- val instructionsListView = findViewById(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
+ setPadding(0, 8, 0, 8)
+ }
+ instructionsLayout.addView(textView)
+ }
}
+
+ fun displayIngredients(ingredients: List, multiplier: Int, container: LinearLayout) {
+ container.removeAllViews() // clear previous views
+
+ for (ingredient in ingredients) {
+ val row = TextView(this)
+ val amount = (ingredient.amount ?: 0.0) * multiplier
+ val amountStr = amount.toBigDecimal().stripTrailingZeros().toPlainString()
+
+ row.text = Html.fromHtml("• ${ingredient.name}: $amountStr ${ingredient.unit ?: ""}", Html.FROM_HTML_MODE_LEGACY)
+ row.textSize = 18f
+ row.setPadding(0, 8, 0, 8)
+ container.addView(row)
+ }
+ }
+
+ runOnUiThread {
+ val nameView = findViewById(R.id.dishDetailName)
+ val descView = findViewById(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)
+ }
+
+ findViewById(R.id.increment_multiplier).setOnClickListener {
+ multiplier++
+ multiplierEditText.setText(multiplier.toString(), TextView.BufferType.EDITABLE)
+
+ displayIngredients(recipe.ingredients, multiplier, ingredientsContainer)
+ }
+
+ findViewById(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(R.id.ingredient_multiplier)
+ val multiplierText = multiplierEditText.text.toString()
+ AddRecipeToShoppingList(this, dishId, multiplierText.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/DishesFragment.kt b/app/app/src/main/java/tech/mercantec/easyeat/ui/dishes/DishesFragment.kt
index 4e1a301..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
@@ -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
@@ -15,8 +15,9 @@ 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 tech.mercantec.easyeat.models.Recipe
import kotlin.concurrent.thread
class DishesFragment : Fragment() {
@@ -36,28 +37,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
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..a2b134b 100644
--- a/app/app/src/main/res/layout/activity_dish_details.xml
+++ b/app/app/src/main/res/layout/activity_dish_details.xml
@@ -1,58 +1,125 @@
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ android:padding="30sp"
+ android:orientation="vertical">
+
+ android:textStyle="bold"
+ style="@style/HighContrastText"
+ />
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:textSize="18sp"
+ android:text="@string/ingredients_label"
+ style="@style/HighContrastText"
+ />
-
+ android:orientation="vertical" />
+
+
+
+
+
+
-
\ No newline at end of file
+
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
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"
- />
+ />
-
-
-
-
-
-
-
-
-
-
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/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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 @@
+
+
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 @@
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 @@
+
+
+
+
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 @@
- @color/dark_cyan
- ?attr/colorPrimaryVariant
- @color/black
+ - @color/black
diff --git a/app/app/src/main/res/values/strings.xml b/app/app/src/main/res/values/strings.xml
index e7d5584..32c8a1f 100644
--- a/app/app/src/main/res/values/strings.xml
+++ b/app/app/src/main/res/values/strings.xml
@@ -32,6 +32,7 @@
Instructions
Cancel
Add shopping item
+ Edit shopping item
Amount
500
Name
@@ -40,13 +41,21 @@
Log out
Checked
Delete
+ Edit
Your shopping list is empty
- Search For Dishes
- Manually
Create Dish
Generate recipe with AI
Name of dish
Generate
+ Add ingredients to Shopping List
+ Ingredients
+ Directions
+ Create manually
+ Generate recipe using AI
+ Portions
+ Instructions
+ Increment portion count
+ Decrement portion size
- g
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 @@
+
+
+
+