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:exported="false" />
<activity
android:name=".ui.dishes.DishDetailsActivity"
android:exported="false" />
<activity
android:name=".ui.profile.ChangePasswordActivity"
android:exported="false" />

View File

@ -1,12 +1,14 @@
package tech.mercantec.easyeat.helpers
import android.content.ClipDescription
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
import tech.mercantec.easyeat.models.Recipe
@Serializable
data class LoginRequest(val emailUsr: String, val password: String)
@ -114,17 +116,24 @@ fun changePassword(ctx: Context, oldPassword: String, newPassword: String) {
}
@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)
requestJson<CreateRecipeRequest, Boolean>(ctx, "POST", "/api/recipe/create", request)
}
@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> {
return requestJson<Unit, List<RecipeResponse>>(ctx, "GET", "/api/Recipe/getall", null)
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)
}

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
@Serializable
data class Recipe(
val id: Int,
val name: String,
val description: String,
val directions: List<String>,
@ -12,7 +14,8 @@ data class Recipe(
@Serializable
data class Ingredient(
val id: Int,
val amount: Double?,
val unit: 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.createRecipe
import tech.mercantec.easyeat.helpers.request
import tech.mercantec.easyeat.models.Direction
import tech.mercantec.easyeat.models.Ingredient
import tech.mercantec.easyeat.models.Recipe
import tech.mercantec.easyeat.models.CreateDirection
import tech.mercantec.easyeat.models.CreateIngredient
import tech.mercantec.easyeat.models.CreateRecipe
import kotlin.concurrent.thread
class CreateDishActivity : AppCompatActivity() {
@ -53,7 +53,7 @@ class CreateDishActivity : AppCompatActivity() {
.map { line -> line.trim() }
.filter { it.isNotEmpty() }
val recipe = Recipe(
val recipe = CreateRecipe(
name = findViewById<EditText>(R.id.dishName).text.toString().trim(),
description = findViewById<EditText>(R.id.dishDescription).text.toString().trim(),
directions = directions,
@ -107,8 +107,8 @@ class CreateDishActivity : AppCompatActivity() {
ingredientContainer.addView(ingredientRow)
}
private fun collectIngredients(): List<Ingredient> {
val ingredients = mutableListOf<Ingredient>()
private fun collectIngredients(): List<CreateIngredient> {
val ingredients = mutableListOf<CreateIngredient>()
for (i in 0 until ingredientContainer.childCount) {
val ingredientView = ingredientContainer.getChildAt(i)
@ -125,7 +125,7 @@ class CreateDishActivity : AppCompatActivity() {
// Optional: Only add non-empty rows
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.models.DishListItem
class DishAdapter(context: Context, dishes: List<DishListItem>) :
ArrayAdapter<DishListItem>(context, 0, dishes) {
class DishAdapter(
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 {
val dish = getItem(position)
@ -19,9 +22,14 @@ class DishAdapter(context: Context, dishes: List<DishListItem>) :
val nameTextView = view.findViewById<TextView>(R.id.dishName)
val descriptionTextView = view.findViewById<TextView>(R.id.descriptionTextView)
nameTextView.text = "Name: ${dish?.name}"
descriptionTextView.text = "Description: ${dish?.description}"
nameTextView.text = dish?.name
descriptionTextView.text = dish?.description
view.setOnClickListener {
dish?.let { onDishClick(it) }
}
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.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -12,16 +11,12 @@ import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.databinding.FragmentDishesBinding
import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.RecipeResponse
import tech.mercantec.easyeat.helpers.getRecipies
import tech.mercantec.easyeat.helpers.login
import tech.mercantec.easyeat.helpers.GetAllRecipesResponse
import tech.mercantec.easyeat.helpers.getAllRecipies
import tech.mercantec.easyeat.models.DishListItem
import tech.mercantec.easyeat.ui.MainActivity
import kotlin.concurrent.thread
class DishesFragment : Fragment() {
@ -69,11 +64,11 @@ class DishesFragment : Fragment() {
return root
}
fun DishesFragment.loadRecipes() {
fun DishesFragment.loadRecipes() {
thread {
val recipes: List<RecipeResponse>
val recipes: List<GetAllRecipesResponse>
try {
recipes = getRecipies(requireContext())
recipes = getAllRecipies(requireContext())
} catch (e: ApiRequestException) {
activity?.runOnUiThread {
Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show()
@ -86,7 +81,12 @@ class DishesFragment : Fragment() {
}
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
}
}

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

View File

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