Allow checking/unchecking shopping items

This commit is contained in:
Reimar 2025-05-08 10:04:29 +02:00
parent f924d2083b
commit b3b4562f21
Signed by: Reimar
GPG Key ID: 93549FA07F0AE268
11 changed files with 93 additions and 6 deletions

View File

@ -16,3 +16,7 @@ fun addShoppingItem(ctx: Context, name: String, amount: Double?, unit: String?)
requestJson<AddShoppingItemRequest, Boolean>(ctx, "POST", "/api/ShoppingList/add", request) requestJson<AddShoppingItemRequest, Boolean>(ctx, "POST", "/api/ShoppingList/add", request)
} }
fun toggleShoppingItemChecked(ctx: Context, item: ShoppingListItem) {
requestJson<Unit, Boolean>(ctx, "PUT", "/api/ShoppingList/check?itemId=${item.id}", null)
}

View File

@ -3,4 +3,4 @@ package tech.mercantec.easyeat.models
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class ShoppingListItem(val id: Int, val name: String, val amount: Double?, val unit: String?, val checked: Boolean) data class ShoppingListItem(val id: Int, var name: String, var amount: Double?, var unit: String?, var checked: Boolean)

View File

@ -1,16 +1,20 @@
package tech.mercantec.easyeat.ui.shopping_list package tech.mercantec.easyeat.ui.shopping_list
import android.content.Context import android.content.Context
import android.graphics.Paint
import android.icu.text.DecimalFormat import android.icu.text.DecimalFormat
import android.util.TypedValue
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.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.content.ContextCompat
import tech.mercantec.easyeat.R import tech.mercantec.easyeat.R
import tech.mercantec.easyeat.models.ShoppingListItem import tech.mercantec.easyeat.models.ShoppingListItem
class ShoppingItemAdapter(context: Context, items: Array<ShoppingListItem>) class ShoppingItemAdapter(context: Context, items: ArrayList<ShoppingListItem>)
: ArrayAdapter<ShoppingListItem>(context, R.layout.shopping_list_item, items) { : ArrayAdapter<ShoppingListItem>(context, R.layout.shopping_list_item, items) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
@ -18,9 +22,37 @@ class ShoppingItemAdapter(context: Context, items: Array<ShoppingListItem>)
val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.shopping_list_item, parent, false) val view = convertView ?: LayoutInflater.from(context).inflate(R.layout.shopping_list_item, parent, false)
item?.let { item -> item?.let { item ->
view.findViewById<TextView>(R.id.amount).text = DecimalFormat("#.##").format(item.amount) val checkmarkView = view.findViewById<ImageView>(R.id.checkmark)
view.findViewById<TextView>(R.id.unit).text = item.unit val amountView = view.findViewById<TextView>(R.id.amount)
view.findViewById<TextView>(R.id.name).text = item.name 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 return view

View File

@ -16,7 +16,10 @@ 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.getShoppingList import tech.mercantec.easyeat.helpers.getShoppingList
import tech.mercantec.easyeat.helpers.toggleShoppingItemChecked
import tech.mercantec.easyeat.models.Dish
import tech.mercantec.easyeat.models.ShoppingListItem import tech.mercantec.easyeat.models.ShoppingListItem
import java.util.ArrayList
import kotlin.concurrent.thread import kotlin.concurrent.thread
class ShoppingListFragment : Fragment() { class ShoppingListFragment : Fragment() {
@ -48,10 +51,28 @@ class ShoppingListFragment : Fragment() {
} }
activity?.runOnUiThread { activity?.runOnUiThread {
binding.shoppingList.adapter = ShoppingItemAdapter(requireContext(), items) binding.shoppingList.adapter = ShoppingItemAdapter(requireContext(), ArrayList(items.toMutableList()))
} }
} }
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)
}
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)

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

@ -1,11 +1,21 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
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"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="12dp" android:padding="12dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="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 <TextView
android:id="@+id/amount" android:id="@+id/amount"
android:layout_width="70dp" android:layout_width="70dp"

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