diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3a8b4fa..fb220db 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -10,7 +10,7 @@ android { defaultConfig { applicationId = "com.shuwei.intelligent.shelves" minSdk = 25 - //noinspection ExpiredTargetSdkVersion + //noinspection EditedTargetSdkVersion,ExpiredTargetSdkVersion targetSdk = 30 versionCode = 1 versionName = "1.0" @@ -41,6 +41,7 @@ android { ndkVersion = "29.0.13846066" } +//noinspection UseTomlInstead dependencies { //implementation(fileTree("libs") { include("*.jar", "*.aar") }) implementation(libs.androidx.core.ktx) @@ -54,16 +55,20 @@ dependencies { implementation("io.github.cymchad:BaseRecyclerViewAdapterHelper4:4.1.2") - implementation("com.squareup.okhttp3:okhttp:4.9.1") - implementation("com.google.code.gson:gson:2.10.1") - implementation("io.github.jeadyx:kmp-serialport:1.0.0") - + // 基础依赖包,必须要依赖 implementation("com.geyifeng.immersionbar:immersionbar:3.2.2") // kotlin扩展(可选) implementation("com.geyifeng.immersionbar:immersionbar-ktx:3.2.2") + implementation("com.squareup.okhttp3:okhttp:4.9.1") + implementation("com.google.code.gson:gson:2.10.1") + implementation("com.squareup.retrofit2:retrofit:2.9.0") + implementation("com.squareup.retrofit2:converter-gson:2.9.0") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2") + // implementation("io.github.jeremyliao:live-event-bus-x:1.8.0") // implementation("com.hoho:android-usb-serial:1.3.0") // implementation("io.github.jeadyx:jserialport:1.5") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a88eddf..a4006df 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,9 +2,12 @@ + - - + + + android:theme="@style/Theme.IntelligentShelves" + android:usesCleartextTraffic="true"> + when (state) { + is UiState.Loading -> showProgress() + is UiState.Success<*> -> updateUI(state.data) + is UiState.Error -> showError(state.msg) + else -> {} + } + } + } + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.getAccessTokenUiState.collect { state -> + when (state) { + is UiState.Loading -> {} + is UiState.Success<*> -> getTokenSuccess(state.data) + is UiState.Error -> UIUtils.toast(state.msg) + else -> {} + } + } + } } TaskManager.startTask() + App.get().androidId = "53babf69-0d2f-3875-a649-f2e12f80ad4c1" + // Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) + Log.d(TAG, "onCreate: androidId=${App.get().androidId}") + + val swDpValue = resources?.configuration?.smallestScreenWidthDp + Log.d(TAG, "onCreate: swDpValue=$swDpValue") + + viewModel.getShelfList(deviceId = App.get().androidId) + + + + + viewModel.getAccessToken(App.get().androidId) + // repeat(100) { // lifecycleScope.launch { -// var data = "D6DADEDB01010C6102000000000000010000000500008000000000060000000500000004000080060000000100000010190080701800800000000000000000000000000000000000000000000000005037414645333633333334333731373056322E313069FFFF" +// val data = "D6DADEDB01010C6102000000000000010000000500008000000000060000000500000004000080060000000100000010190080701800800000000000000000000000000000000000000000000000005037414645333633333334333731373056322E313069FFFF" // receiveSerialPortData(data) -// delay(100) +// delay(500) // } // } } + private fun getTokenSuccess(data: RespData<*>) { + Log.d(TAG, "getTokenSuccess: $data") + data.result?.let { + //App.get().accessToken = it.toString() + } + } + + private fun showProgress() { + Loading.show(this) + } + + @SuppressLint("NotifyDataSetChanged") + private fun updateUI(data: RespData<*>) { + Loading.dismiss() + if (data.result !is ShelfResult) { + UIUtils.toast("数据错误") + return + } + val tempList = data.result.containerGoodsList + if (tempList.isNullOrEmpty()) { + UIUtils.toast("数据为空") + return + } + if (tempList.size < 10) { + UIUtils.toast("数据错误") + return + } + list.clear() + val subList01 = tempList.subList(0, 5) + val subList02 = tempList.subList(5, 10) + repeat(5) { index -> + list.add(subList01[index]) + list.add(subList02[index]) + } + shelfAdapter.notifyDataSetChanged() + } + + private fun showError(message: String) { + Loading.dismiss() + UIUtils.toast(message) + } + private val serialReader by lazy { StringBuilder() } private fun receiveSerialPortData(srcData: String) { @@ -103,7 +194,7 @@ class HomeActivity : BaseActivity() { serialReader.clear() serialReader.append(srcData) return - } else if (srcData.contains(FOOTER).not()){ + } else if (srcData.contains(FOOTER).not()) { serialReader.append(srcData) return } else { @@ -151,9 +242,9 @@ class HomeActivity : BaseActivity() { val temperatureHex = data.substring(temperatureStartIndex, temperatureEndIndex) val temperature = hexToDec(temperatureHex) val tempC = f2C(temperature.toDouble()) - val showTemp = "%.1f".format(tempC.toDouble()) + val showTemp = "%.1f".format(tempC) - val percent = 10 * list.count { it.foodName.isNullOrBlank().not() } + val percent = 10 * list.count { it.goodsName.isNullOrBlank().not() } updateLeftStatus("1-1冷藏柜 ${showTemp}°C / ${percent}%") }.onFailure { @@ -175,18 +266,17 @@ class HomeActivity : BaseActivity() { if (weightHex.first() in '8'..'F') { //负数 val weightHex2 = "0${weightHex.substring(1)}" - realWeight = -1*weightHex2.toInt() - //-1*hexToDec(weightHex2) + realWeight = -1 * weightHex2.toInt() } else { //整数 realWeight = weightHex.toInt() - //hexToDec(weightHex) } - weightArray.put(index, realWeight) + val realWeightDouble = realWeight / 1000.0 + weightArray.put(index, realWeightDouble) if (index <= 10) { - list.first { it.shelfNo == index }.let { - it.foodWeight = realWeight + list.firstOrNull { it.deviceNo == index }?.let { + it.weight = realWeightDouble } shelfAdapter.notifyItemChanged(index) } @@ -216,7 +306,7 @@ class HomeActivity : BaseActivity() { // sendBroadcast(intent) } - private val weightArray by lazy { SparseIntArray() } + private val weightArray by lazy { SparseArray() } private var clickIndex = 0 override fun onDestroy() { @@ -234,13 +324,13 @@ class HomeActivity : BaseActivity() { setOnDebouncedItemClick { adapter, view, position -> this@HomeActivity.clickIndex = position lifecycleScope.launch { - val openCmd = if (list[position].shelfNo in 1..5) + val openCmd = if (list[position].deviceNo in 1..5) LEFT_SHELF_OPEN_CMD else RIGHT_SHELF_OPEN_CMD val openState = SerialPortManager.send(openCmd) if (openState.not()) { - UIUtils.toast("${list[position].foodName}柜门开启失败") + UIUtils.toast("${list[position].goodsName}柜门开启失败") return@launch } launch(Intent(this@HomeActivity, ShelfActivity::class.java).also { @@ -250,9 +340,9 @@ class HomeActivity : BaseActivity() { val model = getSerializableExtra(ShelfActivity.SHELF_MODEL) as ShelfModel list[position].apply { - foodName = model.foodName - foodWeight = model.foodWeight - storeDate = model.storeDate + goodsName = model.goodsName + weight = model.weight + createTime = model.createTime } notifyItemChanged(position) } @@ -271,18 +361,18 @@ class HomeActivity : BaseActivity() { } private fun initList() { -// val list: MutableList = mutableListOf() - list.add(ShelfModel(shelfNo = 1)) - list.add(ShelfModel(shelfNo = 6)) - list.add(ShelfModel(shelfNo = 2)) - list.add(ShelfModel(shelfNo = 7)) - list.add(ShelfModel(shelfNo = 3)) - list.add(ShelfModel(shelfNo = 8)) - list.add(ShelfModel(shelfNo = 4)) - list.add(ShelfModel(shelfNo = 9)) - list.add(ShelfModel(shelfNo = 5)) - list.add(ShelfModel(shelfNo = 10)) -// viewModel.updateItems(list) +//// val list: MutableList = mutableListOf() +// list.add(ShelfModel(deviceNo = 1)) +// list.add(ShelfModel(deviceNo = 6)) +// list.add(ShelfModel(deviceNo = 2)) +// list.add(ShelfModel(deviceNo = 7)) +// list.add(ShelfModel(deviceNo = 3)) +// list.add(ShelfModel(deviceNo = 8)) +// list.add(ShelfModel(deviceNo = 4)) +// list.add(ShelfModel(deviceNo = 9)) +// list.add(ShelfModel(deviceNo = 5)) +// list.add(ShelfModel(deviceNo = 10)) +//// viewModel.updateItems(list) } private val MM_DD_EEEE__HH_MM_SS = "MM月dd日 EEEE HH:mm:ss" diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/ShelfActivity.kt b/app/src/main/java/com/shuwei/intelligent/shelves/ShelfActivity.kt index 7e3d49a..04b868c 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/ShelfActivity.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/ShelfActivity.kt @@ -5,34 +5,39 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Log -import androidx.annotation.RequiresApi +import androidx.activity.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.GridLayoutManager import com.chad.library.adapter4.util.setOnDebouncedItemClick -import com.shuwei.intelligent.shelves.HomeActivity.Companion.ACTIVE_CMD import com.shuwei.intelligent.shelves.HomeActivity.Companion.DEVICE_INFO_CMD -import com.shuwei.intelligent.shelves.utils.ext.addOnActionSearchListener -import com.shuwei.intelligent.shelves.utils.ext.clickWithDebounce -import com.shuwei.intelligent.shelves.utils.ext.toast import com.shuwei.intelligent.shelves.adapter.SearchAdapter import com.shuwei.intelligent.shelves.base.BaseActivity import com.shuwei.intelligent.shelves.databinding.ActivityShelfBinding -import com.shuwei.intelligent.shelves.model.SearchModel +import com.shuwei.intelligent.shelves.model.GoodsModel +import com.shuwei.intelligent.shelves.model.GoodsRecord import com.shuwei.intelligent.shelves.model.ShelfModel +import com.shuwei.intelligent.shelves.net.Loading +import com.shuwei.intelligent.shelves.net.NetViewModel +import com.shuwei.intelligent.shelves.net.RespData +import com.shuwei.intelligent.shelves.net.UiState import com.shuwei.intelligent.shelves.serial.SerialPortManager import com.shuwei.intelligent.shelves.utils.DateTimeUtil import com.shuwei.intelligent.shelves.utils.KeyboardUtil -import com.shuwei.intelligent.shelves.utils.decToHex +import com.shuwei.intelligent.shelves.utils.UIUtils +import com.shuwei.intelligent.shelves.utils.ext.addOnActionSearchListener +import com.shuwei.intelligent.shelves.utils.ext.clickWithDebounce +import com.shuwei.intelligent.shelves.utils.ext.toJsonString +import com.shuwei.intelligent.shelves.utils.ext.toast import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -import kotlin.random.Random @SuppressLint("NotifyDataSetChanged") class ShelfActivity : BaseActivity() { @@ -53,6 +58,9 @@ class ShelfActivity : BaseActivity() { private var realWeight: Int = 0 + private val viewModel: NetViewModel by viewModels() + + @SuppressLint("UnspecifiedRegisterReceiverFlag") @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { @@ -64,8 +72,8 @@ class ShelfActivity : BaseActivity() { shelfModel?.let { binding.tvShelfName.text = it.shelfName - binding.tvFoodName.text = if (it.foodName.isNullOrBlank()) "-" else it.foodName - realWeight = it.foodWeight ?: 0 + binding.tvFoodName.text = if (it.goodsName.isNullOrBlank()) "-" else it.goodsName + realWeight = ((it.weight ?: 0.0) * 1000).toInt() binding.tvFoodWeight.text = "${realWeight}克" } @@ -77,7 +85,11 @@ class ShelfActivity : BaseActivity() { toast(hint.toString()) return@addOnActionSearchListener } - loadSearchData() +// loadSearchData() + viewModel.getGoodsList( + canteenId = "1599670511042785282", + goodsName = text.toString().trim() + ) KeyboardUtil.hideKeyboard(context, this) } } @@ -89,9 +101,9 @@ class ShelfActivity : BaseActivity() { } val data = ShelfModel( shelfName = shelfModel?.shelfName, - foodName = list[clickIndex].foodName, - foodWeight = realWeight, - storeDate = DateTimeUtil.formatDateTime(dateTime = Date()) + goodsName = list[clickIndex].goodsName, + weight = realWeight / 1000.0, + createTime = DateTimeUtil.formatDateTime(dateTime = Date()) ) val intent = Intent().apply { putExtra(SHELF_MODEL, data) @@ -104,7 +116,7 @@ class ShelfActivity : BaseActivity() { } binding.btnClearZero.setOnClickListener { v -> lifecycleScope.launch { - val shelfNo = shelfModel?.shelfNo ?: 0 + val shelfNo = shelfModel?.deviceNo ?: 0 val hex = shelfNo.toString(16).padStart(2, '0').uppercase() Log.d(TAG, "onCreate: hex=$hex") val zeroClearingCmd = @@ -117,9 +129,51 @@ class ShelfActivity : BaseActivity() { lifecycleScope.launch { SerialPortManager.send(DEVICE_INFO_CMD) + + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.getGoodsListUiState.collect { state -> + when (state) { + is UiState.Loading -> showProgress() + is UiState.Success<*> -> updateUI(state.data) + is UiState.Error -> showError(state.msg) + else -> {} + } + } + } } registerReceiver(receiver, IntentFilter(RECEIVER_DEVICE_INFO)) + + + viewModel.getGoodsList( + canteenId = "1599670511042785282" + ) + } + + private fun showProgress() { + Loading.show(this) + } + + @SuppressLint("NotifyDataSetChanged") + private fun updateUI(data: RespData<*>) { + Loading.dismiss() + Log.d(TAG, "updateUI: ${data.toJsonString()}") + if (data.result !is GoodsRecord) { + UIUtils.toast("数据错误") + return + } + if (data.result.records.isNullOrEmpty()) { + UIUtils.toast("数据错误") + return + } + list.clear() + list.addAll(data.result.records) + searchAdapter.notifyDataSetChanged() + } + + private fun showError(message: String) { + Loading.dismiss() + UIUtils.toast(message) } private val receiver = object : BroadcastReceiver() { @@ -127,7 +181,8 @@ class ShelfActivity : BaseActivity() { intent?.let { val data = it.getStringExtra(RECEIVER_DEVICE_INFO) Log.d(TAG, "onReceive: $data") - realWeight = it.getIntExtra(SHELF_WEIGHT, 0) + val weight = it.getDoubleExtra(SHELF_WEIGHT, 0.0) + realWeight = (weight * 1000).toInt() binding.tvFoodWeight.text = "${realWeight}克" } } @@ -142,28 +197,28 @@ class ShelfActivity : BaseActivity() { // realWeight = Random.nextInt(1, 5001) // } - private fun loadSearchData() { - list.add(SearchModel(foodId = 1000, foodName = "菲律宾乳猪五花肉")) - list.add(SearchModel(foodId = 1001, foodName = "金针菇")) - list.add(SearchModel(foodId = 1002, foodName = "大菠菜")) - list.add(SearchModel(foodId = 1003, foodName = "清远麻鸡块")) - list.add(SearchModel(foodId = 1004, foodName = "普罗旺斯番茄")) - list.add(SearchModel(foodId = 1005, foodName = "长条茄子")) - list.add(SearchModel(foodId = 1006, foodName = "得莫利鱼")) - list.add(SearchModel(foodId = 1007, foodName = "土豆丝")) - list.add(SearchModel(foodId = 1008, foodName = "辣椒炒肉")) - list.add(SearchModel(foodId = 1009, foodName = "雪菜烧豆腐")) - list.add(SearchModel(foodId = 1010, foodName = "冬虫夏草炝拌芥兰苗")) - list.add( - SearchModel( - foodId = 1011, - foodName = "蘑菇玉米山药莲藕胡萝卜红枣莲子枸杞清炖排骨汤" - ) - ) - searchAdapter.notifyDataSetChanged() - } +// private fun loadSearchData() { +// list.add(SearchModel(foodId = 1000, foodName = "菲律宾乳猪五花肉")) +// list.add(SearchModel(foodId = 1001, foodName = "金针菇")) +// list.add(SearchModel(foodId = 1002, foodName = "大菠菜")) +// list.add(SearchModel(foodId = 1003, foodName = "清远麻鸡块")) +// list.add(SearchModel(foodId = 1004, foodName = "普罗旺斯番茄")) +// list.add(SearchModel(foodId = 1005, foodName = "长条茄子")) +// list.add(SearchModel(foodId = 1006, foodName = "得莫利鱼")) +// list.add(SearchModel(foodId = 1007, foodName = "土豆丝")) +// list.add(SearchModel(foodId = 1008, foodName = "辣椒炒肉")) +// list.add(SearchModel(foodId = 1009, foodName = "雪菜烧豆腐")) +// list.add(SearchModel(foodId = 1010, foodName = "冬虫夏草炝拌芥兰苗")) +// list.add( +// SearchModel( +// foodId = 1011, +// foodName = "蘑菇玉米山药莲藕胡萝卜红枣莲子枸杞清炖排骨汤" +// ) +// ) +// searchAdapter.notifyDataSetChanged() +// } - private val list: MutableList = mutableListOf() + private val list: MutableList = mutableListOf() private val searchAdapter by lazy { SearchAdapter(list).apply { setOnDebouncedItemClick { adapter, v, position -> @@ -171,7 +226,7 @@ class ShelfActivity : BaseActivity() { list.forEach { it.isClicked = false } list[position].isClicked = true notifyDataSetChanged() - binding.tvFoodName.text = list[position].foodName + binding.tvFoodName.text = list[position].goodsName KeyboardUtil.hideKeyboard(v.context, v) } } diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt index 47a3725..141673f 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/SearchAdapter.kt @@ -11,10 +11,10 @@ import com.chad.library.adapter4.BaseQuickAdapter import com.chad.library.adapter4.viewholder.QuickViewHolder import com.shuwei.intelligent.shelves.R import com.shuwei.intelligent.shelves.databinding.ListItemSearchBinding -import com.shuwei.intelligent.shelves.model.SearchModel +import com.shuwei.intelligent.shelves.model.GoodsModel -class SearchAdapter(list: MutableList) : - BaseQuickAdapter(list) { +class SearchAdapter(list: MutableList) : + BaseQuickAdapter(list) { inner class VH(var binding: ListItemSearchBinding) : QuickViewHolder(binding.root) @@ -24,10 +24,10 @@ class SearchAdapter(list: MutableList) : return VH(binding) } - override fun onBindViewHolder(holder: VH, position: Int, item: SearchModel?) { + override fun onBindViewHolder(holder: VH, position: Int, item: GoodsModel?) { val binding = holder.binding binding.btnFoodName.run { - text = " ${item!!.foodName}" + text = " ${item!!.goodsName}" setTextColor( getColor(if (item.isClicked) R.color.shelf_name_blue else R.color.black999) ) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt index d5edebf..d530788 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/adapter/ShelfAdapter.kt @@ -23,17 +23,17 @@ class ShelfAdapter(list: MutableList) : } override fun onBindViewHolder(holder: VH, position: Int, item: ShelfModel?) { - val shelfNo = item!!.shelfNo + val shelfNo = item!!.deviceNo item.shelfName = "货架-${if (shelfNo < 10) "0${shelfNo}" else "$shelfNo" }" - val weight = item.foodWeight ?: 0 + val weight = item.weight ?: 0.toDouble() val binding = holder.binding binding.tvFoodWeight.run { setTextColor(getColor(R.color.food_weight_orange)) - val showWeight = if(weight == 0) "0" else "%.3f".format(weight/1000F) + val showWeight = if(weight == 0.toDouble()) "0" else "%.3f".format(weight) text = "${showWeight}千克" } //val isBlankShelf = weight <= 0 - val isBlankShelf = item.foodName.isNullOrBlank() + val isBlankShelf = item.goodsName.isNullOrBlank() if (isBlankShelf) { binding.layoutCard.setCardBackgroundColor(getColor(R.color.bg_card_blue)) binding.tvShelfName.run { @@ -61,7 +61,7 @@ class ShelfAdapter(list: MutableList) : } binding.tvFoodName.run { setTextColor(getColor(R.color.food_name_black)) - text = item.foodName + text = item.goodsName } // binding.tvFoodWeight.run { // setTextColor(getColor(R.color.food_weight_orange)) @@ -70,7 +70,7 @@ class ShelfAdapter(list: MutableList) : // } binding.tvStoreDate.run { setTextColor(getColor(R.color.black999)) - text = item.storeDate + text = item.createTime } } diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/SearchModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt similarity index 58% rename from app/src/main/java/com/shuwei/intelligent/shelves/model/SearchModel.kt rename to app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt index 5336314..8f51f90 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/SearchModel.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsModel.kt @@ -2,8 +2,8 @@ package com.shuwei.intelligent.shelves.model import java.io.Serializable -data class SearchModel( - var foodId: Int? = null, - var foodName: String? = null, +data class GoodsModel( + var goodsId: String? = null, + var goodsName: String? = null, var isClicked: Boolean = false ) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt new file mode 100644 index 0000000..5f9596c --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/model/GoodsRecord.kt @@ -0,0 +1,8 @@ +package com.shuwei.intelligent.shelves.model + +data class GoodsRecord( + val total: Int = 0, + val size: Int = 0, + val page: Int = 0, + val records: MutableList? = null +) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt new file mode 100644 index 0000000..ee23f40 --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfBody.kt @@ -0,0 +1,9 @@ +package com.shuwei.intelligent.shelves.model + +class ShelfBody { + + var deviceId: String = "" + var canteenId: String = "" + var goodsList: List? = null + +} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt index 37bb64c..3ef0e2f 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfModel.kt @@ -3,9 +3,11 @@ package com.shuwei.intelligent.shelves.model import java.io.Serializable data class ShelfModel( - var shelfNo: Int = 0, + var id: String? = null, + var deviceNo: Int = 0, var shelfName: String? = null, - var foodName: String? = null, - var foodWeight: Int? = null, - var storeDate: String? = null + var goodsId: Int = 0, + var goodsName: String? = null, + var weight: Double? = null, + var createTime: String? = null ) : Serializable \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt new file mode 100644 index 0000000..64bb13a --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/model/ShelfResult.kt @@ -0,0 +1,7 @@ +package com.shuwei.intelligent.shelves.model + +data class ShelfResult( + val canteenId: String = "", + val canteenName: String = "", + val containerGoodsList: List? = null +) diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt new file mode 100644 index 0000000..7e28b86 --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/ApiService.kt @@ -0,0 +1,33 @@ +package com.shuwei.intelligent.shelves.net + +import com.shuwei.intelligent.shelves.model.GoodsRecord +import com.shuwei.intelligent.shelves.model.ShelfBody +import com.shuwei.intelligent.shelves.model.ShelfResult +import retrofit2.http.Body +import retrofit2.http.FormUrlEncoded +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.Query + +interface ApiService { + + @GET(UrlConfig.GET_ACCESS_TOKEN) + suspend fun getAccessToken(@Query("qrcodeId") qrcodeId: String): RespData + + @GET(UrlConfig.GET_SHELF_LIST) + suspend fun getShelfList(@Query("deviceId") deviceId: String): RespData + + @GET(UrlConfig.GET_GOODS_LIST) + suspend fun getGoodsList( + @Query("canteenId") canteenId: String = "0", + @Query("goodsName") goodsName: String? = null, + @Query("pageNo") pageNo: Int = 1, + @Query("pageSize") pageSize: Int = 50, + ): RespData + + + @FormUrlEncoded + @POST(UrlConfig.SAVE_SHELF_GOODS_LIST) + suspend fun saveShelfGoodsList(@Body body: ShelfBody): RespData + +} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt new file mode 100644 index 0000000..42cbdde --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/HttpManager.kt @@ -0,0 +1,89 @@ +package com.shuwei.intelligent.shelves.net + +import android.annotation.SuppressLint +import android.util.Log +import com.shuwei.intelligent.shelves.App +import okhttp3.Call +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit + +import javax.net.ssl.* +import java.security.SecureRandom +import java.security.cert.X509Certificate +import kotlin.apply + +val apiService: ApiService = Retrofit.Builder() + .baseUrl(UrlConfig.BASE_URL) + .client(HttpManager.instance.client) + .addConverterFactory(GsonConverterFactory.create()) + .build() + .create(ApiService::class.java) + +class HttpManager private constructor() { + val client: OkHttpClient by lazy { + OkHttpClient.Builder() + .apply { + connectTimeout(15, TimeUnit.SECONDS) + readTimeout(30, TimeUnit.SECONDS) + writeTimeout(15, TimeUnit.SECONDS) + sslSocketFactory(createSSLSocketFactory(), TrustAllCerts()) + hostnameVerifier { _, _ -> true } + addInterceptor(LoggingInterceptor()) + addInterceptor { chain -> + val request = chain.request().newBuilder() + .header("x-access-token", App.get().accessToken) + .build() + chain.proceed(request) + } + } + .build() + } + + companion object { + val instance by lazy { HttpManager() } + } + +// fun newCall(request: Request): Call = client.newCall(request) + + inner class LoggingInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + // 打印请求日志 + Log.d("OkHttp", "--> ${request.method},${request.url}") + + val response = chain.proceed(request) + // 打印响应日志 + Log.d("OkHttp", "<-- ${response.code},${response.request.url}") + + return response + } + } + + // 信任所有证书的TrustManager实现 + @SuppressLint("CustomX509TrustManager") + class TrustAllCerts : X509TrustManager { + @SuppressLint("TrustAllX509TrustManager") + override fun checkClientTrusted(chain: Array, authType: String) { + } + + @SuppressLint("TrustAllX509TrustManager") + override fun checkServerTrusted(chain: Array, authType: String) { + } + + override fun getAcceptedIssuers(): Array = arrayOf() + } + + // 创建信任所有证书的SSLSocketFactory + fun createSSLSocketFactory(): SSLSocketFactory { + val sslContext = SSLContext.getInstance("TLS").apply { + init(null, arrayOf(TrustAllCerts()), SecureRandom()) + } + return sslContext.socketFactory + } + +} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/LoadingDialog.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/LoadingDialog.kt new file mode 100644 index 0000000..e6dd43c --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/LoadingDialog.kt @@ -0,0 +1,62 @@ +package com.shuwei.intelligent.shelves.net + +import android.app.Dialog +import android.content.Context +import android.graphics.Color +import android.view.LayoutInflater +import android.view.WindowManager +import androidx.core.graphics.drawable.toDrawable +import com.shuwei.intelligent.shelves.R +import com.shuwei.intelligent.shelves.databinding.DialogLoadingBinding +import kotlin.let +import kotlin.run + +object Loading { + + private var dialog: LoadingDialog? = null + + fun show(context: Context) { + if (dialog?.isShowing == true) { + dialog?.dismiss() + } + + if (dialog == null) { + dialog = LoadingDialog(context) + } + dialog?.show() + } + + fun dismiss() { + dialog?.let { + if (it.isShowing) { + it.dismiss() + } + } + dialog = null + } + +} + +class LoadingDialog( + context: Context, + message: String = "加载中……", + private var onDismiss: () -> Unit = {} +) : Dialog(context, R.style.LoadingDialog) { + init { + val binding = DialogLoadingBinding.inflate(LayoutInflater.from(context)) + binding.tvMessage.text = message + setContentView(binding.root) + setCancelable(true) + window?.run { + setBackgroundDrawable(Color.TRANSPARENT.toDrawable()) + setFlags( + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + ); + } + setOnDismissListener { + onDismiss() + } + } +} + diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt new file mode 100644 index 0000000..3e6cd36 --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/NetViewModel.kt @@ -0,0 +1,109 @@ +package com.shuwei.intelligent.shelves.net + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.shuwei.intelligent.shelves.model.ShelfBody +import com.shuwei.intelligent.shelves.net.HttpManager.Companion.instance +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class NetViewModel : ViewModel() { + +// val apiService: ApiService = HttpManager.instance.apiService +// val apiService: ApiService = Retrofit.Builder() +// .baseUrl(UrlConfig.BASE_URL) +// .client(HttpManager.instance.client) +// .addConverterFactory(GsonConverterFactory.create()) +// .build() +// .create(ApiService::class.java) + + private val _getShelfListUiState = MutableStateFlow(UiState.Loading) + val getShelfListUiState: StateFlow = _getShelfListUiState + + private val _saveShelfGoodsListUiState = MutableStateFlow(UiState.Loading) + val saveShelfGoodsListUiState: StateFlow = _saveShelfGoodsListUiState + + private val _getGoodsListUiState = MutableStateFlow(UiState.Loading) + val getGoodsListUiState: StateFlow = _getGoodsListUiState + + private val _getAccessTokenUiState = MutableStateFlow(UiState.Loading) + val getAccessTokenUiState: StateFlow = _getAccessTokenUiState + + fun getAccessToken(deviceId: String) { + viewModelScope.launch { + _getAccessTokenUiState.value = UiState.Loading + runCatching { + val response = apiService.getAccessToken(deviceId) + if (response.success) { + _getAccessTokenUiState.value = UiState.Success(response) + } else { + _getAccessTokenUiState.value = UiState.Error(response.message ?: "请求失败") + } + }.onFailure { + _getAccessTokenUiState.value = UiState.Error(it.message ?: "请求异常") + } + } + } + + fun getShelfList(deviceId: String) { + viewModelScope.launch { + _getShelfListUiState.value = UiState.Loading + runCatching { + val response = apiService.getShelfList(deviceId) + if (response.success) { + _getShelfListUiState.value = UiState.Success(response) + } else { + _getShelfListUiState.value = UiState.Error(response.message ?: "请求失败") + } + }.onFailure { + _getShelfListUiState.value = UiState.Error(it.message ?: "请求异常") + } + } + } + + fun saveShelfGoodsList(body: ShelfBody) { + viewModelScope.launch { + _saveShelfGoodsListUiState.value = UiState.Loading + runCatching { + val response = apiService.saveShelfGoodsList(body) + if (response.success) { + _saveShelfGoodsListUiState.value = UiState.Success(response) + } else { + _saveShelfGoodsListUiState.value = UiState.Error(response.message ?: "请求失败") + } + }.onFailure { + _saveShelfGoodsListUiState.value = UiState.Error(it.message ?: "请求异常") + } + } + } + + fun getGoodsList( + canteenId: String = "", + goodsName: String = "", + pageNo: Int = 1, + pageSize: Int = 50, + ) { + viewModelScope.launch { + _getGoodsListUiState.value = UiState.Loading + runCatching { + val response = apiService.getGoodsList( + canteenId = canteenId, + goodsName = goodsName, + pageNo = pageNo, + pageSize = pageSize + ) + if (response.success) { + _getGoodsListUiState.value = UiState.Success(response) + } else { + _getGoodsListUiState.value = UiState.Error(response.message ?: "请求失败") + } + }.onFailure { + _getGoodsListUiState.value = UiState.Error(it.message ?: "请求异常") + } + } + } + +} diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/RespData.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/RespData.kt new file mode 100644 index 0000000..d225825 --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/RespData.kt @@ -0,0 +1,8 @@ +package com.shuwei.intelligent.shelves.net + +data class RespData( + val success: Boolean = false, + val message: String? = null, + val code: Int = 0, + val result: T? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/UiState.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/UiState.kt new file mode 100644 index 0000000..eb2eac8 --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/UiState.kt @@ -0,0 +1,7 @@ +package com.shuwei.intelligent.shelves.net + +sealed class UiState { + object Loading : UiState() + data class Success(val data: RespData) : UiState() + data class Error(val msg: String) : UiState() +} \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/net/UrlConfig.kt b/app/src/main/java/com/shuwei/intelligent/shelves/net/UrlConfig.kt new file mode 100644 index 0000000..c6b27ec --- /dev/null +++ b/app/src/main/java/com/shuwei/intelligent/shelves/net/UrlConfig.kt @@ -0,0 +1,12 @@ +package com.shuwei.intelligent.shelves.net + +object UrlConfig { + + const val BASE_URL = "http://192.168.1.7:9002" + const val GET_ACCESS_TOKEN = "/restaurant/equipment/stEquipment/getEquipmentToken" + const val GET_SHELF_LIST = "/inventory/smartShelves/app/getShelvesListByDeviceId" + const val GET_GOODS_LIST = "/inventory/smartShelves/app/getGoodsPageList" + const val SAVE_SHELF_GOODS_LIST = "/inventory/smartShelves/app/saveShelvesGoodsList" + +} + diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt b/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt index 288345e..8d3cb9d 100644 --- a/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt +++ b/app/src/main/java/com/shuwei/intelligent/shelves/task/SyncTask.kt @@ -5,6 +5,9 @@ import android.util.Log import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.shuwei.intelligent.shelves.HomeActivity +import com.shuwei.intelligent.shelves.model.ShelfBody +import com.shuwei.intelligent.shelves.net.HttpManager +import com.shuwei.intelligent.shelves.net.apiService import com.shuwei.intelligent.shelves.utils.ext.toJsonString import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -34,6 +37,14 @@ class SyncTask(appContext: Context, workerParams: WorkerParameters) : withContext(Dispatchers.IO) { val list = HomeActivity.list Log.d(TAG, "performSync: list:${list.toJsonString()}") + val submitList = list.sortedBy { it.deviceNo } + val body = ShelfBody().also { + it.deviceId = "" + it.canteenId = "" + it.goodsList = submitList + } + val resp = apiService.saveShelfGoodsList(body) + Log.d(TAG, "performSync: resp:${resp.toJsonString()}") } } diff --git a/app/src/main/java/com/shuwei/intelligent/shelves/viewmodel/ShelfDataViewModel.kt b/app/src/main/java/com/shuwei/intelligent/shelves/viewmodel/ShelfDataViewModel.kt deleted file mode 100644 index 344d22a..0000000 --- a/app/src/main/java/com/shuwei/intelligent/shelves/viewmodel/ShelfDataViewModel.kt +++ /dev/null @@ -1,19 +0,0 @@ -//package com.shuwei.intelligent.shelves.viewmodel -// -//import androidx.lifecycle.LiveData -//import androidx.lifecycle.MutableLiveData -//import androidx.lifecycle.ViewModel -//import com.shuwei.intelligent.shelves.model.ShelfModel -// -//class ShelfDataViewModel : ViewModel() { -// -// private val _shelfItems = MutableLiveData>() -// val shelfItems: LiveData> = _shelfItems -// -// fun updateItems(newItems: MutableList) { -// _shelfItems.value = newItems -// } -// -// fun getCurrentItems(): MutableList = _shelfItems.value ?: mutableListOf() -// -//} \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_dialog_small.xml b/app/src/main/res/drawable/shape_dialog_small.xml new file mode 100644 index 0000000..cdc268a --- /dev/null +++ b/app/src/main/res/drawable/shape_dialog_small.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-sw360dp/dialog_loading.xml b/app/src/main/res/layout-sw360dp/dialog_loading.xml new file mode 100644 index 0000000..ff85957 --- /dev/null +++ b/app/src/main/res/layout-sw360dp/dialog_loading.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_base.xml b/app/src/main/res/layout-sw600dp/activity_base.xml similarity index 100% rename from app/src/main/res/layout/activity_base.xml rename to app/src/main/res/layout-sw600dp/activity_base.xml diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout-sw600dp/activity_home.xml similarity index 100% rename from app/src/main/res/layout/activity_home.xml rename to app/src/main/res/layout-sw600dp/activity_home.xml diff --git a/app/src/main/res/layout/activity_shelf.xml b/app/src/main/res/layout-sw600dp/activity_shelf.xml similarity index 100% rename from app/src/main/res/layout/activity_shelf.xml rename to app/src/main/res/layout-sw600dp/activity_shelf.xml diff --git a/app/src/main/res/layout/custom_toast.xml b/app/src/main/res/layout-sw600dp/custom_toast.xml similarity index 100% rename from app/src/main/res/layout/custom_toast.xml rename to app/src/main/res/layout-sw600dp/custom_toast.xml diff --git a/app/src/main/res/layout-sw600dp/dialog_loading.xml b/app/src/main/res/layout-sw600dp/dialog_loading.xml new file mode 100644 index 0000000..1aedfa7 --- /dev/null +++ b/app/src/main/res/layout-sw600dp/dialog_loading.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_search.xml b/app/src/main/res/layout-sw600dp/list_item_search.xml similarity index 97% rename from app/src/main/res/layout/list_item_search.xml rename to app/src/main/res/layout-sw600dp/list_item_search.xml index 8a1df3b..5c00083 100644 --- a/app/src/main/res/layout/list_item_search.xml +++ b/app/src/main/res/layout-sw600dp/list_item_search.xml @@ -34,6 +34,8 @@ android:insetTop="0dp" android:insetBottom="0dp" android:maxLines="1" + app:paddingStart="5dp" + app:paddingEnd="5dp" android:insetRight="0dp" android:insetLeft="0dp" android:paddingHorizontal="8dp" diff --git a/app/src/main/res/layout/list_item_shelf.xml b/app/src/main/res/layout-sw600dp/list_item_shelf.xml similarity index 100% rename from app/src/main/res/layout/list_item_shelf.xml rename to app/src/main/res/layout-sw600dp/list_item_shelf.xml diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index b9b3b57..dbbabfc 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -13,4 +13,8 @@ ?attr/colorPrimaryVariant + \ No newline at end of file diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml new file mode 100644 index 0000000..cb88015 --- /dev/null +++ b/app/src/main/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + 192.168.1.7 + +