some refactor, renaming, started working with product on shelf
This commit is contained in:
		@@ -31,6 +31,10 @@
 | 
			
		||||
                android:name=".activities.AddProductActivity"
 | 
			
		||||
                android:exported="false"
 | 
			
		||||
                android:theme="@style/Theme.BarcodeScannerForEmployees"/>
 | 
			
		||||
        <activity
 | 
			
		||||
                android:name=".activities.AddAbstractProductActivity"
 | 
			
		||||
                android:exported="false"
 | 
			
		||||
                android:theme="@style/Theme.BarcodeScannerForEmployees"/>
 | 
			
		||||
        <activity
 | 
			
		||||
                android:name=".activities.FullscreenActivity"
 | 
			
		||||
                android:configChanges="orientation|keyboardHidden|screenSize"
 | 
			
		||||
@@ -40,7 +44,7 @@
 | 
			
		||||
 | 
			
		||||
        <provider
 | 
			
		||||
                android:name="androidx.core.content.FileProvider"
 | 
			
		||||
                android:authorities="com.google.firebase.components.activities.MainActivity.provider;com.google.firebase.components.activities.FullscreenActivity.provider;com.google.firebase.components.activities.AddProductActivity.provider"
 | 
			
		||||
                android:authorities="com.google.firebase.components.activities.MainActivity.provider;com.google.firebase.components.activities.FullscreenActivity.provider;com.google.firebase.components.activities.AddAbstractProductActivity.provider"
 | 
			
		||||
                android:exported="false"
 | 
			
		||||
                android:grantUriPermissions="true">
 | 
			
		||||
            <meta-data
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees
 | 
			
		||||
 | 
			
		||||
class Category(
 | 
			
		||||
    public var id: Int,
 | 
			
		||||
    public var name: String,
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -5,11 +5,12 @@ 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 java.io.File
 | 
			
		||||
 | 
			
		||||
object ProductContract {
 | 
			
		||||
    object ProductEntry : BaseColumns {
 | 
			
		||||
        const val TABLE_NAME = "products"
 | 
			
		||||
object AbstractProductContract {
 | 
			
		||||
    object AbstractProductEntry : BaseColumns {
 | 
			
		||||
        const val TABLE_NAME = "abstract_products"
 | 
			
		||||
        const val PRODUCT_NAME = "name"
 | 
			
		||||
        const val PRODUCT_NET_WEIGHT = "net_weight"
 | 
			
		||||
        const val IMAGE_FILENAME = "image_filename"
 | 
			
		||||
@@ -17,14 +18,6 @@ object ProductContract {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object ShelfContract {
 | 
			
		||||
    object ShelfEntry : BaseColumns {
 | 
			
		||||
        const val TABLE_NAME = "shelf"
 | 
			
		||||
        const val PRODUCT_ID = "product_id"
 | 
			
		||||
        const val EXPIRE_DATE = "expire_date"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
object CategoriesContract {
 | 
			
		||||
    object CategoryEntry : BaseColumns {
 | 
			
		||||
        const val TABLE_NAME = "categories"
 | 
			
		||||
@@ -32,19 +25,31 @@ object CategoriesContract {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const val SQL_CREATE_PRODUCT_TABLE =
 | 
			
		||||
    "CREATE TABLE ${ProductContract.ProductEntry.TABLE_NAME} (" +
 | 
			
		||||
            "${BaseColumns._ID} INTEGER PRIMARY KEY," +
 | 
			
		||||
            "${ProductContract.ProductEntry.PRODUCT_NAME} TEXT," +
 | 
			
		||||
            "${ProductContract.ProductEntry.PRODUCT_NET_WEIGHT} REAL," +
 | 
			
		||||
            "${ProductContract.ProductEntry.IMAGE_FILENAME} TEXT," +
 | 
			
		||||
            "${ProductContract.ProductEntry.CATEGORY} INTEGER)"
 | 
			
		||||
object ProductContract {
 | 
			
		||||
    object ProductEntry : BaseColumns {
 | 
			
		||||
        const val TABLE_NAME = "products"
 | 
			
		||||
        const val ABSTRACT_PRODUCT_ID = "abstract_product_id"
 | 
			
		||||
        const val AMOUNT = "amount"
 | 
			
		||||
        const val DATE_OF_PRODUCTION = "date_of_production"
 | 
			
		||||
        const val EXPIRY_DATE = "expiry_date"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const val SQL_CREATE_SHELF_TABLE =
 | 
			
		||||
    "CREATE TABLE ${ShelfContract.ShelfEntry.TABLE_NAME} (" +
 | 
			
		||||
const val SQL_CREATE_ABSTRACT_PRODUCTS_TABLE =
 | 
			
		||||
    "CREATE TABLE ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} (" +
 | 
			
		||||
            "${BaseColumns._ID} INTEGER PRIMARY KEY," +
 | 
			
		||||
            "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} TEXT," +
 | 
			
		||||
            "${AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT} REAL," +
 | 
			
		||||
            "${AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME} TEXT," +
 | 
			
		||||
            "${AbstractProductContract.AbstractProductEntry.CATEGORY} INTEGER)"
 | 
			
		||||
 | 
			
		||||
const val SQL_CREATE_PRODUCTS_TABLE =
 | 
			
		||||
    "CREATE TABLE ${ProductContract.ProductEntry.TABLE_NAME} (" +
 | 
			
		||||
        "${BaseColumns._ID} INTEGER PRIMARY KEY," +
 | 
			
		||||
        "${ShelfContract.ShelfEntry.PRODUCT_ID} INTEGER," +
 | 
			
		||||
        "${ShelfContract.ShelfEntry.EXPIRE_DATE} DATE)"
 | 
			
		||||
        "${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID} INTEGER," +
 | 
			
		||||
        "${ProductContract.ProductEntry.AMOUNT} INTEGER," +
 | 
			
		||||
        "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} DATE," +
 | 
			
		||||
        "${ProductContract.ProductEntry.EXPIRY_DATE} DATE)"
 | 
			
		||||
 | 
			
		||||
const val SQL_CREATE_CATEGORIES_TABLE =
 | 
			
		||||
    "CREATE TABLE ${CategoriesContract.CategoryEntry.TABLE_NAME} (" +
 | 
			
		||||
@@ -54,8 +59,8 @@ const val SQL_CREATE_CATEGORIES_TABLE =
 | 
			
		||||
class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(db: SQLiteDatabase) {
 | 
			
		||||
        db.execSQL(SQL_CREATE_PRODUCT_TABLE)
 | 
			
		||||
        db.execSQL(SQL_CREATE_SHELF_TABLE)
 | 
			
		||||
        db.execSQL(SQL_CREATE_ABSTRACT_PRODUCTS_TABLE)
 | 
			
		||||
        db.execSQL(SQL_CREATE_PRODUCTS_TABLE)
 | 
			
		||||
        db.execSQL(SQL_CREATE_CATEGORIES_TABLE)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -96,22 +101,22 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
 | 
			
		||||
        var result = mutableListOf<AbstractProduct>()
 | 
			
		||||
        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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<String>(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()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
@@ -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<Button>(R.id.saveButton).setOnClickListener {
 | 
			
		||||
            val db = DBStorageController(this).writableDatabase
 | 
			
		||||
 | 
			
		||||
            if (categoryId == 0) { // Inserting new category
 | 
			
		||||
            if (category.id == 0) { // Inserting new category
 | 
			
		||||
                val values = ContentValues().apply {
 | 
			
		||||
                    put(CategoriesContract.CategoryEntry.CATEGORY_NAME, categoryNameTextEdit.text.toString())
 | 
			
		||||
                }
 | 
			
		||||
@@ -37,7 +37,7 @@ class AddCategoryActivity : Activity() {
 | 
			
		||||
                val values = ContentValues().apply {
 | 
			
		||||
                    put(CategoriesContract.CategoryEntry.CATEGORY_NAME, categoryNameTextEdit.text.toString())
 | 
			
		||||
                }
 | 
			
		||||
                db.update(CategoriesContract.CategoryEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(categoryId.toString()))
 | 
			
		||||
                db.update(CategoriesContract.CategoryEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(category.id.toString()))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            finish()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,200 +1,18 @@
 | 
			
		||||
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.databinding.ActivityAddProductBinding
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.nio.file.Files
 | 
			
		||||
import java.nio.file.StandardCopyOption
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
			
		||||
 | 
			
		||||
class AddProductActivity : 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 product: AbstractProduct? = null
 | 
			
		||||
    private lateinit var pictureFile: File
 | 
			
		||||
    private lateinit var picturesPath: File
 | 
			
		||||
    private lateinit var binding: ActivityAddProductBinding
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
        setContentView(R.layout.fragment_add_product)
 | 
			
		||||
        setContentView(R.layout.activity_add_product)
 | 
			
		||||
 | 
			
		||||
        val extras = intent.extras
 | 
			
		||||
        product = extras!!.get("updatingObject") 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 (product != null) {
 | 
			
		||||
            val imageThumbnailUri = getImageUri(this, File(thumbnailsDir, "${product!!.imageHash}.webp"))
 | 
			
		||||
            pictureFile = File(picturesPath, "${product!!.imageHash}.png]")
 | 
			
		||||
            imageView.setImageURI(imageThumbnailUri)
 | 
			
		||||
            imageView.rotation = 90f
 | 
			
		||||
            productNameText.text = product!!.name
 | 
			
		||||
            netWeightText.text = product!!.netWeight.toString()
 | 
			
		||||
            categorySpinner.setSelection(product!!.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(ProductContract.ProductEntry.PRODUCT_NAME, productName)
 | 
			
		||||
                put(ProductContract.ProductEntry.PRODUCT_NET_WEIGHT, netWeight.toString())
 | 
			
		||||
                put(ProductContract.ProductEntry.IMAGE_FILENAME, pictureFile.nameWithoutExtension)
 | 
			
		||||
                put(ProductContract.ProductEntry.CATEGORY, categorySpinner.selectedItemPosition)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (product == null) {
 | 
			
		||||
                db.insert(ProductContract.ProductEntry.TABLE_NAME, null, values)
 | 
			
		||||
            } else {
 | 
			
		||||
                db.update(ProductContract.ProductEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(product!!.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()
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
//        binding = ActivityAddProductBinding.inflate(layoutInflater)
 | 
			
		||||
 | 
			
		||||
//        setContentView(binding.root)
 | 
			
		||||
        val product = extras!!.get("product") as Product?
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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<String>(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()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,7 +12,9 @@ import androidx.viewpager.widget.ViewPager
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment
 | 
			
		||||
 | 
			
		||||
class MainActivity : AppCompatActivity() {
 | 
			
		||||
@@ -36,25 +38,34 @@ class MainActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
            when (fragment::class.simpleName.toString()) {
 | 
			
		||||
                "StorageFragment" -> {
 | 
			
		||||
                    val addProductIntent = Intent(this, AddProductActivity::class.java)
 | 
			
		||||
                    val addAbstractProductIntent = Intent(this, AddAbstractProductActivity::class.java)
 | 
			
		||||
                    val extras = Bundle()
 | 
			
		||||
                    // I reuse the same stuff for editing and adding new product.
 | 
			
		||||
                    // if updatingObject == null, it means that we need to create new object
 | 
			
		||||
                    extras.putParcelable("updatingObject", null)
 | 
			
		||||
                    addProductIntent.putExtras(extras)
 | 
			
		||||
                    ContextCompat.startActivity(this, addProductIntent, extras)
 | 
			
		||||
                    // if abstractProduct == null, it means that we need to create new object
 | 
			
		||||
                    extras.putParcelable("abstractProduct", null)
 | 
			
		||||
                    addAbstractProductIntent.putExtras(extras)
 | 
			
		||||
                    ContextCompat.startActivity(this, addAbstractProductIntent, extras)
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                "CategoriesFragment" -> {
 | 
			
		||||
                    val addCategoryIntent = Intent(this, AddCategoryActivity::class.java)
 | 
			
		||||
                    val extras = Bundle()
 | 
			
		||||
                    extras.putInt("categoryid", 0)
 | 
			
		||||
                    extras.putString("categoryname", "New category")
 | 
			
		||||
                    //TODO: Implement parcellable for Category class to simplify this
 | 
			
		||||
//                    extras.putInt("categoryid", 0)
 | 
			
		||||
//                    extras.putString("categoryname", "New category")
 | 
			
		||||
                    extras.putParcelable("category", Category(0, "New category"))
 | 
			
		||||
                    addCategoryIntent.putExtras(extras)
 | 
			
		||||
                    ContextCompat.startActivity(this, addCategoryIntent, extras)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
                "ShelfFragment" -> {
 | 
			
		||||
                    val addProductIntent = Intent(this, AddProductActivity::class.java)
 | 
			
		||||
                    val extras = Bundle()
 | 
			
		||||
                    extras.putParcelable("product", null)
 | 
			
		||||
                    addProductIntent.putExtras(extras)
 | 
			
		||||
                    ContextCompat.startActivity(this, addProductIntent, extras)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -63,7 +74,8 @@ class MainActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        adapter.addFragment(CategoriesFragment(), "Categories")
 | 
			
		||||
        adapter.addFragment(StorageFragment(), "Storage")
 | 
			
		||||
        //TODO: shelf and settings fragments
 | 
			
		||||
        adapter.addFragment(ShelfFragment(), "Shelf")
 | 
			
		||||
        //TODO: settings fragments
 | 
			
		||||
 | 
			
		||||
        // setting adapter to view pager.
 | 
			
		||||
        viewpager.setAdapter(adapter)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.dataclasses
 | 
			
		||||
 | 
			
		||||
import android.os.Parcel
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.dataclasses
 | 
			
		||||
 | 
			
		||||
import android.os.Parcel
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
 | 
			
		||||
class Category() : Parcelable {
 | 
			
		||||
    var id = 0
 | 
			
		||||
    var name = ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    constructor(id: Int, name: String) : this() {
 | 
			
		||||
        this.id = id
 | 
			
		||||
        this.name = name
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(parcel: Parcel) : this() {
 | 
			
		||||
        id = parcel.readInt()
 | 
			
		||||
        name = parcel.readString()!!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
			
		||||
        parcel.writeInt(id)
 | 
			
		||||
        parcel.writeString(name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun describeContents(): Int {
 | 
			
		||||
        return 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object CREATOR : Parcelable.Creator<Category> {
 | 
			
		||||
        override fun createFromParcel(parcel: Parcel): Category {
 | 
			
		||||
            return Category(parcel)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun newArray(size: Int): Array<Category?> {
 | 
			
		||||
            return arrayOfNulls(size)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.dataclasses
 | 
			
		||||
 | 
			
		||||
import android.os.Parcel
 | 
			
		||||
import android.os.Parcelable
 | 
			
		||||
 | 
			
		||||
class Product() : Parcelable {
 | 
			
		||||
    var abstractProductId = 0
 | 
			
		||||
    var amount = 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    constructor(abstractProductId: Int, amount: Int) : this() {
 | 
			
		||||
        this.abstractProductId = abstractProductId
 | 
			
		||||
        this.amount = amount
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    constructor(parcel: Parcel) : this() {
 | 
			
		||||
        abstractProductId = parcel.readInt()
 | 
			
		||||
        amount = parcel.readInt()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
			
		||||
        parcel.writeInt(abstractProductId)
 | 
			
		||||
        parcel.writeInt(amount)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun describeContents(): Int {
 | 
			
		||||
        return 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object CREATOR : Parcelable.Creator<Product> {
 | 
			
		||||
        override fun createFromParcel(parcel: Parcel): Product {
 | 
			
		||||
            return Product(parcel)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        override fun newArray(size: Int): Array<Product?> {
 | 
			
		||||
            return arrayOfNulls(size)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.fragments
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.databinding.FragmentAddAbstractProductBinding
 | 
			
		||||
 | 
			
		||||
class AddAbstractProductFragment : Fragment() {
 | 
			
		||||
    private lateinit var binding: FragmentAddAbstractProductBinding
 | 
			
		||||
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
			
		||||
        savedInstanceState: Bundle?
 | 
			
		||||
    ): View {
 | 
			
		||||
        binding = FragmentAddAbstractProductBinding.inflate(layoutInflater)
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_add_abstract_product, container, false)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,7 +12,7 @@ import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.view.children
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.CategoriesContract
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity
 | 
			
		||||
@@ -56,8 +56,7 @@ class CategoriesFragment : Fragment() {
 | 
			
		||||
            if (view.isCategorySelected) {
 | 
			
		||||
                val addCategoryIntent = Intent(context, AddCategoryActivity::class.java)
 | 
			
		||||
                val extras = Bundle()
 | 
			
		||||
                extras.putInt("categoryid", view.category.id)
 | 
			
		||||
                extras.putString("categoryname", view.category.name)
 | 
			
		||||
                extras.putParcelable("category", view.category)
 | 
			
		||||
                addCategoryIntent.putExtras(extras)
 | 
			
		||||
                ContextCompat.startActivity(context!!, addCategoryIntent, extras)
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
package org.foxarmy.barcodescannerforemployees.fragments
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
 | 
			
		||||
class ShelfFragment : Fragment() {
 | 
			
		||||
    override fun onCreateView(
 | 
			
		||||
        inflater: LayoutInflater, container: ViewGroup?,
 | 
			
		||||
        savedInstanceState: Bundle?
 | 
			
		||||
    ): View? {
 | 
			
		||||
        return inflater.inflate(R.layout.fragment_shelf, container, false)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,8 +12,12 @@ import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.view.children
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
import androidx.gridlayout.widget.GridLayout
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.*
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.AddProductActivity
 | 
			
		||||
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.dataclasses.AbstractProduct
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.generateThumbnailForImage
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.views.AbstractProductView
 | 
			
		||||
 | 
			
		||||
class StorageFragment : Fragment() {
 | 
			
		||||
@@ -39,7 +43,7 @@ class StorageFragment : Fragment() {
 | 
			
		||||
        for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
            view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
 | 
			
		||||
            if (view.isProductSelected) {
 | 
			
		||||
                db.eraseAbstractProduct(db.writableDatabase, view.product.id, requireContext())
 | 
			
		||||
                db.eraseAbstractProduct(db.writableDatabase, view.abstractProduct.id, requireContext())
 | 
			
		||||
                deleted = true
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -55,9 +59,9 @@ class StorageFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
        for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
 | 
			
		||||
            if (view.isProductSelected) {
 | 
			
		||||
                val addProductIntent = Intent(requireContext(), AddProductActivity::class.java)
 | 
			
		||||
                val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
 | 
			
		||||
                val extras = Bundle()
 | 
			
		||||
                extras.putParcelable("updatingObject", view.product)
 | 
			
		||||
                extras.putParcelable("abstractProduct", view.abstractProduct)
 | 
			
		||||
                addProductIntent.putExtras(extras)
 | 
			
		||||
                ContextCompat.startActivity(requireContext(), addProductIntent, extras)
 | 
			
		||||
            }
 | 
			
		||||
@@ -72,21 +76,21 @@ class StorageFragment : Fragment() {
 | 
			
		||||
 | 
			
		||||
        val db = DBStorageController(requireContext()).readableDatabase
 | 
			
		||||
        val projection = arrayOf(BaseColumns._ID,
 | 
			
		||||
            ProductContract.ProductEntry.PRODUCT_NAME,
 | 
			
		||||
            ProductContract.ProductEntry.PRODUCT_NET_WEIGHT,
 | 
			
		||||
            ProductContract.ProductEntry.IMAGE_FILENAME,
 | 
			
		||||
            ProductContract.ProductEntry.CATEGORY
 | 
			
		||||
            AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
 | 
			
		||||
            AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
 | 
			
		||||
            AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
 | 
			
		||||
            AbstractProductContract.AbstractProductEntry.CATEGORY
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, null, null, null, null, null)
 | 
			
		||||
        val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, null, null, null, null, null)
 | 
			
		||||
 | 
			
		||||
        with (cursor) {
 | 
			
		||||
            while(moveToNext()) {
 | 
			
		||||
                val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
 | 
			
		||||
                val productName = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NAME))
 | 
			
		||||
                val netWeight = getDouble(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NET_WEIGHT))
 | 
			
		||||
                val productImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME))
 | 
			
		||||
                val category = getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.CATEGORY))
 | 
			
		||||
                val productName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
 | 
			
		||||
                val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
 | 
			
		||||
                val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
 | 
			
		||||
                val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY))
 | 
			
		||||
 | 
			
		||||
                val product = AbstractProduct(productId, productName, netWeight, productImageHash, category)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ import android.widget.TextView
 | 
			
		||||
import androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.content.ContextCompat.startActivity
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.AbstractProduct
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
 | 
			
		||||
@@ -25,12 +25,12 @@ class AbstractProductView: LinearLayout {
 | 
			
		||||
    private var netWeightField: TextView
 | 
			
		||||
    private var categoryField: TextView
 | 
			
		||||
    private var unitField: TextView
 | 
			
		||||
    var product: AbstractProduct
 | 
			
		||||
    var abstractProduct: AbstractProduct
 | 
			
		||||
    var isProductSelected = false
 | 
			
		||||
 | 
			
		||||
    constructor(activity: Activity, context: Context, product: AbstractProduct) : super(context) {
 | 
			
		||||
    constructor(activity: Activity, context: Context, abstractProduct: AbstractProduct) : super(context) {
 | 
			
		||||
 | 
			
		||||
        this.product = product
 | 
			
		||||
        this.abstractProduct = abstractProduct
 | 
			
		||||
 | 
			
		||||
        val inflater:LayoutInflater = activity.layoutInflater
 | 
			
		||||
        inflater.inflate(R.layout.abstract_product_view, this)
 | 
			
		||||
@@ -44,13 +44,13 @@ class AbstractProductView: LinearLayout {
 | 
			
		||||
 | 
			
		||||
        val thumbnailsDir = File(context.cacheDir, "thumbnails")
 | 
			
		||||
        thumbnailsDir.mkdirs()
 | 
			
		||||
        val imageUri = getImageUri(activity, File(thumbnailsDir, "${product.imageHash}.webp"))
 | 
			
		||||
        val imageUri = getImageUri(activity, File(thumbnailsDir, "${abstractProduct.imageHash}.webp"))
 | 
			
		||||
        productPicture.setImageURI(imageUri)
 | 
			
		||||
        productPicture.rotation = 90f
 | 
			
		||||
        productPicture.setOnClickListener {
 | 
			
		||||
            val fullscreenIntent = Intent(activity, FullscreenActivity::class.java)
 | 
			
		||||
            val extras = Bundle()
 | 
			
		||||
            extras.putString("imagehash", product.imageHash)
 | 
			
		||||
            extras.putString("imagehash", abstractProduct.imageHash)
 | 
			
		||||
            fullscreenIntent.putExtras(extras)
 | 
			
		||||
            startActivity(context, fullscreenIntent, extras)
 | 
			
		||||
        }
 | 
			
		||||
@@ -61,9 +61,9 @@ class AbstractProductView: LinearLayout {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        productNameField.text = product.name
 | 
			
		||||
        netWeightField.text = product.netWeight.toString()
 | 
			
		||||
        categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, product.category)
 | 
			
		||||
        productNameField.text = abstractProduct.name
 | 
			
		||||
        netWeightField.text = abstractProduct.netWeight.toString()
 | 
			
		||||
        categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, abstractProduct.category)
 | 
			
		||||
 | 
			
		||||
        //TODO: units
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import android.view.LayoutInflater
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.DBStorageController
 | 
			
		||||
import org.foxarmy.barcodescannerforemployees.R
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								app/src/main/res/layout/activity_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/layout/activity_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.core.widget.NestedScrollView
 | 
			
		||||
        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="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".fragments.AddAbstractProductFragment">
 | 
			
		||||
    <include layout="@layout/content_add_abstract_product" android:id="@+id/include_content"/>
 | 
			
		||||
</androidx.core.widget.NestedScrollView>
 | 
			
		||||
							
								
								
									
										14
									
								
								app/src/main/res/layout/content_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/src/main/res/layout/content_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
        xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
        xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/addAbstractProductLayout">
 | 
			
		||||
 | 
			
		||||
        <androidx.fragment.app.FragmentContainerView
 | 
			
		||||
                android:name="androidx.navigation.fragment.NavHostFragment"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent" app:navGraph="@navigation/nav_graph_add_abstract_product"
 | 
			
		||||
                app:defaultNavHost="true" android:id="@+id/fragmentContainerView"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
@@ -6,9 +6,9 @@
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/addProductLayout">
 | 
			
		||||
 | 
			
		||||
    <androidx.fragment.app.FragmentContainerView
 | 
			
		||||
            android:name="androidx.navigation.fragment.NavHostFragment"
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
            android:layout_height="match_parent" app:navGraph="@navigation/nav_graph_add_product"
 | 
			
		||||
            app:defaultNavHost="true" android:id="@+id/fragmentContainerView"/>
 | 
			
		||||
        <androidx.fragment.app.FragmentContainerView
 | 
			
		||||
                android:name="androidx.navigation.fragment.NavHostFragment"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent" app:navGraph="@navigation/nav_graph_add_product"
 | 
			
		||||
                app:defaultNavHost="true" android:id="@+id/fragmentContainerView"/>
 | 
			
		||||
</androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
							
								
								
									
										83
									
								
								app/src/main/res/layout/fragment_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								app/src/main/res/layout/fragment_add_abstract_product.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<androidx.core.widget.NestedScrollView
 | 
			
		||||
        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="match_parent"
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        tools:context=".fragments.AddAbstractProductFragment">
 | 
			
		||||
    <androidx.constraintlayout.widget.ConstraintLayout
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:padding="16dp">
 | 
			
		||||
        <Button
 | 
			
		||||
                android:id="@+id/scan_button"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:text="@string/scan_label"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp"/>
 | 
			
		||||
        <ImageView
 | 
			
		||||
                android:src="@android:drawable/ic_menu_camera"
 | 
			
		||||
                android:layout_width="356dp"
 | 
			
		||||
                android:layout_height="303dp" android:id="@+id/imageView"
 | 
			
		||||
                android:layout_marginBottom="25dp"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@+id/productName" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                android:layout_marginTop="15dp"/>
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:layout_width="350dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                android:ems="10"
 | 
			
		||||
                android:id="@+id/productName"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp" android:layout_marginEnd="8dp"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@+id/netWeight"
 | 
			
		||||
                app:layout_constraintHorizontal_bias="0.5"
 | 
			
		||||
                android:visibility="visible" android:hint="@string/product_name_label" android:textColorHint="#737373"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/imageView"/>
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:layout_width="350dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                android:ems="10"
 | 
			
		||||
                android:id="@+id/netWeight"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp"
 | 
			
		||||
                android:layout_marginEnd="8dp"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
                android:visibility="visible" android:hint="@string/netWeight" android:textColorHint="#737373"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/productName"/>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="@string/category"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/categoryTextView"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/netWeight"
 | 
			
		||||
                android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp"/>
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/categorySpinner"
 | 
			
		||||
                app:layout_constraintStart_toEndOf="@+id/categoryTextView"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/netWeight" android:layout_marginStart="8dp"
 | 
			
		||||
                android:layout_marginTop="20dp"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="@string/saveButton"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="50dp" android:id="@+id/saveButton"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp" app:layout_constraintEnd_toEndOf="parent"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="@string/takePicture"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="55dp" android:id="@+id/takePictureButton"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp" app:layout_constraintStart_toEndOf="@+id/scan_button"
 | 
			
		||||
                android:layout_marginStart="33dp" app:layout_constraintEnd_toStartOf="@+id/saveButton"
 | 
			
		||||
                android:layout_marginEnd="6dp" app:layout_constraintHorizontal_bias="0.0"/>
 | 
			
		||||
 | 
			
		||||
    </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
</androidx.core.widget.NestedScrollView>
 | 
			
		||||
@@ -10,74 +10,11 @@
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:padding="16dp">
 | 
			
		||||
        <Button
 | 
			
		||||
                android:id="@+id/scan_button"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:text="@string/scan_label"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp"/>
 | 
			
		||||
        <ImageView
 | 
			
		||||
                android:src="@android:drawable/ic_menu_camera"
 | 
			
		||||
                android:layout_width="356dp"
 | 
			
		||||
                android:layout_height="303dp" android:id="@+id/imageView"
 | 
			
		||||
                android:layout_marginBottom="25dp"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@+id/productName" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
 | 
			
		||||
                android:layout_marginTop="15dp"/>
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:layout_width="350dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                android:ems="10"
 | 
			
		||||
                android:id="@+id/productName"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp" android:layout_marginEnd="8dp"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
                app:layout_constraintBottom_toTopOf="@+id/netWeight"
 | 
			
		||||
                app:layout_constraintHorizontal_bias="0.5"
 | 
			
		||||
                android:visibility="visible" android:hint="@string/product_name_label" android:textColorHint="#737373"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/imageView"/>
 | 
			
		||||
        <EditText
 | 
			
		||||
                android:layout_width="350dp"
 | 
			
		||||
                android:layout_height="50dp"
 | 
			
		||||
                android:inputType="text"
 | 
			
		||||
                android:ems="10"
 | 
			
		||||
                android:id="@+id/netWeight"
 | 
			
		||||
                app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp"
 | 
			
		||||
                android:layout_marginEnd="8dp"
 | 
			
		||||
                app:layout_constraintEnd_toEndOf="parent"
 | 
			
		||||
                android:visibility="visible" android:hint="@string/netWeight" android:textColorHint="#737373"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/productName"/>
 | 
			
		||||
        <TextView
 | 
			
		||||
                android:text="@string/category"
 | 
			
		||||
                android:layout_width="wrap_content"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/categoryTextView"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/netWeight"
 | 
			
		||||
                android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
                android:layout_marginStart="8dp"/>
 | 
			
		||||
        <Spinner
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="wrap_content" android:id="@+id/categorySpinner"
 | 
			
		||||
                app:layout_constraintStart_toEndOf="@+id/categoryTextView"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/netWeight" android:layout_marginStart="8dp"
 | 
			
		||||
                android:layout_marginTop="20dp"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="@string/saveButton"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="50dp" android:id="@+id/saveButton"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp" app:layout_constraintEnd_toEndOf="parent"/>
 | 
			
		||||
        <Button
 | 
			
		||||
                android:text="@string/takePicture"
 | 
			
		||||
                android:layout_width="100dp"
 | 
			
		||||
                android:layout_height="55dp" android:id="@+id/takePictureButton"
 | 
			
		||||
                app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
 | 
			
		||||
                android:layout_marginTop="15dp" app:layout_constraintStart_toEndOf="@+id/scan_button"
 | 
			
		||||
                android:layout_marginStart="33dp" app:layout_constraintEnd_toStartOf="@+id/saveButton"
 | 
			
		||||
                android:layout_marginEnd="6dp" app:layout_constraintHorizontal_bias="0.0"/>
 | 
			
		||||
 | 
			
		||||
            android:layout_width="400dp"
 | 
			
		||||
            android:layout_height="50dp" android:id="@+id/abstractProductSelect"
 | 
			
		||||
            app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="12dp"
 | 
			
		||||
            app:layout_constraintStart_toStartOf="parent"
 | 
			
		||||
            app:layout_constraintEnd_toEndOf="parent"/>
 | 
			
		||||
    </androidx.constraintlayout.widget.ConstraintLayout>
 | 
			
		||||
</androidx.core.widget.NestedScrollView>
 | 
			
		||||
							
								
								
									
										6
									
								
								app/src/main/res/layout/fragment_shelf.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/res/layout/fragment_shelf.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
             android:layout_width="match_parent"
 | 
			
		||||
             android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
</FrameLayout>
 | 
			
		||||
							
								
								
									
										7
									
								
								app/src/main/res/layout/product_view.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/src/main/res/layout/product_view.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
              android:orientation="vertical"
 | 
			
		||||
              android:layout_width="match_parent"
 | 
			
		||||
              android:layout_height="match_parent">
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<navigation 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:id="@+id/nav_graph_add_abstract_product"
 | 
			
		||||
            app:startDestination="@id/addAbstractProductFragment">
 | 
			
		||||
 | 
			
		||||
    <fragment android:id="@+id/addAbstractProductFragment"
 | 
			
		||||
              android:name="org.foxarmy.barcodescannerforemployees.fragments.AddAbstractProductFragment"
 | 
			
		||||
              android:label="activity_add_abstract_product" tools:layout="@layout/fragment_add_abstract_product"/>
 | 
			
		||||
</navigation>
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
            android:id="@+id/nav_graph_add_product"
 | 
			
		||||
            app:startDestination="@id/addProductFragment">
 | 
			
		||||
 | 
			
		||||
    <fragment android:id="@+id/addProductFragment" android:name="org.foxarmy.barcodescannerforemployees.fragments.AddProductFragment"
 | 
			
		||||
              android:label="add_product_fragment" tools:layout="@layout/fragment_add_product"/>
 | 
			
		||||
    <fragment android:id="@+id/addProductFragment"
 | 
			
		||||
              android:name="org.foxarmy.barcodescannerforemployees.fragments.AddProductFragment"
 | 
			
		||||
              android:label="activity_add_product" tools:layout="@layout/fragment_add_product"/>
 | 
			
		||||
</navigation>
 | 
			
		||||
		Reference in New Issue
	
	Block a user