real-time sync with websockets (untested)
This commit is contained in:
parent
8c3845a07e
commit
fbf630090c
|
@ -0,0 +1,113 @@
|
|||
package org.foxarmy.barcodescannerforemployees
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import okhttp3.*
|
||||
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
|
||||
|
||||
class WebSocketClient(private val context: Context, private val server: String) {
|
||||
|
||||
private lateinit var webSocket: WebSocket
|
||||
|
||||
fun connect(token: String, currentGroup: String) {
|
||||
val client = OkHttpClient()
|
||||
val request = Request.Builder().url("ws://$server:8282").build()
|
||||
client.newWebSocket(request, object : WebSocketListener() {
|
||||
override fun onOpen(webSocket: WebSocket, response: Response) {
|
||||
this@WebSocketClient.webSocket = webSocket
|
||||
sendMessage("\"token\":\"$token\",\"currentGroup\":\"$currentGroup\"")
|
||||
}
|
||||
|
||||
@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)
|
||||
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)
|
||||
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 Int
|
||||
|
||||
when(item) {
|
||||
"abstractproduct" -> {
|
||||
abstractProductDAO.eraseAbstractProduct(id, context)
|
||||
}
|
||||
"product" -> {
|
||||
productDAO.eraseProduct(id)
|
||||
}
|
||||
"category" -> {
|
||||
categoryDAO.eraseCategory(id, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
|
||||
}
|
||||
|
||||
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun sendMessage(message: String) {
|
||||
webSocket.send(message)
|
||||
}
|
||||
|
||||
fun close() {
|
||||
webSocket.close(1000, "Closing WebSocket connection")
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ class GroupActivity : AppCompatActivity() {
|
|||
binding.createGroupButton.setOnClickListener {
|
||||
val groupName = binding.groupNameTextEdit.text.toString()
|
||||
val groupPassword = binding.groupPasswordTextEdit.text.toString()
|
||||
// group is set to "successful"
|
||||
val net = Net()
|
||||
net.language = sharedPreferences.getString("language", "en-US")!!
|
||||
net.server = sharedPreferences.getString("server", "")!!
|
||||
|
@ -69,7 +68,14 @@ class GroupActivity : AppCompatActivity() {
|
|||
if (!net.serverIsAvailable(this)) {
|
||||
noInternetConnectionAvailableNotification(this)
|
||||
} else {
|
||||
val groupId = net.getGroupId(groupName).toInt()
|
||||
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()
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import androidx.security.crypto.EncryptedSharedPreferences
|
|||
import androidx.security.crypto.MasterKeys
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import okhttp3.internal.wait
|
||||
import org.foxarmy.barcodescannerforemployees.*
|
||||
import org.foxarmy.barcodescannerforemployees.database.AbstractProductDAO
|
||||
import org.foxarmy.barcodescannerforemployees.database.CategoryDAO
|
||||
|
@ -112,8 +113,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
val currentGroup = sharedPreferences.getString("currentGroup", "offline")!!
|
||||
if ( currentGroup != "offline" && !net.serverIsAvailable(this)) {
|
||||
noInternetConnectionAvailableNotification(this)
|
||||
} else {
|
||||
} else if (currentGroup != "offline" && net.serverIsAvailable(this)) {
|
||||
synchronize()
|
||||
val ws = WebSocketClient(this, sharedPreferences.getString("server", "")!!)
|
||||
val token = sharedPreferences.getString("token", "")!!
|
||||
ws.connect(token, currentGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,15 +208,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
|
||||
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()
|
||||
)
|
||||
}
|
||||
val updatedData = Category.createFromJSON(categoryInRemoteDB)
|
||||
|
||||
categoryDAO.updateCategory(updatedData)
|
||||
}
|
||||
|
@ -251,35 +247,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
}
|
||||
|
||||
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())
|
||||
)
|
||||
}
|
||||
val newProduct = Product.createFromJSON(remoteProduct)
|
||||
|
||||
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())
|
||||
)
|
||||
}
|
||||
val updatedData = Product.createFromJSON(productInRemoteDB)
|
||||
|
||||
productDAO.updateProduct(updatedData)
|
||||
}
|
||||
|
@ -330,19 +305,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
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()
|
||||
)
|
||||
}
|
||||
val newAbstractProduct = AbstractProduct.createFromJSON(remoteAbstractProduct)
|
||||
|
||||
abstractProductDAO.addAbstractProduct(newAbstractProduct)
|
||||
|
||||
|
@ -357,20 +320,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
|
|||
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()
|
||||
)
|
||||
}
|
||||
|
||||
val updatedData = AbstractProduct.createFromJSON(abstractProductInRemoteDB)
|
||||
|
||||
abstractProductDAO.updateAbstractProduct(updatedData)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.foxarmy.barcodescannerforemployees.dataclasses
|
|||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import org.foxarmy.barcodescannerforemployees.md5
|
||||
import org.json.JSONObject
|
||||
|
||||
class AbstractProduct() : Parcelable {
|
||||
var id: Int = 0
|
||||
|
@ -59,5 +60,17 @@ class AbstractProduct() : Parcelable {
|
|||
override fun newArray(size: Int): Array<AbstractProduct?> {
|
||||
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.Parcelable
|
||||
import org.foxarmy.barcodescannerforemployees.md5
|
||||
import org.json.JSONObject
|
||||
|
||||
class Category() : Parcelable {
|
||||
var id = 0
|
||||
|
@ -40,5 +41,12 @@ class Category() : Parcelable {
|
|||
override fun newArray(size: Int): Array<Category?> {
|
||||
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 androidx.annotation.RequiresApi
|
||||
import org.foxarmy.barcodescannerforemployees.calculateProductFreshness
|
||||
import org.foxarmy.barcodescannerforemployees.convertToUnixEpochTimestamp
|
||||
import org.foxarmy.barcodescannerforemployees.md5
|
||||
import org.json.JSONObject
|
||||
|
||||
class Product() : Parcelable {
|
||||
var id = 0
|
||||
|
@ -59,5 +61,16 @@ class Product() : Parcelable {
|
|||
override fun newArray(size: Int): Array<Product?> {
|
||||
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())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue