From 5066ded9c7ce2520dd75806a4e8df0a7c3573f2f Mon Sep 17 00:00:00 2001 From: leca Date: Tue, 15 Oct 2024 02:08:29 +0300 Subject: [PATCH] added productView and things around --- .../DBStorageController.kt | 45 ++++++ .../activities/AddProductActivity.kt | 153 ++++++++++++++++-- .../dataclasses/Product.kt | 16 +- .../fragments/ShelfFragment.kt | 54 +++++++ .../views/ProductView.kt | 78 +++++++++ .../main/res/layout/fragment_add_product.xml | 60 ++++++- app/src/main/res/layout/fragment_shelf.xml | 12 +- app/src/main/res/layout/product_view.xml | 61 ++++++- 8 files changed, 456 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/org/foxarmy/barcodescannerforemployees/views/ProductView.kt diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/DBStorageController.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/DBStorageController.kt index 05e9776..4d30b3d 100644 --- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/DBStorageController.kt +++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/DBStorageController.kt @@ -1,11 +1,13 @@ package org.foxarmy.barcodescannerforemployees +import android.content.ContentValues import android.content.Context import android.database.DatabaseUtils import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import android.provider.BaseColumns import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct +import org.foxarmy.barcodescannerforemployees.dataclasses.Product import java.io.File object AbstractProductContract { @@ -166,6 +168,17 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE db.delete(AbstractProductContract.AbstractProductEntry.TABLE_NAME, BaseColumns._ID + "=" + id, null) } + fun insertNewProduct(db: SQLiteDatabase, product: Product) { + val values = ContentValues().apply { + put(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, product.abstractProductId) + put(ProductContract.ProductEntry.AMOUNT, product.amount) + put(ProductContract.ProductEntry.DATE_OF_PRODUCTION, product.dateOfProduction) + put(ProductContract.ProductEntry.EXPIRY_DATE, product.dateOfExpiry) + } + + db.insert(ProductContract.ProductEntry.TABLE_NAME, null, values) + } + fun findAbstractProductByBarcode (db: SQLiteDatabase, barcode: String) : AbstractProduct? { var abstractProduct: AbstractProduct? = null val projection = arrayOf( @@ -196,6 +209,38 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE return abstractProduct } + fun findAbstractProductById(db: SQLiteDatabase, id: Int): AbstractProduct? { + var abstractProduct: AbstractProduct? = null + val projection = arrayOf( + BaseColumns._ID, + AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, + AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, + AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, + AbstractProductContract.AbstractProductEntry.CATEGORY, + AbstractProductContract.AbstractProductEntry.BARCODE + ) + + val selection = "${BaseColumns._ID} = ?" + val selectionArgs = arrayOf(id.toString()) + + val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, null) + + with (cursor) { + while (moveToNext()) { + val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) + val barcode = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.BARCODE)) + val name = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME)) + val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT)) + val imageHash = getString((getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))) + val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY)) + + abstractProduct = AbstractProduct(productId, barcode, name, netWeight, imageHash, category) + } + } + + return abstractProduct + } + companion object { const val DATABASE_VERSION = 1 const val DATABASE_NAME = "database.db" diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddProductActivity.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddProductActivity.kt index 3310da0..c0f7098 100644 --- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddProductActivity.kt +++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddProductActivity.kt @@ -1,19 +1,40 @@ package org.foxarmy.barcodescannerforemployees.activities +import android.app.DatePickerDialog import android.os.Bundle -import android.widget.Button -import android.widget.Toast +import android.view.View +import android.widget.* import androidx.appcompat.app.AppCompatActivity import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.dataclasses.Product import org.foxarmy.barcodescannerforemployees.views.AbstractProductView +import java.util.* class AddProductActivity : AppCompatActivity() { private lateinit var scanButton: Button private lateinit var abstractProductView: AbstractProductView + private lateinit var expiryDateRadioButton: RadioButton + private lateinit var shelfLifeRadioButton: RadioButton + + private lateinit var expiryDateTextView: TextView + private lateinit var expiryDateSelectButton: Button + + private lateinit var shelfLifeTextView: TextView + private lateinit var shelfLifeTextEdit: EditText + + private lateinit var amountTextEdit: EditText + + private lateinit var dateOfProductionSelectButton: Button + private lateinit var saveProductButton: Button + + private var expiryDateOverShelfLife: Boolean? = null + private var dateOfProduction: String = "" + private var dateOfExpiry: String = "" + + private var barcode: String = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -21,27 +42,139 @@ class AddProductActivity : AppCompatActivity() { setContentView(R.layout.fragment_add_product) val extras = intent.extras - val product = extras!!.get("product") as Product? + var product = extras!!.get("product") as Product? scanButton = findViewById(R.id.scanButton) abstractProductView = findViewById(R.id.abstractProductView) - /* - scanButton = findViewById(R.id.scanButton) - abstractProductView = AbstractProductView(this, this, AbstractProduct()) - findViewById(R.id.addProductConstraintLayout).addView(abstractProductView) - */ + expiryDateRadioButton = findViewById(R.id.expiryDateRadio) + shelfLifeRadioButton = findViewById(R.id.shelfLifeRadio) + + expiryDateTextView = findViewById(R.id.expiryDateTextView) + expiryDateSelectButton = findViewById(R.id.selectExpiryDateButton) + + shelfLifeTextView = findViewById(R.id.shelfLife) + shelfLifeTextEdit = findViewById(R.id.shelfLifeTextEdit) + + amountTextEdit = findViewById(R.id.amountTextEdit) + + dateOfProductionSelectButton = findViewById(R.id.selectDateOfProductionButton) + saveProductButton = findViewById(R.id.saveProductButton) scanButton.setOnClickListener { val scanner = GmsBarcodeScanning.getClient(this) scanner.startScan() - .addOnSuccessListener { barcode -> - findAndDisplayAbstractProductByBarcode(barcode.rawValue.toString()) + .addOnSuccessListener { bc -> + barcode = bc.rawValue.toString() + findAndDisplayAbstractProductByBarcode(barcode) } .addOnFailureListener { Toast.makeText(this, "Cannot scan barcode", Toast.LENGTH_SHORT).show() } } + + expiryDateRadioButton.setOnClickListener { + expiryDateTextView.visibility = View.VISIBLE + expiryDateSelectButton.visibility = View.VISIBLE + + shelfLifeTextEdit.visibility = View.INVISIBLE + shelfLifeTextView.visibility = View.INVISIBLE + + expiryDateOverShelfLife = true + } + + shelfLifeRadioButton.setOnClickListener { + expiryDateTextView.visibility = View.INVISIBLE + expiryDateSelectButton.visibility = View.INVISIBLE + + shelfLifeTextEdit.visibility = View.VISIBLE + shelfLifeTextView.visibility = View.VISIBLE + + expiryDateOverShelfLife = false + } + +// shelfLifeTextEdit.addTextChangedListener { +// if (shelfLifeTextEdit.text.toString() == "") { +// return@addTextChangedListener +// } +// +// evaluateDateOfExpiry() +// } + + dateOfProductionSelectButton.setOnClickListener { + val c = Calendar.getInstance() + val year = c.get(Calendar.YEAR) + val month = c.get(Calendar.MONTH) + val day = c.get(Calendar.DAY_OF_MONTH) + + val dpd = DatePickerDialog(this, { _, y, m, d -> + dateOfProduction = "$d.${m+1}.$y" + findViewById(R.id.dateOfProductionTextView).text = "Date of production: $dateOfProduction" + }, year, month, day) + + dpd.show() + } + + expiryDateSelectButton.setOnClickListener { + val c = Calendar.getInstance() + val year = c.get(Calendar.YEAR) + val month = c.get(Calendar.MONTH) + val day = c.get(Calendar.DAY_OF_MONTH) + + val dpd = DatePickerDialog(this, { view, y, m, d -> + dateOfExpiry = "$d.${m+1}.$y" + expiryDateTextView.text = "Expiry date: $dateOfExpiry" + }, year, month, day) + + dpd.show() + } + + saveProductButton.setOnClickListener { + if (expiryDateOverShelfLife == null) { + Toast.makeText(this, "Please, choose and fill in shelf life or expiry date.", Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + if (dateOfProduction == "") { + Toast.makeText(this, "Please, choose date of production.", Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + + if (!expiryDateOverShelfLife!!) { + if (shelfLifeTextEdit.text.toString() != "") { + evaluateDateOfExpiry(shelfLifeTextEdit.text.toString().toInt()) + } + } else { + if (dateOfExpiry == "") { + Toast.makeText(this, "Please, choose date of expiry.", Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + } + + if (amountTextEdit.text.toString() == "") { + Toast.makeText(this, "Please, specify an amount of product.", Toast.LENGTH_SHORT).show() + return@setOnClickListener + } + + val abstractProduct = DBStorageController(this).findAbstractProductByBarcode(DBStorageController(this).readableDatabase, barcode) + product = Product(0, abstractProduct!!.id, amountTextEdit.text.toString().toInt(), dateOfProduction, dateOfExpiry) + + DBStorageController(this).insertNewProduct(DBStorageController(this).writableDatabase, product!!) + finish() + } + } + + fun evaluateDateOfExpiry(shelfLifeMonths: Int) { + if (dateOfProduction == "" ) { + return + } + val c = Calendar.getInstance() + val dateOfProductionSplit = dateOfProduction.split(".") + c.set(Calendar.YEAR, dateOfProductionSplit[0].toInt()) + c.set(Calendar.MONTH, dateOfProductionSplit[1].toInt()) + c.set(Calendar.DAY_OF_MONTH, dateOfProductionSplit[2].toInt()) + + c.add(Calendar.MONTH, shelfLifeMonths) + dateOfExpiry = "${c.get(Calendar.YEAR)}.${c.get(Calendar.MONTH)}.${c.get(Calendar.DAY_OF_MONTH)}" } fun findAndDisplayAbstractProductByBarcode(barcode: String) { diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/dataclasses/Product.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/dataclasses/Product.kt index 9d38f04..4b97f0d 100644 --- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/dataclasses/Product.kt +++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/dataclasses/Product.kt @@ -4,23 +4,34 @@ import android.os.Parcel import android.os.Parcelable class Product() : Parcelable { + var id = 0 var abstractProductId = 0 var amount = 0 + var dateOfProduction = "01.01.1970" + var dateOfExpiry = "01.01.1970" - - constructor(abstractProductId: Int, amount: Int) : this() { + 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 } constructor(parcel: Parcel) : this() { + id = parcel.readInt() abstractProductId = parcel.readInt() amount = parcel.readInt() + dateOfProduction = parcel.readString()!! + dateOfExpiry = parcel.readString()!! } override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(id) parcel.writeInt(abstractProductId) parcel.writeInt(amount) + parcel.writeString(dateOfProduction) + parcel.writeString(dateOfExpiry) } override fun describeContents(): Int { @@ -36,5 +47,4 @@ class Product() : Parcelable { return arrayOfNulls(size) } } - } \ No newline at end of file diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/fragments/ShelfFragment.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/fragments/ShelfFragment.kt index a6e9c92..979bf6a 100644 --- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/fragments/ShelfFragment.kt +++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/fragments/ShelfFragment.kt @@ -1,17 +1,71 @@ package org.foxarmy.barcodescannerforemployees.fragments import android.os.Bundle +import android.provider.BaseColumns import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.gridlayout.widget.GridLayout +import org.foxarmy.barcodescannerforemployees.DBStorageController +import org.foxarmy.barcodescannerforemployees.ProductContract import org.foxarmy.barcodescannerforemployees.R +import org.foxarmy.barcodescannerforemployees.dataclasses.Product +import org.foxarmy.barcodescannerforemployees.views.ProductView class ShelfFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { + return inflater.inflate(R.layout.fragment_shelf, container, false) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + updateContent() + } + + override fun onResume() { + super.onResume() + + updateContent() + } + + fun updateContent() { + val grv = view?.findViewById(R.id.contentGridLayout) + grv?.removeAllViews() + + val db = DBStorageController(requireContext()).readableDatabase + val projection = arrayOf( + BaseColumns._ID, + ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, + ProductContract.ProductEntry.AMOUNT, + ProductContract.ProductEntry.DATE_OF_PRODUCTION, + ProductContract.ProductEntry.EXPIRY_DATE, + ) + + val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, null, null, null, null, null) + + with (cursor) { + while(moveToNext()) { + val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) + val abstractProductId = getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID)) + val amount = getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.AMOUNT)) + val dateOfProduction = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.DATE_OF_PRODUCTION)) + val dateOfExpiry = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.EXPIRY_DATE)) + + val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry) + + val productView = ProductView( + requireActivity(), + requireContext(), + product + ) + grv?.addView(productView) + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/views/ProductView.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/views/ProductView.kt new file mode 100644 index 0000000..ffafb0e --- /dev/null +++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/views/ProductView.kt @@ -0,0 +1,78 @@ +package org.foxarmy.barcodescannerforemployees.views + +import android.app.Activity +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import org.foxarmy.barcodescannerforemployees.DBStorageController +import org.foxarmy.barcodescannerforemployees.R +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 + +class ProductView: LinearLayout { + var product: Product = Product() + var isProductSelected = false + private lateinit var activity: Activity + + private lateinit var productImageView: ImageView + private lateinit var productNameTextView: TextView + private lateinit var productNetWeightTextView: TextView + private lateinit var productAmountTextView: TextView + private lateinit var productCategoryView: TextView + private lateinit var productLifeSpan: TextView + + constructor(context: Context, a: AttributeSet) : super(context, a) { + activity = getActivity(context)!! + val inflater: LayoutInflater = activity.layoutInflater + inflater.inflate(R.layout.product_view, this) + } + + constructor(activity: Activity, context: Context, product: Product) : super(context) { + this.product = product + this.activity = activity + val inflater: LayoutInflater = activity.layoutInflater + inflater.inflate(R.layout.product_view, this) + + productImageView = findViewById(R.id.productPicture) + productNameTextView = findViewById(R.id.productNameView) + productNetWeightTextView = findViewById(R.id.productNetWeightView) + productAmountTextView = findViewById(R.id.amountView) + productCategoryView = findViewById(R.id.categoryView) + productLifeSpan = findViewById(R.id.dateSpan) + + update() + } + + fun update () { + val linkedAbstractProduct: AbstractProduct = DBStorageController(activity).findAbstractProductById(DBStorageController(activity).readableDatabase, product.abstractProductId)!! + + val picturesDir = File(activity.filesDir, "pictures") + picturesDir.mkdirs() + val pictureFile = File(picturesDir, "${linkedAbstractProduct.imageHash}.png") + val imageUri = getImageUri(activity, pictureFile) + productImageView.setImageURI(imageUri) + + productNameTextView.text = linkedAbstractProduct.name + productNetWeightTextView.text = linkedAbstractProduct.netWeight.toString() + productAmountTextView.text = product.amount.toString() + productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category) + productLifeSpan.text = "${product.dateOfProduction}-${product.dateOfExpiry}" + + this.background = ContextCompat.getDrawable(context, if (isProductSelected) R.drawable.outline_selected else R.drawable.outline) + + + findViewById(R.id.productLayout).setOnLongClickListener { + isProductSelected = !isProductSelected + this.background = ContextCompat.getDrawable(context, if (isProductSelected) R.drawable.outline_selected else R.drawable.outline) + true + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_add_product.xml b/app/src/main/res/layout/fragment_add_product.xml index 03009c9..ae9f7b4 100644 --- a/app/src/main/res/layout/fragment_add_product.xml +++ b/app/src/main/res/layout/fragment_add_product.xml @@ -32,24 +32,72 @@