some refactor, renaming, started working with product on shelf

This commit is contained in:
leca 2024-10-11 04:58:31 +03:00
parent 926403f9ea
commit 3bfad0f6ad
28 changed files with 571 additions and 349 deletions

View File

@ -46,6 +46,8 @@ dependencies {
implementation(libs.firebase.crashlytics.buildtools) implementation(libs.firebase.crashlytics.buildtools)
implementation(libs.androidx.gridlayout) implementation(libs.androidx.gridlayout)
implementation(libs.androidx.activity) implementation(libs.androidx.activity)
implementation(libs.androidx.legacy.support.v4)
implementation(libs.androidx.fragment)
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)

View File

@ -31,6 +31,10 @@
android:name=".activities.AddProductActivity" android:name=".activities.AddProductActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.BarcodeScannerForEmployees"/> android:theme="@style/Theme.BarcodeScannerForEmployees"/>
<activity
android:name=".activities.AddAbstractProductActivity"
android:exported="false"
android:theme="@style/Theme.BarcodeScannerForEmployees"/>
<activity <activity
android:name=".activities.FullscreenActivity" android:name=".activities.FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
@ -40,7 +44,7 @@
<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.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:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data

View File

@ -1,8 +0,0 @@
package org.foxarmy.barcodescannerforemployees
class Category(
public var id: Int,
public var name: String,
) {
}

View File

@ -5,11 +5,12 @@ import android.database.DatabaseUtils
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper import android.database.sqlite.SQLiteOpenHelper
import android.provider.BaseColumns import android.provider.BaseColumns
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
import java.io.File import java.io.File
object ProductContract { object AbstractProductContract {
object ProductEntry : BaseColumns { object AbstractProductEntry : BaseColumns {
const val TABLE_NAME = "products" const val TABLE_NAME = "abstract_products"
const val PRODUCT_NAME = "name" const val PRODUCT_NAME = "name"
const val PRODUCT_NET_WEIGHT = "net_weight" const val PRODUCT_NET_WEIGHT = "net_weight"
const val IMAGE_FILENAME = "image_filename" 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 CategoriesContract {
object CategoryEntry : BaseColumns { object CategoryEntry : BaseColumns {
const val TABLE_NAME = "categories" const val TABLE_NAME = "categories"
@ -32,19 +25,31 @@ object CategoriesContract {
} }
} }
const val SQL_CREATE_PRODUCT_TABLE = 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_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} (" + "CREATE TABLE ${ProductContract.ProductEntry.TABLE_NAME} (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY," + "${BaseColumns._ID} INTEGER PRIMARY KEY," +
"${ProductContract.ProductEntry.PRODUCT_NAME} TEXT," + "${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID} INTEGER," +
"${ProductContract.ProductEntry.PRODUCT_NET_WEIGHT} REAL," + "${ProductContract.ProductEntry.AMOUNT} INTEGER," +
"${ProductContract.ProductEntry.IMAGE_FILENAME} TEXT," + "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} DATE," +
"${ProductContract.ProductEntry.CATEGORY} INTEGER)" "${ProductContract.ProductEntry.EXPIRY_DATE} DATE)"
const val SQL_CREATE_SHELF_TABLE =
"CREATE TABLE ${ShelfContract.ShelfEntry.TABLE_NAME} (" +
"${BaseColumns._ID} INTEGER PRIMARY KEY," +
"${ShelfContract.ShelfEntry.PRODUCT_ID} INTEGER," +
"${ShelfContract.ShelfEntry.EXPIRE_DATE} DATE)"
const val SQL_CREATE_CATEGORIES_TABLE = const val SQL_CREATE_CATEGORIES_TABLE =
"CREATE TABLE ${CategoriesContract.CategoryEntry.TABLE_NAME} (" + "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) { class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
override fun onCreate(db: SQLiteDatabase) { override fun onCreate(db: SQLiteDatabase) {
db.execSQL(SQL_CREATE_PRODUCT_TABLE) db.execSQL(SQL_CREATE_ABSTRACT_PRODUCTS_TABLE)
db.execSQL(SQL_CREATE_SHELF_TABLE) db.execSQL(SQL_CREATE_PRODUCTS_TABLE)
db.execSQL(SQL_CREATE_CATEGORIES_TABLE) db.execSQL(SQL_CREATE_CATEGORIES_TABLE)
} }
@ -96,22 +101,22 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
var result = mutableListOf<AbstractProduct>() var result = mutableListOf<AbstractProduct>()
val projection = arrayOf( val projection = arrayOf(
BaseColumns._ID, BaseColumns._ID,
ProductContract.ProductEntry.PRODUCT_NAME, AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
ProductContract.ProductEntry.IMAGE_FILENAME, AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
ProductContract.ProductEntry.PRODUCT_NET_WEIGHT, AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
) )
val selection = "${ProductContract.ProductEntry.CATEGORY} = ?" val selection = "${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?"
val selectionArgs = arrayOf(id.toString()) 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) { with(cursor) {
while (moveToNext()) { while (moveToNext()) {
val abstractProductId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) val abstractProductId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
val abstractProductName = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NAME)) val abstractProductName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NET_WEIGHT)) val abstractProductNetWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
val abstractProductImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME)) val abstractProductImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
val abstractProduct = AbstractProduct(abstractProductId, abstractProductName, abstractProductNetWeight, abstractProductImageHash, category = id) 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 { 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) { fun eraseAbstractProduct(db: SQLiteDatabase, id: Int, context: Context) {
val projection = arrayOf( val projection = arrayOf(
ProductContract.ProductEntry.IMAGE_FILENAME AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME
) )
val selection = "${BaseColumns._ID} = ?" val selection = "${BaseColumns._ID} = ?"
val selectionArgs = arrayOf(id.toString()) val selectionArgs = arrayOf(id.toString())
val cursor = db.query( val cursor = db.query(
ProductContract.ProductEntry.TABLE_NAME, AbstractProductContract.AbstractProductEntry.TABLE_NAME,
projection, projection,
selection, selection,
selectionArgs, selectionArgs,
@ -145,7 +150,7 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
with (cursor) { with (cursor) {
while(moveToNext()) { while(moveToNext()) {
val productImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME)) val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
imageHash = productImageHash imageHash = productImageHash
} }
} }
@ -154,7 +159,7 @@ class DBStorageController(context: Context) : SQLiteOpenHelper(context, DATABASE
File(picturesDir, "$imageHash.png").delete() File(picturesDir, "$imageHash.png").delete()
File(thumbnailsDir, "$imageHash.webp").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 { companion object {

View File

@ -1,5 +1,7 @@
package org.foxarmy.barcodescannerforemployees package org.foxarmy.barcodescannerforemployees
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
class Parser constructor(payloadStartRegex: String, payloadEndRegex: String, payloadRegex: String){ class Parser constructor(payloadStartRegex: String, payloadEndRegex: String, payloadRegex: String){
val payloadStartRegex: String = payloadStartRegex val payloadStartRegex: String = payloadStartRegex
val payloadEndRegex: String = payloadEndRegex val payloadEndRegex: String = payloadEndRegex

View File

@ -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()
}
}
}

View File

@ -7,6 +7,7 @@ import android.provider.BaseColumns
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
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
@ -17,17 +18,16 @@ class AddCategoryActivity : Activity() {
setContentView(R.layout.activity_add_category) setContentView(R.layout.activity_add_category)
val extras = intent.extras val extras = intent.extras
val categoryId = extras!!.get("categoryid") as Int? val category = extras!!.get("category") as Category?
val categoryName = extras.get("categoryname") as String?
val categoryNameTextEdit: EditText = findViewById(R.id.newCategoryName) val categoryNameTextEdit: EditText = findViewById(R.id.newCategoryName)
categoryNameTextEdit.setText(categoryName) categoryNameTextEdit.setText(category!!.name)
findViewById<Button>(R.id.saveButton).setOnClickListener { findViewById<Button>(R.id.saveButton).setOnClickListener {
val db = DBStorageController(this).writableDatabase val db = DBStorageController(this).writableDatabase
if (categoryId == 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())
} }
@ -37,7 +37,7 @@ class AddCategoryActivity : Activity() {
val values = ContentValues().apply { val values = ContentValues().apply {
put(CategoriesContract.CategoryEntry.CATEGORY_NAME, categoryNameTextEdit.text.toString()) 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() finish()

View File

@ -1,200 +1,18 @@
package org.foxarmy.barcodescannerforemployees.activities package org.foxarmy.barcodescannerforemployees.activities
import android.Manifest
import android.content.ContentValues
import android.os.Build
import android.os.Bundle 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 androidx.appcompat.app.AppCompatActivity
import com.google.mlkit.vision.barcode.common.Barcode import org.foxarmy.barcodescannerforemployees.R
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions import org.foxarmy.barcodescannerforemployees.dataclasses.Product
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
class AddProductActivity : AppCompatActivity() { 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.fragment_add_product) setContentView(R.layout.activity_add_product)
val extras = intent.extras val extras = intent.extras
product = extras!!.get("updatingObject") as AbstractProduct? val product = extras!!.get("product") as Product?
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)
} }
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()
}
}
} }

View File

@ -12,7 +12,9 @@ import androidx.viewpager.widget.ViewPager
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment
import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment
import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -36,25 +38,34 @@ class MainActivity : AppCompatActivity() {
when (fragment::class.simpleName.toString()) { when (fragment::class.simpleName.toString()) {
"StorageFragment" -> { "StorageFragment" -> {
val addProductIntent = Intent(this, AddProductActivity::class.java) val addAbstractProductIntent = Intent(this, AddAbstractProductActivity::class.java)
val extras = Bundle() val extras = Bundle()
// I reuse the same stuff for editing and adding new product. // I reuse the same stuff for editing and adding new product.
// if updatingObject == null, it means that we need to create new object // if abstractProduct == null, it means that we need to create new object
extras.putParcelable("updatingObject", null) extras.putParcelable("abstractProduct", null)
addProductIntent.putExtras(extras) addAbstractProductIntent.putExtras(extras)
ContextCompat.startActivity(this, addProductIntent, extras) ContextCompat.startActivity(this, addAbstractProductIntent, extras)
} }
"CategoriesFragment" -> { "CategoriesFragment" -> {
val addCategoryIntent = Intent(this, AddCategoryActivity::class.java) val addCategoryIntent = Intent(this, AddCategoryActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putInt("categoryid", 0) //TODO: Implement parcellable for Category class to simplify this
extras.putString("categoryname", "New category") // extras.putInt("categoryid", 0)
// extras.putString("categoryname", "New category")
extras.putParcelable("category", Category(0, "New category"))
addCategoryIntent.putExtras(extras) addCategoryIntent.putExtras(extras)
ContextCompat.startActivity(this, addCategoryIntent, 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(CategoriesFragment(), "Categories")
adapter.addFragment(StorageFragment(), "Storage") adapter.addFragment(StorageFragment(), "Storage")
//TODO: shelf and settings fragments adapter.addFragment(ShelfFragment(), "Shelf")
//TODO: settings fragments
// setting adapter to view pager. // setting adapter to view pager.
viewpager.setAdapter(adapter) viewpager.setAdapter(adapter)

View File

@ -1,4 +1,4 @@
package org.foxarmy.barcodescannerforemployees package org.foxarmy.barcodescannerforemployees.dataclasses
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}

View File

@ -12,7 +12,7 @@ import androidx.core.content.ContextCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import org.foxarmy.barcodescannerforemployees.CategoriesContract import org.foxarmy.barcodescannerforemployees.CategoriesContract
import org.foxarmy.barcodescannerforemployees.Category import org.foxarmy.barcodescannerforemployees.dataclasses.Category
import org.foxarmy.barcodescannerforemployees.DBStorageController import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.R import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity import org.foxarmy.barcodescannerforemployees.activities.AddCategoryActivity
@ -56,8 +56,7 @@ class CategoriesFragment : Fragment() {
if (view.isCategorySelected) { if (view.isCategorySelected) {
val addCategoryIntent = Intent(context, AddCategoryActivity::class.java) val addCategoryIntent = Intent(context, AddCategoryActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putInt("categoryid", view.category.id) extras.putParcelable("category", view.category)
extras.putString("categoryname", view.category.name)
addCategoryIntent.putExtras(extras) addCategoryIntent.putExtras(extras)
ContextCompat.startActivity(context!!, addCategoryIntent, extras) ContextCompat.startActivity(context!!, addCategoryIntent, extras)
} }

View File

@ -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)
}
}

View File

@ -12,8 +12,12 @@ import androidx.core.content.ContextCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.gridlayout.widget.GridLayout import androidx.gridlayout.widget.GridLayout
import org.foxarmy.barcodescannerforemployees.* import org.foxarmy.barcodescannerforemployees.AbstractProductContract
import org.foxarmy.barcodescannerforemployees.activities.AddProductActivity 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 import org.foxarmy.barcodescannerforemployees.views.AbstractProductView
class StorageFragment : Fragment() { class StorageFragment : Fragment() {
@ -39,7 +43,7 @@ class StorageFragment : Fragment() {
for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) { for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
view.findViewById<ImageView>(R.id.productPicture).setImageURI(null) view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
if (view.isProductSelected) { if (view.isProductSelected) {
db.eraseAbstractProduct(db.writableDatabase, view.product.id, requireContext()) db.eraseAbstractProduct(db.writableDatabase, view.abstractProduct.id, requireContext())
deleted = true deleted = true
} }
} }
@ -55,9 +59,9 @@ class StorageFragment : Fragment() {
for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) { for (view: AbstractProductView in grv?.children!!.iterator() as Iterator<AbstractProductView>) {
if (view.isProductSelected) { if (view.isProductSelected) {
val addProductIntent = Intent(requireContext(), AddProductActivity::class.java) val addProductIntent = Intent(requireContext(), AddAbstractProductActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putParcelable("updatingObject", view.product) extras.putParcelable("abstractProduct", view.abstractProduct)
addProductIntent.putExtras(extras) addProductIntent.putExtras(extras)
ContextCompat.startActivity(requireContext(), addProductIntent, extras) ContextCompat.startActivity(requireContext(), addProductIntent, extras)
} }
@ -72,21 +76,21 @@ class StorageFragment : Fragment() {
val db = DBStorageController(requireContext()).readableDatabase val db = DBStorageController(requireContext()).readableDatabase
val projection = arrayOf(BaseColumns._ID, val projection = arrayOf(BaseColumns._ID,
ProductContract.ProductEntry.PRODUCT_NAME, AbstractProductContract.AbstractProductEntry.PRODUCT_NAME,
ProductContract.ProductEntry.PRODUCT_NET_WEIGHT, AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT,
ProductContract.ProductEntry.IMAGE_FILENAME, AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME,
ProductContract.ProductEntry.CATEGORY 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) { with (cursor) {
while(moveToNext()) { while(moveToNext()) {
val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID)) val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
val productName = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NAME)) val productName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
val netWeight = getDouble(getColumnIndexOrThrow(ProductContract.ProductEntry.PRODUCT_NET_WEIGHT)) val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
val productImageHash = getString(getColumnIndexOrThrow(ProductContract.ProductEntry.IMAGE_FILENAME)) val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
val category = getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.CATEGORY)) val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY))
val product = AbstractProduct(productId, productName, netWeight, productImageHash, category) val product = AbstractProduct(productId, productName, netWeight, productImageHash, category)

View File

@ -11,7 +11,7 @@ import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import org.foxarmy.barcodescannerforemployees.AbstractProduct import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
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.FullscreenActivity import org.foxarmy.barcodescannerforemployees.activities.FullscreenActivity
@ -25,12 +25,12 @@ class AbstractProductView: LinearLayout {
private var netWeightField: TextView private var netWeightField: TextView
private var categoryField: TextView private var categoryField: TextView
private var unitField: TextView private var unitField: TextView
var product: AbstractProduct var abstractProduct: AbstractProduct
var isProductSelected = false 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 val inflater:LayoutInflater = activity.layoutInflater
inflater.inflate(R.layout.abstract_product_view, this) inflater.inflate(R.layout.abstract_product_view, this)
@ -44,13 +44,13 @@ class AbstractProductView: LinearLayout {
val thumbnailsDir = File(context.cacheDir, "thumbnails") val thumbnailsDir = File(context.cacheDir, "thumbnails")
thumbnailsDir.mkdirs() thumbnailsDir.mkdirs()
val imageUri = getImageUri(activity, File(thumbnailsDir, "${product.imageHash}.webp")) val imageUri = getImageUri(activity, File(thumbnailsDir, "${abstractProduct.imageHash}.webp"))
productPicture.setImageURI(imageUri) productPicture.setImageURI(imageUri)
productPicture.rotation = 90f productPicture.rotation = 90f
productPicture.setOnClickListener { productPicture.setOnClickListener {
val fullscreenIntent = Intent(activity, FullscreenActivity::class.java) val fullscreenIntent = Intent(activity, FullscreenActivity::class.java)
val extras = Bundle() val extras = Bundle()
extras.putString("imagehash", product.imageHash) extras.putString("imagehash", abstractProduct.imageHash)
fullscreenIntent.putExtras(extras) fullscreenIntent.putExtras(extras)
startActivity(context, fullscreenIntent, extras) startActivity(context, fullscreenIntent, extras)
} }
@ -61,9 +61,9 @@ class AbstractProductView: LinearLayout {
productNameField.text = product.name productNameField.text = abstractProduct.name
netWeightField.text = product.netWeight.toString() netWeightField.text = abstractProduct.netWeight.toString()
categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, product.category) categoryField.text = DBStorageController(context).getCategoryNameById(DBStorageController(context).readableDatabase, abstractProduct.category)
//TODO: units //TODO: units

View File

@ -6,7 +6,7 @@ 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.Category 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

View 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>

View 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>

View 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>

View File

@ -10,74 +10,11 @@
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">
<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 <Spinner
android:layout_width="match_parent" android:layout_width="400dp"
android:layout_height="wrap_content" android:id="@+id/categorySpinner" android:layout_height="50dp" android:id="@+id/abstractProductSelect"
app:layout_constraintStart_toEndOf="@+id/categoryTextView" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="12dp"
app:layout_constraintTop_toBottomOf="@+id/netWeight" android:layout_marginStart="8dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="20dp"/> app:layout_constraintEnd_toEndOf="parent"/>
<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.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>

View 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>

View 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>

View File

@ -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>

View File

@ -5,6 +5,7 @@
android:id="@+id/nav_graph_add_product" android:id="@+id/nav_graph_add_product"
app:startDestination="@id/addProductFragment"> app:startDestination="@id/addProductFragment">
<fragment android:id="@+id/addProductFragment" android:name="org.foxarmy.barcodescannerforemployees.fragments.AddProductFragment" <fragment android:id="@+id/addProductFragment"
android:label="add_product_fragment" tools:layout="@layout/fragment_add_product"/> android:name="org.foxarmy.barcodescannerforemployees.fragments.AddProductFragment"
android:label="activity_add_product" tools:layout="@layout/fragment_add_product"/>
</navigation> </navigation>

View File

@ -15,6 +15,8 @@ navigationUiKtx = "2.8.0"
firebaseCrashlyticsBuildtools = "3.0.2" firebaseCrashlyticsBuildtools = "3.0.2"
gridlayout = "1.0.0" gridlayout = "1.0.0"
activity = "1.9.2" activity = "1.9.2"
legacySupportV4 = "1.0.0"
fragment = "1.8.4"
[libraries] [libraries]
androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraView" } androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraView" }
@ -31,6 +33,8 @@ androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation
firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" } firebase-crashlytics-buildtools = { group = "com.google.firebase", name = "firebase-crashlytics-buildtools", version.ref = "firebaseCrashlyticsBuildtools" }
androidx-gridlayout = { group = "androidx.gridlayout", name = "gridlayout", version.ref = "gridlayout" } androidx-gridlayout = { group = "androidx.gridlayout", name = "gridlayout", version.ref = "gridlayout" }
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacySupportV4" }
androidx-fragment = { group = "androidx.fragment", name = "fragment", version.ref = "fragment" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }