Merge branch 'master' of git.reim.ar:ReiMerc/easyeat

This commit is contained in:
Jeas0001 2025-05-13 12:13:18 +02:00
commit c423a9e19d
15 changed files with 309 additions and 35 deletions

View File

@ -48,6 +48,10 @@
android:name=".ui.dishes.CreateDishAIActivity" android:name=".ui.dishes.CreateDishAIActivity"
android:exported="false" /> android:exported="false" />
<activity
android:name=".ui.dishes.DishDetailsActivity"
android:exported="false" />
<activity <activity
android:name=".ui.profile.ChangePasswordActivity" android:name=".ui.profile.ChangePasswordActivity"
android:exported="false" /> android:exported="false" />

View File

@ -1,12 +1,14 @@
package tech.mercantec.easyeat.helpers package tech.mercantec.easyeat.helpers
import android.content.ClipDescription
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import kotlinx.serialization.Serializable 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.Direction
import tech.mercantec.easyeat.models.Ingredient import tech.mercantec.easyeat.models.Ingredient
import tech.mercantec.easyeat.models.Recipe
@Serializable @Serializable
data class LoginRequest(val emailUsr: String, val password: String) data class LoginRequest(val emailUsr: String, val password: String)
@ -114,17 +116,24 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
} }
@Serializable @Serializable
data class CreateRecipeRequest(val name: String, val description: String, val directions: List<Direction>, val ingredients: List<Ingredient>) data class CreateRecipeRequest(val name: String, val description: String, val directions: List<CreateDirection>, val ingredients: List<CreateIngredient>)
fun createRecipe(ctx: Context, recipe: Recipe) { fun createRecipe(ctx: Context, recipe: CreateRecipe) {
val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients) val request = CreateRecipeRequest(recipe.name, recipe.description, recipe.directions, recipe.ingredients)
requestJson<CreateRecipeRequest, Boolean>(ctx, "POST", "/api/recipe/create", request) requestJson<CreateRecipeRequest, Boolean>(ctx, "POST", "/api/recipe/create", request)
} }
@Serializable @Serializable
data class RecipeResponse(val id: Int, val name: String, val description: String) data class GetAllRecipesResponse(val id: Int, val name: String, val description: String)
fun getRecipies(ctx: Context): List<RecipeResponse> { fun getAllRecipies(ctx: Context): List<GetAllRecipesResponse> {
return requestJson<Unit, List<RecipeResponse>>(ctx, "GET", "/api/Recipe/getall", null) 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)
} }

View File

@ -0,0 +1,24 @@
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
)

View File

@ -2,8 +2,10 @@ package tech.mercantec.easyeat.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class Recipe( data class Recipe(
val id: Int,
val name: String, val name: String,
val description: String, val description: String,
val directions: List<String>, val directions: List<String>,
@ -12,7 +14,8 @@ data class Recipe(
@Serializable @Serializable
data class Ingredient( data class Ingredient(
val id: Int,
val amount: Double?, val amount: Double?,
val unit: String?, val unit: String?,
val name: String val name: String
) )

View File

@ -20,9 +20,9 @@ import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.changePassword import tech.mercantec.easyeat.helpers.changePassword
import tech.mercantec.easyeat.helpers.createRecipe import tech.mercantec.easyeat.helpers.createRecipe
import tech.mercantec.easyeat.helpers.request import tech.mercantec.easyeat.helpers.request
import tech.mercantec.easyeat.models.Direction import tech.mercantec.easyeat.models.CreateDirection
import tech.mercantec.easyeat.models.Ingredient import tech.mercantec.easyeat.models.CreateIngredient
import tech.mercantec.easyeat.models.Recipe import tech.mercantec.easyeat.models.CreateRecipe
import kotlin.concurrent.thread import kotlin.concurrent.thread
class CreateDishActivity : AppCompatActivity() { class CreateDishActivity : AppCompatActivity() {
@ -53,7 +53,7 @@ class CreateDishActivity : AppCompatActivity() {
.map { line -> line.trim() } .map { line -> line.trim() }
.filter { it.isNotEmpty() } .filter { it.isNotEmpty() }
val recipe = Recipe( val recipe = CreateRecipe(
name = findViewById<EditText>(R.id.dishName).text.toString().trim(), name = findViewById<EditText>(R.id.dishName).text.toString().trim(),
description = findViewById<EditText>(R.id.dishDescription).text.toString().trim(), description = findViewById<EditText>(R.id.dishDescription).text.toString().trim(),
directions = directions, directions = directions,
@ -107,8 +107,8 @@ class CreateDishActivity : AppCompatActivity() {
ingredientContainer.addView(ingredientRow) ingredientContainer.addView(ingredientRow)
} }
private fun collectIngredients(): List<Ingredient> { private fun collectIngredients(): List<CreateIngredient> {
val ingredients = mutableListOf<Ingredient>() val ingredients = mutableListOf<CreateIngredient>()
for (i in 0 until ingredientContainer.childCount) { for (i in 0 until ingredientContainer.childCount) {
val ingredientView = ingredientContainer.getChildAt(i) val ingredientView = ingredientContainer.getChildAt(i)
@ -125,7 +125,7 @@ class CreateDishActivity : AppCompatActivity() {
// Optional: Only add non-empty rows // Optional: Only add non-empty rows
if (element.isNotEmpty() && amount.isNotEmpty()) { if (element.isNotEmpty() && amount.isNotEmpty()) {
ingredients.add(Ingredient(name = element, amount = amount.toDouble(), unit = unit)) ingredients.add(CreateIngredient(name = element, amount = amount.toDouble(), unit = unit))
} }
} }

View File

@ -9,8 +9,11 @@ import android.widget.TextView
import tech.mercantec.easyeat.R import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.models.DishListItem import tech.mercantec.easyeat.models.DishListItem
class DishAdapter(context: Context, dishes: List<DishListItem>) : class DishAdapter(
ArrayAdapter<DishListItem>(context, 0, dishes) { context: Context,
private val dishes: List<DishListItem>,
private val onDishClick: (DishListItem) -> Unit
) : ArrayAdapter<DishListItem>(context, 0, dishes) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val dish = getItem(position) val dish = getItem(position)
@ -19,9 +22,14 @@ class DishAdapter(context: Context, dishes: List<DishListItem>) :
val nameTextView = view.findViewById<TextView>(R.id.dishName) val nameTextView = view.findViewById<TextView>(R.id.dishName)
val descriptionTextView = view.findViewById<TextView>(R.id.descriptionTextView) val descriptionTextView = view.findViewById<TextView>(R.id.descriptionTextView)
nameTextView.text = "Name: ${dish?.name}" nameTextView.text = dish?.name
descriptionTextView.text = "Description: ${dish?.description}" descriptionTextView.text = dish?.description
view.setOnClickListener {
dish?.let { onDishClick(it) }
}
return view return view
} }
} }

View File

@ -0,0 +1,54 @@
package tech.mercantec.easyeat.ui.dishes
import android.os.Bundle
import android.util.Log
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.RecipeDetailsResponse
import tech.mercantec.easyeat.helpers.getRecipeDetails
import kotlin.concurrent.thread
import android.widget.ListView
import android.widget.TextView
class DishDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dish_details)
val dishId = intent.getIntExtra("dish_id", -1)
if (dishId == -1) {
Toast.makeText(this, "No dish ID provided", Toast.LENGTH_SHORT).show()
finish()
return
}
thread {
val recipe: RecipeDetailsResponse
try {
recipe = getRecipeDetails(this, dishId)
} catch (e: ApiRequestException) {
runOnUiThread {
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
}
return@thread
}
Log.i("DISH", recipe.ingredients.toString())
runOnUiThread {
// Set title and description
findViewById<TextView>(R.id.dishDetailName).text = recipe.name
findViewById<TextView>(R.id.dishDetailDescription).text = recipe.description
// 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
}
}
}
}

View File

@ -3,7 +3,6 @@ package tech.mercantec.easyeat.ui.dishes
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -12,16 +11,12 @@ import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import tech.mercantec.easyeat.R import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.databinding.FragmentDishesBinding import tech.mercantec.easyeat.databinding.FragmentDishesBinding
import tech.mercantec.easyeat.helpers.ApiRequestException import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.RecipeResponse import tech.mercantec.easyeat.helpers.GetAllRecipesResponse
import tech.mercantec.easyeat.helpers.getRecipies import tech.mercantec.easyeat.helpers.getAllRecipies
import tech.mercantec.easyeat.helpers.login
import tech.mercantec.easyeat.models.DishListItem import tech.mercantec.easyeat.models.DishListItem
import tech.mercantec.easyeat.ui.MainActivity
import kotlin.concurrent.thread import kotlin.concurrent.thread
class DishesFragment : Fragment() { class DishesFragment : Fragment() {
@ -69,11 +64,11 @@ class DishesFragment : Fragment() {
return root return root
} }
fun DishesFragment.loadRecipes() { fun DishesFragment.loadRecipes() {
thread { thread {
val recipes: List<RecipeResponse> val recipes: List<GetAllRecipesResponse>
try { try {
recipes = getRecipies(requireContext()) recipes = getAllRecipies(requireContext())
} catch (e: ApiRequestException) { } catch (e: ApiRequestException) {
activity?.runOnUiThread { activity?.runOnUiThread {
Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show() Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show()
@ -86,7 +81,12 @@ class DishesFragment : Fragment() {
} }
activity?.runOnUiThread { activity?.runOnUiThread {
val adapter = DishAdapter(requireContext(), dishes) val adapter = DishAdapter(requireContext(), dishes) { selectedDish ->
// Open details activity
val intent = Intent(requireContext(), DishDetailsActivity::class.java)
intent.putExtra("dish_id", selectedDish.id)
startActivity(intent)
}
binding.dishesList.adapter = adapter binding.dishesList.adapter = adapter
} }
} }

View File

@ -0,0 +1,30 @@
package tech.mercantec.easyeat.ui.dishes
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.TextView
import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.models.Ingredient
class IngredientAdapter(context: Context, ingredients: List<Ingredient>)
: ArrayAdapter<Ingredient>(context, 0, ingredients) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val ingredient = getItem(position)
val view = convertView ?: LayoutInflater.from(context)
.inflate(R.layout.activity_dish_details_ingredient_list_item, parent, false)
val nameView = view.findViewById<TextView>(R.id.ingredientName)
val amountView = view.findViewById<TextView>(R.id.ingredientAmount)
val unitView = view.findViewById<TextView>(R.id.ingredientUnit)
nameView.text = ingredient?.name ?: ""
amountView.text = ingredient?.amount?.toString() ?: "-"
unitView.text = ingredient?.unit ?: "-"
return view
}
}

View File

@ -0,0 +1,26 @@
package tech.mercantec.easyeat.ui.dishes
import android.content.Context
import android.view.LayoutInflater
import android.view.View
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) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val ingredient = 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 ?: ""
return view
}
}

View File

@ -15,7 +15,9 @@
android:text="@string/general" android:text="@string/general"
android:textAlignment="center" android:textAlignment="center"
android:textSize="24sp" android:textSize="24sp"
android:layout_marginTop="20dp"/> android:layout_marginTop="20dp"
android:textStyle="bold"
/>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -44,7 +46,9 @@
android:text="@string/ingredients" android:text="@string/ingredients"
android:textAlignment="center" android:textAlignment="center"
android:textSize="24sp" android:textSize="24sp"
android:layout_marginTop="20dp"/> android:layout_marginTop="20dp"
android:textStyle="bold"
/>
<LinearLayout <LinearLayout
android:id="@+id/ingredientContainer" android:id="@+id/ingredientContainer"
@ -65,7 +69,9 @@
android:text="@string/Instructions" android:text="@string/Instructions"
android:textAlignment="center" android:textAlignment="center"
android:textSize="24sp" android:textSize="24sp"
android:layout_marginTop="20dp"/> android:layout_marginTop="20dp"
android:textStyle="bold"
/>
<EditText <EditText
android:id="@+id/instructions" android:id="@+id/instructions"

View File

@ -43,8 +43,7 @@
<EditText <EditText
android:id="@+id/ingredientAmountEditText" android:id="@+id/ingredientAmountEditText"
android:layout_width="173dp" android:layout_width="173dp"
android:layout_height="48dp" android:layout_height="48dp" />
android:hint="0" />
</LinearLayout> </LinearLayout>
<!-- Measurement field --> <!-- Measurement field -->

View File

@ -0,0 +1,58 @@
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
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" />
<TextView
android:id="@+id/dishDetailDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textAlignment="center" />
<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"/>
<ListView
android:id="@+id/dishDetailIngredients"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<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"/>
<ListView
android:id="@+id/dishDetailInstructions"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
</ScrollView>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/ingredientName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Name"
android:textSize="20sp"
/>
<TextView
android:id="@+id/ingredientAmount"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Amount"
android:textSize="20sp"
/>
<TextView
android:id="@+id/ingredientUnit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Unit"
android:textSize="20sp"
/>
</LinearLayout>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/instructionText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
/>
</LinearLayout>