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

This commit is contained in:
LilleBRG 2025-05-08 12:12:04 +02:00
commit 80e52cd22b
22 changed files with 411 additions and 122 deletions

View File

@ -102,6 +102,6 @@ inline fun <reified Req, reified Res> requestJson(ctx: Context, method: String,
Log.e("EasyEat", e.message!!) Log.e("EasyEat", e.message!!)
Log.e("EasyEat", response.body) Log.e("EasyEat", response.body)
throw ApiRequestException("Failed to parse response: $response", e) throw ApiRequestException("Failed to parse response: ${response.body}", e)
} }
} }

View File

@ -2,9 +2,7 @@ package tech.mercantec.easyeat.helpers
import android.content.Context import android.content.Context
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import tech.mercantec.easyeat.models.ShoppingListItem
@Serializable
data class ShoppingListItem(val id: Int, val name: String, val amount: Double?, val unit: String?, val checked: Boolean)
fun getShoppingList(ctx: Context): Array<ShoppingListItem> { fun getShoppingList(ctx: Context): Array<ShoppingListItem> {
return requestJson<Unit, Array<ShoppingListItem>>(ctx, "GET", "/api/ShoppingList/get", null) return requestJson<Unit, Array<ShoppingListItem>>(ctx, "GET", "/api/ShoppingList/get", null)
@ -13,8 +11,16 @@ fun getShoppingList(ctx: Context): Array<ShoppingListItem> {
@Serializable @Serializable
data class AddShoppingItemRequest(val name: String, val amount: Double?, val unit: String?, val checked: Boolean) data class AddShoppingItemRequest(val name: String, val amount: Double?, val unit: String?, val checked: Boolean)
fun addShoppingItem(ctx: Context, name: String, amount: Double?, unit: String?) { fun addShoppingItem(ctx: Context, name: String, amount: Double?, unit: String?): ShoppingListItem {
val request = AddShoppingItemRequest(name, amount, unit, false) val request = AddShoppingItemRequest(name, amount, unit, false)
requestJson<AddShoppingItemRequest, Boolean>(ctx, "POST", "/api/ShoppingList/add", request) return requestJson<AddShoppingItemRequest, ShoppingListItem>(ctx, "POST", "/api/ShoppingList/add", request)
}
fun toggleShoppingItemChecked(ctx: Context, item: ShoppingListItem) {
requestJson<Unit, Boolean>(ctx, "PUT", "/api/ShoppingList/check?itemId=${item.id}", null)
}
fun deleteShoppingItem(ctx: Context, item: ShoppingListItem) {
requestJson<Unit, Boolean>(ctx, "DELETE", "/api/ShoppingList/delete?itemId=${item.id}", null)
} }

View File

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

View File

@ -0,0 +1,60 @@
package tech.mercantec.easyeat.ui.shopping_list
import android.content.Context
import android.graphics.Paint
import android.icu.text.DecimalFormat
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.models.ShoppingListItem
class ShoppingItemAdapter(context: Context, items: ArrayList<ShoppingListItem>)
: ArrayAdapter<ShoppingListItem>(context, R.layout.shopping_list_item, items) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val item = getItem(position)
val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.shopping_list_item, parent, false)
item?.let { item ->
val checkmarkView = view.findViewById<ImageView>(R.id.checkmark)
val amountView = view.findViewById<TextView>(R.id.amount)
val unitView = view.findViewById<TextView>(R.id.unit)
val nameView = view.findViewById<TextView>(R.id.name)
val textViews = listOf(amountView, unitView, nameView)
amountView.text = DecimalFormat("#.##").format(item.amount)
unitView.text = item.unit
nameView.text = item.name
if (item.checked) {
textViews.forEach {
it.paintFlags = it.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
val color = TypedValue()
context.theme.resolveAttribute(R.attr.colorDisabled, color, true)
it.setTextColor(ContextCompat.getColor(context, color.resourceId))
checkmarkView.visibility = View.VISIBLE
}
} else {
textViews.forEach {
it.paintFlags = it.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
val color = TypedValue()
context.theme.resolveAttribute(android.R.attr.textColorSecondary, color, true)
it.setTextColor(ContextCompat.getColor(context, color.resourceId))
checkmarkView.visibility = View.INVISIBLE
}
}
}
return view
}
}

View File

@ -1,13 +1,13 @@
package tech.mercantec.easyeat.ui.shopping_list package tech.mercantec.easyeat.ui.shopping_list
import android.app.AlertDialog import android.app.AlertDialog
import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.EditText import android.widget.EditText
import android.widget.PopupMenu
import android.widget.Spinner import android.widget.Spinner
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -15,24 +15,106 @@ import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.databinding.FragmentShoppingListBinding import tech.mercantec.easyeat.databinding.FragmentShoppingListBinding
import tech.mercantec.easyeat.helpers.ApiRequestException import tech.mercantec.easyeat.helpers.ApiRequestException
import tech.mercantec.easyeat.helpers.addShoppingItem import tech.mercantec.easyeat.helpers.addShoppingItem
import tech.mercantec.easyeat.helpers.deleteShoppingItem
import tech.mercantec.easyeat.helpers.getShoppingList
import tech.mercantec.easyeat.helpers.toggleShoppingItemChecked
import tech.mercantec.easyeat.models.ShoppingListItem
import java.util.ArrayList
import kotlin.concurrent.thread import kotlin.concurrent.thread
class ShoppingListFragment : Fragment() { class ShoppingListFragment : Fragment() {
private var _binding: FragmentShoppingListBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = FragmentShoppingListBinding.inflate(inflater, container, false) val binding = FragmentShoppingListBinding.inflate(inflater, container, false)
val root: View = binding.root
binding.shoppingList.visibility = View.GONE
binding.emptyShoppingList.visibility = View.GONE
binding.addToShoppingList.visibility = View.GONE
binding.loading.visibility = View.VISIBLE
// Fetch shopping list items
thread {
val items: Array<ShoppingListItem>
try {
items = getShoppingList(requireContext())
} catch (e: ApiRequestException) {
activity?.runOnUiThread {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
binding.loading.visibility = View.GONE
}
return@thread
}
activity?.runOnUiThread {
binding.shoppingList.visibility = View.VISIBLE
binding.emptyShoppingList.visibility = View.VISIBLE
binding.addToShoppingList.visibility = View.VISIBLE
binding.loading.visibility = View.GONE
binding.shoppingList.emptyView = binding.emptyShoppingList
binding.shoppingList.adapter = ShoppingItemAdapter(requireContext(), ArrayList(items.toMutableList()))
}
}
// Check / uncheck when clicking shopping item
binding.shoppingList.setOnItemClickListener { parent, view, position, id ->
val item = parent.getItemAtPosition(position) as ShoppingListItem
item.checked = !item.checked
thread {
try {
toggleShoppingItemChecked(requireContext(), item)
} catch (e: ApiRequestException) {
Toast.makeText(requireContext(), e.message, Toast.LENGTH_LONG).show()
}
}
val adapter = parent.adapter as ShoppingItemAdapter
adapter.remove(item)
adapter.insert(item, position)
}
// Show context menu when long clicking shopping item
binding.shoppingList.setOnItemLongClickListener { parent, view, position, id ->
val item = parent.getItemAtPosition(position) as ShoppingListItem
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 -> {
(parent.adapter as ShoppingItemAdapter).remove(item)
thread {
try {
deleteShoppingItem(requireContext(), item)
} catch (e: ApiRequestException) {
activity?.runOnUiThread {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
}
}
}
true
}
else -> false
}
}
show()
}
return@setOnItemLongClickListener true
}
// Show new item dialog when clicking add
binding.addToShoppingList.setOnClickListener { binding.addToShoppingList.setOnClickListener {
val view = requireActivity().layoutInflater.inflate(R.layout.dialog_add_to_shopping_list, null) val view = requireActivity().layoutInflater.inflate(R.layout.dialog_add_to_shopping_list, null)
@ -49,17 +131,35 @@ class ShoppingListFragment : Fragment() {
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false
thread { thread {
val item: ShoppingListItem
try { try {
addShoppingItem(requireContext(), name, amount, unit) item = addShoppingItem(requireContext(), name, amount, unit)
} catch (e: ApiRequestException) { } catch (e: ApiRequestException) {
activity?.runOnUiThread { activity?.runOnUiThread {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
} }
return@thread
} finally { } finally {
activity?.runOnUiThread { activity?.runOnUiThread {
dialog.dismiss() dialog.dismiss()
} }
} }
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)
}
} }
} }
.setNegativeButton(R.string.cancel_label) { dialog, _ -> .setNegativeButton(R.string.cancel_label) { dialog, _ ->
@ -75,11 +175,6 @@ class ShoppingListFragment : Fragment() {
dialog.findViewById<Spinner>(R.id.unit_selector).adapter = adapter dialog.findViewById<Spinner>(R.id.unit_selector).adapter = adapter
} }
return root return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
} }
} }

View File

@ -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="M382,720L154,492L211,435L382,606L749,239L806,296L382,720Z"/>
</vector>

View File

@ -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,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>

View File

@ -2,11 +2,9 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container" android:id="@+id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:paddingTop="?attr/actionBarSize">
<fragment <fragment
android:id="@+id/nav_host_fragment_activity_main" android:id="@+id/nav_host_fragment_activity_main"

View File

@ -1,10 +1,19 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
android:indeterminate="true"
/>
<ListView <ListView
android:id="@+id/shopping_list" android:id="@+id/shopping_list"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -13,15 +22,24 @@
android:dividerHeight="1dp" android:dividerHeight="1dp"
/> />
<TextView
android:id="@+id/empty_shopping_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/empty_shopping_list"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_to_shopping_list" android:id="@+id/add_to_shopping_list"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_margin="16dp" android:layout_margin="16dp"
android:backgroundTint="@color/cyan" android:backgroundTint="@color/cyan"
app:srcCompat="@android:drawable/ic_input_add" app:srcCompat="@android:drawable/ic_input_add"
app:tint="@android:color/white" app:tint="@android:color/white"
/> />
</FrameLayout> </RelativeLayout>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:padding="12dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/checkmark"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/ic_check_24px"
app:tint="@color/green"
android:contentDescription="@string/checked_desc"
/>
<TextView
android:id="@+id/amount"
android:layout_width="70dp"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textAlignment="textEnd"
android:textStyle="bold"
/>
<TextView
android:id="@+id/unit"
android:layout_marginStart="3dp"
android:layout_width="70dp"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/name"
android:layout_marginStart="3dp"
android:textSize="24sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/remove_shopping_item"
android:icon="@drawable/ic_delete_24px"
android:title="@string/delete_label"
/>
</menu>

View File

@ -4,6 +4,7 @@
<item name="colorPrimaryVariant">@color/dark_cyan</item> <item name="colorPrimaryVariant">@color/dark_cyan</item>
<item name="colorOnPrimary">@color/white</item> <item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/dark_gray</item> <item name="colorSecondary">@color/dark_gray</item>
<item name="colorDisabled">@color/dark_gray</item>
<item name="colorSurface">@color/dark_cyan</item> <item name="colorSurface">@color/dark_cyan</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:colorBackground">@color/black</item> <item name="android:colorBackground">@color/black</item>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="EasyEat">
<attr name="colorDisabled" format="color" />
</declare-styleable>
</resources>

View File

@ -7,4 +7,5 @@
<color name="black">#FF242424</color> <color name="black">#FF242424</color>
<color name="white">#FFF9F9F9</color> <color name="white">#FFF9F9F9</color>
<color name="red">#D62D2D </color> <color name="red">#D62D2D </color>
<color name="green">#4CAF50</color>
</resources> </resources>

View File

@ -38,6 +38,9 @@
<string name="ingredient_name_hint">Beef</string> <string name="ingredient_name_hint">Beef</string>
<string name="change_password_label">Change password</string> <string name="change_password_label">Change password</string>
<string name="logout_label">Log out</string> <string name="logout_label">Log out</string>
<string name="checked_desc">Checked</string>
<string name="delete_label">Delete</string>
<string name="empty_shopping_list">Your shopping list is empty</string>
<string-array name="units"> <string-array name="units">
<item></item> <item></item>
<item>g</item> <item>g</item>

View File

@ -4,6 +4,7 @@
<item name="colorPrimaryVariant">@color/dark_cyan</item> <item name="colorPrimaryVariant">@color/dark_cyan</item>
<item name="colorOnPrimary">@color/white</item> <item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/dark_gray</item> <item name="colorSecondary">@color/dark_gray</item>
<item name="colorDisabled">@color/gray</item>
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="android:colorBackground">@color/white</item> <item name="android:colorBackground">@color/white</item>
</style> </style>

View File

@ -28,63 +28,32 @@ namespace API.BusinessLogic
{ {
var user = await _dbAccess.ReadShoppingList(userId); var user = await _dbAccess.ReadShoppingList(userId);
List<ShoppingList> shoppingList = user.ShoppingList; List<ShoppingListItem> shoppingList = user.ShoppingList;
if (shoppingList.Any(s => s.Name == listItemDTO.Name)) if (shoppingList.Any(s => s.Name == listItemDTO.Name))
{ {
ShoppingList item = shoppingList.Where(s => s.Name == listItemDTO.Name).FirstOrDefault(); ShoppingListItem item = shoppingList.Where(s => s.Name == listItemDTO.Name).FirstOrDefault();
shoppingList.Remove(item); shoppingList.Remove(item);
if (item.Unit == listItemDTO.Unit) user.ShoppingList.Add(await UnitAdjustmentSameName(listItemDTO, item));
{
item.Amount += listItemDTO.Amount;
}
else if (item.Unit == "g" && listItemDTO.Unit == "kg")
{
item.Amount = (item.Amount / 1000) + listItemDTO.Amount;
item.Unit = "kg";
}
else if (item.Unit == "ml" && listItemDTO.Unit == "l")
{
item.Amount = (item.Amount / 1000) + listItemDTO.Amount;
item.Unit = "l";
}
else if (item.Unit == "dl" && listItemDTO.Unit == "l")
{
item.Amount = (item.Amount / 10) + listItemDTO.Amount;
item.Unit = "l";
}
item.Checked = false;
if (item.Unit == "g" && item.Amount >= 1000)
{
item.Unit = "kg";
item.Amount = item.Amount / 1000;
}
else if (item.Unit == "ml" && item.Amount >= 1000)
{
item.Unit = "l";
item.Amount = item.Amount / 1000;
}
else if (item.Unit == "dl" && item.Amount >= 10)
{
item.Unit = "l";
item.Amount = item.Amount / 10;
}
user.ShoppingList.Add(item);
} }
else else
{ {
ShoppingList newItem = new ShoppingList(); ShoppingListItem newItem = new ShoppingListItem();
newItem.Name = listItemDTO.Name; newItem.Name = listItemDTO.Name;
newItem.Amount = listItemDTO.Amount; newItem.Amount = listItemDTO.Amount;
newItem.Unit = listItemDTO.Unit; newItem.Unit = listItemDTO.Unit;
newItem.Checked = false; newItem.Checked = false;
user.ShoppingList.Add(newItem); user.ShoppingList.Add(await UnitAdjustment(newItem));
} }
return await _dbAccess.UpdateShoppingList(user); bool succes = await _dbAccess.AddItemToShoppingList(user);
var updatedShoppingList = await _dbAccess.ReadShoppingList(userId);
if (succes) { return new OkObjectResult(updatedShoppingList.ShoppingList.Where(s => s.Name == listItemDTO.Name).First()); }
return new ConflictObjectResult(new { message = "Could not save to database" });
} }
// Gets the shoppinglist and tries to find the item and when it does it checks/unchecks that item // Gets the shoppinglist and tries to find the item and when it does it checks/unchecks that item
@ -134,11 +103,11 @@ namespace API.BusinessLogic
{ {
var user = await _dbAccess.ReadShoppingList(userId); var user = await _dbAccess.ReadShoppingList(userId);
int itemIndex = user.ShoppingList.FindIndex(x => x.Id == itemId); var item = user.ShoppingList.Where(x => x.Id == itemId).FirstOrDefault();
user.ShoppingList.RemoveAt(itemIndex); if (item == null) { return new ConflictObjectResult(new { message = "Could not find item" }); }
return await _dbAccess.UpdateShoppingList(user); return await _dbAccess.DeleteItemFromShoppinglist(item);
} }
// Adds an entire recipes ingredients to the shoppinglist // Adds an entire recipes ingredients to the shoppinglist
@ -150,66 +119,96 @@ namespace API.BusinessLogic
foreach (var ingredient in ingredients) foreach (var ingredient in ingredients)
{ {
List<ShoppingList> shoppingList = user.ShoppingList; List<ShoppingListItem> shoppingList = user.ShoppingList;
if (shoppingList.Any(s => s.Name == ingredient.Name)) if (shoppingList.Any(s => s.Name == ingredient.Name))
{ {
ShoppingList item = shoppingList.Where(s => s.Name == ingredient.Name).FirstOrDefault(); ShoppingListItem item = shoppingList.Where(s => s.Name == ingredient.Name).FirstOrDefault();
shoppingList.Remove(item); shoppingList.Remove(item);
if (item.Unit == ingredient.Unit) ShoppingListItemDTO listItemDTO = new ShoppingListItemDTO();
{ listItemDTO.Name = ingredient.Name;
item.Amount += ingredient.Amount; listItemDTO.Amount = ingredient.Amount;
} listItemDTO.Unit = ingredient.Unit;
else if (item.Unit == "g" && ingredient.Unit == "kg") listItemDTO.Checked = false;
{
item.Amount = (item.Amount / 1000) + ingredient.Amount;
item.Unit = "kg";
}
else if (item.Unit == "ml" && item.Unit == "l")
{
item.Amount = (item.Amount / 1000) + ingredient.Amount;
item.Unit = "l";
}
else if (item.Unit == "dl" && item.Unit == "l")
{
item.Amount = (item.Amount / 10) + ingredient.Amount;
item.Unit = "l";
}
item.Checked = false; user.ShoppingList.Add(await UnitAdjustmentSameName(listItemDTO, item));
if (item.Unit == "g" && item.Amount >= 1000)
{
item.Unit = "kg";
item.Amount = item.Amount / 1000;
}
else if (item.Unit == "ml" && item.Amount >= 1000)
{
item.Unit = "l";
item.Amount = item.Amount / 1000;
}
else if (item.Unit == "dl" && item.Amount >= 10)
{
item.Unit = "l";
item.Amount = item.Amount / 10;
}
user.ShoppingList.Add(item);
} }
else else
{ {
ShoppingList newItem = new ShoppingList(); ShoppingListItem newItem = new ShoppingListItem();
newItem.Name = ingredient.Name; newItem.Name = ingredient.Name;
newItem.Amount = ingredient.Amount; newItem.Amount = ingredient.Amount;
newItem.Unit = ingredient.Unit; newItem.Unit = ingredient.Unit;
newItem.Checked = false; newItem.Checked = false;
user.ShoppingList.Add(newItem); user.ShoppingList.Add(await UnitAdjustment(newItem));
} }
} }
return await _dbAccess.UpdateShoppingList(user); return await _dbAccess.UpdateShoppingList(user);
} }
public async Task<ShoppingListItem> UnitAdjustmentSameName(ShoppingListItemDTO listItemDTO, ShoppingListItem listItem)
{
if (listItem.Unit == listItemDTO.Unit)
{
listItem.Amount += listItemDTO.Amount;
}
else if (listItem.Unit == "g" && listItemDTO.Unit == "kg")
{
listItem.Amount = (listItem.Amount / 1000) + listItemDTO.Amount;
listItem.Unit = "kg";
}
else if (listItem.Unit == "kg" && listItemDTO.Unit == "g")
{
listItem.Amount = (listItemDTO.Amount / 1000) + listItem.Amount;
listItem.Unit = "kg";
}
else if (listItem.Unit == "ml" && listItemDTO.Unit == "l")
{
listItem.Amount = (listItem.Amount / 1000) + listItemDTO.Amount;
listItem.Unit = "l";
}
else if (listItem.Unit == "l" && listItemDTO.Unit == "ml")
{
listItem.Amount = (listItemDTO.Amount / 1000) + listItem.Amount;
listItem.Unit = "l";
}
else if (listItem.Unit == "dl" && listItemDTO.Unit == "l")
{
listItem.Amount = (listItem.Amount / 10) + listItemDTO.Amount;
listItem.Unit = "l";
}
else if (listItem.Unit == "l" && listItemDTO.Unit == "dl")
{
listItem.Amount = (listItemDTO.Amount / 10) + listItem.Amount;
listItem.Unit = "l";
}
listItem.Checked = false;
return await UnitAdjustment(listItem);
}
public async Task<ShoppingListItem> UnitAdjustment(ShoppingListItem listItem)
{
if (listItem.Unit == "g" && listItem.Amount >= 1000)
{
listItem.Unit = "kg";
listItem.Amount = listItem.Amount / 1000;
}
else if (listItem.Unit == "ml" && listItem.Amount >= 1000)
{
listItem.Unit = "l";
listItem.Amount = listItem.Amount / 1000;
}
else if (listItem.Unit == "dl" && listItem.Amount >= 10)
{
listItem.Unit = "l";
listItem.Amount = listItem.Amount / 10;
}
return listItem;
}
} }
} }

View File

@ -67,7 +67,7 @@ namespace API.BusinessLogic
Password = hashedPassword, Password = hashedPassword,
Salt = salt, Salt = salt,
Recipes = new List<Recipe>(), Recipes = new List<Recipe>(),
ShoppingList = new List<ShoppingList>(), ShoppingList = new List<ShoppingListItem>(),
}; };
return await _dbAccess.CreateUser(user); return await _dbAccess.CreateUser(user);

View File

@ -11,7 +11,7 @@ namespace API.DBAccess
public DbSet<Recipe> Recipes { get; set; } public DbSet<Recipe> Recipes { get; set; }
public DbSet<ShoppingList> ShoppingList { get; set; } public DbSet<ShoppingListItem> ShoppingList { get; set; }
public DBContext(DbContextOptions<DBContext> options) : base(options) { } public DBContext(DbContextOptions<DBContext> options) : base(options) { }
} }

View File

@ -34,5 +34,27 @@ namespace API.DBAccess
return new ConflictObjectResult(new { message = "Could not save to database" }); return new ConflictObjectResult(new { message = "Could not save to database" });
} }
// Adds an item to the shoppinglist
public async Task<bool> AddItemToShoppingList(User user)
{
_context.Entry(user).State = EntityState.Modified;
bool saved = await _context.SaveChangesAsync() >= 1;
if (saved) { return true; }
return false;
}
public async Task<IActionResult> DeleteItemFromShoppinglist(ShoppingListItem item)
{
_context.ShoppingList.Remove(item);
bool saved = await _context.SaveChangesAsync() >= 0;
if (saved) { return new OkObjectResult(saved); }
return new ConflictObjectResult(new { message = "Could not save to database" });
}
} }
} }

View File

@ -1,6 +1,6 @@
namespace API.Models.ShoppingListModels namespace API.Models.ShoppingListModels
{ {
public class ShoppingList public class ShoppingListItem
{ {
public int Id { get; set; } public int Id { get; set; }

View File

@ -21,6 +21,6 @@ namespace API.Models.UserModels
public List<Recipe> Recipes { get; set; } public List<Recipe> Recipes { get; set; }
public List<ShoppingList> ShoppingList { get; set; } public List<ShoppingListItem> ShoppingList { get; set; }
} }
} }