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.io.FileOutputStream
 | 
				
			||||||
import java.net.URLEncoder
 | 
					import java.net.URLEncoder
 | 
				
			||||||
import java.security.MessageDigest
 | 
					import java.security.MessageDigest
 | 
				
			||||||
 | 
					import java.time.Duration
 | 
				
			||||||
 | 
					import java.time.LocalDate
 | 
				
			||||||
 | 
					import java.time.format.DateTimeFormatter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun getImageUri(activity: Activity, imageFile: File): Uri? {
 | 
					fun getImageUri(activity: Activity, imageFile: File): Uri? {
 | 
				
			||||||
    return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + "." + activity.localClassName + ".provider", imageFile)
 | 
					    return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + "." + activity.localClassName + ".provider", imageFile)
 | 
				
			||||||
@@ -70,3 +73,17 @@ fun getActivity(context: Context?): Activity? {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return null
 | 
					    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
 | 
					package org.foxarmy.barcodescannerforemployees.dataclasses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.Build
 | 
				
			||||||
import android.os.Parcel
 | 
					import android.os.Parcel
 | 
				
			||||||
import android.os.Parcelable
 | 
					import android.os.Parcelable
 | 
				
			||||||
 | 
					import androidx.annotation.RequiresApi
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.calculateProductFreshness
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Product() : Parcelable {
 | 
					class Product() : Parcelable {
 | 
				
			||||||
    var id = 0
 | 
					    var id = 0
 | 
				
			||||||
@@ -9,13 +12,16 @@ class Product() : Parcelable {
 | 
				
			|||||||
    var amount = 0
 | 
					    var amount = 0
 | 
				
			||||||
    var dateOfProduction = "01.01.1970"
 | 
					    var dateOfProduction = "01.01.1970"
 | 
				
			||||||
    var dateOfExpiry = "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() {
 | 
					    constructor(id: Int, abstractProductId: Int, amount: Int, dateOfProduction: String, dateOfExpiry: String) : this() {
 | 
				
			||||||
        this.id = id
 | 
					        this.id = id
 | 
				
			||||||
        this.abstractProductId = abstractProductId
 | 
					        this.abstractProductId = abstractProductId
 | 
				
			||||||
        this.amount = amount
 | 
					        this.amount = amount
 | 
				
			||||||
        this.dateOfProduction = dateOfProduction
 | 
					        this.dateOfProduction = dateOfProduction
 | 
				
			||||||
        this.dateOfExpiry = dateOfExpiry
 | 
					        this.dateOfExpiry = dateOfExpiry
 | 
				
			||||||
 | 
					        this.freshness = calculateProductFreshness(dateOfProduction, dateOfExpiry)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(parcel: Parcel) : this() {
 | 
					    constructor(parcel: Parcel) : this() {
 | 
				
			||||||
@@ -24,6 +30,7 @@ class Product() : Parcelable {
 | 
				
			|||||||
        amount = parcel.readInt()
 | 
					        amount = parcel.readInt()
 | 
				
			||||||
        dateOfProduction = parcel.readString()!!
 | 
					        dateOfProduction = parcel.readString()!!
 | 
				
			||||||
        dateOfExpiry = parcel.readString()!!
 | 
					        dateOfExpiry = parcel.readString()!!
 | 
				
			||||||
 | 
					        freshness = parcel.readDouble()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
					    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
				
			||||||
@@ -32,6 +39,7 @@ class Product() : Parcelable {
 | 
				
			|||||||
        parcel.writeInt(amount)
 | 
					        parcel.writeInt(amount)
 | 
				
			||||||
        parcel.writeString(dateOfProduction)
 | 
					        parcel.writeString(dateOfProduction)
 | 
				
			||||||
        parcel.writeString(dateOfExpiry)
 | 
					        parcel.writeString(dateOfExpiry)
 | 
				
			||||||
 | 
					        parcel.writeDouble(freshness)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun describeContents(): Int {
 | 
					    override fun describeContents(): Int {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,10 +12,10 @@ import androidx.core.content.ContextCompat
 | 
				
			|||||||
import androidx.core.view.children
 | 
					import androidx.core.view.children
 | 
				
			||||||
import androidx.fragment.app.Fragment
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.CategoriesContract
 | 
					import org.foxarmy.barcodescannerforemployees.CategoriesContract
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
					 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity
 | 
					import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.views.CategoryView
 | 
					import org.foxarmy.barcodescannerforemployees.views.CategoryView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CategoriesFragment : Fragment() {
 | 
					class CategoriesFragment : Fragment() {
 | 
				
			||||||
@@ -61,8 +61,6 @@ class CategoriesFragment : Fragment() {
 | 
				
			|||||||
                ContextCompat.startActivity(context!!, addCategoryIntent, extras)
 | 
					                ContextCompat.startActivity(context!!, addCategoryIntent, extras)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun updateContent() {
 | 
					    fun updateContent() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,31 +5,57 @@ import android.provider.BaseColumns
 | 
				
			|||||||
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.AdapterView
 | 
				
			||||||
 | 
					import android.widget.ArrayAdapter
 | 
				
			||||||
import android.widget.ImageView
 | 
					import android.widget.ImageView
 | 
				
			||||||
import android.widget.Toast
 | 
					import android.widget.Toast
 | 
				
			||||||
import androidx.core.view.children
 | 
					import androidx.core.view.children
 | 
				
			||||||
import androidx.fragment.app.Fragment
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
import androidx.gridlayout.widget.GridLayout
 | 
					import androidx.gridlayout.widget.GridLayout
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.AbstractProductContract
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.ProductContract
 | 
					import org.foxarmy.barcodescannerforemployees.ProductContract
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.databinding.FragmentShelfBinding
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.views.ProductView
 | 
					import org.foxarmy.barcodescannerforemployees.views.ProductView
 | 
				
			||||||
import kotlin.concurrent.thread
 | 
					import kotlin.concurrent.thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ShelfFragment : Fragment() {
 | 
					class ShelfFragment : Fragment() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lateinit var binding: FragmentShelfBinding
 | 
				
			||||||
 | 
					    private var updateInProgress = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onCreateView(
 | 
					    override fun onCreateView(
 | 
				
			||||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
					        inflater: LayoutInflater, container: ViewGroup?,
 | 
				
			||||||
        savedInstanceState: Bundle?
 | 
					        savedInstanceState: Bundle?
 | 
				
			||||||
    ): View? {
 | 
					    ): View {
 | 
				
			||||||
 | 
					        binding = FragmentShelfBinding.inflate(layoutInflater)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return inflater.inflate(R.layout.fragment_shelf, container, false)
 | 
					        fillUpSortBySpinner()
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
					        binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
 | 
				
			||||||
        super.onCreate(savedInstanceState)
 | 
					            override fun onNothingSelected(parent: AdapterView<*>?) {
 | 
				
			||||||
 | 
					                updateContent()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
 | 
				
			||||||
 | 
					                updateContent()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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() {
 | 
					    override fun onResume() {
 | 
				
			||||||
@@ -40,6 +66,8 @@ class ShelfFragment : Fragment() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fun updateContent() {
 | 
					    fun updateContent() {
 | 
				
			||||||
        thread {
 | 
					        thread {
 | 
				
			||||||
 | 
					            if (updateInProgress) return@thread
 | 
				
			||||||
 | 
					            updateInProgress = true
 | 
				
			||||||
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
					            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
				
			||||||
            activity!!.runOnUiThread {
 | 
					            activity!!.runOnUiThread {
 | 
				
			||||||
                grv?.removeAllViews()
 | 
					                grv?.removeAllViews()
 | 
				
			||||||
@@ -54,7 +82,37 @@ class ShelfFragment : Fragment() {
 | 
				
			|||||||
                ProductContract.ProductEntry.EXPIRY_DATE,
 | 
					                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) {
 | 
					            with(cursor) {
 | 
				
			||||||
                while (moveToNext()) {
 | 
					                while (moveToNext()) {
 | 
				
			||||||
@@ -68,16 +126,34 @@ class ShelfFragment : Fragment() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
 | 
					                    val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    val productView = ProductView(
 | 
					                    if (binding.spinner.selectedItem == "Freshness") {
 | 
				
			||||||
                        requireActivity(),
 | 
					                        products.add(product)
 | 
				
			||||||
                        requireContext(),
 | 
					                    } else {
 | 
				
			||||||
                        product
 | 
					                        val productView = ProductView(
 | 
				
			||||||
                    )
 | 
					                            requireActivity(),
 | 
				
			||||||
                    activity!!.runOnUiThread {
 | 
					                            requireContext(),
 | 
				
			||||||
                        grv?.addView(productView)
 | 
					                            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)
 | 
					                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (view.isProductSelected) {
 | 
					                if (view.isProductSelected) {
 | 
				
			||||||
//                    db.eraseAbstractProduct(db.writableDatabase, view.abstractProduct.id, requireContext())
 | 
					 | 
				
			||||||
                    db.eraseProduct(db.writableDatabase, view.product.id)
 | 
					                    db.eraseProduct(db.writableDatabase, view.product.id)
 | 
				
			||||||
                    deleted = true
 | 
					                    deleted = true
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,19 +3,22 @@ package org.foxarmy.barcodescannerforemployees.fragments
 | 
				
			|||||||
import android.content.Intent
 | 
					import android.content.Intent
 | 
				
			||||||
import android.os.Bundle
 | 
					import android.os.Bundle
 | 
				
			||||||
import android.provider.BaseColumns
 | 
					import android.provider.BaseColumns
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					import android.widget.AdapterView
 | 
				
			||||||
 | 
					import android.widget.ArrayAdapter
 | 
				
			||||||
import android.widget.ImageView
 | 
					import android.widget.ImageView
 | 
				
			||||||
import android.widget.Toast
 | 
					import android.widget.Toast
 | 
				
			||||||
import androidx.core.content.ContextCompat
 | 
					import androidx.core.content.ContextCompat
 | 
				
			||||||
import androidx.core.view.children
 | 
					import androidx.core.view.children
 | 
				
			||||||
import androidx.fragment.app.Fragment
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
import androidx.gridlayout.widget.GridLayout
 | 
					 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.AbstractProductContract
 | 
					import org.foxarmy.barcodescannerforemployees.AbstractProductContract
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.activities.AddAbstractProductActivity
 | 
					import org.foxarmy.barcodescannerforemployees.activities.AddAbstractProductActivity
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.databinding.FragmentStorageBinding
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.generateThumbnailForImage
 | 
					import org.foxarmy.barcodescannerforemployees.generateThumbnailForImage
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.views.AbstractProductView
 | 
					import org.foxarmy.barcodescannerforemployees.views.AbstractProductView
 | 
				
			||||||
@@ -23,11 +26,27 @@ import kotlin.concurrent.thread
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class StorageFragment : Fragment() {
 | 
					class StorageFragment : Fragment() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private lateinit var binding: FragmentStorageBinding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onCreateView(
 | 
					    override fun onCreateView(
 | 
				
			||||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
					        inflater: LayoutInflater, container: ViewGroup?,
 | 
				
			||||||
        savedInstanceState: Bundle?
 | 
					        savedInstanceState: Bundle?
 | 
				
			||||||
    ): View? {
 | 
					    ): View {
 | 
				
			||||||
        return inflater.inflate(R.layout.fragment_storage, container, false)
 | 
					        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() {
 | 
					    override fun onResume() {
 | 
				
			||||||
@@ -36,20 +55,21 @@ class StorageFragment : Fragment() {
 | 
				
			|||||||
        updateContent()
 | 
					        updateContent()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun onStop() {
 | 
					    private fun fillUpSortBySpinner() {
 | 
				
			||||||
        super.onStop()
 | 
					        val sorts = mutableListOf("Name", "Category")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
					        val arrayAdapter = ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
 | 
				
			||||||
        grv?.removeAllViews()
 | 
					        arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
 | 
				
			||||||
 | 
					        binding.spinner.adapter = arrayAdapter
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun removeSelected() {
 | 
					    fun removeSelected() {
 | 
				
			||||||
        thread {
 | 
					        thread {
 | 
				
			||||||
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
 | 
					            val grv = binding.contentGridLayout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val db = DBStorageController(requireContext())
 | 
					            val db = DBStorageController(requireContext())
 | 
				
			||||||
            var deleted = false
 | 
					            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 {
 | 
					                activity!!.runOnUiThread {
 | 
				
			||||||
                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
					                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -69,9 +89,9 @@ class StorageFragment : Fragment() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun updateSelected() {
 | 
					    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) {
 | 
					            if (view.isProductSelected) {
 | 
				
			||||||
                val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
 | 
					                val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
 | 
				
			||||||
                val extras = Bundle()
 | 
					                val extras = Bundle()
 | 
				
			||||||
@@ -84,9 +104,9 @@ class StorageFragment : Fragment() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fun updateContent() {
 | 
					    fun updateContent() {
 | 
				
			||||||
        thread {
 | 
					        thread {
 | 
				
			||||||
            val grv:GridLayout? = view?.findViewById(R.id.contentGridLayout)
 | 
					            val grv = binding.contentGridLayout
 | 
				
			||||||
            activity!!.runOnUiThread{
 | 
					            activity!!.runOnUiThread{
 | 
				
			||||||
                grv?.removeAllViews()
 | 
					                grv.removeAllViews()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val db = DBStorageController(requireContext()).readableDatabase
 | 
					            val db = DBStorageController(requireContext()).readableDatabase
 | 
				
			||||||
@@ -99,7 +119,18 @@ class StorageFragment : Fragment() {
 | 
				
			|||||||
                AbstractProductContract.AbstractProductEntry.CATEGORY
 | 
					                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) {
 | 
					            with (cursor) {
 | 
				
			||||||
                while(moveToNext()) {
 | 
					                while(moveToNext()) {
 | 
				
			||||||
@@ -121,7 +152,7 @@ class StorageFragment : Fragment() {
 | 
				
			|||||||
                    )
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    activity!!.runOnUiThread{
 | 
					                    activity!!.runOnUiThread{
 | 
				
			||||||
                        grv?.addView(abstractProduct)
 | 
					                        grv.addView(abstractProduct)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,12 @@ package org.foxarmy.barcodescannerforemployees.views
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import android.app.Activity
 | 
					import android.app.Activity
 | 
				
			||||||
import android.content.Context
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.Intent
 | 
				
			||||||
import android.graphics.Color
 | 
					import android.graphics.Color
 | 
				
			||||||
import android.graphics.drawable.GradientDrawable
 | 
					import android.graphics.drawable.GradientDrawable
 | 
				
			||||||
import android.os.Build
 | 
					import android.os.Build
 | 
				
			||||||
 | 
					import android.os.Bundle
 | 
				
			||||||
import android.util.AttributeSet
 | 
					import android.util.AttributeSet
 | 
				
			||||||
import android.util.Log
 | 
					 | 
				
			||||||
import android.view.LayoutInflater
 | 
					import android.view.LayoutInflater
 | 
				
			||||||
import android.widget.ImageView
 | 
					import android.widget.ImageView
 | 
				
			||||||
import android.widget.LinearLayout
 | 
					import android.widget.LinearLayout
 | 
				
			||||||
@@ -14,20 +15,17 @@ import android.widget.TextView
 | 
				
			|||||||
import androidx.annotation.RequiresApi
 | 
					import androidx.annotation.RequiresApi
 | 
				
			||||||
import androidx.constraintlayout.widget.ConstraintLayout
 | 
					import androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
import androidx.core.content.ContextCompat
 | 
					import androidx.core.content.ContextCompat
 | 
				
			||||||
 | 
					import androidx.core.content.ContextCompat.startActivity
 | 
				
			||||||
import androidx.core.graphics.blue
 | 
					import androidx.core.graphics.blue
 | 
				
			||||||
import androidx.core.graphics.green
 | 
					import androidx.core.graphics.green
 | 
				
			||||||
import androidx.core.graphics.red
 | 
					import androidx.core.graphics.red
 | 
				
			||||||
import androidx.core.math.MathUtils.clamp
 | 
					import androidx.core.math.MathUtils.clamp
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.*
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.getActivity
 | 
					 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.getImageUri
 | 
					 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
import java.time.Duration
 | 
					import java.text.DecimalFormat
 | 
				
			||||||
import java.time.LocalDate
 | 
					 | 
				
			||||||
import java.time.format.DateTimeFormatter
 | 
					 | 
				
			||||||
import kotlin.concurrent.thread
 | 
					import kotlin.concurrent.thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProductView: LinearLayout {
 | 
					class ProductView: LinearLayout {
 | 
				
			||||||
@@ -41,6 +39,8 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
    private lateinit var productAmountTextView: TextView
 | 
					    private lateinit var productAmountTextView: TextView
 | 
				
			||||||
    private lateinit var productCategoryView: TextView
 | 
					    private lateinit var productCategoryView: TextView
 | 
				
			||||||
    private lateinit var productLifeSpan: TextView
 | 
					    private lateinit var productLifeSpan: TextView
 | 
				
			||||||
 | 
					    private lateinit var productFreshnessTextView: TextView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private var backgroundColor: Int = 0xffffff
 | 
					    private var backgroundColor: Int = 0xffffff
 | 
				
			||||||
    private var strokeColor: Int = 0x000000
 | 
					    private var strokeColor: Int = 0x000000
 | 
				
			||||||
    private lateinit var outline: GradientDrawable
 | 
					    private lateinit var outline: GradientDrawable
 | 
				
			||||||
@@ -64,6 +64,7 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
        productAmountTextView = findViewById(R.id.amountView)
 | 
					        productAmountTextView = findViewById(R.id.amountView)
 | 
				
			||||||
        productCategoryView = findViewById(R.id.categoryView)
 | 
					        productCategoryView = findViewById(R.id.categoryView)
 | 
				
			||||||
        productLifeSpan = findViewById(R.id.dateSpan)
 | 
					        productLifeSpan = findViewById(R.id.dateSpan)
 | 
				
			||||||
 | 
					        productFreshnessTextView = findViewById(R.id.freshnessPercentTextView)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        findViewById<ConstraintLayout>(R.id.productLayout).setOnLongClickListener {
 | 
					        findViewById<ConstraintLayout>(R.id.productLayout).setOnLongClickListener {
 | 
				
			||||||
            isProductSelected = !isProductSelected
 | 
					            isProductSelected = !isProductSelected
 | 
				
			||||||
@@ -71,6 +72,15 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
            true
 | 
					            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()
 | 
					        update()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -90,7 +100,12 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
        productAmountTextView.text = product.amount.toString()
 | 
					        productAmountTextView.text = product.amount.toString()
 | 
				
			||||||
        productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category)
 | 
					        productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category)
 | 
				
			||||||
        productLifeSpan.text = "${product.dateOfProduction}-${product.dateOfExpiry}"
 | 
					        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()
 | 
					        updateStroke()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -118,17 +133,7 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @RequiresApi(Build.VERSION_CODES.O)
 | 
					    @RequiresApi(Build.VERSION_CODES.O)
 | 
				
			||||||
    fun evaluateColor(): Int {
 | 
					    fun evaluateColor(): Int {
 | 
				
			||||||
        val dateFormatter: DateTimeFormatter =  DateTimeFormatter.ofPattern("d.M.yyyy")
 | 
					        val freshnessPercentage = calculateProductFreshness(product.dateOfProduction, product.dateOfExpiry)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        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()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return calculateFreshnessGradient(freshnessPercentage)
 | 
					        return calculateFreshnessGradient(freshnessPercentage)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -153,9 +158,6 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val colorString = "#$redHex$greenHex$blueHex"
 | 
					        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)
 | 
					        return Color.parseColor(colorString)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -166,8 +168,6 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
        val red = c.red() * (1 - darkPercent)
 | 
					        val red = c.red() * (1 - darkPercent)
 | 
				
			||||||
        val green = c.green() * (1 - darkPercent)
 | 
					        val green = c.green() * (1 - darkPercent)
 | 
				
			||||||
        val blue = c.blue() * (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())
 | 
					        return Color.rgb(red.toFloat(), green.toFloat(), blue.toFloat())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<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"
 | 
					        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:layout_height="wrap_content" app:barrierMargin="1dp" android:clickable="false"
 | 
				
			||||||
        android:outlineProvider="background" android:background="@drawable/outline">
 | 
					        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"
 | 
					             xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
 | 
				
			||||||
             android:layout_height="match_parent">
 | 
					             android:layout_height="match_parent">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <ScrollView
 | 
					    <androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
            android:layout_width="match_parent"
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
            android:layout_height="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>
 | 
					        <TextView
 | 
				
			||||||
    </ScrollView>
 | 
					                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>
 | 
					</FrameLayout>
 | 
				
			||||||
@@ -5,14 +5,35 @@
 | 
				
			|||||||
             android:layout_height="match_parent"
 | 
					             android:layout_height="match_parent"
 | 
				
			||||||
             android:id="@+id/fragment_storage"
 | 
					             android:id="@+id/fragment_storage"
 | 
				
			||||||
             tools:context=".fragments.StorageFragment">
 | 
					             tools:context=".fragments.StorageFragment">
 | 
				
			||||||
    <ScrollView
 | 
					    <androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
            android:layout_width="match_parent"
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
            android:layout_height="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>
 | 
					        <TextView
 | 
				
			||||||
    </ScrollView>
 | 
					                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>
 | 
					</FrameLayout>
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
					<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
              xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical"
 | 
					              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">
 | 
					              android:layout_height="wrap_content">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <androidx.constraintlayout.widget.ConstraintLayout
 | 
					    <androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
@@ -14,6 +14,12 @@
 | 
				
			|||||||
                android:id="@+id/productPicture"
 | 
					                android:id="@+id/productPicture"
 | 
				
			||||||
                app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
 | 
					                app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
                app:layout_constraintEnd_toEndOf="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
 | 
					        <TextView
 | 
				
			||||||
                android:text="@string/sample_product_name"
 | 
					                android:text="@string/sample_product_name"
 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user