diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 6a97330..764c87e 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -46,6 +46,8 @@ dependencies {
implementation(libs.firebase.crashlytics.buildtools)
implementation(libs.androidx.gridlayout)
implementation(libs.androidx.activity)
+ implementation(libs.androidx.legacy.support.v4)
+ implementation(libs.androidx.fragment)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e8b3101..1dc263f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,6 +31,10 @@
android:name=".activities.AddProductActivity"
android:exported="false"
android:theme="@style/Theme.BarcodeScannerForEmployees"/>
+
()
val projection = arrayOf(
BaseColumns._ID,
- ProductContract.ProductEntry.PRODUCT_NAME,
- ProductContract.ProductEntry.IMAGE_FILENAME,
- ProductContract.ProductEntry.PRODUCT_NET_WEIGHT,
+ AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
+ AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
+ AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
)
- val selection = "${ProductContract.ProductEntry.CATEGORY} = ?"
+ val selection = "${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?"
val selectionArgs = arrayOf(id.toString())
- val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, null)
+ val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, null)
with(cursor) {
while (moveToNext()) {
val abstractProductId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
- val abstractProductName = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NAME))
- val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NET_WEIGHT))
- val abstractProductImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME))
+ val abstractProductName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
+ val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
+ val abstractProductImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
val abstractProduct = AbstractProduct(abstractProductId, abstractProductName, abstractProductNetWeight, abstractProductImageHash, category = id)
@@ -123,17 +128,17 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
}
fun getAmountOfAbstractProductsInCategory(db:SQLiteDatabase, id: Int) : Int {
- return DatabaseUtils.longForQuery(db, "SELECT COUNT(*) FROM ${ProductContract.ProductEntry.TABLE_NAME} WHERE ${ProductContract.ProductEntry.CATEGORY} = ?", arrayOf(id.toString())).toInt()
+ return DatabaseUtils.longForQuery(db, "SELECT COUNT(*) FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?", arrayOf(id.toString())).toInt()
}
fun eraseAbstractProduct(db: SQLiteDatabase, id: Int, context: Context) {
val projection = arrayOf(
- ProductContract.ProductEntry.IMAGE_FILENAME
+ AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME
)
val selection = "${BaseColumns._ID} = ?"
val selectionArgs = arrayOf(id.toString())
val cursor = db.query(
- ProductContract.ProductEntry.TABLE_NAME,
+ AbstractProductContract.AbstractProductEntry.TABLE_NAME,
projection,
selection,
selectionArgs,
@@ -145,7 +150,7 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
with (cursor) {
while(moveToNext()) {
- val productImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME))
+ val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
imageHash = productImageHash
}
}
@@ -154,7 +159,7 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
File(picturesDir, "$imageHash.png").delete()
File(thumbnailsDir, "$imageHash.webp").delete()
- db.delete(ProductContract.ProductEntry.TABLE_NAME, BaseColumns._ID + "=" + id, null)
+ db.delete(AbstractProductContract.AbstractProductEntry.TABLE_NAME, BaseColumns._ID + "=" + id, null)
}
companion object {
diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/Parser.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/Parser.kt
index 1d7958b..741d48c 100644
--- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/Parser.kt
+++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/Parser.kt
@@ -1,5 +1,7 @@
package org.foxarmy.barcodescannerforemployees
+import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
+
class Parser constructor(payloadStartRegex: String, payloadEndRegex: String, payloadRegex: String){
val payloadStartRegex: String = payloadStartRegex
val payloadEndRegex: String = payloadEndRegex
diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddAbstractProductActivity.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddAbstractProductActivity.kt
new file mode 100644
index 0000000..9b2dacb
--- /dev/null
+++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddAbstractProductActivity.kt
@@ -0,0 +1,194 @@
+package org.foxarmy.barcodescannerforemployees.activities
+
+import android.Manifest
+import android.content.ContentValues
+import android.os.Build
+import android.os.Bundle
+import android.provider.BaseColumns
+import android.util.Log
+import android.widget.*
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.RequiresApi
+import androidx.appcompat.app.AppCompatActivity
+import com.google.mlkit.vision.barcode.common.Barcode
+import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
+import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
+import org.foxarmy.barcodescannerforemployees.*
+import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.StandardCopyOption
+
+class AddAbstractProductActivity : AppCompatActivity() {
+ private lateinit var imageView: ImageView
+
+ private lateinit var saveButton: Button
+ private lateinit var takePictureButton: Button
+ private lateinit var scanButton: Button
+
+ private lateinit var productNameText: TextView
+ private lateinit var netWeightText: TextView
+
+ private lateinit var categorySpinner: Spinner
+
+ private var abstractProduct: AbstractProduct? = null
+ private lateinit var pictureFile: File
+ private lateinit var picturesPath: File
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContentView(R.layout.fragment_add_abstract_product)
+
+ val extras = intent.extras
+ abstractProduct = extras!!.get("abstractProduct") as AbstractProduct?
+
+ picturesPath = File(filesDir, "pictures")
+ val thumbnailsDir = File(cacheDir, "thumbnails")
+ thumbnailsDir.mkdirs()
+ picturesPath.mkdirs()
+ imageView = findViewById(R.id.imageView)
+
+ saveButton = findViewById(R.id.saveButton)
+ takePictureButton = findViewById(R.id.takePictureButton)
+ scanButton = findViewById(R.id.scan_button)
+
+ productNameText = findViewById(R.id.productName)
+ netWeightText = findViewById(R.id.netWeight)
+
+ categorySpinner = findViewById(R.id.categorySpinner)
+
+ fillupCategorySpinner()
+
+ if (abstractProduct != null) {
+ val imageThumbnailUri = getImageUri(this, File(thumbnailsDir, "${abstractProduct!!.imageHash}.webp"))
+ pictureFile = File(picturesPath, "${abstractProduct!!.imageHash}.png]")
+ imageView.setImageURI(imageThumbnailUri)
+ imageView.rotation = 90f
+ productNameText.text = abstractProduct!!.name
+ netWeightText.text = abstractProduct!!.netWeight.toString()
+ categorySpinner.setSelection(abstractProduct!!.category)
+ }
+
+ saveButton.setOnClickListener {
+ val productName = productNameText.text.toString()
+ val netWeight = netWeightText.text
+ if (!this::pictureFile.isInitialized && !pictureFile.exists()) {
+
+ Toast.makeText(this, "Please, make a picture of a product!", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+
+ if (productName == "") {
+ Toast.makeText(this, "Please, write a name of a product!", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+ if (netWeight.toString() == "" || netWeight.toString().toDoubleOrNull() == null) {
+ Toast.makeText(this, "Please, write a valid net weight of a product!", Toast.LENGTH_SHORT).show()
+ }
+
+ val db = DBStorageController(this).writableDatabase
+ val values = ContentValues().apply {
+ put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, productName)
+ put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, netWeight.toString())
+ put(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME, pictureFile.nameWithoutExtension)
+ put(AbstractProductContract.AbstractProductEntry.CATEGORY, categorySpinner.selectedItemPosition)
+ }
+
+ if (abstractProduct == null) {
+ db.insert(AbstractProductContract.AbstractProductEntry.TABLE_NAME, null, values)
+ } else {
+ db.update(AbstractProductContract.AbstractProductEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(abstractProduct!!.id.toString()))
+ }
+
+ finish()
+ }
+
+ takePictureButton.setOnClickListener {
+ requestPermissionLauncher.launch(Manifest.permission.CAMERA)
+ }
+
+ scanButton.setOnClickListener {
+ val options = GmsBarcodeScannerOptions.Builder()
+ .setBarcodeFormats(
+ Barcode.FORMAT_EAN_13
+ )
+ .build()
+ val scanner = GmsBarcodeScanning.getClient(this)
+ scanner.startScan()
+ .addOnSuccessListener { barcode ->
+ productNameText.setText(barcode.rawValue)
+ }
+ .addOnFailureListener { e ->
+ Toast.makeText(
+ this,
+ "Failed to scan barcode. Please, try again or enter data manually",
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
+ }
+
+ fun fillupCategorySpinner() {
+ val db = DBStorageController(this).readableDatabase
+
+ val categories = mutableListOf("")
+
+ val projection = arrayOf(
+ CategoriesContract.CategoryEntry.CATEGORY_NAME
+ )
+
+ val cursor = db.query(CategoriesContract.CategoryEntry.TABLE_NAME, projection, null, null, null, null, BaseColumns._ID+" ASC")
+
+ with (cursor) {
+ while (moveToNext()) {
+ categories.add(getString(getColumnIndexOrThrow(CategoriesContract.CategoryEntry.CATEGORY_NAME)))
+ }
+ }
+
+ val arrayAdapter = ArrayAdapter(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, categories)
+ arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
+ categorySpinner.adapter = arrayAdapter
+ }
+
+ @RequiresApi(Build.VERSION_CODES.R)
+ val takePicture = registerForActivityResult(ActivityResultContracts.TakePicture()) { success: Boolean ->
+ if (success) {
+ //Move picture to a proper directory according to its calculated hash
+ val tempfile = File(filesDir, "image.png")
+ val imageContent = tempfile.inputStream().readBytes()
+ val imageHash = imageContent.toString(Charsets.UTF_8).md5()
+
+ pictureFile = File(picturesPath, "$imageHash.png")
+ Files.move(tempfile.toPath(), pictureFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
+ tempfile.delete()
+ generateThumbnailForImage(this, imageHash)
+
+ imageView.setImageURI(getImageUri(this, pictureFile))
+ } else {
+ Log.e("QWERTYUIOP", "Cannot save a picture")
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.R)
+ fun getPicture () {
+ //Saving picture to a temp file for further hash calculation and moving to a proper directory
+ val imageFile = File(this.filesDir, "image.png")
+ val imageUri = getImageUri(this, imageFile)
+ if (imageUri != null) {
+ takePicture.launch(imageUri)
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.R)
+ val requestPermissionLauncher =
+ registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted: Boolean ->
+ if (isGranted) {
+ getPicture()
+ } else {
+ Toast.makeText(this, "I need permission in order to take a picture", Toast.LENGTH_LONG).show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddCategoryActivity.kt b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddCategoryActivity.kt
index 6f0827b..9c178d8 100644
--- a/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddCategoryActivity.kt
+++ b/app/src/main/java/org/foxarmy/barcodescannerforemployees/activities/AddCategoryActivity.kt
@@ -7,6 +7,7 @@ import android.provider.BaseColumns
import android.widget.Button
import android.widget.EditText
import org.foxarmy.barcodescannerforemployees.CategoriesContract
+import org.foxarmy.barcodescannerforemployees.dataclasses.Category
import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R
@@ -17,17 +18,16 @@ class AddCategoryActivity : Activity() {
setContentView(R.layout.activity_add_category)
val extras = intent.extras
- val categoryId = extras!!.get("categoryid") as Int?
- val categoryName = extras.get("categoryname") as String?
+ val category = extras!!.get("category") as Category?
val categoryNameTextEdit: EditText = findViewById(R.id.newCategoryName)
- categoryNameTextEdit.setText(categoryName)
+ categoryNameTextEdit.setText(category!!.name)
findViewById