10 Commits

Author SHA1 Message Date
3a0d8cbf7f added things my wife asked 2024-10-20 00:54:31 +03:00
54693ff15d remade scaling, fixed updating 2024-10-19 23:50:01 +03:00
6ce23c2081 handling non-existend abstract products 2024-10-19 23:09:50 +03:00
8a018903f0 translated app to russian 2024-10-19 19:25:39 +03:00
cba0e8594f fixed negative percents of freshness 2024-10-19 18:03:52 +03:00
244ef95a99 UI improvements 2024-10-19 18:02:08 +03:00
05f95ef30d removed google play's barcodescanner dependency 2024-10-19 17:54:22 +03:00
385a19a6ee update gitignore 2024-10-19 13:04:49 +03:00
d89d32a793 remove binaries from repo 2024-10-19 13:04:27 +03:00
dfe6fa9c3e fixed ignoring manual barcode typing 2024-10-18 17:35:48 +03:00
25 changed files with 459 additions and 177 deletions

2
.gitignore vendored
View File

@@ -146,3 +146,5 @@ dist
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
release

View File

@@ -32,7 +32,10 @@ android {
} }
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
buildConfig = true
} }
} }
dependencies { dependencies {
@@ -50,14 +53,14 @@ dependencies {
testImplementation(libs.junit) testImplementation(libs.junit)
implementation(libs.volley) implementation(libs.volley)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
implementation (libs.play.services.code.scanner) implementation(libs.zxing.android.embedded)
implementation("com.google.zxing:core:3.4.1")
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
// implementation("com.google.android.material:1.2.0")
// Barcode scanning API // Barcode scanning API
implementation (libs.barcode.scanning) implementation (libs.barcode.scanning)
// CameraX library
// CameraX library
implementation (libs.androidx.camera.camera2) implementation (libs.androidx.camera.camera2)
implementation (libs.androidx.camera.lifecycle) implementation (libs.androidx.camera.lifecycle)

View File

@@ -43,6 +43,10 @@
android:label="@string/title_activity_fullscreen" android:label="@string/title_activity_fullscreen"
android:theme="@style/Theme.BarcodeScannerForEmployees.Fullscreen"/> android:theme="@style/Theme.BarcodeScannerForEmployees.Fullscreen"/>
<activity android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="android:screenOrientation"/>
<provider <provider
android:name="androidx.core.content.FileProvider" 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.AddAbstractProductActivity.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;com.google.firebase.components.activities.AddProductActivity.provider"
@@ -53,11 +57,6 @@
android:resource="@xml/file_path"/> android:resource="@xml/file_path"/>
</provider> </provider>
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="barcode_ui">
</meta-data>
<activity <activity
android:name=".activities.MainActivity" android:name=".activities.MainActivity"
android:exported="true" android:exported="true"

View File

@@ -1,6 +1,5 @@
package org.foxarmy.barcodescannerforemployees package org.foxarmy.barcodescannerforemployees
import android.util.Log
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
class Parser constructor() { class Parser constructor() {
@@ -14,9 +13,6 @@ class Parser constructor() {
val found = foundByRegex.groupValues[0] val found = foundByRegex.groupValues[0]
text = text.replace(found, "") text = text.replace(found, "")
netWeight = stripNetWeight(found) netWeight = stripNetWeight(found)
// when (found.lowercase().strip()) {
// "кг" -> netWeight *= 1000
// "мл" -> netWeight /= 1000
// } // }
return Triple(text, netWeight, found) return Triple(text, netWeight, found)
} }
@@ -28,11 +24,11 @@ class Parser constructor() {
val (name, netWeight, unit) = findNetWeightInText( val (name, netWeight, unit) = findNetWeightInText(
text, text,
listOf( listOf(
Regex("[0-9]+,?[0-9]*\\s*[лЛ]"), Regex("\\d*[.,]?\\d+\\s*[лЛ]"),
Regex("[0-9]+,?[0-9]*\\s*((мл)|(МЛ)|(Мл))"), Regex("[0-9]+((,?)|(.?))+[0-9]*\\s*((мл)|(МЛ)|(Мл))"),
Regex("[0-9]+,?[0-9]*\\s*((кг)|(Кг))"), Regex("[0-9]+((,?)|(.?))+[0-9]*\\s*((кг)|(Кг))"),
Regex("[0-9]+,?[0-9]*\\s*[гГ]"), Regex("[0-9]+((,?)|(.?))+[0-9]*\\s*[гГ]"),
Regex("[0-9]+,?[0-9*]\\s*((шт)|(Шт))") Regex("\\d+\\s*(шт)|(Шт)")
) )
) )
var unitNumber = -1 var unitNumber = -1
@@ -46,7 +42,6 @@ class Parser constructor() {
else -> { -1 } else -> { -1 }
} }
Log.d("QWERTYUIOP", "Unit: ${strippedUnit}, number: ${unitNumber}")
return AbstractProduct(0, "", name, netWeight, "", 0, unitNumber) return AbstractProduct(0, "", name, netWeight, "", 0, unitNumber)
} }

View File

@@ -5,11 +5,11 @@ import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.graphics.scale
import com.google.firebase.components.BuildConfig import com.google.firebase.components.BuildConfig
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -33,8 +33,12 @@ fun generateThumbnailForImage(context: Context, imageHash: String) {
val imageFile = File(picturesDir, "$imageHash.png") val imageFile = File(picturesDir, "$imageHash.png")
val imageContent = imageFile.inputStream().readBytes() val imageContent = imageFile.inputStream().readBytes()
var img = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.size) var img = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.size)
img = img.scale(img.width/4,img.height/4)
img.compress(Bitmap.CompressFormat.WEBP_LOSSY, 25, FileOutputStream(thumbnailFile)) val matrix = Matrix();
matrix.postRotate(90f)
val scaled = Bitmap.createScaledBitmap(img, img.width/4, img.height/4, true)
val rotated = Bitmap.createBitmap(scaled, 0, 0, scaled.width, scaled.height, matrix, true)
rotated.compress(Bitmap.CompressFormat.WEBP_LOSSY, 25, FileOutputStream(thumbnailFile))
} }
@OptIn(ExperimentalStdlibApi::class) @OptIn(ExperimentalStdlibApi::class)

View File

@@ -1,6 +1,8 @@
package org.foxarmy.barcodescannerforemployees.activities package org.foxarmy.barcodescannerforemployees.activities
import android.Manifest //import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
//import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
import android.content.ContentValues import android.content.ContentValues
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
@@ -14,9 +16,10 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.google.mlkit.vision.barcode.common.Barcode import androidx.core.widget.addTextChangedListener
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions import com.journeyapps.barcodescanner.ScanContract
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
import org.foxarmy.barcodescannerforemployees.* import org.foxarmy.barcodescannerforemployees.*
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import java.io.File import java.io.File
@@ -42,19 +45,15 @@ class AddAbstractProductActivity : AppCompatActivity() {
private lateinit var pictureFile: File private lateinit var pictureFile: File
private lateinit var picturesPath: File private lateinit var picturesPath: File
private var barcode: String = "" private var barcode: String = ""
private var action: String = "new"
private var scanningBarcode = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_add_abstract_product) setContentView(R.layout.fragment_add_abstract_product)
val extras = intent.extras
abstractProduct = extras!!.get("abstractProduct") as AbstractProduct?
if (abstractProduct != null) {
barcode = abstractProduct!!.barcode
}
picturesPath = File(filesDir, "pictures") picturesPath = File(filesDir, "pictures")
val thumbnailsDir = File(cacheDir, "thumbnails") val thumbnailsDir = File(cacheDir, "thumbnails")
@@ -76,15 +75,27 @@ class AddAbstractProductActivity : AppCompatActivity() {
fillupCategorySpinner() fillupCategorySpinner()
fillupUnitsSpinner() fillupUnitsSpinner()
if (abstractProduct?.name == "" && abstractProduct?.barcode != "") { barcodeText.addTextChangedListener {
performRequest(abstractProduct?.barcode!!) this.barcode = barcodeText.text.toString()
}
val extras = intent.extras
action = extras!!.get("action") as String
when (action) {
"update" -> {
abstractProduct = extras.get("abstractProduct") as AbstractProduct?
}
"new_from_barcode" -> {
abstractProduct = extras.get("abstractProduct") as AbstractProduct?
barcode = abstractProduct!!.barcode
performRequest(abstractProduct!!.barcode)
}
} }
if (abstractProduct != null) { if (abstractProduct != null) {
val imageThumbnailUri = getImageUri(this, File(thumbnailsDir, "${abstractProduct!!.imageHash}.webp")) val imageThumbnailUri = getImageUri(this, File(thumbnailsDir, "${abstractProduct!!.imageHash}.webp"))
pictureFile = File(picturesPath, "${abstractProduct!!.imageHash}.png]") pictureFile = File(picturesPath, "${abstractProduct!!.imageHash}.png]")
imageView.setImageURI(imageThumbnailUri) imageView.setImageURI(imageThumbnailUri)
imageView.rotation = 90f
barcodeText.setText(abstractProduct!!.barcode) barcodeText.setText(abstractProduct!!.barcode)
productNameText.text = abstractProduct!!.name productNameText.text = abstractProduct!!.name
netWeightText.text = abstractProduct!!.netWeight.toString() netWeightText.text = abstractProduct!!.netWeight.toString()
@@ -96,21 +107,21 @@ class AddAbstractProductActivity : AppCompatActivity() {
val productName = productNameText.text.toString() val productName = productNameText.text.toString()
val netWeight = netWeightText.text val netWeight = netWeightText.text
if (abstractProduct == null && (!this::pictureFile.isInitialized || !pictureFile.exists())) { if (abstractProduct == null && (!this::pictureFile.isInitialized || !pictureFile.exists())) {
Toast.makeText(this, "Please, make a picture of a product!", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.product_picture_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
if (barcode == "") { if (barcode == "") {
Toast.makeText(this, "Please, scan barcode on a product", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.product_barcode_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
if (productName == "") { if (productName == "") {
Toast.makeText(this, "Please, write a name of a product!", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.product_name_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
if (netWeight.toString() == "" || netWeight.toString().toDoubleOrNull() == null) { if (netWeight.toString() == "" || netWeight.toString().toDoubleOrNull() == null) {
Toast.makeText(this, "Please, write a valid net weight of a product!", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.product_net_weight_request), Toast.LENGTH_SHORT).show()
} }
val db = DBStorageController(this).writableDatabase val db = DBStorageController(this).writableDatabase
@@ -123,39 +134,27 @@ class AddAbstractProductActivity : AppCompatActivity() {
put(AbstractProductContract.AbstractProductEntry.UNIT, unitTypeSpinner.selectedItemPosition) put(AbstractProductContract.AbstractProductEntry.UNIT, unitTypeSpinner.selectedItemPosition)
} }
if (abstractProduct == null) { if (action == "update") {
db.update(
AbstractProductContract.AbstractProductEntry.TABLE_NAME,
values,
"${BaseColumns._ID} = ?",
arrayOf(abstractProduct!!.id.toString())
)
} else if (action == "new" || action == "new_from_barcode"){
db.insert(AbstractProductContract.AbstractProductEntry.TABLE_NAME, null, values) db.insert(AbstractProductContract.AbstractProductEntry.TABLE_NAME, null, values)
} else {
db.update(AbstractProductContract.AbstractProductEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(abstractProduct!!.id.toString()))
} }
finish() finish()
} }
takePictureButton.setOnClickListener { takePictureButton.setOnClickListener {
requestPermissionLauncher.launch(Manifest.permission.CAMERA) requestPermissionLauncher.launch(android.Manifest.permission.CAMERA)
} }
scanButton.setOnClickListener { scanButton.setOnClickListener {
val options = GmsBarcodeScannerOptions.Builder() scanningBarcode = true
.setBarcodeFormats( requestPermissionLauncher.launch(android.Manifest.permission.CAMERA)
Barcode.FORMAT_EAN_13
)
.build()
val scanner = GmsBarcodeScanning.getClient(this)
scanner.startScan()
.addOnSuccessListener { barcode ->
this.barcode = barcode.rawValue.toString()
performRequest(this.barcode)
}
.addOnFailureListener { e ->
Toast.makeText(
this,
"Failed to scan barcode. Please, try again or enter data manually",
Toast.LENGTH_LONG
).show()
}
} }
} }
@@ -165,7 +164,11 @@ class AddAbstractProductActivity : AppCompatActivity() {
requester.request(this, barcode) requester.request(this, barcode)
var abstractProduct: AbstractProduct var abstractProduct: AbstractProduct
if (DBStorageController(this).findAbstractProductByBarcode(DBStorageController(this).readableDatabase, this.barcode) != null) { if (DBStorageController(this).findAbstractProductByBarcode(
DBStorageController(this).readableDatabase,
this.barcode
) != null
) {
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setMessage("You've got an abstract product with such barcode in your database") .setMessage("You've got an abstract product with such barcode in your database")
.setPositiveButton("Quit") { _: DialogInterface, _: Int -> .setPositiveButton("Quit") { _: DialogInterface, _: Int ->
@@ -174,7 +177,10 @@ class AddAbstractProductActivity : AppCompatActivity() {
.setNegativeButton("Edit existing") { _: DialogInterface, _: Int -> .setNegativeButton("Edit existing") { _: DialogInterface, _: Int ->
val addProductIntent = Intent(this, AddAbstractProductActivity::class.java) val addProductIntent = Intent(this, AddAbstractProductActivity::class.java)
val extras = Bundle() val extras = Bundle()
val existingAbstractProduct = DBStorageController(this).findAbstractProductByBarcode(DBStorageController(this).readableDatabase, this.barcode) val existingAbstractProduct = DBStorageController(this).findAbstractProductByBarcode(
DBStorageController(this).readableDatabase,
this.barcode
)
extras.putParcelable("abstractProduct", existingAbstractProduct) extras.putParcelable("abstractProduct", existingAbstractProduct)
addProductIntent.putExtras(extras) addProductIntent.putExtras(extras)
ContextCompat.startActivity(this, addProductIntent, extras) ContextCompat.startActivity(this, addProductIntent, extras)
@@ -184,10 +190,12 @@ class AddAbstractProductActivity : AppCompatActivity() {
thread { thread {
// Я сам в ахуях какой это костыль, пока хз как фиксить, потом придумаю :)) // Я сам в ахуях какой это костыль, пока хз как фиксить, потом придумаю :))
while (requester.response == "") { } while (requester.response == "") {
}
if (requester.response == "Not found 404") { if (requester.response == "Not found 404") {
runOnUiThread { runOnUiThread {
Toast.makeText(this, "Product not found. Please, try again or type manually", Toast.LENGTH_LONG).show() Toast.makeText(this, "Product not found. Please, try again or type manually", Toast.LENGTH_LONG)
.show()
} }
return@thread return@thread
} }
@@ -212,7 +220,8 @@ class AddAbstractProductActivity : AppCompatActivity() {
) )
val arrayAdapter = ArrayAdapter<String>(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, units) val arrayAdapter =
ArrayAdapter<String>(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, units)
arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item) arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
unitTypeSpinner.adapter = arrayAdapter unitTypeSpinner.adapter = arrayAdapter
} }
@@ -226,15 +235,24 @@ class AddAbstractProductActivity : AppCompatActivity() {
CategoriesContract.CategoryEntry.CATEGORY_NAME CategoriesContract.CategoryEntry.CATEGORY_NAME
) )
val cursor = db.query(CategoriesContract.CategoryEntry.TABLE_NAME, projection, null, null, null, null, BaseColumns._ID+" ASC") val cursor = db.query(
CategoriesContract.CategoryEntry.TABLE_NAME,
projection,
null,
null,
null,
null,
BaseColumns._ID + " ASC"
)
with (cursor) { with(cursor) {
while (moveToNext()) { while (moveToNext()) {
categories.add(getString(getColumnIndexOrThrow(CategoriesContract.CategoryEntry.CATEGORY_NAME))) categories.add(getString(getColumnIndexOrThrow(CategoriesContract.CategoryEntry.CATEGORY_NAME)))
} }
} }
val arrayAdapter = ArrayAdapter<String>(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, categories) 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) arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
categorySpinner.adapter = arrayAdapter categorySpinner.adapter = arrayAdapter
} }
@@ -259,7 +277,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
} }
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
fun getPicture () { fun getPicture() {
//Saving picture to a temp file for further hash calculation and moving to a proper directory //Saving picture to a temp file for further hash calculation and moving to a proper directory
val imageFile = File(this.filesDir, "image.png") val imageFile = File(this.filesDir, "image.png")
val imageUri = getImageUri(this, imageFile) val imageUri = getImageUri(this, imageFile)
@@ -274,9 +292,38 @@ class AddAbstractProductActivity : AppCompatActivity() {
ActivityResultContracts.RequestPermission() ActivityResultContracts.RequestPermission()
) { isGranted: Boolean -> ) { isGranted: Boolean ->
if (isGranted) { if (isGranted) {
getPicture() if (scanningBarcode) {
prepareBarcodeScanner()
} else {
getPicture()
}
} else { } else {
Toast.makeText(this, "I need permission in order to take a picture", Toast.LENGTH_LONG).show() Toast.makeText(this, getString(R.string.camera_permission_for_picture_request), Toast.LENGTH_LONG).show()
} }
} }
private val scanLauncher = registerForActivityResult(ScanContract()) { result: ScanIntentResult ->
run {
if (result.contents == null) {
Toast.makeText(this, getString(R.string.cancelled), Toast.LENGTH_SHORT).show()
} else {
scanningBarcode = false
val scannedBarcode = result.contents
barcodeText.setText(scannedBarcode)
performRequest(scannedBarcode)
}
}
}
private fun prepareBarcodeScanner() {
val options = ScanOptions()
options.setDesiredBarcodeFormats(ScanOptions.EAN_13)
options.setPrompt(getString(R.string.scan_barcode_of_a_product))
options.setCameraId(0)
options.setBeepEnabled(false)
options.setBarcodeImageEnabled(true)
options.setOrientationLocked(false)
scanLauncher.launch(options)
}
} }

View File

@@ -6,10 +6,11 @@ import android.os.Bundle
import android.provider.BaseColumns import android.provider.BaseColumns
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.Toast
import org.foxarmy.barcodescannerforemployees.CategoriesContract import org.foxarmy.barcodescannerforemployees.CategoriesContract
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
class AddCategoryActivity : Activity() { class AddCategoryActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -27,6 +28,11 @@ class AddCategoryActivity : Activity() {
findViewById<Button>(R.id.saveButton).setOnClickListener { findViewById<Button>(R.id.saveButton).setOnClickListener {
val db = DBStorageController(this).writableDatabase val db = DBStorageController(this).writableDatabase
if (categoryNameTextEdit.text.toString() == "") {
Toast.makeText(this, getString(R.string.category_name_required), Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
if (category.id == 0) { // Inserting new category if (category.id == 0) { // Inserting new category
val values = ContentValues().apply { val values = ContentValues().apply {
put(CategoriesContract.CategoryEntry.CATEGORY_NAME, categoryNameTextEdit.text.toString()) put(CategoriesContract.CategoryEntry.CATEGORY_NAME, categoryNameTextEdit.text.toString())

View File

@@ -1,12 +1,20 @@
package org.foxarmy.barcodescannerforemployees.activities package org.foxarmy.barcodescannerforemployees.activities
import android.app.DatePickerDialog import android.app.DatePickerDialog
import android.content.Intent
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.* import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions
import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
@@ -55,6 +63,7 @@ class AddProductActivity : AppCompatActivity() {
shelfLifeTextEdit = findViewById(R.id.shelfLifeTextEdit) shelfLifeTextEdit = findViewById(R.id.shelfLifeTextEdit)
amountTextEdit = findViewById(R.id.amountTextEdit) amountTextEdit = findViewById(R.id.amountTextEdit)
amountTextEdit.setText("1")
dateOfProductionSelectButton = findViewById(R.id.selectDateOfProductionButton) dateOfProductionSelectButton = findViewById(R.id.selectDateOfProductionButton)
saveProductButton = findViewById(R.id.saveProductButton) saveProductButton = findViewById(R.id.saveProductButton)
@@ -77,17 +86,7 @@ class AddProductActivity : AppCompatActivity() {
} }
scanButton.setOnClickListener { scanButton.setOnClickListener {
val scanner = GmsBarcodeScanning.getClient(this) requestPermissionLauncher.launch(android.Manifest.permission.CAMERA)
scanner.startScan()
.addOnSuccessListener { bc ->
abstractProduct = DBStorageController(this).findAbstractProductByBarcode(DBStorageController(this).readableDatabase, bc.rawValue.toString())
product!!.abstractProductId = abstractProduct!!.id
displayAbstractProduct(abstractProduct!!)
}
.addOnFailureListener {
Toast.makeText(this, "Cannot scan barcode", Toast.LENGTH_SHORT).show()
}
} }
expiryDateRadioButton.setOnClickListener { expiryDateRadioButton.setOnClickListener {
@@ -136,11 +135,11 @@ class AddProductActivity : AppCompatActivity() {
saveProductButton.setOnClickListener { saveProductButton.setOnClickListener {
if (expiryDateOverShelfLife == null) { if (expiryDateOverShelfLife == null) {
Toast.makeText(this, "Please, choose and fill in shelf life or expiry date.", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.shell_life_or_expiry_date_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
if (product!!.dateOfProduction == 0.toLong()) { if (product!!.dateOfProduction == 0.toLong()) {
Toast.makeText(this, "Please, choose date of production.", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.date_of_production_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
@@ -150,13 +149,13 @@ class AddProductActivity : AppCompatActivity() {
} }
} else { } else {
if (product!!.dateOfExpiry == 0.toLong()) { if (product!!.dateOfExpiry == 0.toLong()) {
Toast.makeText(this, "Please, choose date of expiry.", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.expiry_date_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
} }
if (product!!.amount == 0) { if (product!!.amount == 0) {
Toast.makeText(this, "Please, specify an amount of product.", Toast.LENGTH_SHORT).show() Toast.makeText(this, getString(R.string.product_amount_request), Toast.LENGTH_SHORT).show()
return@setOnClickListener return@setOnClickListener
} }
@@ -185,10 +184,10 @@ class AddProductActivity : AppCompatActivity() {
shelfLifeTextView.visibility = View.VISIBLE shelfLifeTextView.visibility = View.VISIBLE
} }
val dateOfProductionParsed = SimpleDateFormat("dd.MM.yyyy").format(Date(product!!.dateOfProduction * 1000)) val dateOfProductionParsed = SimpleDateFormat("dd.MM.yyyy").format(Date(product!!.dateOfProduction * 1000))
findViewById<TextView>(R.id.dateOfProductionTextView).text = "Date of production: $dateOfProductionParsed" findViewById<TextView>(R.id.dateOfProductionTextView).text = "${getString(R.string.date_of_production)}: $dateOfProductionParsed"
val expiryDateParsed = SimpleDateFormat("dd.MM.yyyy").format(Date(product!!.dateOfExpiry * 1000)) val expiryDateParsed = SimpleDateFormat("dd.MM.yyyy").format(Date(product!!.dateOfExpiry * 1000))
expiryDateTextView.text = "Expiry date: $expiryDateParsed" expiryDateTextView.text = "${getString(R.string.expiry_date)}: $expiryDateParsed"
if (amountTextEdit.text.toString() == "") { if (amountTextEdit.text.toString() == "") {
amountTextEdit.setText(product!!.amount.toString()) amountTextEdit.setText(product!!.amount.toString())
@@ -211,8 +210,64 @@ class AddProductActivity : AppCompatActivity() {
product!!.dateOfExpiry = c.timeInMillis / 1000 product!!.dateOfExpiry = c.timeInMillis / 1000
} }
private fun displayAbstractProduct(abstractProduct: AbstractProduct) { private fun displayAbstractProduct(abstractProduct: AbstractProduct?, scannedBarcode: String) {
abstractProductView.abstractProduct = abstractProduct if (abstractProduct == null) {
abstractProductView.update() AlertDialog.Builder(this)
.setMessage(getString(R.string.abstract_product_does_not_exist))
.setPositiveButton(R.string.yes) { _, _ ->
val addAbstractProductIntent = Intent(this, AddAbstractProductActivity::class.java)
val extras = Bundle()
extras.putParcelable("abstractProduct", AbstractProduct(0, scannedBarcode, "", 0.0, "", 0, 0))
extras.putString("action", "new_from_barcode")
addAbstractProductIntent.putExtras(extras)
ContextCompat.startActivity(this, addAbstractProductIntent, extras)
}
.setNegativeButton(R.string.no) {_, _ ->
}.show()
} else {
abstractProductView.abstractProduct = abstractProduct
abstractProductView.update()
}
} }
}
@RequiresApi(Build.VERSION_CODES.R)
val requestPermissionLauncher =
registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
prepareBarcodeScanner()
} else {
Toast.makeText(this, getString(R.string.camera_permission_for_scanning_request), Toast.LENGTH_LONG).show()
}
}
private val scanLauncher = registerForActivityResult(ScanContract()) { result: ScanIntentResult ->
run {
if (result.contents == null) {
Toast.makeText(this, getString(R.string.cancelled), Toast.LENGTH_SHORT).show()
} else {
val scannedBarcode = result.contents
abstractProduct = DBStorageController(this).findAbstractProductByBarcode(DBStorageController(this).readableDatabase, scannedBarcode)
displayAbstractProduct(abstractProduct, scannedBarcode)
if (abstractProduct != null) {
product?.abstractProductId = abstractProduct!!.id
}
}
}
}
private fun prepareBarcodeScanner() {
val options = ScanOptions()
options.setDesiredBarcodeFormats(ScanOptions.EAN_13)
options.setPrompt(getString(R.string.scan_barcode_of_a_product))
options.setCameraId(0)
options.setBeepEnabled(false)
options.setBarcodeImageEnabled(true)
options.setOrientationLocked(false)
scanLauncher.launch(options)
}
}

View File

@@ -43,6 +43,7 @@ class MainActivity : AppCompatActivity() {
// I reuse the same stuff for editing and adding new product. // I reuse the same stuff for editing and adding new product.
// if abstractProduct == null, it means that we need to create new object // if abstractProduct == null, it means that we need to create new object
extras.putParcelable("abstractProduct", null) extras.putParcelable("abstractProduct", null)
extras.putString("action", "new")
addAbstractProductIntent.putExtras(extras) addAbstractProductIntent.putExtras(extras)
ContextCompat.startActivity(this, addAbstractProductIntent, extras) ContextCompat.startActivity(this, addAbstractProductIntent, extras)
} }
@@ -50,7 +51,7 @@ class MainActivity : AppCompatActivity() {
"CategoriesFragment" -> { "CategoriesFragment" -> {
val addCategoryIntent = Intent(this, AddCategoryActivity::class.java) val addCategoryIntent = Intent(this, AddCategoryActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putParcelable("category", Category(0, "New category")) extras.putParcelable("category", Category(0, ""))
addCategoryIntent.putExtras(extras) addCategoryIntent.putExtras(extras)
ContextCompat.startActivity(this, addCategoryIntent, extras) ContextCompat.startActivity(this, addCategoryIntent, extras)
} }
@@ -69,13 +70,14 @@ class MainActivity : AppCompatActivity() {
private fun setupViewPager(viewpager: ViewPager) { private fun setupViewPager(viewpager: ViewPager) {
adapter = ViewPagerAdapter(supportFragmentManager) adapter = ViewPagerAdapter(supportFragmentManager)
adapter.addFragment(CategoriesFragment(), "Categories") adapter.addFragment(StorageFragment(), getString(R.string.storage_title))
adapter.addFragment(StorageFragment(), "Storage") adapter.addFragment(ShelfFragment(), getString(R.string.shelf_title))
adapter.addFragment(ShelfFragment(), "Shelf") adapter.addFragment(CategoriesFragment(), getString(R.string.categories_title))
//TODO: settings fragments //TODO: settings fragments
// setting adapter to view pager. // setting adapter to view pager.
viewpager.setAdapter(adapter) viewpager.adapter = adapter
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -99,24 +101,24 @@ class MainActivity : AppCompatActivity() {
when (fragment::class.simpleName.toString()) { when (fragment::class.simpleName.toString()) {
"StorageFragment" -> { "StorageFragment" -> {
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setMessage("Deleting an abstract product will also delete ALL the products, that belong to it. Do you want to proceed?") .setMessage(getString(R.string.deleting_abstract_product_warning))
.setPositiveButton("Yes") { _: DialogInterface, _: Int -> .setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val storageFragment = fragment as StorageFragment val storageFragment = fragment as StorageFragment
storageFragment.removeSelected() storageFragment.removeSelected()
} }
.setNegativeButton("No") { _: DialogInterface, _: Int -> .setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
}.show() }.show()
} }
"CategoriesFragment" -> { "CategoriesFragment" -> {
AlertDialog.Builder(this) AlertDialog.Builder(this)
.setMessage("Deleting a category will also delete ALL the products, that belong to that category. Do you want to proceed?") .setMessage(getString(R.string.deleting_category_warning))
.setPositiveButton("Yes") { _: DialogInterface, _: Int -> .setPositiveButton(getString(R.string.yes)) { _: DialogInterface, _: Int ->
val categoriesFragment = fragment as CategoriesFragment val categoriesFragment = fragment as CategoriesFragment
categoriesFragment.removeSelected() categoriesFragment.removeSelected()
} }
.setNegativeButton("No") { _: DialogInterface, _: Int -> .setNegativeButton(getString(R.string.no)) { _: DialogInterface, _: Int ->
}.show() }.show()
} }
@@ -151,4 +153,14 @@ class MainActivity : AppCompatActivity() {
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
fun filterAbstractProductsByCategory(id: Int) {
binding.tabViewpager.setCurrentItem(0, true)
val currentPosition = binding.tabTablayout.selectedTabPosition
val fragment = adapter.getItem(currentPosition)
val storageFragment = fragment as StorageFragment
storageFragment.filterByCategory(id)
}
} }

View File

@@ -45,7 +45,7 @@ class CategoriesFragment : Fragment() {
} }
if (!deleted) { if (!deleted) {
Toast.makeText(requireContext(), "Nothing to delete", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), getString(R.string.nothing_to_delete), Toast.LENGTH_SHORT).show()
} }
updateContent() updateContent()
} }

View File

@@ -69,13 +69,13 @@ class ShelfFragment : Fragment() {
} }
if (!updated) { if (!updated) {
Toast.makeText(requireContext(), "Nothing to update", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), getString(R.string.nothing_to_update), Toast.LENGTH_SHORT).show()
} }
updateContent() updateContent()
} }
private fun fillUpSortBySpinner() { private fun fillUpSortBySpinner() {
val sorts = mutableListOf("Name", "Category", "Freshness", "Date of production", "Date of expiry") val sorts = resources.getStringArray(R.array.product_sort_types)
val arrayAdapter = val arrayAdapter =
ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts) ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
@@ -109,13 +109,13 @@ class ShelfFragment : Fragment() {
var orderBy: String = "" var orderBy: String = ""
when (binding.spinner.selectedItem) { when (binding.spinner.selectedItemPosition) {
"Name" -> { 0 -> {
orderBy = orderBy =
"(SELECT ${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC" "(SELECT ${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
} }
"Category" -> { 1 -> {
orderBy = orderBy =
"(SELECT ${AbstractProductContract.AbstractProductEntry.CATEGORY} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC" "(SELECT ${AbstractProductContract.AbstractProductEntry.CATEGORY} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
} }
@@ -126,11 +126,11 @@ class ShelfFragment : Fragment() {
// "(SELECT ( (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday('now', 'localtime')) / (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday(${ProductContract.ProductEntry.DATE_OF_PRODUCTION})) )) ASC" // "(SELECT ( (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday('now', 'localtime')) / (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday(${ProductContract.ProductEntry.DATE_OF_PRODUCTION})) )) ASC"
// } // }
"Date of production" -> { 3 -> {
orderBy = "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} ASC" orderBy = "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} ASC"
} }
"Date of expiry" -> { 4 -> {
orderBy = "${ProductContract.ProductEntry.EXPIRY_DATE} ASC" orderBy = "${ProductContract.ProductEntry.EXPIRY_DATE} ASC"
} }
} }
@@ -151,7 +151,7 @@ class ShelfFragment : Fragment() {
val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry) val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
if (binding.spinner.selectedItem == "Freshness") { if (binding.spinner.selectedItemPosition == 2) { //freshness
products.add(product) products.add(product)
} else { } else {
val productView = ProductView( val productView = ProductView(
@@ -200,7 +200,7 @@ class ShelfFragment : Fragment() {
if (!deleted) { if (!deleted) {
activity!!.runOnUiThread { activity!!.runOnUiThread {
Toast.makeText(requireContext(), "Nothing to delete", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), getString(R.string.nothing_to_delete), Toast.LENGTH_SHORT).show()
} }
} }
updateContent() updateContent()

View File

@@ -3,7 +3,6 @@ package org.foxarmy.barcodescannerforemployees.fragments
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.provider.BaseColumns import android.provider.BaseColumns
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@@ -27,7 +26,7 @@ import kotlin.concurrent.thread
class StorageFragment : Fragment() { class StorageFragment : Fragment() {
private lateinit var binding: FragmentStorageBinding private lateinit var binding: FragmentStorageBinding
private var filterByCategory = ""
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@@ -46,6 +45,11 @@ class StorageFragment : Fragment() {
} }
} }
binding.dropFiltersButton.setOnClickListener {
filterByCategory = ""
updateContent()
}
return binding.root return binding.root
} }
@@ -56,8 +60,7 @@ class StorageFragment : Fragment() {
} }
private fun fillUpSortBySpinner() { private fun fillUpSortBySpinner() {
val sorts = mutableListOf("Name", "Category") val sorts = resources.getStringArray(R.array.abstract_product_sort_types)
val arrayAdapter = ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts) val arrayAdapter = ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item) arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
binding.spinner.adapter = arrayAdapter binding.spinner.adapter = arrayAdapter
@@ -81,7 +84,7 @@ class StorageFragment : Fragment() {
if (!deleted) { if (!deleted) {
activity!!.runOnUiThread { activity!!.runOnUiThread {
Toast.makeText(requireContext(), "Nothing to delete", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), getString(R.string.nothing_to_delete), Toast.LENGTH_SHORT).show()
} }
} }
updateContent() updateContent()
@@ -96,6 +99,7 @@ class StorageFragment : Fragment() {
val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java) val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putParcelable("abstractProduct", view.abstractProduct) extras.putParcelable("abstractProduct", view.abstractProduct)
extras.putString("action", "update")
addProductIntent.putExtras(extras) addProductIntent.putExtras(extras)
ContextCompat.startActivity(requireContext(), addProductIntent, extras) ContextCompat.startActivity(requireContext(), addProductIntent, extras)
} }
@@ -121,17 +125,24 @@ class StorageFragment : Fragment() {
) )
var orderBy: String = "" var orderBy: String = ""
Log.d("QWERTYUIOP", binding.spinner.selectedItem.toString()) when(binding.spinner.selectedItemPosition) {
when(binding.spinner.selectedItem) { 0 -> {
"Name" -> {
orderBy = "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} ASC" orderBy = "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} ASC"
} }
"Category" -> { 1 -> {
orderBy = "${AbstractProductContract.AbstractProductEntry.CATEGORY} ASC" orderBy = "${AbstractProductContract.AbstractProductEntry.CATEGORY} ASC"
} }
} }
val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, null, null, null, null, orderBy) var selection = ""
var selectionArgs: Array<String>? = null
if (filterByCategory != "") {
selection = "${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?"
selectionArgs = arrayOf(filterByCategory)
}
val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, orderBy)
with (cursor) { with (cursor) {
while(moveToNext()) { while(moveToNext()) {
@@ -166,4 +177,10 @@ class StorageFragment : Fragment() {
updateContent() updateContent()
} }
fun filterByCategory(id: Int) {
// filterByCategory = DBStorageController(context!!).getCategoryNameById(DBStorageController(context!!).readableDatabase, id)
filterByCategory = "$id"
updateContent()
}
} }

View File

@@ -80,7 +80,7 @@ class AbstractProductView: LinearLayout {
thumbnailsDir.mkdirs() thumbnailsDir.mkdirs()
val imageUri = getImageUri(activity, File(thumbnailsDir, "${abstractProduct.imageHash}.webp")) val imageUri = getImageUri(activity, File(thumbnailsDir, "${abstractProduct.imageHash}.webp"))
productPicture!!.setImageURI(imageUri) productPicture!!.setImageURI(imageUri)
productPicture!!.rotation = 90f // productPicture!!.rotation = 90f
productNameField!!.text = abstractProduct.name productNameField!!.text = abstractProduct.name
netWeightField!!.text = abstractProduct.netWeight.toString() netWeightField!!.text = abstractProduct.netWeight.toString()

View File

@@ -6,9 +6,10 @@ import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.activities.MainActivity
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
class CategoryView : LinearLayout { class CategoryView : LinearLayout {
var category: Category var category: Category
@@ -35,5 +36,8 @@ class CategoryView : LinearLayout {
this.background = ContextCompat.getDrawable(context, if (isCategorySelected) R.drawable.outline_selected else R.drawable.outline) this.background = ContextCompat.getDrawable(context, if (isCategorySelected) R.drawable.outline_selected else R.drawable.outline)
true true
} }
setOnClickListener {
(activity as MainActivity).filterAbstractProductsByCategory(category.id)
}
} }
} }

View File

@@ -95,7 +95,7 @@ class ProductView: LinearLayout {
val pictureFile = File(thumbnailsDir, "${linkedAbstractProduct.imageHash}.webp") val pictureFile = File(thumbnailsDir, "${linkedAbstractProduct.imageHash}.webp")
val imageUri = getImageUri(activity, pictureFile) val imageUri = getImageUri(activity, pictureFile)
productImageView.setImageURI(imageUri) productImageView.setImageURI(imageUri)
productImageView.rotation = 90f // productImageView.rotation = 90f
productNameTextView.text = linkedAbstractProduct.name productNameTextView.text = linkedAbstractProduct.name
productNetWeightTextView.text = linkedAbstractProduct.netWeight.toString() productNetWeightTextView.text = linkedAbstractProduct.netWeight.toString()
@@ -103,8 +103,8 @@ class ProductView: LinearLayout {
productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category) productCategoryView.text = DBStorageController(activity).getCategoryNameById(DBStorageController(activity).readableDatabase, linkedAbstractProduct.category)
productLifeSpan.text = "${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfProduction*1000))}-${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfExpiry*1000))}" productLifeSpan.text = "${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfProduction*1000))}-${SimpleDateFormat("dd.MM.yyyy").format(Date(product.dateOfExpiry*1000))}"
productFreshnessTextView.text = productFreshnessTextView.text =
if (product.freshness == Double.NEGATIVE_INFINITY || product.freshness == Double.POSITIVE_INFINITY) { if (product.freshness == Double.NEGATIVE_INFINITY || product.freshness == Double.POSITIVE_INFINITY || product.freshness < 0) {
"Expired" context.getString(R.string.expired)
} else { } else {
"${DecimalFormat("#.#").format(product.freshness*100)}%" "${DecimalFormat("#.#").format(product.freshness*100)}%"
} }

View File

@@ -7,7 +7,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/productLayout" android:outlineProvider="bounds" android:layout_height="match_parent" android:id="@+id/productLayout" android:outlineProvider="bounds"
android:background="#00FFFEFE" android:clickable="true"> android:background="#00FFFEFE" android:clickable="true">
<ImageView <ImageView
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -4,19 +4,18 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main" android:id="@+id/main"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
tools:context=".activities.AddCategoryActivity"> tools:context=".activities.AddCategoryActivity" android:layout_gravity="center">
<EditText <EditText
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text" android:inputType="text"
android:text="@string/sample_category"
android:ems="10" android:ems="10"
android:id="@+id/newCategoryName" app:layout_constraintStart_toStartOf="parent" android:id="@+id/newCategoryName" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="20dp"/> android:layout_marginTop="20dp" android:hint="@string/sample_category"/>
<Button <Button
android:text="@string/saveButton" android:text="@string/saveButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@@ -9,7 +9,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp"> android:padding="16dp" android:layout_gravity="center">
<Button <Button
android:id="@+id/scan_button" android:id="@+id/scan_button"
android:layout_width="100dp" android:layout_width="100dp"
@@ -17,27 +17,27 @@
android:text="@string/scan_label" android:text="@string/scan_label"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/categoryTextView" app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
android:layout_marginTop="15dp"/> android:layout_marginTop="40dp" android:layout_marginStart="5dp"/>
<ImageView <ImageView
android:src="@android:drawable/ic_menu_camera" android:src="@android:drawable/ic_menu_camera"
android:layout_width="356dp" android:layout_width="0dp"
android:layout_height="303dp" android:id="@+id/imageView" android:layout_height="303dp" android:id="@+id/imageView"
android:layout_marginBottom="25dp" android:layout_marginBottom="25dp"
app:layout_constraintBottom_toTopOf="@+id/productName" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toTopOf="@+id/productName" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="15dp"/> android:layout_marginTop="15dp" android:layout_marginStart="5dp" android:layout_marginEnd="5dp"/>
<EditText <EditText
android:layout_width="350dp" android:layout_width="0dp"
android:layout_height="50dp" android:layout_height="50dp"
android:inputType="text" android:inputType="text"
android:ems="10" android:ems="10"
android:id="@+id/productName" android:id="@+id/productName"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="5dp" android:layout_marginEnd="5dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/netWeight" app:layout_constraintBottom_toTopOf="@+id/netWeight"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
android:visibility="visible" android:hint="@string/product_name_label" android:textColorHint="#737373" android:visibility="visible" android:hint="@string/productName" android:textColorHint="#737373"
android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/barcodeTextEdit"/> android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/barcodeTextEdit"/>
<EditText <EditText
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -46,7 +46,7 @@
android:ems="10" android:ems="10"
android:id="@+id/netWeight" android:id="@+id/netWeight"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" android:layout_marginStart="5dp"
android:visibility="visible" android:hint="@string/netWeight" android:textColorHint="#737373" android:visibility="visible" android:hint="@string/netWeight" android:textColorHint="#737373"
app:layout_constraintTop_toBottomOf="@+id/productName" app:layout_constraintTop_toBottomOf="@+id/productName"
/> />
@@ -56,40 +56,41 @@
app:layout_constraintStart_toEndOf="@+id/netWeight" app:layout_constraintStart_toEndOf="@+id/netWeight"
app:layout_constraintTop_toBottomOf="@+id/productName" app:layout_constraintEnd_toEndOf="parent"/> app:layout_constraintTop_toBottomOf="@+id/productName" app:layout_constraintEnd_toEndOf="parent"/>
<EditText <EditText
android:layout_width="350dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text" android:inputType="text"
android:ems="10" android:ems="10"
android:id="@+id/barcodeTextEdit" app:layout_constraintTop_toBottomOf="@+id/imageView" android:id="@+id/barcodeTextEdit" app:layout_constraintTop_toBottomOf="@+id/imageView"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="8dp" android:hint="Barcode" android:textColorHint="#737373"/> android:layout_marginTop="8dp" android:hint="Barcode" android:textColorHint="#737373"
android:layout_marginStart="5dp" android:layout_marginEnd="5dp"/>
<TextView <TextView
android:text="@string/category" android:text="@string/category"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/categoryTextView" android:layout_height="wrap_content" android:id="@+id/categoryTextView"
app:layout_constraintTop_toBottomOf="@+id/netWeight" app:layout_constraintTop_toBottomOf="@+id/netWeight"
android:layout_marginTop="20dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="30dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/> android:layout_marginStart="8dp"/>
<Spinner <Spinner
android:layout_width="match_parent" android:layout_width="140dp"
android:layout_height="wrap_content" android:id="@+id/categorySpinner" android:layout_height="50dp" android:id="@+id/categorySpinner"
app:layout_constraintStart_toEndOf="@+id/categoryTextView" app:layout_constraintStart_toEndOf="@+id/categoryTextView"
app:layout_constraintTop_toBottomOf="@+id/netWeight" android:layout_marginStart="8dp" app:layout_constraintTop_toBottomOf="@+id/netWeight" android:layout_marginStart="8dp"
android:layout_marginTop="18dp"/> android:layout_marginTop="18dp" android:outlineProvider="bounds"/>
<Button <Button
android:text="@string/saveButton" android:text="@string/saveButton"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="50dp" android:id="@+id/saveButton" android:layout_height="50dp" android:id="@+id/saveButton"
app:layout_constraintTop_toBottomOf="@+id/categoryTextView" app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
android:layout_marginTop="15dp" app:layout_constraintEnd_toEndOf="parent"/> android:layout_marginTop="40dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="5dp"/>
<Button <Button
android:text="@string/takePicture" android:text="@string/takePicture"
android:layout_width="100dp" android:layout_width="100dp"
android:layout_height="55dp" android:id="@+id/takePictureButton" android:layout_height="55dp" android:id="@+id/takePictureButton"
app:layout_constraintTop_toBottomOf="@+id/categoryTextView" app:layout_constraintTop_toBottomOf="@+id/categoryTextView"
android:layout_marginTop="15dp" app:layout_constraintStart_toEndOf="@+id/scan_button" android:layout_marginTop="40dp"
android:layout_marginStart="33dp" app:layout_constraintEnd_toStartOf="@+id/saveButton" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/>
android:layout_marginEnd="6dp" app:layout_constraintHorizontal_bias="0.0"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View File

@@ -24,13 +24,13 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/abstractProductView" android:layout_marginTop="16dp"/> app:layout_constraintTop_toBottomOf="@+id/abstractProductView" android:layout_marginTop="16dp"/>
<TextView <TextView
android:text="Date of production:" android:text="@string/date_of_production"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/dateOfProductionTextView" android:layout_height="wrap_content" android:id="@+id/dateOfProductionTextView"
app:layout_constraintTop_toBottomOf="@+id/scanButton" app:layout_constraintTop_toBottomOf="@+id/scanButton"
android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent"/> android:layout_marginTop="16dp" app:layout_constraintStart_toStartOf="parent"/>
<Button <Button
android:text="Select" android:text="@string/select"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/selectDateOfProductionButton" android:layout_height="wrap_content" android:id="@+id/selectDateOfProductionButton"
app:layout_constraintTop_toBottomOf="@+id/scanButton" app:layout_constraintTop_toBottomOf="@+id/scanButton"
@@ -43,11 +43,11 @@
app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp"
android:orientation="horizontal" android:id="@+id/radioGroup"> android:orientation="horizontal" android:id="@+id/radioGroup">
<RadioButton <RadioButton
android:text="Expiry date" android:text="@string/expiry_date"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/expiryDateRadio"/> android:layout_height="wrap_content" android:id="@+id/expiryDateRadio"/>
<RadioButton <RadioButton
android:text="Shelf life" android:text="@string/shelf_life"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/shelfLifeRadio"/> android:layout_height="wrap_content" android:id="@+id/shelfLifeRadio"/>
</RadioGroup> </RadioGroup>
@@ -80,11 +80,11 @@
app:layout_constraintStart_toEndOf="@+id/expiryDateTextView" android:layout_marginStart="16dp" app:layout_constraintStart_toEndOf="@+id/expiryDateTextView" android:layout_marginStart="16dp"
android:visibility="invisible"/> android:visibility="invisible"/>
<TextView <TextView
android:text="Amount"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/amountText" android:layout_height="wrap_content" android:id="@+id/amountText"
app:layout_constraintTop_toBottomOf="@+id/shelfLifeTextEdit" app:layout_constraintTop_toBottomOf="@+id/shelfLifeTextEdit"
app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="16dp"/> app:layout_constraintStart_toStartOf="parent" android:layout_marginTop="16dp"
android:text="@string/amount"/>
<EditText <EditText
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -8,6 +8,7 @@
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/categoriesLayout"> android:layout_height="match_parent" android:id="@+id/categoriesLayout"
android:layout_gravity="center" android:layout_margin="2dp">
</LinearLayout> </LinearLayout>
</FrameLayout> </FrameLayout>

View File

@@ -8,13 +8,12 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:text="Sort by"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:id="@+id/sortByTextView" android:layout_height="0dp" android:id="@+id/sortByTextView"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/scrollView" android:textAlignment="center" app:layout_constraintBottom_toTopOf="@+id/scrollView" android:textAlignment="center"
/> android:text="@string/sort_by"/>
<Spinner <Spinner
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="32dp" android:id="@+id/spinner" android:layout_height="32dp" android:id="@+id/spinner"

View File

@@ -10,7 +10,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:text="Sort by" android:text="@string/sort_by"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="0dp" android:id="@+id/sortByTextView" android:layout_height="0dp" android:id="@+id/sortByTextView"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@@ -22,12 +22,21 @@
android:layout_height="32dp" android:id="@+id/spinner" android:layout_height="32dp" android:id="@+id/spinner"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/sortByTextView" app:layout_constraintStart_toEndOf="@+id/sortByTextView"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:layout_constraintEnd_toStartOf="@+id/dropFiltersButton" android:layout_marginEnd="10dp"
/> />
<Button
android:text="@string/drop_filters"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/dropFiltersButton"
app:layout_constraintStart_toEndOf="@+id/spinner"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" app:layout_constraintTop_toTopOf="parent"/>
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/spinner" android:layout_height="wrap_content"
android:id="@+id/scrollView2"> android:id="@+id/scrollView2"
app:layout_constraintTop_toBottomOf="@+id/dropFiltersButton">
<androidx.gridlayout.widget.GridLayout <androidx.gridlayout.widget.GridLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2" android:layout_height="wrap_content" android:id="@+id/contentGridLayout" app:columnCount="2"

View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">СканнерШтрихкодовДляРаботников</string>
<string name="action_settings">Настройки</string>
<string name="first_fragment_label">Добавить продукт</string>
<string name="second_fragment_label">Продукты</string>
<string name="scan_label">Сканировать</string>
<string name="netWeight">Вес нетто</string>
<string name="saveButton">Сохранить</string>
<string name="takePicture">Сфотографировать</string>
<string name="productName">Имя продукта</string>
<string name="productType">Тип продукта</string>
<string name="imageOfAProduct">Изображение продукта</string>
<string name="sample_product_name">Пример имени продукта</string>
<string name="sample_product_net_weight">100</string>
<string name="sample_unit">г</string>
<string name="sample_category">Пример категории</string>
<string name="title_activity_fullscreen">Полноэкранный режим</string>
<string name="fullscreen_image">Полноэкранное изображение</string>
<string name="delete_menu">Удалить предмет(ы)</string>
<string name="update_menu">Изменить предмет(ы)</string>
<string name="update">Обновить</string>
<string name="delete">Удалить</string>
<string name="category">Категория</string>
<string name="date_of_production">Дата производства</string>
<string name="expiry_date">Годен до</string>
<string name="select">Выбрать</string>
<string name="shelf_life">Срок годности</string>
<string name="amount">Количество</string>
<string name="sort_by">Сортировать по</string>
<string name="kilogram">кг</string>
<string name="gram">г</string>
<string name="liter">л</string>
<string name="milliliter">мл</string>
<string name="pieces">шт</string>
<string name="product_picture_request">Пожалуйста, сфотографируйте продукт!</string>
<string name="product_barcode_request">Пожалуйста, отсканируйте штрихкод на продукте!</string>
<string name="product_name_request">Пожалуйста, напишите название продукта</string>
<string name="product_net_weight_request">Пожалуйста, впишите верный вес нетто продукта</string>
<string name="camera_permission_for_picture_request">Требуется разрешение на доступ к камере для снятия
изображения
</string>
<string name="cancelled">Отменено</string>
<string name="scan_barcode_of_a_product">Простанируйте штрихкод продукта</string>
<string name="shell_life_or_expiry_date_request">Пожалуйста, выберите и заполните срок годности или годен до
</string>
<string name="date_of_production_request">Пожалуйста, выберите дату производства</string>
<string name="expiry_date_request">Пожалуйста, выберите годен до</string>
<string name="product_amount_request">Пожалуйста, укажите количество продукта</string>
<string name="camera_permission_for_scanning_request">Требуется разрешение на доступ к камере для сканирования
штрихкода
</string>
<string name="categories_title">Категории</string>
<string name="storage_title">Склад</string>
<string name="shelf_title">Полка</string>
<string name="deleting_abstract_product_warning">Удаление абстрактного продукта приведёт к удалению ВСЕХ продуктов
на полке, которые к нему принадлежат. Вы хотите продолжить?
</string>
<string name="deleting_category_warning">Удаление категории приведёт к удалению ВСЕХ продуктов, принадлежащих к ней.
Вы хотите продолжить?
</string>
<string name="yes">Да</string>
<string name="no">Нет</string>
<string name="nothing_to_delete">Нечего удалять</string>
<string name="nothing_to_update">Нечего обновлять</string>
<string name="expired">Просрочено</string>
<string name="barcode">Штрихкод</string>
<string-array name="product_sort_types">
<item>Имя</item>
<item>Категория</item>
<item>Свежесть</item>
<item>Дата производства</item>
<item>Годен до</item>
</string-array>
<string-array name="abstract_product_sort_types">
<item>Имя</item>
<item>Категория</item>
</string-array>
<string name="abstract_product_does_not_exist">Абстрактный продукт с таким штрихкодом не существует. Хотите его добавить?. </string>
<string name="drop_filters">Убрать фильтры</string>
<string name="category_name_required">Требуется название категории</string>
</resources>

View File

@@ -3,10 +3,7 @@
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string name="first_fragment_label">Add new product</string> <string name="first_fragment_label">Add new product</string>
<string name="second_fragment_label">Products</string> <string name="second_fragment_label">Products</string>
<string name="scan_label">Scan</string> <string name="netWeight">Net weight</string>
<string name="previous">Previous</string>
<string name="product_name_label">Product name</string>
<string name="netWeight">Net weight (g)</string>
<string name="saveButton">Save</string> <string name="saveButton">Save</string>
<string name="takePicture">Take picture</string> <string name="takePicture">Take picture</string>
<string name="productName">Product name</string> <string name="productName">Product name</string>
@@ -17,16 +14,18 @@
<string name="sample_unit">g</string> <string name="sample_unit">g</string>
<string name="sample_category">Sample category</string> <string name="sample_category">Sample category</string>
<string name="title_activity_fullscreen">FullscreenActivity</string> <string name="title_activity_fullscreen">FullscreenActivity</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<string name="fullscreen_image">Fullscreen image</string> <string name="fullscreen_image">Fullscreen image</string>
<string name="next">Next</string>
<string name="delete_menu">Delete item(s)…</string> <string name="delete_menu">Delete item(s)…</string>
<string name="update_menu">Update item</string> <string name="update_menu">Update item</string>
<string name="update">update</string> <string name="update">update</string>
<string name="delete">delete</string> <string name="delete">delete</string>
<string name="category">Category</string> <string name="category">Category</string>
<string name="date_of_production">Date of production</string> <string name="date_of_production">Date of production</string>
<string name="expiry_date">Expiry date</string>
<string name="select">Select</string>
<string name="shelf_life">Shelf life</string>
<string name="amount">Amount</string>
<string name="sort_by">Sort by</string>
<!-- Unit names --> <!-- Unit names -->
<string name="kilogram">kg</string> <string name="kilogram">kg</string>
@@ -34,4 +33,49 @@
<string name="liter">l</string> <string name="liter">l</string>
<string name="milliliter">ml</string> <string name="milliliter">ml</string>
<string name="pieces">pc</string> <string name="pieces">pc</string>
<string name="product_picture_request">Please, make a picture of a product!</string>
<string name="product_barcode_request">Please, scan barcode on a product</string>
<string name="product_name_request">Please, write a name of a product!</string>
<string name="product_net_weight_request">"Please, write a valid net weight of a product!"</string>
<string name="camera_permission_for_picture_request">I need permission in order to take a picture</string>
<string name="cancelled">Cancelled</string>
<string name="scan_barcode_of_a_product">Scan barcode of a product</string>
<string name="shell_life_or_expiry_date_request">Please, choose and fill in shelf life or expiry date.</string>
<string name="date_of_production_request">Please, choose date of production.</string>
<string name="expiry_date_request">Please, choose expiry date.</string>
<string name="product_amount_request">Please, specify an amount of product.</string>
<string name="camera_permission_for_scanning_request">I need permission in order to scan a barcode</string>
<string name="categories_title">Categories</string>
<string name="storage_title">Storage</string>
<string name="shelf_title">Shelf</string>
<string name="deleting_abstract_product_warning">Deleting an abstract product will also delete ALL the products, that belong to it. Do you want to proceed?</string>
<string name="deleting_category_warning">Deleting a category will also delete ALL the products, that belong to that category. Do you want to proceed?</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="nothing_to_delete">Nothing to delete</string>
<string name="nothing_to_update">Nothing to update</string>
<string-array name="product_sort_types">
<item>Name</item>
<item>Category</item>
<item>Freshness</item>
<item>Date of production</item>
<item>Expiry date</item>
</string-array>
<string-array name="abstract_product_sort_types">
<item>Name</item>
<item>Category</item>
</string-array>
<string name="expired">Expired</string>
<string name="barcode">Barcode</string>
<string name="scan_label">Scan</string>
<string name="abstract_product_does_not_exist">Abstract product with such barcode does not exist. Do you want to add one?</string>
<string name="drop_filters">Drop filters</string>
<string name="category_name_required">Category name required</string>
</resources> </resources>

View File

@@ -19,6 +19,7 @@ legacySupportV4 = "1.0.0"
fragment = "1.8.4" fragment = "1.8.4"
playServicesCodeScanner = "16.1.0" playServicesCodeScanner = "16.1.0"
volley = "1.2.1" volley = "1.2.1"
zxingAndroidEmbedded = "4.3.0"
[libraries] [libraries]
androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraView" } androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraView" }
@@ -41,6 +42,7 @@ androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" } androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" }
play-services-code-scanner = { module = "com.google.android.gms:play-services-code-scanner", version.ref = "playServicesCodeScanner" } play-services-code-scanner = { module = "com.google.android.gms:play-services-code-scanner", version.ref = "playServicesCodeScanner" }
volley = { module = "com.android.volley:volley", version.ref = "volley" } volley = { module = "com.android.volley:volley", version.ref = "volley" }
zxing-android-embedded = { module = "com.journeyapps:zxing-android-embedded", version.ref = "zxingAndroidEmbedded" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }