Added sorting, freshness precentage, fullscreen view for products on shelf
This commit is contained in:
		@@ -15,6 +15,9 @@ import java.io.File
 | 
			
		||||
import java.io.FileOutputStream
 | 
			
		||||
import java.net.URLEncoder
 | 
			
		||||
import java.security.MessageDigest
 | 
			
		||||
import java.time.Duration
 | 
			
		||||
import java.time.LocalDate
 | 
			
		||||
import java.time.format.DateTimeFormatter
 | 
			
		||||
 | 
			
		||||
fun getImageUri(activity: Activity, imageFile: File): Uri? {
 | 
			
		||||
    return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + "." + activity.localClassName + ".provider", imageFile)
 | 
			
		||||
@@ -69,4 +72,18 @@ fun getActivity(context: Context?): Activity? {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@RequiresApi(Build.VERSION_CODES.O)
 | 
			
		||||
fun calculateProductFreshness(dateOfProduction: String, dateOfExpiry: String): Double {
 | 
			
		||||
    val dateFormatter: DateTimeFormatter =  DateTimeFormatter.ofPattern("d.M.yyyy")
 | 
			
		||||
 | 
			
		||||
    val fresh = LocalDate.parse(dateOfProduction, dateFormatter)
 | 
			
		||||
    val expired = LocalDate.parse(dateOfExpiry, dateFormatter)
 | 
			
		||||
 | 
			
		||||
    val shelfLife = Duration.between(fresh.atStartOfDay(), expired.atStartOfDay()).toDays()
 | 
			
		||||
    val today = LocalDate.parse(LocalDate.now().format(dateFormatter), dateFormatter)
 | 
			
		||||
    val daysBeforeExpiry = Duration.between(today.atStartOfDay(), expired.atStartOfDay()).toDays()
 | 
			
		||||
 | 
			
		||||
    return daysBeforeExpiry / shelfLife.toDouble()
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.dataclasses
 | 
			
		||||
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Parcel
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
import androidx.annotation.RequiresApi
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.calculateProductFreshness
 | 
			
		||||
 | 
			
		||||
class Product() : Parcelable {
 | 
			
		||||
    var id = 0
 | 
			
		||||
@@ -9,13 +12,16 @@ class Product() : Parcelable {
 | 
			
		||||
    var amount = 0
 | 
			
		||||
    var dateOfProduction = "01.01.1970"
 | 
			
		||||
    var dateOfExpiry = "01.01.1970"
 | 
			
		||||
    var freshness: Double = 0.0
 | 
			
		||||
 | 
			
		||||
    @RequiresApi(Build.VERSION_CODES.O)
 | 
			
		||||
    constructor(id: Int, abstractProductId: Int, amount: Int, dateOfProduction: String, dateOfExpiry: String) : this() {
 | 
			
		||||
        this.id = id
 | 
			
		||||
        this.abstractProductId = abstractProductId
 | 
			
		||||
        this.amount = amount
 | 
			
		||||
        this.dateOfProduction = dateOfProduction
 | 
			
		||||
        this.dateOfExpiry = dateOfExpiry
 | 
			
		||||
        this.freshness = calculateProductFreshness(dateOfProduction, dateOfExpiry)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(parcel: Parcel) : this() {
 | 
			
		||||
@@ -24,6 +30,7 @@ class Product() : Parcelable {
 | 
			
		||||
        amount = parcel.readInt()
 | 
			
		||||
        dateOfProduction = parcel.readString()!!
 | 
			
		||||
        dateOfExpiry = parcel.readString()!!
 | 
			
		||||
        freshness = parcel.readDouble()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
			
		||||
@@ -32,6 +39,7 @@ class Product() : Parcelable {
 | 
			
		||||
        parcel.writeInt(amount)
 | 
			
		||||
        parcel.writeString(dateOfProduction)
 | 
			
		||||
        parcel.writeString(dateOfExpiry)
 | 
			
		||||
        parcel.writeDouble(freshness)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun describeContents(): Int {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,10 +12,10 @@ import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.view.children
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.CategoriesContract
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.views.CategoryView
 | 
			
		||||
 | 
			
		||||
class CategoriesFragment : Fragment() {
 | 
			
		||||
@@ -61,8 +61,6 @@ class CategoriesFragment : Fragment() {
 | 
			
		||||
                ContextCompat.startActivity(context!!, addCategoryIntent, extras)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateContent() {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,31 +5,57 @@ import android.provider.BaseColumns
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.AdapterView
 | 
			
		||||
import android.widget.ArrayAdapter
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.core.view.children
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.gridlayout.widget.GridLayout
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.AbstractProductContract
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.ProductContract
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.databinding.FragmentShelfBinding
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.views.ProductView
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class ShelfFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: FragmentShelfBinding
 | 
			
		||||
    private var updateInProgress = false
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
			
		||||
        savedInstanceState: Bundle?
 | 
			
		||||
    ): View? {
 | 
			
		||||
    ): View {
 | 
			
		||||
        binding = FragmentShelfBinding.inflate(layoutInflater)
 | 
			
		||||
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_shelf, container, false)
 | 
			
		||||
    }
 | 
			
		||||
        fillUpSortBySpinner()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
        binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
 | 
			
		||||
            override fun onNothingSelected(parent: AdapterView<*>?) {
 | 
			
		||||
                updateContent()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
 | 
			
		||||
                updateContent()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        updateContent()
 | 
			
		||||
 | 
			
		||||
        return binding.root
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun fillUpSortBySpinner() {
 | 
			
		||||
        val sorts = mutableListOf("Name", "Category", "Freshness", "Date of production", "Date of expiry")
 | 
			
		||||
 | 
			
		||||
        val arrayAdapter =
 | 
			
		||||
            ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
 | 
			
		||||
        arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
 | 
			
		||||
        binding.spinner.adapter = arrayAdapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
@@ -40,6 +66,8 @@ class ShelfFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
    fun updateContent() {
 | 
			
		||||
        thread {
 | 
			
		||||
            if (updateInProgress) return@thread
 | 
			
		||||
            updateInProgress = true
 | 
			
		||||
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
			
		||||
            activity!!.runOnUiThread {
 | 
			
		||||
                grv?.removeAllViews()
 | 
			
		||||
@@ -54,7 +82,37 @@ class ShelfFragment : Fragment() {
 | 
			
		||||
                ProductContract.ProductEntry.EXPIRY_DATE,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, null, null, null, null, null)
 | 
			
		||||
            var orderBy: String = ""
 | 
			
		||||
 | 
			
		||||
            when (binding.spinner.selectedItem) {
 | 
			
		||||
                "Name" -> {
 | 
			
		||||
                    orderBy =
 | 
			
		||||
                        "(SELECT ${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                "Category" -> {
 | 
			
		||||
                    orderBy =
 | 
			
		||||
                        "(SELECT ${AbstractProductContract.AbstractProductEntry.CATEGORY} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
 | 
			
		||||
                }
 | 
			
		||||
// Wow, I wrote this on first try but unfortunately SQLite can't do that :(
 | 
			
		||||
// I'll leave it here as a memory.
 | 
			
		||||
//                "Freshness" -> {
 | 
			
		||||
//                    orderBy =
 | 
			
		||||
//                        "(SELECT ( (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday('now', 'localtime')) / (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday(${ProductContract.ProductEntry.DATE_OF_PRODUCTION})) )) ASC"
 | 
			
		||||
//                }
 | 
			
		||||
 | 
			
		||||
                "Date of production" -> {
 | 
			
		||||
                    orderBy = "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} ASC"
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                "Date of expiry" -> {
 | 
			
		||||
                    orderBy = "${ProductContract.ProductEntry.EXPIRY_DATE} ASC"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, null, null, null, null, orderBy)
 | 
			
		||||
 | 
			
		||||
            val products = mutableListOf<Product>()
 | 
			
		||||
 | 
			
		||||
            with(cursor) {
 | 
			
		||||
                while (moveToNext()) {
 | 
			
		||||
@@ -68,16 +126,34 @@ class ShelfFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
                    val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
 | 
			
		||||
 | 
			
		||||
                    val productView = ProductView(
 | 
			
		||||
                        requireActivity(),
 | 
			
		||||
                        requireContext(),
 | 
			
		||||
                        product
 | 
			
		||||
                    )
 | 
			
		||||
                    activity!!.runOnUiThread {
 | 
			
		||||
                        grv?.addView(productView)
 | 
			
		||||
                    if (binding.spinner.selectedItem == "Freshness") {
 | 
			
		||||
                        products.add(product)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        val productView = ProductView(
 | 
			
		||||
                            requireActivity(),
 | 
			
		||||
                            requireContext(),
 | 
			
		||||
                            product
 | 
			
		||||
                        )
 | 
			
		||||
                        activity!!.runOnUiThread {
 | 
			
		||||
                            grv?.addView(productView)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            products.sortWith(compareByDescending { it.freshness })
 | 
			
		||||
 | 
			
		||||
            for (product in products.iterator()) {
 | 
			
		||||
                val productView = ProductView(
 | 
			
		||||
                    requireActivity(),
 | 
			
		||||
                    requireContext(),
 | 
			
		||||
                    product
 | 
			
		||||
                )
 | 
			
		||||
                activity!!.runOnUiThread {
 | 
			
		||||
                    grv?.addView(productView)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            updateInProgress = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +168,6 @@ class ShelfFragment : Fragment() {
 | 
			
		||||
                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
			
		||||
                }
 | 
			
		||||
                if (view.isProductSelected) {
 | 
			
		||||
//                    db.eraseAbstractProduct(db.writableDatabase, view.abstractProduct.id, requireContext())
 | 
			
		||||
                    db.eraseProduct(db.writableDatabase, view.product.id)
 | 
			
		||||
                    deleted = true
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,19 +3,22 @@ package org.foxarmy.barcodescannerforemployees.fragments
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.provider.BaseColumns
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.AdapterView
 | 
			
		||||
import android.widget.ArrayAdapter
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.view.children
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.gridlayout.widget.GridLayout
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.AbstractProductContract
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.AddAbstractProductActivity
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.databinding.FragmentStorageBinding
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.generateThumbnailForImage
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.views.AbstractProductView
 | 
			
		||||
@@ -23,11 +26,27 @@ import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class StorageFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: FragmentStorageBinding
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
			
		||||
        savedInstanceState: Bundle?
 | 
			
		||||
    ): View? {
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_storage, container, false)
 | 
			
		||||
    ): View {
 | 
			
		||||
        binding = FragmentStorageBinding.inflate(inflater)
 | 
			
		||||
 | 
			
		||||
        fillUpSortBySpinner()
 | 
			
		||||
 | 
			
		||||
        binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
 | 
			
		||||
            override fun onNothingSelected(parent: AdapterView<*>?) {
 | 
			
		||||
                updateContent()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
 | 
			
		||||
                updateContent()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return binding.root
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onResume() {
 | 
			
		||||
@@ -36,20 +55,21 @@ class StorageFragment : Fragment() {
 | 
			
		||||
        updateContent()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onStop() {
 | 
			
		||||
        super.onStop()
 | 
			
		||||
    private fun fillUpSortBySpinner() {
 | 
			
		||||
        val sorts = mutableListOf("Name", "Category")
 | 
			
		||||
 | 
			
		||||
        val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
			
		||||
        grv?.removeAllViews()
 | 
			
		||||
        val arrayAdapter = ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
 | 
			
		||||
        arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
 | 
			
		||||
        binding.spinner.adapter = arrayAdapter
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun removeSelected() {
 | 
			
		||||
        thread {
 | 
			
		||||
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
			
		||||
            val grv = binding.contentGridLayout
 | 
			
		||||
 | 
			
		||||
            val db = DBStorageController(requireContext())
 | 
			
		||||
            var deleted = false
 | 
			
		||||
            for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
            for (view: AbstractProductView in grv.children.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
                activity!!.runOnUiThread {
 | 
			
		||||
                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
			
		||||
                }
 | 
			
		||||
@@ -69,9 +89,9 @@ class StorageFragment : Fragment() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun updateSelected() {
 | 
			
		||||
        val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
			
		||||
        val grv = binding.contentGridLayout
 | 
			
		||||
 | 
			
		||||
        for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
        for (view: AbstractProductView in grv.children.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
            if (view.isProductSelected) {
 | 
			
		||||
                val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
 | 
			
		||||
                val extras = Bundle()
 | 
			
		||||
@@ -84,9 +104,9 @@ class StorageFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
    fun updateContent() {
 | 
			
		||||
        thread {
 | 
			
		||||
            val grv:GridLayout? = view?.findViewById(R.id.contentGridLayout)
 | 
			
		||||
            val grv = binding.contentGridLayout
 | 
			
		||||
            activity!!.runOnUiThread{
 | 
			
		||||
                grv?.removeAllViews()
 | 
			
		||||
                grv.removeAllViews()
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val db = DBStorageController(requireContext()).readableDatabase
 | 
			
		||||
@@ -99,7 +119,18 @@ class StorageFragment : Fragment() {
 | 
			
		||||
                AbstractProductContract.AbstractProductEntry.CATEGORY
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, null, null, null, null, null)
 | 
			
		||||
            var orderBy: String = ""
 | 
			
		||||
            Log.d("QWERTYUIOP", binding.spinner.selectedItem.toString())
 | 
			
		||||
            when(binding.spinner.selectedItem) {
 | 
			
		||||
                "Name" -> {
 | 
			
		||||
                    orderBy = "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} ASC"
 | 
			
		||||
                }
 | 
			
		||||
                "Category" -> {
 | 
			
		||||
                    orderBy = "${AbstractProductContract.AbstractProductEntry.CATEGORY} ASC"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, null, null, null, null, orderBy)
 | 
			
		||||
 | 
			
		||||
            with (cursor) {
 | 
			
		||||
                while(moveToNext()) {
 | 
			
		||||
@@ -121,7 +152,7 @@ class StorageFragment : Fragment() {
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    activity!!.runOnUiThread{
 | 
			
		||||
                        grv?.addView(abstractProduct)
 | 
			
		||||
                        grv.addView(abstractProduct)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,12 @@ package org.foxarmy.barcodescannerforemployees.views
 | 
			
		||||
 | 
			
		||||
import android.app.Activity
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.graphics.Color
 | 
			
		||||
import android.graphics.drawable.GradientDrawable
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.util.AttributeSet
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.widget.ImageView
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
@@ -14,20 +15,17 @@ import android.widget.TextView
 | 
			
		||||
import androidx.annotation.RequiresApi
 | 
			
		||||
import androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.content.ContextCompat.startActivity
 | 
			
		||||
import androidx.core.graphics.blue
 | 
			
		||||
import androidx.core.graphics.green
 | 
			
		||||
import androidx.core.graphics.red
 | 
			
		||||
import androidx.core.math.MathUtils.clamp
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.*
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.getActivity
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.getImageUri
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.time.Duration
 | 
			
		||||
import java.time.LocalDate
 | 
			
		||||
import java.time.format.DateTimeFormatter
 | 
			
		||||
import java.text.DecimalFormat
 | 
			
		||||
import kotlin.concurrent.thread
 | 
			
		||||
 | 
			
		||||
class ProductView: LinearLayout {
 | 
			
		||||
@@ -41,6 +39,8 @@ class ProductView: LinearLayout {
 | 
			
		||||
    private lateinit var productAmountTextView: TextView
 | 
			
		||||
    private lateinit var productCategoryView: TextView
 | 
			
		||||
    private lateinit var productLifeSpan: TextView
 | 
			
		||||
    private lateinit var productFreshnessTextView: TextView
 | 
			
		||||
 | 
			
		||||
    private var backgroundColor: Int = 0xffffff
 | 
			
		||||
    private var strokeColor: Int = 0x000000
 | 
			
		||||
    private lateinit var outline: GradientDrawable
 | 
			
		||||
@@ -64,6 +64,7 @@ class ProductView: LinearLayout {
 | 
			
		||||
        productAmountTextView = findViewById(R.id.amountView)
 | 
			
		||||
        productCategoryView = findViewById(R.id.categoryView)
 | 
			
		||||
        productLifeSpan = findViewById(R.id.dateSpan)
 | 
			
		||||
        productFreshnessTextView = findViewById(R.id.freshnessPercentTextView)
 | 
			
		||||
 | 
			
		||||
        findViewById<ConstraintLayout>(R.id.productLayout).setOnLongClickListener {
 | 
			
		||||
            isProductSelected = !isProductSelected
 | 
			
		||||
@@ -71,6 +72,15 @@ class ProductView: LinearLayout {
 | 
			
		||||
            true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        productImageView.setOnClickListener {
 | 
			
		||||
            val fullscreenIntent = Intent(activity, FullscreenActivity::class.java)
 | 
			
		||||
            val extras = Bundle()
 | 
			
		||||
            val abstractProduct = DBStorageController(context).findAbstractProductById(DBStorageController(context).readableDatabase, product.abstractProductId)
 | 
			
		||||
            extras.putString("imagehash", abstractProduct!!.imageHash)
 | 
			
		||||
            fullscreenIntent.putExtras(extras)
 | 
			
		||||
            startActivity(context, fullscreenIntent, extras)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        update()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -90,7 +100,12 @@ class ProductView: LinearLayout {
 | 
			
		||||
        productAmountTextView.text = product.amount.toString()
 | 
			
		||||
        productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category)
 | 
			
		||||
        productLifeSpan.text = "${product.dateOfProduction}-${product.dateOfExpiry}"
 | 
			
		||||
 | 
			
		||||
        productFreshnessTextView.text =
 | 
			
		||||
        if (product.freshness == Double.NEGATIVE_INFINITY || product.freshness == Double.POSITIVE_INFINITY) {
 | 
			
		||||
            "Expired"
 | 
			
		||||
        } else {
 | 
			
		||||
            "${DecimalFormat("#.#").format(product.freshness*100)}%"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        updateStroke()
 | 
			
		||||
    }
 | 
			
		||||
@@ -118,17 +133,7 @@ class ProductView: LinearLayout {
 | 
			
		||||
 | 
			
		||||
    @RequiresApi(Build.VERSION_CODES.O)
 | 
			
		||||
    fun evaluateColor(): Int {
 | 
			
		||||
        val dateFormatter: DateTimeFormatter =  DateTimeFormatter.ofPattern("d.M.yyyy")
 | 
			
		||||
 | 
			
		||||
        val fresh = LocalDate.parse(product.dateOfProduction, dateFormatter)
 | 
			
		||||
        val expired = LocalDate.parse(product.dateOfExpiry, dateFormatter)
 | 
			
		||||
 | 
			
		||||
        val shelfLife = Duration.between(fresh.atStartOfDay(), expired.atStartOfDay()).toDays()
 | 
			
		||||
        val today = LocalDate.parse(LocalDate.now().format(dateFormatter), dateFormatter)
 | 
			
		||||
        val daysBeforeExpiry = Duration.between(today.atStartOfDay(), expired.atStartOfDay()).toDays()
 | 
			
		||||
 | 
			
		||||
        val freshnessPercentage: Double = daysBeforeExpiry / shelfLife.toDouble()
 | 
			
		||||
 | 
			
		||||
        val freshnessPercentage = calculateProductFreshness(product.dateOfProduction, product.dateOfExpiry)
 | 
			
		||||
        return calculateFreshnessGradient(freshnessPercentage)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -153,9 +158,6 @@ class ProductView: LinearLayout {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        val colorString = "#$redHex$greenHex$blueHex"
 | 
			
		||||
        Log.d("QWERTYUIOP", "$red:$green:$blue")
 | 
			
		||||
        Log.d("QWERTYUIOP", "$redHex-$greenHex-$blueHex")
 | 
			
		||||
        Log.d("QWERTYUIOP", colorString)
 | 
			
		||||
        return Color.parseColor(colorString)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -166,8 +168,6 @@ class ProductView: LinearLayout {
 | 
			
		||||
        val red = c.red() * (1 - darkPercent)
 | 
			
		||||
        val green = c.green() * (1 - darkPercent)
 | 
			
		||||
        val blue = c.blue() * (1 - darkPercent)
 | 
			
		||||
        Log.d("QWERTYUIOP", "....A:${c.red()}, ${c.green()}, ${c.blue()}")
 | 
			
		||||
        Log.d("QWERTYUIOP", "....B:${red.toFloat()}, ${green.toFloat()}, ${blue.toFloat()}")
 | 
			
		||||
 | 
			
		||||
        return Color.rgb(red.toFloat(), green.toFloat(), blue.toFloat())
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<LinearLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="200dp"
 | 
			
		||||
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="190dp"
 | 
			
		||||
        android:layout_height="wrap_content" app:barrierMargin="1dp" android:clickable="false"
 | 
			
		||||
        android:outlineProvider="background" android:background="@drawable/outline">
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,36 @@
 | 
			
		||||
             xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
 | 
			
		||||
             android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
    <ScrollView
 | 
			
		||||
    <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent">
 | 
			
		||||
        <androidx.gridlayout.widget.GridLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2"
 | 
			
		||||
                app:rowCount="100" android:nestedScrollingEnabled="true">
 | 
			
		||||
 | 
			
		||||
        </androidx.gridlayout.widget.GridLayout>
 | 
			
		||||
    </ScrollView>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="Sort by"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="0dp" android:id="@+id/sortByTextView"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@+id/scrollView" android:textAlignment="center"
 | 
			
		||||
        />
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:layout_width="0dp"
 | 
			
		||||
                android:layout_height="32dp" android:id="@+id/spinner"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                app:layout_constraintStart_toEndOf="@+id/sortByTextView"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="16dp"
 | 
			
		||||
        />
 | 
			
		||||
        <ScrollView
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent" app:layout_constraintTop_toBottomOf="@+id/spinner"
 | 
			
		||||
                android:layout_marginTop="32dp" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" android:id="@+id/scrollView">
 | 
			
		||||
            <androidx.gridlayout.widget.GridLayout
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2"
 | 
			
		||||
                    app:rowCount="100" android:nestedScrollingEnabled="true">
 | 
			
		||||
 | 
			
		||||
            </androidx.gridlayout.widget.GridLayout>
 | 
			
		||||
        </ScrollView>
 | 
			
		||||
    </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
</FrameLayout>
 | 
			
		||||
@@ -5,14 +5,35 @@
 | 
			
		||||
             android:layout_height="match_parent"
 | 
			
		||||
             android:id="@+id/fragment_storage"
 | 
			
		||||
             tools:context=".fragments.StorageFragment">
 | 
			
		||||
    <ScrollView
 | 
			
		||||
    <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent">
 | 
			
		||||
        <androidx.gridlayout.widget.GridLayout
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2"
 | 
			
		||||
                app:rowCount="100" android:nestedScrollingEnabled="true">
 | 
			
		||||
 | 
			
		||||
        </androidx.gridlayout.widget.GridLayout>
 | 
			
		||||
    </ScrollView>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="Sort by"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="0dp" android:id="@+id/sortByTextView"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                android:textAlignment="center"
 | 
			
		||||
                app:layout_constraintBottom_toBottomOf="@+id/scrollView2"/>
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:layout_width="0dp"
 | 
			
		||||
                android:layout_height="32dp" android:id="@+id/spinner"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                app:layout_constraintStart_toEndOf="@+id/sortByTextView"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="16dp"
 | 
			
		||||
        />
 | 
			
		||||
        <ScrollView
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/spinner"
 | 
			
		||||
                android:id="@+id/scrollView2">
 | 
			
		||||
            <androidx.gridlayout.widget.GridLayout
 | 
			
		||||
                    android:layout_width="match_parent"
 | 
			
		||||
                    android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2"
 | 
			
		||||
                    app:rowCount="100" android:nestedScrollingEnabled="true">
 | 
			
		||||
 | 
			
		||||
            </androidx.gridlayout.widget.GridLayout>
 | 
			
		||||
        </ScrollView>
 | 
			
		||||
    </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
</FrameLayout>
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?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="vertical"
 | 
			
		||||
              android:layout_width="200dp"
 | 
			
		||||
              android:layout_width="190dp"
 | 
			
		||||
              android:layout_height="wrap_content">
 | 
			
		||||
 | 
			
		||||
    <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
@@ -14,6 +14,12 @@
 | 
			
		||||
                android:id="@+id/productPicture"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent"/>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="0%"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/freshnessPercentTextView"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="10dp"
 | 
			
		||||
                app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="5dp"/>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="@string/sample_product_name"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user