synchronizing
This commit is contained in:
		@@ -5,7 +5,11 @@ import okhttp3.MediaType.Companion.toMediaType
 | 
				
			|||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
					import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
				
			||||||
import okhttp3.RequestBody.Companion.asRequestBody
 | 
					import okhttp3.RequestBody.Companion.asRequestBody
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
				
			||||||
import java.io.File
 | 
					import java.io.File
 | 
				
			||||||
 | 
					import java.io.FileOutputStream
 | 
				
			||||||
 | 
					import java.io.IOException
 | 
				
			||||||
import kotlin.concurrent.thread
 | 
					import kotlin.concurrent.thread
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Net {
 | 
					class Net {
 | 
				
			||||||
@@ -383,4 +387,190 @@ class Net {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return response
 | 
					        return response
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun uploadCategory(groupId: Int, category: Category): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val body = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("localId", category.id.toString())
 | 
				
			||||||
 | 
					                .add("categoryName", category.name)
 | 
				
			||||||
 | 
					                .add("groupId", groupId.toString())
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/category/create")
 | 
				
			||||||
 | 
					                .post(body)
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun updateCategory(groupId: Int, category: Category): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val body = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("localId", category.id.toString())
 | 
				
			||||||
 | 
					                .add("categoryName", category.name)
 | 
				
			||||||
 | 
					                .add("groupId", groupId.toString())
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/category/update")
 | 
				
			||||||
 | 
					                .post(body)
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun uploadProduct(groupId: Int, product: Product): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val body = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("localId", product.id.toString())
 | 
				
			||||||
 | 
					                .add("groupId", groupId.toString())
 | 
				
			||||||
 | 
					                .add("abstract_product_id", product.abstractProductId.toString())
 | 
				
			||||||
 | 
					                .add("amount", product.amount.toString())
 | 
				
			||||||
 | 
					                .add("date_of_production", product.dateOfProduction.toString())
 | 
				
			||||||
 | 
					                .add("expiry_date", product.dateOfExpiry.toString())
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/product/create")
 | 
				
			||||||
 | 
					                .post(body)
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun updateProduct(groupId: Int, product: Product): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val body = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("localId", product.id.toString())
 | 
				
			||||||
 | 
					                .add("groupId", groupId.toString())
 | 
				
			||||||
 | 
					                .add("abstract_product_id", product.abstractProductId.toString())
 | 
				
			||||||
 | 
					                .add("amount", product.amount.toString())
 | 
				
			||||||
 | 
					                .add("date_of_production", product.dateOfProduction.toString())
 | 
				
			||||||
 | 
					                .add("expiry_date", product.dateOfExpiry.toString())
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/product/update")
 | 
				
			||||||
 | 
					                .post(body)
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun synchronize(groupId: Int): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/user/synchronize/$groupId")
 | 
				
			||||||
 | 
					                .get()
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getProduct(groupId: Int, localId: Int): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/product/$groupId/$localId")
 | 
				
			||||||
 | 
					                .get()
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getAbstractProduct(groupId: Int, localId: Int): Response {
 | 
				
			||||||
 | 
					        lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url("https://$server/api/abstractproduct/$groupId/$localId")
 | 
				
			||||||
 | 
					                .get()
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            response = client.newCall(request).execute()
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return response
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun downloadImage(url: String, file: File) {
 | 
				
			||||||
 | 
					        thread {
 | 
				
			||||||
 | 
					            val client = OkHttpClient()
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url(url)
 | 
				
			||||||
 | 
					                .addHeader("Authorization", "Bearer $token")
 | 
				
			||||||
 | 
					                .addHeader("accept-language", language)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client.newCall(request).execute().use { response ->
 | 
				
			||||||
 | 
					                if (!response.isSuccessful) throw IOException("Unexpected code $response")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                val fos = FileOutputStream(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                response.body?.byteStream()?.use { inputStream ->
 | 
				
			||||||
 | 
					                    fos.use {
 | 
				
			||||||
 | 
					                        inputStream.copyTo(fos)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }.join()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -12,11 +12,19 @@ import androidx.annotation.RequiresApi
 | 
				
			|||||||
import androidx.core.content.FileProvider
 | 
					import androidx.core.content.FileProvider
 | 
				
			||||||
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.FileOutputStream
 | 
					import java.io.FileOutputStream
 | 
				
			||||||
import java.net.URLEncoder
 | 
					 | 
				
			||||||
import java.security.MessageDigest
 | 
					import java.security.MessageDigest
 | 
				
			||||||
 | 
					import java.text.SimpleDateFormat
 | 
				
			||||||
import java.util.*
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun convertToUnixEpochTimestamp(dateString: String): Long {
 | 
				
			||||||
 | 
					    val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
 | 
				
			||||||
 | 
					    format.timeZone = TimeZone.getTimeZone("UTC")
 | 
				
			||||||
 | 
					    val date = format.parse(dateString)
 | 
				
			||||||
 | 
					    return date!!.time / 1000
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -60,8 +68,6 @@ fun removeSubstringsFromString(text: String, toRemove: Array<String>): String {
 | 
				
			|||||||
    return result
 | 
					    return result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun String.utf8(): String = URLEncoder.encode(this, "UTF-8")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fun getActivity(context: Context?): Activity? {
 | 
					fun getActivity(context: Context?): Activity? {
 | 
				
			||||||
    if (context == null) {
 | 
					    if (context == null) {
 | 
				
			||||||
        return null
 | 
					        return null
 | 
				
			||||||
@@ -99,3 +105,28 @@ fun getUnitNameById (context: Context, id: Int): String {
 | 
				
			|||||||
fun parseArray(input: String): IntArray {
 | 
					fun parseArray(input: String): IntArray {
 | 
				
			||||||
    return input.trim('[', ']').split(",").map { it.trim().toInt() }.toIntArray()
 | 
					    return input.trim('[', ']').split(",").map { it.trim().toInt() }.toIntArray()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun calculateMd5Hash(file: File): String {
 | 
				
			||||||
 | 
					    val digest = MessageDigest.getInstance("MD5")
 | 
				
			||||||
 | 
					    val fis = FileInputStream(file)
 | 
				
			||||||
 | 
					    val buffer = ByteArray(1024)
 | 
				
			||||||
 | 
					    var bytesRead = fis.read(buffer)
 | 
				
			||||||
 | 
					    while (bytesRead != -1) {
 | 
				
			||||||
 | 
					        digest.update(buffer, 0, bytesRead)
 | 
				
			||||||
 | 
					        bytesRead = fis.read(buffer)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fis.close()
 | 
				
			||||||
 | 
					    return bytesToHex(digest.digest())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun bytesToHex(bytes: ByteArray): String {
 | 
				
			||||||
 | 
					    val hexString = StringBuilder()
 | 
				
			||||||
 | 
					    for (byte in bytes) {
 | 
				
			||||||
 | 
					        val hex = Integer.toHexString(0xff and byte.toInt())
 | 
				
			||||||
 | 
					        if (hex.length == 1) {
 | 
				
			||||||
 | 
					            hexString.append('0')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        hexString.append(hex)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return hexString.toString()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -154,7 +154,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
 | 
				
			|||||||
            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", "")!!
 | 
					            val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            lateinit var response: Response
 | 
					            lateinit var response: Response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -164,7 +164,7 @@ class AddAbstractProductActivity : AppCompatActivity() {
 | 
				
			|||||||
                productName,
 | 
					                productName,
 | 
				
			||||||
                netWeight.toString().toDouble(),
 | 
					                netWeight.toString().toDouble(),
 | 
				
			||||||
                pictureFile.nameWithoutExtension,
 | 
					                pictureFile.nameWithoutExtension,
 | 
				
			||||||
                categorySpinner.selectedItemPosition,
 | 
					                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")
 | 
				
			||||||
@@ -269,8 +269,9 @@ 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 imageContent = tempfile.inputStream().readBytes()
 | 
					            val imageHash = calculateMd5Hash(tempfile)
 | 
				
			||||||
            val imageHash = imageContent.toString(Charsets.UTF_8).md5()
 | 
					//            val imageContent = tempfile.inputStream().readBytes()
 | 
				
			||||||
 | 
					//            val imageHash = imageContent.toString(Charsets.UTF_8).md5()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pictureFile = File(picturesPath, "$imageHash.png")
 | 
					            pictureFile = File(picturesPath, "$imageHash.png")
 | 
				
			||||||
            Files.move(tempfile.toPath(), pictureFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
 | 
					            Files.move(tempfile.toPath(), pictureFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ import android.widget.EditText
 | 
				
			|||||||
import android.widget.Toast
 | 
					import android.widget.Toast
 | 
				
			||||||
import androidx.security.crypto.EncryptedSharedPreferences
 | 
					import androidx.security.crypto.EncryptedSharedPreferences
 | 
				
			||||||
import androidx.security.crypto.MasterKeys
 | 
					import androidx.security.crypto.MasterKeys
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.Net
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
 | 
					import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.database.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.database.DBStorageController
 | 
				
			||||||
@@ -31,7 +32,7 @@ class AddCategoryActivity : Activity() {
 | 
				
			|||||||
            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 = CategoryDAO(dbHelper)
 | 
					        DAO = CategoryDAO(dbHelper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val extras = intent.extras
 | 
					        val extras = intent.extras
 | 
				
			||||||
@@ -41,6 +42,14 @@ class AddCategoryActivity : Activity() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        categoryNameTextEdit.setText(category!!.name)
 | 
					        categoryNameTextEdit.setText(category!!.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val net = Net()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        net.token = sharedPreferences.getString("token", "")!!
 | 
				
			||||||
 | 
					        net.server = sharedPreferences.getString("server", "")!!
 | 
				
			||||||
 | 
					        net.language = sharedPreferences.getString("language", "")!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!.toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        findViewById<Button>(R.id.saveButton).setOnClickListener {
 | 
					        findViewById<Button>(R.id.saveButton).setOnClickListener {
 | 
				
			||||||
            if (categoryNameTextEdit.text.toString() == "") {
 | 
					            if (categoryNameTextEdit.text.toString() == "") {
 | 
				
			||||||
                Toast.makeText(this, getString(R.string.category_name_required), Toast.LENGTH_SHORT).show()
 | 
					                Toast.makeText(this, getString(R.string.category_name_required), Toast.LENGTH_SHORT).show()
 | 
				
			||||||
@@ -48,9 +57,13 @@ class AddCategoryActivity : Activity() {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (category.id == 0) { // Inserting new category
 | 
					            if (category.id == 0) { // Inserting new category
 | 
				
			||||||
                DAO.addCategory(Category(0, categoryNameTextEdit.text.toString()))
 | 
					                val newCategory = Category(0, categoryNameTextEdit.text.toString())
 | 
				
			||||||
 | 
					                newCategory.id = DAO.addCategory(newCategory).toInt()
 | 
				
			||||||
 | 
					                net.uploadCategory(currentGroup, newCategory)
 | 
				
			||||||
            } else { // Updating existing category
 | 
					            } else { // Updating existing category
 | 
				
			||||||
 | 
					                category.name = categoryNameTextEdit.text.toString()
 | 
				
			||||||
                DAO.updateCategory(category)
 | 
					                DAO.updateCategory(category)
 | 
				
			||||||
 | 
					                net.updateCategory(currentGroup, category)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            finish()
 | 
					            finish()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,6 +18,8 @@ import androidx.security.crypto.MasterKeys
 | 
				
			|||||||
import com.journeyapps.barcodescanner.ScanContract
 | 
					import com.journeyapps.barcodescanner.ScanContract
 | 
				
			||||||
import com.journeyapps.barcodescanner.ScanIntentResult
 | 
					import com.journeyapps.barcodescanner.ScanIntentResult
 | 
				
			||||||
import com.journeyapps.barcodescanner.ScanOptions
 | 
					import com.journeyapps.barcodescanner.ScanOptions
 | 
				
			||||||
 | 
					import okhttp3.Response
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.Net
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
 | 
					import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.database.DBStorageController
 | 
					import org.foxarmy.barcodescannerforemployees.database.DBStorageController
 | 
				
			||||||
@@ -67,10 +69,11 @@ class AddProductActivity : 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")!!)
 | 
				
			||||||
        productDAO = ProductDAO(dbHelper)
 | 
					        productDAO = ProductDAO(dbHelper)
 | 
				
			||||||
        abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
					        abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        scanButton = findViewById(R.id.scanButton)
 | 
					        scanButton = findViewById(R.id.scanButton)
 | 
				
			||||||
        noBarcodeButton = findViewById(R.id.noBarcodeButton)
 | 
					        noBarcodeButton = findViewById(R.id.noBarcodeButton)
 | 
				
			||||||
        abstractProductView = findViewById(R.id.abstractProductView)
 | 
					        abstractProductView = findViewById(R.id.abstractProductView)
 | 
				
			||||||
@@ -137,6 +140,12 @@ class AddProductActivity : AppCompatActivity() {
 | 
				
			|||||||
            product!!.amount = text.toInt()
 | 
					            product!!.amount = text.toInt()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val net = Net()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        net.language = sharedPreferences.getString("language", "en-US")!!
 | 
				
			||||||
 | 
					        net.server = sharedPreferences.getString("server", "")!!
 | 
				
			||||||
 | 
					        net.token = sharedPreferences.getString("token", "")!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        saveProductButton.setOnClickListener {
 | 
					        saveProductButton.setOnClickListener {
 | 
				
			||||||
            if (abstractProduct == null) {
 | 
					            if (abstractProduct == null) {
 | 
				
			||||||
                Toast.makeText(this, getString(R.string.abstract_product_request), Toast.LENGTH_SHORT).show()
 | 
					                Toast.makeText(this, getString(R.string.abstract_product_request), Toast.LENGTH_SHORT).show()
 | 
				
			||||||
@@ -168,10 +177,20 @@ class AddProductActivity : AppCompatActivity() {
 | 
				
			|||||||
                return@setOnClickListener
 | 
					                return@setOnClickListener
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val currentGroup: Int = if (sharedPreferences.getString("currentGroup", "")!! == "") 0 else sharedPreferences.getString("currentGroup", "")!!.toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var response: Response? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (updatingExistentProduct) {
 | 
					            if (updatingExistentProduct) {
 | 
				
			||||||
                productDAO.updateProduct(product!!)
 | 
					                productDAO.updateProduct(product!!)
 | 
				
			||||||
 | 
					                if (currentGroup > 0) response = net.updateProduct(currentGroup, product!!)
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                productDAO.insertNewProduct(product!!)
 | 
					                product!!.id = productDAO.insertNewProduct(product!!).toInt()
 | 
				
			||||||
 | 
					                if (currentGroup > 0) response = net.uploadProduct(currentGroup, product!!)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (response != null) {
 | 
				
			||||||
 | 
					                Toast.makeText(this, response.body!!.string(), Toast.LENGTH_LONG).show()
 | 
				
			||||||
            }   
 | 
					            }   
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            finish()
 | 
					            finish()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,9 +57,11 @@ class LoginActivity : AppCompatActivity() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val r = n.getMyGroups().body!!.string()
 | 
					                val r = n.getMyGroups().body!!.string()
 | 
				
			||||||
                val myGroups = parseArray(r)
 | 
					                val myGroups = parseArray(r).map { a -> a.toString()}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                sharedPreferences.edit().putStringSet("groups", myGroups.toSet()).apply()
 | 
				
			||||||
 | 
					                sharedPreferences.edit().putString("currentGroup", myGroups[0]).apply()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                sharedPreferences.edit().putStringSet("groups", myGroups.map { a -> a.toString()}.toSet())
 | 
					 | 
				
			||||||
                val intent = Intent(this, MainActivity::class.java)
 | 
					                val intent = Intent(this, MainActivity::class.java)
 | 
				
			||||||
                startActivity(intent)
 | 
					                startActivity(intent)
 | 
				
			||||||
                finish()
 | 
					                finish()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,5 @@
 | 
				
			|||||||
package org.foxarmy.barcodescannerforemployees.activities
 | 
					package org.foxarmy.barcodescannerforemployees.activities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//import android.R
 | 
					 | 
				
			||||||
import android.content.DialogInterface
 | 
					import android.content.DialogInterface
 | 
				
			||||||
import android.content.Intent
 | 
					import android.content.Intent
 | 
				
			||||||
import android.os.Bundle
 | 
					import android.os.Bundle
 | 
				
			||||||
@@ -11,15 +10,28 @@ import androidx.appcompat.app.AlertDialog
 | 
				
			|||||||
import androidx.appcompat.app.AppCompatActivity
 | 
					import androidx.appcompat.app.AppCompatActivity
 | 
				
			||||||
import androidx.core.content.ContextCompat
 | 
					import androidx.core.content.ContextCompat
 | 
				
			||||||
import androidx.drawerlayout.widget.DrawerLayout
 | 
					import androidx.drawerlayout.widget.DrawerLayout
 | 
				
			||||||
 | 
					import androidx.security.crypto.EncryptedSharedPreferences
 | 
				
			||||||
 | 
					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.R
 | 
					import org.foxarmy.barcodescannerforemployees.R
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
 | 
					import org.foxarmy.barcodescannerforemployees.ViewPagerAdapter
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.convertToUnixEpochTimestamp
 | 
				
			||||||
 | 
					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.databinding.ActivityMainBinding
 | 
					import org.foxarmy.barcodescannerforemployees.databinding.ActivityMainBinding
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.AbstractProduct
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
				
			||||||
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Product
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment
 | 
					import org.foxarmy.barcodescannerforemployees.fragments.CategoriesFragment
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment
 | 
					import org.foxarmy.barcodescannerforemployees.fragments.ShelfFragment
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment
 | 
					import org.foxarmy.barcodescannerforemployees.fragments.StorageFragment
 | 
				
			||||||
 | 
					import org.json.JSONArray
 | 
				
			||||||
 | 
					import org.json.JSONObject
 | 
				
			||||||
 | 
					import java.io.File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
 | 
					class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
 | 
				
			||||||
@@ -90,6 +102,234 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val net = Net()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        net.language = sharedPreferences.getString("language", "en-US")!!
 | 
				
			||||||
 | 
					        net.server = sharedPreferences.getString("server", "")!!
 | 
				
			||||||
 | 
					        net.token = sharedPreferences.getString("token", "")!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val currentGroup = sharedPreferences.getString("currentGroup", "")!!.toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val data = JSONObject(net.synchronize(currentGroup).body!!.string())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val remoteAbstractProducts = data["abstract_products"] as JSONArray
 | 
				
			||||||
 | 
					        val remoteProducts = data["products"] as JSONArray
 | 
				
			||||||
 | 
					        val remoteCategories = data["categories"] as JSONArray
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val dbHelper = DBStorageController(this, sharedPreferences.getString("currentGroup", "")!!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
				
			||||||
 | 
					        val productDAO = ProductDAO(dbHelper)
 | 
				
			||||||
 | 
					        val categoryDAO = CategoryDAO(dbHelper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val localAbstractProducts = abstractProductDAO.getSortedListOfAbstractProducts(0, "", arrayOf(""))
 | 
				
			||||||
 | 
					        val localProducts = productDAO.getSortedListOfProducts(0, "", "")
 | 
				
			||||||
 | 
					        val localCategories = categoryDAO.getAllCategories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        syncAbstractProducts(net, currentGroup, abstractProductDAO, remoteAbstractProducts, localAbstractProducts)
 | 
				
			||||||
 | 
					        syncProducts(productDAO, remoteProducts, localProducts)
 | 
				
			||||||
 | 
					        syncCategories(categoryDAO, remoteCategories, localCategories)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun syncCategories(
 | 
				
			||||||
 | 
					        categoryDAO: CategoryDAO,
 | 
				
			||||||
 | 
					        remoteCategories: JSONArray,
 | 
				
			||||||
 | 
					        localCategories: List<Category>
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        for (i in 0 until remoteCategories.length()) {
 | 
				
			||||||
 | 
					            var categoryInRemoteDB: JSONObject? = null
 | 
				
			||||||
 | 
					            var categoryInLocalDB: Category? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val remoteCategory = remoteCategories.getJSONObject(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (localCategory in localCategories) {
 | 
				
			||||||
 | 
					                if (remoteCategory["local_id"] == localCategory.id) {
 | 
				
			||||||
 | 
					                    categoryInRemoteDB = remoteCategory
 | 
				
			||||||
 | 
					                    categoryInLocalDB = localCategory
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (categoryInLocalDB == null && remoteCategory != null) {
 | 
				
			||||||
 | 
					                var newCategory: Category
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                with (remoteCategory) {
 | 
				
			||||||
 | 
					                    newCategory = Category(
 | 
				
			||||||
 | 
					                        this["local_id"].toString().toInt(),
 | 
				
			||||||
 | 
					                        this["name"].toString()
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                categoryDAO.addCategory(newCategory)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (categoryInRemoteDB != null && categoryInLocalDB != null) {
 | 
				
			||||||
 | 
					                if (categoryInRemoteDB["hash"] != categoryInLocalDB.calculateHash()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var updatedData: Category
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    with(categoryInRemoteDB) {
 | 
				
			||||||
 | 
					                        updatedData = Category(
 | 
				
			||||||
 | 
					                            this["local_id"].toString().toInt(),
 | 
				
			||||||
 | 
					                            this["name"].toString()
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    categoryDAO.updateCategory(updatedData)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun syncProducts(
 | 
				
			||||||
 | 
					        productDAO: ProductDAO,
 | 
				
			||||||
 | 
					        remoteProducts: JSONArray,
 | 
				
			||||||
 | 
					        localProducts: List<Product>
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        for (i in 0 until remoteProducts.length()) {
 | 
				
			||||||
 | 
					            var productInRemoteDB: JSONObject? = null
 | 
				
			||||||
 | 
					            var productInLocalDB: Product? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val remoteProduct = remoteProducts.getJSONObject(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (localProduct in localProducts) {
 | 
				
			||||||
 | 
					                if (remoteProduct["local_id"] == localProduct.id) {
 | 
				
			||||||
 | 
					                    productInRemoteDB = remoteProduct
 | 
				
			||||||
 | 
					                    productInLocalDB = localProduct
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (productInLocalDB == null && remoteProduct != null) {
 | 
				
			||||||
 | 
					                var newProduct: Product
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (productInRemoteDB != null && productInLocalDB != null) {
 | 
				
			||||||
 | 
					                if (productInRemoteDB["hash"] != productInLocalDB.calculateHash()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    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)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun syncAbstractProducts(
 | 
				
			||||||
 | 
					        net: Net,
 | 
				
			||||||
 | 
					        currentGroup: Int,
 | 
				
			||||||
 | 
					        abstractProductDAO: AbstractProductDAO,
 | 
				
			||||||
 | 
					        remoteAbstractProducts: JSONArray,
 | 
				
			||||||
 | 
					        localAbstractProducts: List<AbstractProduct>
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        for (i in 0 until remoteAbstractProducts.length()) {
 | 
				
			||||||
 | 
					            var abstractProductInRemoteDB: JSONObject? = null
 | 
				
			||||||
 | 
					            var abstractProductInLocalDB: AbstractProduct? = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val remoteAbstractProduct = remoteAbstractProducts.getJSONObject(i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (localAbstractProduct in localAbstractProducts) {
 | 
				
			||||||
 | 
					                if (remoteAbstractProduct["local_id"] == localAbstractProduct.id) {
 | 
				
			||||||
 | 
					                    abstractProductInRemoteDB = remoteAbstractProduct
 | 
				
			||||||
 | 
					                    abstractProductInLocalDB = localAbstractProduct
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (abstractProductInLocalDB == null && remoteAbstractProduct != null) {
 | 
				
			||||||
 | 
					                val localId = remoteAbstractProduct["local_id"].toString().toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                val picturesDir = File(filesDir, "pictures")
 | 
				
			||||||
 | 
					                picturesDir.mkdirs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                val pictureFile =
 | 
				
			||||||
 | 
					                    File(picturesDir, "${remoteAbstractProduct["image_filename"]}.png")
 | 
				
			||||||
 | 
					                val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
 | 
				
			||||||
 | 
					                net.downloadImage(url, pictureFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                var newAbstractProduct: AbstractProduct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (abstractProductInRemoteDB != null && abstractProductInLocalDB != null) {
 | 
				
			||||||
 | 
					                if (abstractProductInRemoteDB["hash"] != abstractProductInLocalDB.calculateHash()) {
 | 
				
			||||||
 | 
					                    val localId = abstractProductInRemoteDB["local_id"].toString().toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    val pictureFile =
 | 
				
			||||||
 | 
					                        File(File(filesDir, "pictures"), "${abstractProductInRemoteDB["image_filename"]}.png")
 | 
				
			||||||
 | 
					                    val url = "https://${net.server}/api/abstractproduct/getImage/${currentGroup}/${localId}"
 | 
				
			||||||
 | 
					                    net.downloadImage(url, pictureFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var updatedData: AbstractProduct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    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)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun setupViewPager(viewpager: ViewPager) {
 | 
					    private fun setupViewPager(viewpager: ViewPager) {
 | 
				
			||||||
@@ -117,9 +357,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
 | 
				
			|||||||
            R.id.nav_account -> {
 | 
					            R.id.nav_account -> {
 | 
				
			||||||
                intent = Intent(this, AccountSettingsActivity::class.java)
 | 
					                intent = Intent(this, AccountSettingsActivity::class.java)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            R.id.nav_groups -> {
 | 
					            R.id.nav_groups -> {
 | 
				
			||||||
                intent = Intent(this, MyGroupsActivity::class.java)
 | 
					                intent = Intent(this, MyGroupsActivity::class.java)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            R.id.nav_settings -> {
 | 
					            R.id.nav_settings -> {
 | 
				
			||||||
                //TODO: Settings
 | 
					                //TODO: Settings
 | 
				
			||||||
                return false
 | 
					                return false
 | 
				
			||||||
@@ -169,6 +411,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                                }.show()
 | 
					                                }.show()
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        "ShelfFragment" -> {
 | 
					                        "ShelfFragment" -> {
 | 
				
			||||||
                            val shelfFragment = fragment as ShelfFragment
 | 
					                            val shelfFragment = fragment as ShelfFragment
 | 
				
			||||||
                            shelfFragment.removeSelected()
 | 
					                            shelfFragment.removeSelected()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -232,6 +232,7 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        val db = dbHelper.writableDatabase
 | 
					        val db = dbHelper.writableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
 | 
					            if (abstractProduct.id > 0) put(BaseColumns._ID, abstractProduct.id)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.BARCODE, abstractProduct.barcode)
 | 
					            put(AbstractProductContract.AbstractProductEntry.BARCODE, abstractProduct.barcode)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, abstractProduct.name)
 | 
					            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, abstractProduct.name)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, abstractProduct.netWeight.toString())
 | 
					            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, abstractProduct.netWeight.toString())
 | 
				
			||||||
@@ -249,6 +250,7 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        val db = dbHelper.writableDatabase
 | 
					        val db = dbHelper.writableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
 | 
					            put(BaseColumns._ID, abstractProduct.id)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.BARCODE, abstractProduct.barcode)
 | 
					            put(AbstractProductContract.AbstractProductEntry.BARCODE, abstractProduct.barcode)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, abstractProduct.name)
 | 
					            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME, abstractProduct.name)
 | 
				
			||||||
            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, abstractProduct.netWeight.toString())
 | 
					            put(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT, abstractProduct.netWeight.toString())
 | 
				
			||||||
@@ -265,7 +267,11 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun getSortedListOfAbstractProducts(selectedSort: Int, filterBy: String, filter: Array<String>): List<AbstractProduct> {
 | 
					    fun getSortedListOfAbstractProducts(
 | 
				
			||||||
 | 
					        selectedSort: Int,
 | 
				
			||||||
 | 
					        filterBy: String,
 | 
				
			||||||
 | 
					        filter: Array<String>
 | 
				
			||||||
 | 
					    ): List<AbstractProduct> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val db = dbHelper.readableDatabase
 | 
					        val db = dbHelper.readableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -282,10 +288,11 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var orderBy: String = ""
 | 
					        var orderBy: String = ""
 | 
				
			||||||
        when(selectedSort) {
 | 
					        when (selectedSort) {
 | 
				
			||||||
            0 -> {
 | 
					            0 -> {
 | 
				
			||||||
                orderBy = "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} ASC"
 | 
					                orderBy = "${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} ASC"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            1 -> {
 | 
					            1 -> {
 | 
				
			||||||
                orderBy = "${AbstractProductContract.AbstractProductEntry.CATEGORY} ASC"
 | 
					                orderBy = "${AbstractProductContract.AbstractProductEntry.CATEGORY} ASC"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -299,6 +306,7 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
                selection = "${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?"
 | 
					                selection = "${AbstractProductContract.AbstractProductEntry.CATEGORY} = ?"
 | 
				
			||||||
                selectionArgs = filter
 | 
					                selectionArgs = filter
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            "barcodeless" -> {
 | 
					            "barcodeless" -> {
 | 
				
			||||||
                selection = "${AbstractProductContract.AbstractProductEntry.BARCODE} = '' "
 | 
					                selection = "${AbstractProductContract.AbstractProductEntry.BARCODE} = '' "
 | 
				
			||||||
                selectionArgs = null
 | 
					                selectionArgs = null
 | 
				
			||||||
@@ -306,24 +314,35 @@ class AbstractProductDAO(private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val cursor = db.query(AbstractProductContract.AbstractProductEntry.TABLE_NAME, projection, selection, selectionArgs, null, null, orderBy)
 | 
					        val cursor = db.query(
 | 
				
			||||||
 | 
					            AbstractProductContract.AbstractProductEntry.TABLE_NAME,
 | 
				
			||||||
 | 
					            projection,
 | 
				
			||||||
 | 
					            selection,
 | 
				
			||||||
 | 
					            selectionArgs,
 | 
				
			||||||
 | 
					            null,
 | 
				
			||||||
 | 
					            null,
 | 
				
			||||||
 | 
					            orderBy
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (cursor) {
 | 
					        with(cursor) {
 | 
				
			||||||
            while(moveToNext()) {
 | 
					            while (moveToNext()) {
 | 
				
			||||||
                val productId = getInt(getColumnIndexOrThrow(android.provider.BaseColumns._ID))
 | 
					                val productId = getInt(getColumnIndexOrThrow(android.provider.BaseColumns._ID))
 | 
				
			||||||
                val barcode = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.BARCODE))
 | 
					                val barcode = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.BARCODE))
 | 
				
			||||||
                val productName = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
 | 
					                val productName =
 | 
				
			||||||
                val netWeight = getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
 | 
					                    getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NAME))
 | 
				
			||||||
                val productImageHash = getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
 | 
					                val netWeight =
 | 
				
			||||||
 | 
					                    getDouble(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.PRODUCT_NET_WEIGHT))
 | 
				
			||||||
 | 
					                val productImageHash =
 | 
				
			||||||
 | 
					                    getString(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.IMAGE_FILENAME))
 | 
				
			||||||
                val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY))
 | 
					                val category = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.CATEGORY))
 | 
				
			||||||
                val unit = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.UNIT))
 | 
					                val unit = getInt(getColumnIndexOrThrow(AbstractProductContract.AbstractProductEntry.UNIT))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val product = AbstractProduct(productId, barcode, productName, netWeight, productImageHash, category, unit)
 | 
					                val product =
 | 
				
			||||||
 | 
					                    AbstractProduct(productId, barcode, productName, netWeight, productImageHash, category, unit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                abstractProducts.add(product)
 | 
					                abstractProducts.add(product)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return  abstractProducts
 | 
					        return abstractProducts
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -5,7 +5,7 @@ import android.content.Context
 | 
				
			|||||||
import android.provider.BaseColumns
 | 
					import android.provider.BaseColumns
 | 
				
			||||||
import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
					import org.foxarmy.barcodescannerforemployees.dataclasses.Category
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CategoryDAO (private val dbHelper: DBStorageController) {
 | 
					class CategoryDAO(private val dbHelper: DBStorageController) {
 | 
				
			||||||
    fun eraseCategory(id: Int, context: Context) {
 | 
					    fun eraseCategory(id: Int, context: Context) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
					        val abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
				
			||||||
@@ -56,6 +56,7 @@ class CategoryDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        val categories = mutableListOf<Category>()
 | 
					        val categories = mutableListOf<Category>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val projection = arrayOf(
 | 
					        val projection = arrayOf(
 | 
				
			||||||
 | 
					            BaseColumns._ID,
 | 
				
			||||||
            CategoriesContract.CategoryEntry.CATEGORY_NAME
 | 
					            CategoriesContract.CategoryEntry.CATEGORY_NAME
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,7 +73,7 @@ class CategoryDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        with(cursor) {
 | 
					        with(cursor) {
 | 
				
			||||||
            while (moveToNext()) {
 | 
					            while (moveToNext()) {
 | 
				
			||||||
                val category = Category(
 | 
					                val category = Category(
 | 
				
			||||||
                    getInt(getColumnIndexOrThrow(android.provider.BaseColumns._ID)),
 | 
					                    getInt(getColumnIndexOrThrow(BaseColumns._ID)),
 | 
				
			||||||
                    getString(getColumnIndexOrThrow(CategoriesContract.CategoryEntry.CATEGORY_NAME))
 | 
					                    getString(getColumnIndexOrThrow(CategoriesContract.CategoryEntry.CATEGORY_NAME))
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
                categories.add(category)
 | 
					                categories.add(category)
 | 
				
			||||||
@@ -82,15 +83,18 @@ class CategoryDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        return categories
 | 
					        return categories
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun addCategory(category: Category) {
 | 
					    fun addCategory(category: Category): Long {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val db = dbHelper.writableDatabase
 | 
					        val db = dbHelper.writableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
 | 
					            if (category.id > 0) put(BaseColumns._ID, category.id)
 | 
				
			||||||
            put(CategoriesContract.CategoryEntry.CATEGORY_NAME, category.name)
 | 
					            put(CategoriesContract.CategoryEntry.CATEGORY_NAME, category.name)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.insert(CategoriesContract.CategoryEntry.TABLE_NAME, null, values)
 | 
					        val id = db.insert(CategoriesContract.CategoryEntry.TABLE_NAME, null, values)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return id
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun updateCategory(category: Category) {
 | 
					    fun updateCategory(category: Category) {
 | 
				
			||||||
@@ -100,6 +104,11 @@ class CategoryDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
            put(CategoriesContract.CategoryEntry.CATEGORY_NAME, category.name)
 | 
					            put(CategoriesContract.CategoryEntry.CATEGORY_NAME, category.name)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        db.update(CategoriesContract.CategoryEntry.TABLE_NAME, values, "${BaseColumns._ID} = ?", arrayOf(category.id.toString()))
 | 
					        db.update(
 | 
				
			||||||
 | 
					            CategoriesContract.CategoryEntry.TABLE_NAME,
 | 
				
			||||||
 | 
					            values,
 | 
				
			||||||
 | 
					            "${BaseColumns._ID} = ?",
 | 
				
			||||||
 | 
					            arrayOf(category.id.toString())
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -13,18 +13,20 @@ class ProductDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        db.delete(ProductContract.ProductEntry.TABLE_NAME, BaseColumns._ID + "=" + id, null)
 | 
					        db.delete(ProductContract.ProductEntry.TABLE_NAME, BaseColumns._ID + "=" + id, null)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun insertNewProduct(product: Product) {
 | 
					    fun insertNewProduct(product: Product) : Long{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val db = dbHelper.writableDatabase
 | 
					        val db = dbHelper.writableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
 | 
					            if (product.id > 0) put(BaseColumns._ID, product.id)
 | 
				
			||||||
            put(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, product.abstractProductId)
 | 
					            put(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, product.abstractProductId)
 | 
				
			||||||
            put(ProductContract.ProductEntry.AMOUNT, product.amount)
 | 
					            put(ProductContract.ProductEntry.AMOUNT, product.amount)
 | 
				
			||||||
            put(ProductContract.ProductEntry.DATE_OF_PRODUCTION, product.dateOfProduction)
 | 
					            put(ProductContract.ProductEntry.DATE_OF_PRODUCTION, product.dateOfProduction)
 | 
				
			||||||
            put(ProductContract.ProductEntry.EXPIRY_DATE, product.dateOfExpiry)
 | 
					            put(ProductContract.ProductEntry.EXPIRY_DATE, product.dateOfExpiry)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        db.insert(ProductContract.ProductEntry.TABLE_NAME, null, values)
 | 
					        val id = db.insert(ProductContract.ProductEntry.TABLE_NAME, null, values)
 | 
				
			||||||
 | 
					        return id
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun findAmountOfProductsWithExpiryDate(date: Long): Int {
 | 
					    fun findAmountOfProductsWithExpiryDate(date: Long): Int {
 | 
				
			||||||
@@ -82,6 +84,7 @@ class ProductDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
        val db = dbHelper.writableDatabase
 | 
					        val db = dbHelper.writableDatabase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val values = ContentValues().apply {
 | 
					        val values = ContentValues().apply {
 | 
				
			||||||
 | 
					            put(BaseColumns._ID, product.id)
 | 
				
			||||||
            put(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, product.abstractProductId)
 | 
					            put(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID, product.abstractProductId)
 | 
				
			||||||
            put(ProductContract.ProductEntry.AMOUNT, product.amount)
 | 
					            put(ProductContract.ProductEntry.AMOUNT, product.amount)
 | 
				
			||||||
            put(ProductContract.ProductEntry.DATE_OF_PRODUCTION, product.dateOfProduction)
 | 
					            put(ProductContract.ProductEntry.DATE_OF_PRODUCTION, product.dateOfProduction)
 | 
				
			||||||
@@ -157,9 +160,7 @@ class ProductDAO (private val dbHelper: DBStorageController) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
 | 
					                val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (selectedSort == 2) { //freshness
 | 
					                products.add(product)
 | 
				
			||||||
                    products.add(product)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractProduct() : Parcelable {
 | 
					class AbstractProduct() : Parcelable {
 | 
				
			||||||
    var id: Int = 0
 | 
					    var id: Int = 0
 | 
				
			||||||
@@ -32,6 +33,10 @@ class AbstractProduct() : Parcelable {
 | 
				
			|||||||
        unit = parcel.readInt()
 | 
					        unit = parcel.readInt()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun calculateHash(): String {
 | 
				
			||||||
 | 
					        return "$id:$barcode:$name:${if (netWeight % 1 == 0.0) netWeight.toInt() else netWeight}:$imageHash:$category:$unit".md5()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
					    override fun writeToParcel(parcel: Parcel, flags: Int) {
 | 
				
			||||||
        parcel.writeInt(id)
 | 
					        parcel.writeInt(id)
 | 
				
			||||||
        parcel.writeString(barcode)
 | 
					        parcel.writeString(barcode)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Category() : Parcelable {
 | 
					class Category() : Parcelable {
 | 
				
			||||||
    var id = 0
 | 
					    var id = 0
 | 
				
			||||||
@@ -27,6 +28,10 @@ class Category() : Parcelable {
 | 
				
			|||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun calculateHash(): String {
 | 
				
			||||||
 | 
					        return "$id:$name".md5()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object CREATOR : Parcelable.Creator<Category> {
 | 
					    companion object CREATOR : Parcelable.Creator<Category> {
 | 
				
			||||||
        override fun createFromParcel(parcel: Parcel): Category {
 | 
					        override fun createFromParcel(parcel: Parcel): Category {
 | 
				
			||||||
            return Category(parcel)
 | 
					            return Category(parcel)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ 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.md5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Product() : Parcelable {
 | 
					class Product() : Parcelable {
 | 
				
			||||||
    var id = 0
 | 
					    var id = 0
 | 
				
			||||||
@@ -46,6 +47,10 @@ class Product() : Parcelable {
 | 
				
			|||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun calculateHash(): String {
 | 
				
			||||||
 | 
					        return "$id:$abstractProductId:$amount:$dateOfProduction:$dateOfExpiry".md5()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object CREATOR : Parcelable.Creator<Product> {
 | 
					    companion object CREATOR : Parcelable.Creator<Product> {
 | 
				
			||||||
        override fun createFromParcel(parcel: Parcel): Product {
 | 
					        override fun createFromParcel(parcel: Parcel): Product {
 | 
				
			||||||
            return Product(parcel)
 | 
					            return Product(parcel)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,13 +37,24 @@ class AbstractProductView: LinearLayout {
 | 
				
			|||||||
    var isProductSelected = false
 | 
					    var isProductSelected = false
 | 
				
			||||||
    private var activity: Activity
 | 
					    private var activity: Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private lateinit var categoryDAO: CategoryDAO
 | 
					    private var categoryDAO: CategoryDAO
 | 
				
			||||||
    private lateinit var sharedPreferences: SharedPreferences
 | 
					    private var sharedPreferences: SharedPreferences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(context: Context, a: AttributeSet) : super(context, a) {
 | 
					    constructor(context: Context, a: AttributeSet) : super(context, a) {
 | 
				
			||||||
        activity = getActivity(context)!!
 | 
					        activity = getActivity(context)!!
 | 
				
			||||||
        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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sharedPreferences = EncryptedSharedPreferences.create(
 | 
				
			||||||
 | 
					            "sensitive",
 | 
				
			||||||
 | 
					            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
 | 
				
			||||||
 | 
					            context,
 | 
				
			||||||
 | 
					            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
 | 
				
			||||||
 | 
					            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val dbHelper = DBStorageController(context, sharedPreferences.getString("currentGroup", "database")!!)
 | 
				
			||||||
 | 
					        categoryDAO = CategoryDAO(dbHelper)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(activity: Activity, context: Context, abstractProduct: AbstractProduct) : super(context) {
 | 
					    constructor(activity: Activity, context: Context, abstractProduct: AbstractProduct) : super(context) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,7 +42,7 @@ import kotlin.concurrent.thread
 | 
				
			|||||||
class ProductView: LinearLayout {
 | 
					class ProductView: LinearLayout {
 | 
				
			||||||
    var product: Product = Product()
 | 
					    var product: Product = Product()
 | 
				
			||||||
    var isProductSelected = false
 | 
					    var isProductSelected = false
 | 
				
			||||||
    private lateinit var activity: Activity
 | 
					    private var activity: Activity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private lateinit var productImageView: ImageView
 | 
					    private lateinit var productImageView: ImageView
 | 
				
			||||||
    private lateinit var productNameTextView: TextView
 | 
					    private lateinit var productNameTextView: TextView
 | 
				
			||||||
@@ -56,9 +56,9 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
    private var strokeColor: Int = 0x000000
 | 
					    private var strokeColor: Int = 0x000000
 | 
				
			||||||
    private lateinit var outline: GradientDrawable
 | 
					    private lateinit var outline: GradientDrawable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private lateinit var categoryDAO: CategoryDAO
 | 
					    private var categoryDAO: CategoryDAO
 | 
				
			||||||
    private lateinit var abstractProductDAO: AbstractProductDAO
 | 
					    private var abstractProductDAO: AbstractProductDAO
 | 
				
			||||||
    private lateinit var sharedPreferences: SharedPreferences
 | 
					    private var sharedPreferences: SharedPreferences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(context: Context, a: AttributeSet) : super(context, a) {
 | 
					    constructor(context: Context, a: AttributeSet) : super(context, a) {
 | 
				
			||||||
        activity = getActivity(context)!!
 | 
					        activity = getActivity(context)!!
 | 
				
			||||||
@@ -71,7 +71,7 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
 | 
					            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val dbHelper = DBStorageController(context, sharedPreferences.getString("currentGroup", "database")!!)
 | 
					        val dbHelper = DBStorageController(context, sharedPreferences.getString("currentGroup", "offline")!!)
 | 
				
			||||||
        abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
					        abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
				
			||||||
        categoryDAO = CategoryDAO(dbHelper)
 | 
					        categoryDAO = CategoryDAO(dbHelper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,6 +86,18 @@ class ProductView: LinearLayout {
 | 
				
			|||||||
        val inflater: LayoutInflater = activity.layoutInflater
 | 
					        val inflater: LayoutInflater = activity.layoutInflater
 | 
				
			||||||
        inflater.inflate(R.layout.product_view, this)
 | 
					        inflater.inflate(R.layout.product_view, this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sharedPreferences = EncryptedSharedPreferences.create(
 | 
				
			||||||
 | 
					            "sensitive",
 | 
				
			||||||
 | 
					            MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
 | 
				
			||||||
 | 
					            context,
 | 
				
			||||||
 | 
					            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
 | 
				
			||||||
 | 
					            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val dbHelper = DBStorageController(context, sharedPreferences.getString("currentGroup", "offline")!!)
 | 
				
			||||||
 | 
					        abstractProductDAO = AbstractProductDAO(dbHelper)
 | 
				
			||||||
 | 
					        categoryDAO = CategoryDAO(dbHelper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        productImageView = findViewById(R.id.productPicture)
 | 
					        productImageView = findViewById(R.id.productPicture)
 | 
				
			||||||
        productNameTextView = findViewById(R.id.productNameView)
 | 
					        productNameTextView = findViewById(R.id.productNameView)
 | 
				
			||||||
        productNetWeightTextView = findViewById(R.id.productNetWeightView)
 | 
					        productNetWeightTextView = findViewById(R.id.productNetWeightView)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user