Compare commits
8 Commits
alpha-0.0.
...
master
Author | SHA1 | Date |
---|---|---|
leca | 58a7ea7357 | |
leca | 2ebcfff51a | |
leca | 2676d8083e | |
leca | e5772bcad3 | |
leca | 988272070d | |
leca | fbf630090c | |
leca | 8c3845a07e | |
leca | d08a79e981 |
|
@ -13,6 +13,7 @@
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.foxarmy.barcodescannerforemployees
|
package org.foxarmy.barcodescannerforemployees
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import okhttp3.MediaType.Companion.toMediaType
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
|
@ -17,6 +18,28 @@ class Net {
|
||||||
var server = "bsfe.foxarmy.org"
|
var server = "bsfe.foxarmy.org"
|
||||||
var token = ""
|
var token = ""
|
||||||
|
|
||||||
|
fun serverIsAvailable(context: Context): Boolean {
|
||||||
|
if (!isInternetConnectionAvailable(context)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var flag = false
|
||||||
|
thread {
|
||||||
|
val client = OkHttpClient();
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url("https://$server/status")
|
||||||
|
.get()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
val response = client.newCall(request).execute();
|
||||||
|
flag = response.code == 200;
|
||||||
|
} catch (e: Exception) {
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
}.join()
|
||||||
|
return flag
|
||||||
|
}
|
||||||
|
|
||||||
fun requestProductFromOnlineDB(barcode: String): String {
|
fun requestProductFromOnlineDB(barcode: String): String {
|
||||||
var response = ""
|
var response = ""
|
||||||
thread {
|
thread {
|
||||||
|
|
|
@ -14,8 +14,6 @@ class Parser constructor() {
|
||||||
text = text.replace(found, "")
|
text = text.replace(found, "")
|
||||||
netWeight = stripNetWeight(found)
|
netWeight = stripNetWeight(found)
|
||||||
return Triple(text, netWeight, found)
|
return Triple(text, netWeight, found)
|
||||||
} else {
|
|
||||||
return Triple(text, 0.0, "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Triple("", 0.0, "")
|
return Triple("", 0.0, "")
|
||||||
|
|
|
@ -7,10 +7,15 @@ import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.media.ExifInterface
|
import android.media.ExifInterface
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.net.NetworkCapabilities
|
||||||
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.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
|
import androidx.security.crypto.MasterKeys
|
||||||
import com.google.firebase.components.BuildConfig
|
import com.google.firebase.components.BuildConfig
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
import java.io.FileInputStream
|
||||||
|
@ -18,6 +23,7 @@ import java.io.FileOutputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
fun convertToUnixEpochTimestamp(dateString: String): Long {
|
fun convertToUnixEpochTimestamp(dateString: String): Long {
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||||
|
@ -27,7 +33,11 @@ fun convertToUnixEpochTimestamp(dateString: String): Long {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImageUri(activity: Activity, imageFile: File): Uri? {
|
fun getImageUri(activity: Activity, imageFile: File): Uri? {
|
||||||
return FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + "." + activity.localClassName + ".provider", imageFile)
|
return FileProvider.getUriForFile(
|
||||||
|
activity,
|
||||||
|
BuildConfig.APPLICATION_ID + "." + activity.localClassName + ".provider",
|
||||||
|
imageFile
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
@RequiresApi(Build.VERSION_CODES.R)
|
||||||
|
@ -65,7 +75,10 @@ fun String.md5(): String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stripNetWeight(netWeight: String): Double {
|
fun stripNetWeight(netWeight: String): Double {
|
||||||
return removeSubstringsFromString(netWeight, arrayOf("Л", "л", "мл", "Мл", "г", "Г", "кг", "Кг", "шт", "Шт", ",", " ", ".")).toDouble()
|
return removeSubstringsFromString(
|
||||||
|
netWeight,
|
||||||
|
arrayOf("Л", "л", "мл", "Мл", "г", "Г", "кг", "Кг", "шт", "Шт", ",", " ", ".")
|
||||||
|
).toDouble()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeSubstringsFromString(text: String, toRemove: Array<String>): String {
|
fun removeSubstringsFromString(text: String, toRemove: Array<String>): String {
|
||||||
|
@ -101,12 +114,29 @@ fun calculateProductFreshness(dateOfProduction: Long, dateOfExpiry: Long): Doubl
|
||||||
|
|
||||||
fun getUnitNameById(context: Context, id: Int): String {
|
fun getUnitNameById(context: Context, id: Int): String {
|
||||||
return when (id) {
|
return when (id) {
|
||||||
0 -> { context.getString(R.string.kilogram) }
|
0 -> {
|
||||||
1 -> { context.getString(R.string.gram) }
|
context.getString(R.string.kilogram)
|
||||||
2 -> { context.getString(R.string.liter) }
|
}
|
||||||
3 -> { context.getString(R.string.milliliter) }
|
|
||||||
4 -> { context.getString(R.string.pieces) }
|
1 -> {
|
||||||
else -> { "" }
|
context.getString(R.string.gram)
|
||||||
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
context.getString(R.string.liter)
|
||||||
|
}
|
||||||
|
|
||||||
|
3 -> {
|
||||||
|
context.getString(R.string.milliliter)
|
||||||
|
}
|
||||||
|
|
||||||
|
4 -> {
|
||||||
|
context.getString(R.string.pieces)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,3 +168,48 @@ fun bytesToHex(bytes: ByteArray): String {
|
||||||
}
|
}
|
||||||
return hexString.toString()
|
return hexString.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isInternetConnectionAvailable(context: Context): Boolean {
|
||||||
|
if (context.getSystemService(Context.CONNECTIVITY_SERVICE) == null) return false
|
||||||
|
val connectivityManager =
|
||||||
|
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
if (connectivityManager != null) {
|
||||||
|
val capabilities =
|
||||||
|
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||||
|
if (capabilities != null) {
|
||||||
|
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||||
|
return true
|
||||||
|
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||||
|
return true
|
||||||
|
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun noInternetConnectionAvailableNotification(context: Context) {
|
||||||
|
(context as Activity).runOnUiThread {
|
||||||
|
AlertDialog.Builder(context)
|
||||||
|
.setMessage(context.getString(R.string.no_internet_connection))
|
||||||
|
.setPositiveButton(R.string.quit) { _, _ ->
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.logout) { _, _ ->
|
||||||
|
val sharedPreferences = EncryptedSharedPreferences.create(
|
||||||
|
"sensitive",
|
||||||
|
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
||||||
|
context,
|
||||||
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
|
)
|
||||||
|
|
||||||
|
sharedPreferences.edit().putString("token", "").apply()
|
||||||
|
sharedPreferences.edit().putString("server", "").apply()
|
||||||
|
sharedPreferences.edit().putStringSet("groups", emptySet()).apply()
|
||||||
|
sharedPreferences.edit().putString("currentGroup", "").apply()
|
||||||
|
exitProcess(0)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package org.foxarmy.barcodescannerforemployees
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import okhttp3.*
|
||||||
|
import org.foxarmy.barcodescannerforemployees.activities.MainActivity
|
||||||
|
import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
|
||||||
|
import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
|
||||||
|
import org.foxarmy.barcodescannerforemployees.database.DBStorageController
|
||||||
|
import org.foxarmy.barcodescannerforemployees.database.ProductDAO
|
||||||
|
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
|
||||||
|
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
|
||||||
|
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class WebSocketClient(private val context: Context, private val server: String) {
|
||||||
|
|
||||||
|
private lateinit var webSocket: WebSocket
|
||||||
|
|
||||||
|
fun connect(token: String, currentGroup: String) {
|
||||||
|
val client = OkHttpClient.Builder()
|
||||||
|
.connectTimeout(5, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(1, TimeUnit.MINUTES)
|
||||||
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.callTimeout(1, TimeUnit.MINUTES)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url("wss://$server")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
client.newWebSocket(request, object : WebSocketListener() {
|
||||||
|
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||||
|
this@WebSocketClient.webSocket = webSocket
|
||||||
|
sendMessage("{\"token\":\"$token\",\"currentGroup\":\"$currentGroup\"}")
|
||||||
|
keepAlive()
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
override fun onMessage(webSocket: WebSocket, text: String) {
|
||||||
|
val payload = JSONObject(text)
|
||||||
|
|
||||||
|
val item = payload["item"] as String
|
||||||
|
val data = payload["data"] as JSONObject
|
||||||
|
val action = payload["action"] as String
|
||||||
|
val currentGroup = payload["groupId"] as String
|
||||||
|
|
||||||
|
val dbHelper = DBStorageController(context, currentGroup)
|
||||||
|
val abstractProductDAO = AbstractProductDAO(dbHelper)
|
||||||
|
val productDAO = ProductDAO(dbHelper)
|
||||||
|
val categoryDAO = CategoryDAO(dbHelper)
|
||||||
|
|
||||||
|
when (action) {
|
||||||
|
"create" -> {
|
||||||
|
when (item) {
|
||||||
|
"abstractproduct" -> {
|
||||||
|
val newAbstractProduct = AbstractProduct.createFromJSON(data)
|
||||||
|
|
||||||
|
val net = Net()
|
||||||
|
net.server = server
|
||||||
|
net.token = token
|
||||||
|
|
||||||
|
val picturesDir = File(context.filesDir, "pictures")
|
||||||
|
picturesDir.mkdirs()
|
||||||
|
|
||||||
|
val pictureFile =
|
||||||
|
File(picturesDir, "${data["image_filename"]}.png")
|
||||||
|
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${data["local_id"]}"
|
||||||
|
net.downloadImage(url, pictureFile)
|
||||||
|
|
||||||
|
abstractProductDAO.addAbstractProduct(newAbstractProduct)
|
||||||
|
}
|
||||||
|
|
||||||
|
"product" -> {
|
||||||
|
val newProduct = Product.createFromJSON(data)
|
||||||
|
productDAO.insertNewProduct(newProduct)
|
||||||
|
}
|
||||||
|
|
||||||
|
"category" -> {
|
||||||
|
val newCategory = Category.createFromJSON(data)
|
||||||
|
categoryDAO.addCategory(newCategory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"update" -> {
|
||||||
|
when (item) {
|
||||||
|
"abstractproduct" -> {
|
||||||
|
val updatedAbstractProduct = AbstractProduct.createFromJSON(data)
|
||||||
|
|
||||||
|
val net = Net()
|
||||||
|
net.server = server
|
||||||
|
net.token = token
|
||||||
|
|
||||||
|
val picturesDir = File(context.filesDir, "pictures")
|
||||||
|
picturesDir.mkdirs()
|
||||||
|
|
||||||
|
val pictureFile =
|
||||||
|
File(picturesDir, "${data["image_filename"]}.png")
|
||||||
|
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${data["local_id"]}"
|
||||||
|
net.downloadImage(url, pictureFile)
|
||||||
|
|
||||||
|
abstractProductDAO.updateAbstractProduct(updatedAbstractProduct)
|
||||||
|
}
|
||||||
|
"product" -> {
|
||||||
|
val updatedProduct = Product.createFromJSON(data)
|
||||||
|
productDAO.updateProduct(updatedProduct)
|
||||||
|
}
|
||||||
|
"category" -> {
|
||||||
|
val updatedCategory = Category.createFromJSON(data)
|
||||||
|
categoryDAO.updateCategory(updatedCategory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"delete" -> {
|
||||||
|
val id = data["local_id"] as String
|
||||||
|
|
||||||
|
when(item) {
|
||||||
|
"abstractproduct" -> {
|
||||||
|
abstractProductDAO.eraseAbstractProduct(id.toInt(), context)
|
||||||
|
}
|
||||||
|
"product" -> {
|
||||||
|
productDAO.eraseProduct(id.toInt())
|
||||||
|
}
|
||||||
|
"category" -> {
|
||||||
|
categoryDAO.eraseCategory(id.toInt(), context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(context as MainActivity).updateAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||||
|
Log.d("QWERTYUIOP", "Closing ws. Reason: $reason")
|
||||||
|
noInternetConnectionAvailableNotification(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||||
|
Log.d("QWERTYUIOP","Connection failed: ${t.message}")
|
||||||
|
noInternetConnectionAvailableNotification(context)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun keepAlive() {
|
||||||
|
Thread {
|
||||||
|
while (true) {
|
||||||
|
Thread.sleep(30000)
|
||||||
|
webSocket.send("keepalive")
|
||||||
|
}
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMessage(message: String) {
|
||||||
|
webSocket.send(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
webSocket.close(1000, "Closing WebSocket connection")
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import java.io.FileOutputStream
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class AddAbstractProductActivity : AppCompatActivity() {
|
class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
private lateinit var imageView: ImageView
|
private lateinit var imageView: ImageView
|
||||||
|
@ -73,7 +74,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
)
|
)
|
||||||
|
|
||||||
val dbHelper = DBStorageController(this, sharedPreferences.getString("currentGroup", "database")!!)
|
val dbHelper = DBStorageController(this, sharedPreferences.getString("currentGroup", "offline")!!)
|
||||||
DAO = AbstractProductDAO(dbHelper)
|
DAO = AbstractProductDAO(dbHelper)
|
||||||
|
|
||||||
picturesPath = File(filesDir, "pictures")
|
picturesPath = File(filesDir, "pictures")
|
||||||
|
@ -109,25 +110,28 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
action = extras!!.get("action") as String
|
action = extras!!.get("action") as String
|
||||||
when (action) {
|
when (action) {
|
||||||
"update" -> {
|
"update" -> {
|
||||||
abstractProduct = extras.get("abstractProduct") as AbstractProduct?
|
abstractProduct = extras.get("abstractProduct") as AbstractProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
"new_from_barcode" -> {
|
"new_from_barcode" -> {
|
||||||
abstractProduct = extras.get("abstractProduct") as AbstractProduct?
|
abstractProduct = extras.get("abstractProduct") as AbstractProduct
|
||||||
barcode = abstractProduct!!.barcode
|
barcode = abstractProduct!!.barcode
|
||||||
performRequest(abstractProduct!!.barcode)
|
performRequest(abstractProduct!!.barcode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abstractProduct != null) {
|
if (abstractProduct != null && action == "update") {
|
||||||
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)
|
||||||
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()
|
||||||
categorySpinner.setSelection(abstractProduct!!.category)
|
categorySpinner.setSelection(abstractProduct!!.category - 1)
|
||||||
unitTypeSpinner.setSelection(abstractProduct!!.unit)
|
unitTypeSpinner.setSelection(abstractProduct!!.unit)
|
||||||
|
if (abstractProduct!!.barcode == "" || abstractProduct!!.barcode == " ") {
|
||||||
|
noBarcodeCheckBox.isChecked = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveButton.setOnClickListener {
|
saveButton.setOnClickListener {
|
||||||
|
@ -149,17 +153,24 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
if (netWeight.toString() == "" || netWeight.toString().toDoubleOrNull() == null) {
|
if (netWeight.toString() == "" || netWeight.toString().toDoubleOrNull() == null) {
|
||||||
Toast.makeText(this, getString(R.string.product_net_weight_request), Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, getString(R.string.product_net_weight_request), Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
val currentGroup: Int
|
||||||
|
val currentGroupString = sharedPreferences.getString("currentGroup", "offline")!!
|
||||||
|
|
||||||
|
lateinit var response: Response
|
||||||
val net = Net()
|
val net = Net()
|
||||||
|
|
||||||
|
if (currentGroupString != "offline") {
|
||||||
|
currentGroup = currentGroupString.toInt()
|
||||||
|
|
||||||
net.token = sharedPreferences.getString("token", "")!!
|
net.token = sharedPreferences.getString("token", "")!!
|
||||||
net.server = sharedPreferences.getString("server", "")!!
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
net.language = sharedPreferences.getString("language", "en-US")!!
|
net.language = sharedPreferences.getString("language", "en-US")!!
|
||||||
|
|
||||||
val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!
|
} else {
|
||||||
|
currentGroup = 0
|
||||||
lateinit var response: Response
|
}
|
||||||
|
|
||||||
abstractProduct = AbstractProduct(
|
abstractProduct = AbstractProduct(
|
||||||
if (abstractProduct == null) 0 else abstractProduct!!.id,
|
if (abstractProduct == null) 0 else abstractProduct!!.id,
|
||||||
|
@ -170,16 +181,18 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
categorySpinner.selectedItemPosition + 1,
|
categorySpinner.selectedItemPosition + 1,
|
||||||
unitTypeSpinner.selectedItemPosition
|
unitTypeSpinner.selectedItemPosition
|
||||||
)
|
)
|
||||||
|
|
||||||
val pictureFile = File(File(filesDir, "pictures"), "${abstractProduct!!.imageHash}.png")
|
val pictureFile = File(File(filesDir, "pictures"), "${abstractProduct!!.imageHash}.png")
|
||||||
|
|
||||||
if (action == "update") {
|
if (action == "update") {
|
||||||
DAO.updateAbstractProduct(abstractProduct!!)
|
DAO.updateAbstractProduct(abstractProduct!!)
|
||||||
response = net.updateAbstractProduct(currentGroup.toInt(), abstractProduct!!, pictureFile)
|
if (currentGroup > 0) response = net.updateAbstractProduct(currentGroup, abstractProduct!!, pictureFile)
|
||||||
} else if (action == "new" || action == "new_from_barcode") {
|
} else if (action == "new" || action == "new_from_barcode") {
|
||||||
abstractProduct!!.id = DAO.addAbstractProduct(abstractProduct!!).toInt()
|
abstractProduct!!.id = DAO.addAbstractProduct(abstractProduct!!).toInt()
|
||||||
response = net.uploadAbstractProduct(currentGroup.toInt(), abstractProduct!!, pictureFile);
|
if (currentGroup > 0) response =
|
||||||
|
net.uploadAbstractProduct(currentGroup, abstractProduct!!, pictureFile)
|
||||||
}
|
}
|
||||||
Toast.makeText(this, response.body!!.string(), Toast.LENGTH_LONG).show()
|
if (currentGroup > 0) Toast.makeText(this, response.body!!.string(), Toast.LENGTH_LONG).show()
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
@ -198,7 +211,6 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
barcodeText.setText(this.barcode)
|
barcodeText.setText(this.barcode)
|
||||||
val net = Net();
|
val net = Net();
|
||||||
val result = net.requestProductFromOnlineDB(barcode)
|
val result = net.requestProductFromOnlineDB(barcode)
|
||||||
Log.d("QWERTYUIOP", "Result of request: $result")
|
|
||||||
|
|
||||||
var abstractProduct: AbstractProduct
|
var abstractProduct: AbstractProduct
|
||||||
|
|
||||||
|
@ -257,7 +269,8 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
|
|
||||||
fun fillupCategorySpinner() {
|
fun fillupCategorySpinner() {
|
||||||
|
|
||||||
val categoriesDAO = CategoryDAO(DBStorageController(this, sharedPreferences.getString("currentGroup", "database")!!))
|
val categoriesDAO =
|
||||||
|
CategoryDAO(DBStorageController(this, sharedPreferences.getString("currentGroup", "database")!!))
|
||||||
|
|
||||||
val categories = categoriesDAO.getAllCategories().map { category -> category.name }
|
val categories = categoriesDAO.getAllCategories().map { category -> category.name }
|
||||||
|
|
||||||
|
@ -272,18 +285,11 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
if (success) {
|
if (success) {
|
||||||
//Move picture to a proper directory according to its calculated hash
|
//Move picture to a proper directory according to its calculated hash
|
||||||
val tempfile = File(filesDir, "image.png")
|
val tempfile = File(filesDir, "image.png")
|
||||||
val imageHash = calculateMd5Hash(tempfile)
|
|
||||||
// val imageContent = tempfile.inputStream().readBytes()
|
|
||||||
// val imageHash = imageContent.toString(Charsets.UTF_8).md5()
|
|
||||||
|
|
||||||
pictureFile = File(picturesPath, "$imageHash.png")
|
val imageContent = tempfile.inputStream().readBytes()
|
||||||
Files.move(tempfile.toPath(), pictureFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
tempfile.delete()
|
|
||||||
|
|
||||||
val imageContent = pictureFile.inputStream().readBytes()
|
|
||||||
var img = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.size)
|
var img = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.size)
|
||||||
|
|
||||||
val exif = ExifInterface(pictureFile.absoluteFile.toString())
|
val exif = ExifInterface(tempfile.absoluteFile.toString())
|
||||||
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
|
||||||
val matrix = Matrix()
|
val matrix = Matrix()
|
||||||
|
|
||||||
|
@ -298,9 +304,15 @@ class AddAbstractProductActivity : AppCompatActivity() {
|
||||||
rotated.compress(
|
rotated.compress(
|
||||||
Bitmap.CompressFormat.WEBP_LOSSY,
|
Bitmap.CompressFormat.WEBP_LOSSY,
|
||||||
100 * (15 / (16 - compressionFactor)),
|
100 * (15 / (16 - compressionFactor)),
|
||||||
FileOutputStream(pictureFile)
|
FileOutputStream(tempfile)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val imageHash = calculateMd5Hash(tempfile)
|
||||||
|
|
||||||
|
pictureFile = File(picturesPath, "$imageHash.png")
|
||||||
|
Files.move(tempfile.toPath(), pictureFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
tempfile.delete()
|
||||||
|
|
||||||
generateThumbnailForImage(this, imageHash)
|
generateThumbnailForImage(this, imageHash)
|
||||||
|
|
||||||
imageView.setImageURI(getImageUri(this, pictureFile))
|
imageView.setImageURI(getImageUri(this, pictureFile))
|
||||||
|
|
|
@ -48,7 +48,7 @@ class AddCategoryActivity : Activity() {
|
||||||
net.server = sharedPreferences.getString("server", "")!!
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
net.language = sharedPreferences.getString("language", "")!!
|
net.language = sharedPreferences.getString("language", "")!!
|
||||||
|
|
||||||
val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!.toInt()
|
val currentGroup: Int = if (sharedPreferences.getString("currentGroup", "offline")!! == "offline") 0 else sharedPreferences.getString("currentGroup", "")!!.toInt()
|
||||||
|
|
||||||
findViewById<Button>(R.id.saveButton).setOnClickListener {
|
findViewById<Button>(R.id.saveButton).setOnClickListener {
|
||||||
if (categoryNameTextEdit.text.toString() == "") {
|
if (categoryNameTextEdit.text.toString() == "") {
|
||||||
|
@ -59,11 +59,11 @@ class AddCategoryActivity : Activity() {
|
||||||
if (category.id == 0) { // Inserting new category
|
if (category.id == 0) { // Inserting new category
|
||||||
val newCategory = Category(0, categoryNameTextEdit.text.toString())
|
val newCategory = Category(0, categoryNameTextEdit.text.toString())
|
||||||
newCategory.id = DAO.addCategory(newCategory).toInt()
|
newCategory.id = DAO.addCategory(newCategory).toInt()
|
||||||
net.uploadCategory(currentGroup, newCategory)
|
if (currentGroup > 0) net.uploadCategory(currentGroup, newCategory)
|
||||||
} else { // Updating existing category
|
} else { // Updating existing category
|
||||||
category.name = categoryNameTextEdit.text.toString()
|
category.name = categoryNameTextEdit.text.toString()
|
||||||
DAO.updateCategory(category)
|
DAO.updateCategory(category)
|
||||||
net.updateCategory(currentGroup, category)
|
if (currentGroup > 0) net.updateCategory(currentGroup, category)
|
||||||
}
|
}
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
|
|
|
@ -177,7 +177,7 @@ class AddProductActivity : AppCompatActivity() {
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentGroup: Int = if (sharedPreferences.getString("currentGroup", "")!! == "") 0 else sharedPreferences.getString("currentGroup", "")!!.toInt()
|
val currentGroup: Int = if (sharedPreferences.getString("currentGroup", "offline")!! == "offline") 0 else sharedPreferences.getString("currentGroup", "")!!.toInt()
|
||||||
|
|
||||||
var response: Response? = null
|
var response: Response? = null
|
||||||
|
|
||||||
|
@ -200,8 +200,11 @@ class AddProductActivity : AppCompatActivity() {
|
||||||
val today = SimpleDateFormat("dd.MM.yyyy").format(Calendar.getInstance().time).split(".")
|
val today = SimpleDateFormat("dd.MM.yyyy").format(Calendar.getInstance().time).split(".")
|
||||||
|
|
||||||
|
|
||||||
dateOfProductionDatePicker.updateDate(today[2].toInt(), today[1].toInt(), today[0].toInt())
|
dateOfProductionDatePicker.updateDate(today[2].toInt(), today[1].toInt() - 1, today[0].toInt())
|
||||||
expiryDatePicker.updateDate(today[2].toInt(), today[1].toInt(), today[0].toInt())
|
expiryDatePicker.updateDate(today[2].toInt(), today[1].toInt() - 1, today[0].toInt())
|
||||||
|
product!!.dateOfProduction = SimpleDateFormat("dd.MM.yyyy").parse("${today[0]}.${today[1]}.${today[2]}")!!.time / 1000
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val intentLauncher =
|
private val intentLauncher =
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
import androidx.security.crypto.MasterKeys
|
import androidx.security.crypto.MasterKeys
|
||||||
import org.foxarmy.barcodescannerforemployees.Net
|
import org.foxarmy.barcodescannerforemployees.Net
|
||||||
import org.foxarmy.barcodescannerforemployees.databinding.ActivityGroupBinding
|
import org.foxarmy.barcodescannerforemployees.databinding.ActivityGroupBinding
|
||||||
|
import org.foxarmy.barcodescannerforemployees.noInternetConnectionAvailableNotification
|
||||||
|
|
||||||
class GroupActivity : AppCompatActivity() {
|
class GroupActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
@ -30,13 +31,15 @@ class GroupActivity : AppCompatActivity() {
|
||||||
binding.createGroupButton.setOnClickListener {
|
binding.createGroupButton.setOnClickListener {
|
||||||
val groupName = binding.groupNameTextEdit.text.toString()
|
val groupName = binding.groupNameTextEdit.text.toString()
|
||||||
val groupPassword = binding.groupPasswordTextEdit.text.toString()
|
val groupPassword = binding.groupPasswordTextEdit.text.toString()
|
||||||
// group is set to "successful"
|
val net = Net()
|
||||||
val n = Net()
|
net.language = sharedPreferences.getString("language", "en-US")!!
|
||||||
n.language = sharedPreferences.getString("language", "en-US")!!
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
n.server = sharedPreferences.getString("server", "")!!
|
net.token = sharedPreferences.getString("token", "")!!
|
||||||
n.token = sharedPreferences.getString("token", "")!!
|
|
||||||
|
|
||||||
val response = n.createGroup(groupName, groupPassword)
|
if (!net.serverIsAvailable(this)) {
|
||||||
|
noInternetConnectionAvailableNotification(this)
|
||||||
|
} else {
|
||||||
|
val response = net.createGroup(groupName, groupPassword)
|
||||||
val responseText = response.body!!.string()
|
val responseText = response.body!!.string()
|
||||||
|
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
|
@ -51,18 +54,29 @@ class GroupActivity : AppCompatActivity() {
|
||||||
Toast.makeText(this, responseText, Toast.LENGTH_LONG).show()
|
Toast.makeText(this, responseText, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.joinGroupButton.setOnClickListener {
|
binding.joinGroupButton.setOnClickListener {
|
||||||
val groupName = binding.groupNameTextEdit.text.toString()
|
val groupName = binding.groupNameTextEdit.text.toString()
|
||||||
val groupPassword = binding.groupPasswordTextEdit.text.toString()
|
val groupPassword = binding.groupPasswordTextEdit.text.toString()
|
||||||
|
|
||||||
val n = Net()
|
val net = Net()
|
||||||
n.language = sharedPreferences.getString("language", "en-US")!!
|
net.language = sharedPreferences.getString("language", "en-US")!!
|
||||||
n.server = sharedPreferences.getString("server", "")!!
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
n.token = sharedPreferences.getString("token", "")!!
|
net.token = sharedPreferences.getString("token", "")!!
|
||||||
|
|
||||||
val groupId = n.getGroupId(groupName).toInt()
|
if (!net.serverIsAvailable(this)) {
|
||||||
val response = n.joinGroup(groupId, groupPassword)
|
noInternetConnectionAvailableNotification(this)
|
||||||
|
} else {
|
||||||
|
val requestGroupIdResponse = net.getGroupId(groupName)
|
||||||
|
var groupId: Int
|
||||||
|
try {
|
||||||
|
groupId = requestGroupIdResponse.toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(this, requestGroupIdResponse, Toast.LENGTH_SHORT).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
val response = net.joinGroup(groupId, groupPassword)
|
||||||
val responseText = response.body!!.string()
|
val responseText = response.body!!.string()
|
||||||
|
|
||||||
if (response.code == 200) {
|
if (response.code == 200) {
|
||||||
|
@ -79,3 +93,4 @@ class GroupActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import androidx.security.crypto.MasterKeys
|
||||||
import org.foxarmy.barcodescannerforemployees.Net
|
import org.foxarmy.barcodescannerforemployees.Net
|
||||||
import org.foxarmy.barcodescannerforemployees.R
|
import org.foxarmy.barcodescannerforemployees.R
|
||||||
import org.foxarmy.barcodescannerforemployees.databinding.ActivityLoginBinding
|
import org.foxarmy.barcodescannerforemployees.databinding.ActivityLoginBinding
|
||||||
|
import org.foxarmy.barcodescannerforemployees.noInternetConnectionAvailableNotification
|
||||||
import org.foxarmy.barcodescannerforemployees.parseArray
|
import org.foxarmy.barcodescannerforemployees.parseArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
@ -40,23 +41,26 @@ class LoginActivity : AppCompatActivity() {
|
||||||
val language = resources.getStringArray(R.array.languages)[binding.languageSpinner.selectedItemPosition]
|
val language = resources.getStringArray(R.array.languages)[binding.languageSpinner.selectedItemPosition]
|
||||||
sharedPreferences.edit().putString("language", language).apply()
|
sharedPreferences.edit().putString("language", language).apply()
|
||||||
|
|
||||||
val n = Net()
|
val net = Net()
|
||||||
n.language = sharedPreferences.getString("language", "en-US")!!
|
net.language = sharedPreferences.getString("language", "en-US")!!
|
||||||
n.server = server
|
net.server = server
|
||||||
|
|
||||||
val response = n.login(username, password)
|
if (!net.serverIsAvailable(this)) {
|
||||||
|
noInternetConnectionAvailableNotification(this)
|
||||||
|
} else {
|
||||||
|
val response = net.login(username, password)
|
||||||
val responseText = response.body!!.string()
|
val responseText = response.body!!.string()
|
||||||
if (response.code != 200) {
|
if (response.code != 200) {
|
||||||
Toast.makeText(this, responseText, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, responseText, Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
val json = JSONObject(responseText)
|
val json = JSONObject(responseText)
|
||||||
sharedPreferences.edit().putString("token", json["token"].toString()).apply()
|
sharedPreferences.edit().putString("token", json["token"].toString()).apply()
|
||||||
n.token = json["token"].toString()
|
net.token = json["token"].toString()
|
||||||
sharedPreferences.edit().putInt("userId", json["id"].toString().toInt()).apply()
|
sharedPreferences.edit().putInt("userId", json["id"].toString().toInt()).apply()
|
||||||
sharedPreferences.edit().putString("server", server).apply()
|
sharedPreferences.edit().putString("server", server).apply()
|
||||||
|
|
||||||
|
|
||||||
val r = n.getMyGroups().body!!.string()
|
val r = net.getMyGroups().body!!.string()
|
||||||
val myGroups = parseArray(r).map { a -> a.toString()}
|
val myGroups = parseArray(r).map { a -> a.toString()}
|
||||||
|
|
||||||
sharedPreferences.edit().putStringSet("groups", myGroups.toSet()).apply()
|
sharedPreferences.edit().putStringSet("groups", myGroups.toSet()).apply()
|
||||||
|
@ -67,6 +71,7 @@ class LoginActivity : AppCompatActivity() {
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.registerButton.setOnClickListener {
|
binding.registerButton.setOnClickListener {
|
||||||
val server = binding.serverTextEdit.text.toString()
|
val server = binding.serverTextEdit.text.toString()
|
||||||
|
@ -76,16 +81,20 @@ class LoginActivity : AppCompatActivity() {
|
||||||
sharedPreferences.edit().putString("language", language).apply()
|
sharedPreferences.edit().putString("language", language).apply()
|
||||||
sharedPreferences.edit().putString("server", server).apply()
|
sharedPreferences.edit().putString("server", server).apply()
|
||||||
|
|
||||||
val n = Net()
|
val net = Net()
|
||||||
n.language = language
|
net.language = language
|
||||||
n.server = server
|
net.server = server
|
||||||
val response = n.registerAccount(username, password);
|
|
||||||
|
if (!net.serverIsAvailable(this)) {
|
||||||
|
noInternetConnectionAvailableNotification(this)
|
||||||
|
} else {
|
||||||
|
val response = net.registerAccount(username, password);
|
||||||
val responseText = response.body!!.string()
|
val responseText = response.body!!.string()
|
||||||
if (response.code != 200) {
|
if (response.code != 200) {
|
||||||
Toast.makeText(this, responseText, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, responseText, Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
sharedPreferences.edit().putInt("userId", responseText.toInt()).apply()
|
sharedPreferences.edit().putInt("userId", responseText.toInt()).apply()
|
||||||
val token = JSONObject(n.login(username, password).body!!.string())["token"].toString()
|
val token = JSONObject(net.login(username, password).body!!.string())["token"].toString()
|
||||||
sharedPreferences.edit().putString("token", token).apply()
|
sharedPreferences.edit().putString("token", token).apply()
|
||||||
|
|
||||||
sharedPreferences.edit().putString("server", server).apply()
|
sharedPreferences.edit().putString("server", server).apply()
|
||||||
|
@ -96,6 +105,16 @@ class LoginActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.offlineButton.setOnClickListener {
|
||||||
|
sharedPreferences.edit().putString("currentGroup", "offline").apply()
|
||||||
|
sharedPreferences.edit().putStringSet("groups", setOf("offline")).apply()
|
||||||
|
|
||||||
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun fillUpLanguagesSpinner() {
|
private fun fillUpLanguagesSpinner() {
|
||||||
val languages = resources.getStringArray(R.array.languages)
|
val languages = resources.getStringArray(R.array.languages)
|
||||||
val arrayAdapter = ArrayAdapter(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, languages)
|
val arrayAdapter = ArrayAdapter(this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, languages)
|
||||||
|
|
|
@ -3,9 +3,12 @@ package org.foxarmy.barcodescannerforemployees.activities
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
@ -16,10 +19,7 @@ import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
import androidx.security.crypto.MasterKeys
|
import androidx.security.crypto.MasterKeys
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
import org.foxarmy.barcodescannerforemployees.Net
|
import org.foxarmy.barcodescannerforemployees.*
|
||||||
import org.foxarmy.barcodescannerforemployees.R
|
|
||||||
import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
|
|
||||||
import org.foxarmy.barcodescannerforemployees.convertToUnixEpochTimestamp
|
|
||||||
import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
|
import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
|
||||||
import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
|
import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
|
||||||
import org.foxarmy.barcodescannerforemployees.database.DBStorageController
|
import org.foxarmy.barcodescannerforemployees.database.DBStorageController
|
||||||
|
@ -39,9 +39,12 @@ import java.io.File
|
||||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
lateinit var adapter: ViewPagerAdapter
|
private lateinit var adapter: ViewPagerAdapter
|
||||||
var drawerLayout: DrawerLayout? = null
|
private var drawerLayout: DrawerLayout? = null
|
||||||
var actionBarDrawerToggle: ActionBarDrawerToggle? = null
|
private var actionBarDrawerToggle: ActionBarDrawerToggle? = null
|
||||||
|
private lateinit var ws: WebSocketClient
|
||||||
|
|
||||||
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -49,6 +52,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
sharedPreferences = EncryptedSharedPreferences.create(
|
||||||
|
"sensitive",
|
||||||
|
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
||||||
|
applicationContext,
|
||||||
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
|
)
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
setupViewPager(binding.tabViewpager)
|
setupViewPager(binding.tabViewpager)
|
||||||
binding.tabTablayout.setupWithViewPager(binding.tabViewpager)
|
binding.tabTablayout.setupWithViewPager(binding.tabViewpager)
|
||||||
|
@ -60,9 +71,16 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
actionBarDrawerToggle!!.syncState()
|
actionBarDrawerToggle!!.syncState()
|
||||||
binding.navView.setNavigationItemSelectedListener(this)
|
binding.navView.setNavigationItemSelectedListener(this)
|
||||||
|
|
||||||
// to make the Navigation drawer icon always appear on the action bar
|
|
||||||
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
|
val sharedPreferences = EncryptedSharedPreferences.create(
|
||||||
|
"sensitive",
|
||||||
|
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
||||||
|
applicationContext,
|
||||||
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
|
)
|
||||||
|
|
||||||
binding.expiryCalendarFab.setOnClickListener { _ ->
|
binding.expiryCalendarFab.setOnClickListener { _ ->
|
||||||
val expiryCalendarIntent = Intent(this, ExpiryCalendarActivity::class.java)
|
val expiryCalendarIntent = Intent(this, ExpiryCalendarActivity::class.java)
|
||||||
val extras = Bundle()
|
val extras = Bundle()
|
||||||
|
@ -78,8 +96,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
"StorageFragment" -> {
|
"StorageFragment" -> {
|
||||||
val addAbstractProductIntent = Intent(this, AddAbstractProductActivity::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.
|
|
||||||
// if abstractProduct == null, it means that we need to create new object
|
|
||||||
extras.putParcelable("abstractProduct", null)
|
extras.putParcelable("abstractProduct", null)
|
||||||
extras.putString("action", "new")
|
extras.putString("action", "new")
|
||||||
addAbstractProductIntent.putExtras(extras)
|
addAbstractProductIntent.putExtras(extras)
|
||||||
|
@ -104,19 +120,20 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val net = Net()
|
||||||
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
|
val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!
|
||||||
|
if ( currentGroup != "offline" && !net.serverIsAvailable(this)) {
|
||||||
|
noInternetConnectionAvailableNotification(this)
|
||||||
|
} else if (currentGroup != "offline" && net.serverIsAvailable(this)) {
|
||||||
synchronize()
|
synchronize()
|
||||||
|
ws = WebSocketClient(this, sharedPreferences.getString("server", "")!!)
|
||||||
|
val token = sharedPreferences.getString("token", "")!!
|
||||||
|
ws.connect(token, currentGroup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun synchronize() {
|
private fun synchronize() {
|
||||||
|
|
||||||
val sharedPreferences = EncryptedSharedPreferences.create(
|
|
||||||
"sensitive",
|
|
||||||
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
|
||||||
applicationContext,
|
|
||||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
||||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
||||||
)
|
|
||||||
|
|
||||||
if (sharedPreferences.getString("currentGroup", "offline")!! == "offline") return
|
if (sharedPreferences.getString("currentGroup", "offline")!! == "offline") return
|
||||||
|
|
||||||
val net = Net()
|
val net = Net()
|
||||||
|
@ -194,15 +211,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
|
|
||||||
if (categoryInRemoteDB != null && categoryInLocalDB != null) {
|
if (categoryInRemoteDB != null && categoryInLocalDB != null) {
|
||||||
if (categoryInRemoteDB["hash"] != categoryInLocalDB.calculateHash()) {
|
if (categoryInRemoteDB["hash"] != categoryInLocalDB.calculateHash()) {
|
||||||
|
val updatedData = Category.createFromJSON(categoryInRemoteDB)
|
||||||
var updatedData: Category
|
|
||||||
|
|
||||||
with(categoryInRemoteDB) {
|
|
||||||
updatedData = Category(
|
|
||||||
this["local_id"].toString().toInt(),
|
|
||||||
this["name"].toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
categoryDAO.updateCategory(updatedData)
|
categoryDAO.updateCategory(updatedData)
|
||||||
}
|
}
|
||||||
|
@ -241,35 +250,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productInLocalDB == null && remoteProduct != null) {
|
if (productInLocalDB == null && remoteProduct != null) {
|
||||||
var newProduct: Product
|
val newProduct = Product.createFromJSON(remoteProduct)
|
||||||
|
|
||||||
with(remoteProduct) {
|
|
||||||
newProduct = Product(
|
|
||||||
this["local_id"].toString().toInt(),
|
|
||||||
this["abstract_product_id"].toString().toInt(),
|
|
||||||
this["amount"].toString().toInt(),
|
|
||||||
convertToUnixEpochTimestamp(this["date_of_production"].toString()),
|
|
||||||
convertToUnixEpochTimestamp(this["expiry_date"].toString())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
productDAO.insertNewProduct(newProduct)
|
productDAO.insertNewProduct(newProduct)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productInRemoteDB != null && productInLocalDB != null) {
|
if (productInRemoteDB != null && productInLocalDB != null) {
|
||||||
if (productInRemoteDB["hash"] != productInLocalDB.calculateHash()) {
|
if (productInRemoteDB["hash"] != productInLocalDB.calculateHash()) {
|
||||||
|
val updatedData = Product.createFromJSON(productInRemoteDB)
|
||||||
var updatedData: Product
|
|
||||||
|
|
||||||
with(productInRemoteDB) {
|
|
||||||
updatedData = Product(
|
|
||||||
this["local_id"].toString().toInt(),
|
|
||||||
this["abstract_product_id"].toString().toInt(),
|
|
||||||
this["amount"].toString().toInt(),
|
|
||||||
convertToUnixEpochTimestamp(this["date_of_production"].toString()),
|
|
||||||
convertToUnixEpochTimestamp(this["expiry_date"].toString())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
productDAO.updateProduct(updatedData)
|
productDAO.updateProduct(updatedData)
|
||||||
}
|
}
|
||||||
|
@ -320,19 +308,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
|
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
|
||||||
net.downloadImage(url, pictureFile)
|
net.downloadImage(url, pictureFile)
|
||||||
|
|
||||||
var newAbstractProduct: AbstractProduct
|
val newAbstractProduct = AbstractProduct.createFromJSON(remoteAbstractProduct)
|
||||||
|
|
||||||
with(remoteAbstractProduct) {
|
|
||||||
newAbstractProduct = AbstractProduct(
|
|
||||||
this["local_id"].toString().toInt(),
|
|
||||||
this["barcode"].toString(),
|
|
||||||
this["name"].toString(),
|
|
||||||
this["net_weight"].toString().toDouble(),
|
|
||||||
this["image_filename"].toString(),
|
|
||||||
this["category"].toString().toInt(),
|
|
||||||
this["unit"].toString().toInt()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstractProductDAO.addAbstractProduct(newAbstractProduct)
|
abstractProductDAO.addAbstractProduct(newAbstractProduct)
|
||||||
|
|
||||||
|
@ -347,20 +323,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
|
val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
|
||||||
net.downloadImage(url, pictureFile)
|
net.downloadImage(url, pictureFile)
|
||||||
|
|
||||||
var updatedData: AbstractProduct
|
val updatedData = AbstractProduct.createFromJSON(abstractProductInRemoteDB)
|
||||||
|
|
||||||
with(abstractProductInRemoteDB) {
|
|
||||||
updatedData = AbstractProduct(
|
|
||||||
this["local_id"].toString().toInt(),
|
|
||||||
this["barcode"].toString(),
|
|
||||||
this["name"].toString(),
|
|
||||||
this["net_weight"].toString().toDouble(),
|
|
||||||
this["image_filename"].toString(),
|
|
||||||
this["category"].toString().toInt(),
|
|
||||||
this["unit"].toString().toInt()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
abstractProductDAO.updateAbstractProduct(updatedData)
|
abstractProductDAO.updateAbstractProduct(updatedData)
|
||||||
}
|
}
|
||||||
|
@ -384,22 +347,43 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isOffline(): Boolean {
|
||||||
|
return sharedPreferences.getString("currentGroup", "") == "offline"
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||||
lateinit var intent: Intent
|
lateinit var intent: Intent
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.nav_account -> {
|
R.id.nav_account -> {
|
||||||
|
if (isOffline()) {
|
||||||
|
Toast.makeText(this, getString(R.string.online_only_feature), Toast.LENGTH_SHORT).show()
|
||||||
|
return false
|
||||||
|
}
|
||||||
intent = Intent(this, AccountSettingsActivity::class.java)
|
intent = Intent(this, AccountSettingsActivity::class.java)
|
||||||
settingsActivityLauncher.launch(intent)
|
settingsActivityLauncher.launch(intent)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_groups -> {
|
R.id.nav_groups -> {
|
||||||
|
if (isOffline()) {
|
||||||
|
Toast.makeText(this, getString(R.string.online_only_feature), Toast.LENGTH_SHORT).show()
|
||||||
|
return false
|
||||||
|
}
|
||||||
intent = Intent(this, MyGroupsActivity::class.java)
|
intent = Intent(this, MyGroupsActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.nav_settings -> {
|
R.id.nav_settings -> {
|
||||||
intent = Intent(this, SettingsActivity::class.java)
|
intent = Intent(this, SettingsActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.nav_logout -> {
|
||||||
|
sharedPreferences.edit().putString("currentGroup", "").apply()
|
||||||
|
sharedPreferences.edit().putStringSet("groups", emptySet()).apply()
|
||||||
|
sharedPreferences.edit().putString("token", "").apply()
|
||||||
|
sharedPreferences.edit().putString("server", "").apply()
|
||||||
|
|
||||||
|
intent = Intent(this, LoginActivity::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
|
|
||||||
|
@ -416,6 +400,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateAll() {
|
fun updateAll() {
|
||||||
|
runOnUiThread {
|
||||||
|
try {
|
||||||
val storageFragment: StorageFragment = adapter.getItem(0) as StorageFragment
|
val storageFragment: StorageFragment = adapter.getItem(0) as StorageFragment
|
||||||
val shelfFragment: ShelfFragment = adapter.getItem(1) as ShelfFragment
|
val shelfFragment: ShelfFragment = adapter.getItem(1) as ShelfFragment
|
||||||
val categoriesFragment: CategoriesFragment = adapter.getItem(2) as CategoriesFragment
|
val categoriesFragment: CategoriesFragment = adapter.getItem(2) as CategoriesFragment
|
||||||
|
@ -423,6 +409,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
||||||
storageFragment.updateContent()
|
storageFragment.updateContent()
|
||||||
shelfFragment.updateContent()
|
shelfFragment.updateContent()
|
||||||
categoriesFragment.updateContent()
|
categoriesFragment.updateContent()
|
||||||
|
} catch (e:Exception) {
|
||||||
|
Log.e("BSFE/MainActivity", e.message!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
|
|
@ -24,19 +24,22 @@ class NavigatorActivity : Activity() {
|
||||||
|
|
||||||
var intent = Intent(this, MainActivity::class.java)
|
var intent = Intent(this, MainActivity::class.java)
|
||||||
|
|
||||||
if (!isInGroup()) {
|
if (!isInGroup() && !isOffline()) {
|
||||||
intent = Intent(this, GroupActivity::class.java)
|
intent = Intent(this, GroupActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAuthenticated()) {
|
if (!isAuthenticated() && !isOffline()) {
|
||||||
intent = Intent(this, LoginActivity::class.java);
|
intent = Intent(this, LoginActivity::class.java);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isOffline(): Boolean {
|
||||||
|
return sharedPreferences.getString("currentGroup", "")!! == "offline"
|
||||||
|
}
|
||||||
|
|
||||||
private fun isAuthenticated(): Boolean {
|
private fun isAuthenticated(): Boolean {
|
||||||
return sharedPreferences.getString("token", "") != ""
|
return sharedPreferences.getString("token", "") != ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,17 +37,23 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
net.language = sharedPreferences.getString("language", "")!!
|
net.language = sharedPreferences.getString("language", "")!!
|
||||||
net.server = sharedPreferences.getString("server", "")!!
|
net.server = sharedPreferences.getString("server", "")!!
|
||||||
|
|
||||||
|
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
setUpImageCompressionSeekBar()
|
||||||
|
|
||||||
|
|
||||||
|
if (isOffline()) {
|
||||||
|
binding.currentGroupSetting.visibility = View.GONE
|
||||||
|
} else {
|
||||||
groupsNames = mutableListOf()
|
groupsNames = mutableListOf()
|
||||||
|
|
||||||
for (myGroup in myGroups) {
|
for (myGroup in myGroups) {
|
||||||
groupsNames.add(net.getGroupName(myGroup.toInt()))
|
groupsNames.add(net.getGroupName(myGroup.toInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
|
|
||||||
setUpImageCompressionSeekBar()
|
|
||||||
fillUpCurrentGroupSpinner()
|
fillUpCurrentGroupSpinner()
|
||||||
|
}
|
||||||
|
|
||||||
binding.saveButton.setOnClickListener {
|
binding.saveButton.setOnClickListener {
|
||||||
sharedPreferences.edit().putString("currentGroup", net.getGroupId(binding.currentGroupSpinner.selectedItem.toString())).apply()
|
sharedPreferences.edit().putString("currentGroup", net.getGroupId(binding.currentGroupSpinner.selectedItem.toString())).apply()
|
||||||
|
@ -62,14 +68,16 @@ class SettingsActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isOffline(): Boolean {
|
||||||
|
return sharedPreferences.getString("currentGroup", "offline") == "offline"
|
||||||
|
}
|
||||||
|
|
||||||
private fun setUpImageCompressionSeekBar() {
|
private fun setUpImageCompressionSeekBar() {
|
||||||
val compressionFactor = sharedPreferences.getInt("imageCompression", 1)
|
val compressionFactor = sharedPreferences.getInt("imageCompression", 1)
|
||||||
binding.imageCompressionFactorSeekBar.progress = compressionFactor - 1
|
binding.imageCompressionFactorSeekBar.progress = compressionFactor - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fillUpCurrentGroupSpinner() {
|
private fun fillUpCurrentGroupSpinner() {
|
||||||
|
|
||||||
|
|
||||||
if (currentGroup == "offline") {
|
if (currentGroup == "offline") {
|
||||||
binding.currentGroupSetting.visibility = View.GONE
|
binding.currentGroupSetting.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
|
||||||
|
|
||||||
with(cursor) {
|
with(cursor) {
|
||||||
while (moveToNext()) {
|
while (moveToNext()) {
|
||||||
val id = getInt(getColumnIndexOrThrow(android.provider.BaseColumns._ID))
|
val id = getInt(getColumnIndexOrThrow(BaseColumns._ID))
|
||||||
val productName =
|
val productName =
|
||||||
getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
|
getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
|
||||||
val imageFilename =
|
val imageFilename =
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.foxarmy.barcodescannerforemployees.dataclasses
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import org.foxarmy.barcodescannerforemployees.md5
|
import org.foxarmy.barcodescannerforemployees.md5
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
class AbstractProduct() : Parcelable {
|
class AbstractProduct() : Parcelable {
|
||||||
var id: Int = 0
|
var id: Int = 0
|
||||||
|
@ -59,5 +60,17 @@ class AbstractProduct() : Parcelable {
|
||||||
override fun newArray(size: Int): Array<AbstractProduct?> {
|
override fun newArray(size: Int): Array<AbstractProduct?> {
|
||||||
return arrayOfNulls(size)
|
return arrayOfNulls(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createFromJSON(json: JSONObject): AbstractProduct {
|
||||||
|
return AbstractProduct(
|
||||||
|
json["local_id"].toString().toInt(),
|
||||||
|
json["barcode"].toString(),
|
||||||
|
json["name"].toString(),
|
||||||
|
json["net_weight"].toString().toDouble(),
|
||||||
|
json["image_filename"].toString(),
|
||||||
|
json["category"].toString().toInt(),
|
||||||
|
json["unit"].toString().toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,7 @@ package org.foxarmy.barcodescannerforemployees.dataclasses
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import org.foxarmy.barcodescannerforemployees.md5
|
import org.foxarmy.barcodescannerforemployees.md5
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
class Category() : Parcelable {
|
class Category() : Parcelable {
|
||||||
var id = 0
|
var id = 0
|
||||||
|
@ -40,5 +41,12 @@ class Category() : Parcelable {
|
||||||
override fun newArray(size: Int): Array<Category?> {
|
override fun newArray(size: Int): Array<Category?> {
|
||||||
return arrayOfNulls(size)
|
return arrayOfNulls(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createFromJSON(json: JSONObject): Category {
|
||||||
|
return Category(
|
||||||
|
json["local_id"].toString().toInt(),
|
||||||
|
json["name"].toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,9 @@ import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import org.foxarmy.barcodescannerforemployees.calculateProductFreshness
|
import org.foxarmy.barcodescannerforemployees.calculateProductFreshness
|
||||||
|
import org.foxarmy.barcodescannerforemployees.convertToUnixEpochTimestamp
|
||||||
import org.foxarmy.barcodescannerforemployees.md5
|
import org.foxarmy.barcodescannerforemployees.md5
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
class Product() : Parcelable {
|
class Product() : Parcelable {
|
||||||
var id = 0
|
var id = 0
|
||||||
|
@ -59,5 +61,16 @@ class Product() : Parcelable {
|
||||||
override fun newArray(size: Int): Array<Product?> {
|
override fun newArray(size: Int): Array<Product?> {
|
||||||
return arrayOfNulls(size)
|
return arrayOfNulls(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
fun createFromJSON(json: JSONObject): Product {
|
||||||
|
return Product(
|
||||||
|
json["local_id"].toString().toInt(),
|
||||||
|
json["abstract_product_id"].toString().toInt(),
|
||||||
|
json["amount"].toString().toInt(),
|
||||||
|
convertToUnixEpochTimestamp(json["date_of_production"].toString()),
|
||||||
|
convertToUnixEpochTimestamp(json["expiry_date"].toString())
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,6 +37,8 @@ class StorageFragment : Fragment() {
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View {
|
): View {
|
||||||
|
binding = FragmentStorageBinding.inflate(inflater)
|
||||||
|
|
||||||
sharedPreferences = EncryptedSharedPreferences.create(
|
sharedPreferences = EncryptedSharedPreferences.create(
|
||||||
"sensitive",
|
"sensitive",
|
||||||
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
||||||
|
@ -47,8 +49,6 @@ class StorageFragment : Fragment() {
|
||||||
|
|
||||||
prepareDatabaseConnection()
|
prepareDatabaseConnection()
|
||||||
|
|
||||||
binding = FragmentStorageBinding.inflate(inflater)
|
|
||||||
|
|
||||||
fillUpSortBySpinner()
|
fillUpSortBySpinner()
|
||||||
|
|
||||||
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
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_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
android:layout_marginTop="8dp" android:hint="Barcode" android:textColorHint="#737373"
|
android:layout_marginTop="8dp" android:hint="@string/barcode" android:textColorHint="#737373"
|
||||||
android:layout_marginStart="5dp"/>
|
android:layout_marginStart="5dp"/>
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:text="@string/no_barcode"
|
android:text="@string/no_barcode"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
|
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#141218">
|
>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -12,4 +12,5 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/nav_settings"
|
android:id="@+id/nav_settings"
|
||||||
android:title="@string/settings"/>
|
android:title="@string/settings"/>
|
||||||
|
<item android:title="@string/logout" android:id="@+id/nav_logout"/>
|
||||||
</menu>
|
</menu>
|
|
@ -114,6 +114,10 @@
|
||||||
<string name="image_compress_factor">Степень сжатия изображения</string>
|
<string name="image_compress_factor">Степень сжатия изображения</string>
|
||||||
<string name="current_group">Текущая группа</string>
|
<string name="current_group">Текущая группа</string>
|
||||||
<string name="cancel">Отмена</string>
|
<string name="cancel">Отмена</string>
|
||||||
|
<string name="no_internet_connection">Не могу установить соединение с сервером. Возможно, вы отключены от сети?</string>
|
||||||
|
<string name="ok">Ок</string>
|
||||||
|
<string name="logout">Выйти</string>
|
||||||
|
<string name="online_only_feature">Эта возможность доступна только с онлайн аккаунтом</string>
|
||||||
<string-array name="languages">
|
<string-array name="languages">
|
||||||
<item>en-US</item>
|
<item>en-US</item>
|
||||||
<item>ru-RU</item>
|
<item>ru-RU</item>
|
||||||
|
|
|
@ -112,6 +112,10 @@
|
||||||
<string name="image_compress_factor">Image compression factor</string>
|
<string name="image_compress_factor">Image compression factor</string>
|
||||||
<string name="current_group">Current group</string>
|
<string name="current_group">Current group</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
|
<string name="no_internet_connection">Cannot reach the server. Maybe, you lost internet connection?</string>
|
||||||
|
<string name="ok">OK</string>
|
||||||
|
<string name="logout">Log out</string>
|
||||||
|
<string name="online_only_feature">This feature is online only</string>
|
||||||
<string-array name="languages">
|
<string-array name="languages">
|
||||||
<item>en-US</item>
|
<item>en-US</item>
|
||||||
<item>ru-RU</item>
|
<item>ru-RU</item>
|
||||||
|
|
Loading…
Reference in New Issue