Merge remote-tracking branch 'origin/feat/general-cart-and-payment' into ui-design
This commit is contained in:
commit
dd87f1ca6e
@ -10,7 +10,7 @@ plugins {
|
||||
// 避免不同尺寸機台間版本號產生衝突。
|
||||
// =========================================================================
|
||||
def verMinor = 1
|
||||
def verPatch = 93
|
||||
def verPatch = 96
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1130,7 +1130,12 @@ public class StarCloudAPI {
|
||||
Log.i(TAG, "persistCurrentSettings() - Saving to DB: machineID=" + MyApp.getInstance().getMachine().getMachineID()
|
||||
+ ", token=" + MyApp.getInstance().getMachine().getApiKey());
|
||||
SettingsDao settingsDao = new SettingsDao(handlerMain.getContext());
|
||||
settingsDao.deleteAll();
|
||||
// 只刪除本方法接下來要重寫的這 4 個設定 key,避免 deleteAll() 連坐刪掉廣告(VideoEoxPlayer)等其他持久資料。
|
||||
// 否則「遠端更新設定→重啟」會因廣告列被清空且啟動不會主動抓 B005,導致廣告消失。
|
||||
settingsDao.deleteWhere(MyApp.getInstance().getMachine().getClass().getSimpleName());
|
||||
settingsDao.deleteWhere(MyApp.getInstance().getEsunpay().getClass().getSimpleName());
|
||||
settingsDao.deleteWhere(MyApp.getInstance().getGreenInvoice().getClass().getSimpleName());
|
||||
settingsDao.deleteWhere(MyApp.getInstance().getGreenpaySetting().getClass().getSimpleName());
|
||||
|
||||
settingsDao.insertOne(new SettingStructure(MyApp.getInstance().getMachine().getClass().getSimpleName(),
|
||||
new String[] {
|
||||
|
||||
@ -47,6 +47,14 @@ public class TransactionFinalizeBuilder {
|
||||
/** 累積的出貨結果清單 */
|
||||
private final List<TransactionFinalizePayload.DispenseRecord> dispenseRecords = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 商品明細快照。在「buyList 仍完整」時擷取(例如進入出貨流程當下);
|
||||
* 之後 build() 會優先採用此快照,不再即時讀 live buyList。
|
||||
* 用以修正掃碼支付(玉山)等較慢流程:結案前 buyList 可能被取消/倒數路徑清空,
|
||||
* 導致 order.items 變成空陣列(出現「無商品紀錄」),但出貨其實成功。
|
||||
*/
|
||||
private List<TransactionFinalizePayload.ItemRecord> itemsSnapshot = null;
|
||||
|
||||
private String codeId = "0";
|
||||
|
||||
/** 交易生命週期狀態(pending/completed/failed/abandoned);預設 completed 維持成功路徑原行為。 */
|
||||
@ -151,6 +159,42 @@ public class TransactionFinalizeBuilder {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 擷取目前 buyList 的商品明細快照。
|
||||
* 應在「buyList 仍完整」時呼叫(例如 DispatchDialog 進入出貨流程當下);
|
||||
* 之後 {@link #build()} 會優先採用此快照,不再即時讀 live buyList,
|
||||
* 避免結案前 buyList 被取消/倒數等其他執行緒清空,導致 order.items 變成空陣列。
|
||||
* buyList 為空時不覆寫既有快照(避免把有效快照洗成空)。
|
||||
*/
|
||||
public void captureItems() {
|
||||
List<BuyStructure> buyList = MyApp.getInstance().getBuyList();
|
||||
if (buyList == null || buyList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.itemsSnapshot = buildItemRecords(buyList);
|
||||
Log.i(TAG, "captureItems: snapshot " + this.itemsSnapshot.size()
|
||||
+ " item(s), flow_id=" + flowId);
|
||||
}
|
||||
|
||||
/** 由 buyList 組出 items 明細(captureItems 與 build() fallback 共用)。 */
|
||||
private List<TransactionFinalizePayload.ItemRecord> buildItemRecords(List<BuyStructure> buyList) {
|
||||
List<TransactionFinalizePayload.ItemRecord> items = new ArrayList<>();
|
||||
if (buyList != null) {
|
||||
for (BuyStructure buy : buyList) {
|
||||
int productId = 0;
|
||||
try {
|
||||
productId = Integer.parseInt(buy.getProduct().getProductID());
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Cannot parse productID to int: " + buy.getProduct().getProductID());
|
||||
}
|
||||
int price = buy.getProduct().getRealPrice();
|
||||
int quantity = buy.getCount() > 0 ? buy.getCount() : 1;
|
||||
items.add(new TransactionFinalizePayload.ItemRecord(productId, price, quantity));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入一筆出貨結果記錄(每個貨道出貨後呼叫一次)。
|
||||
*
|
||||
@ -309,20 +353,13 @@ public class TransactionFinalizeBuilder {
|
||||
order.setMachine_time(orderMachineTime);
|
||||
|
||||
// --- 組裝購買商品清單 (items) ---
|
||||
List<TransactionFinalizePayload.ItemRecord> items = new ArrayList<>();
|
||||
List<BuyStructure> buyList = MyApp.getInstance().getBuyList();
|
||||
if (buyList != null) {
|
||||
for (BuyStructure buy : buyList) {
|
||||
int productId = 0;
|
||||
try {
|
||||
productId = Integer.parseInt(buy.getProduct().getProductID());
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Cannot parse productID to int: " + buy.getProduct().getProductID());
|
||||
}
|
||||
int price = buy.getProduct().getRealPrice();
|
||||
int quantity = buy.getCount() > 0 ? buy.getCount() : 1;
|
||||
items.add(new TransactionFinalizePayload.ItemRecord(productId, price, quantity));
|
||||
}
|
||||
// 優先採用 captureItems() 在出貨流程開始時擷取的快照;無快照時才即時讀 live buyList。
|
||||
// 快照可避免結案前 buyList 被其他執行緒清空(掃碼支付等慢流程的競態),造成「無商品紀錄」。
|
||||
List<TransactionFinalizePayload.ItemRecord> items;
|
||||
if (itemsSnapshot != null && !itemsSnapshot.isEmpty()) {
|
||||
items = new ArrayList<>(itemsSnapshot);
|
||||
} else {
|
||||
items = buildItemRecords(MyApp.getInstance().getBuyList());
|
||||
}
|
||||
order.setItems(items);
|
||||
|
||||
|
||||
@ -335,8 +335,8 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
getLogs().update("Temperature", String.valueOf(DevXinYuanController.getTemperature()), "℃");
|
||||
|
||||
// 同步更新機台資訊列
|
||||
binding.textMachineInfoName.setText(MyApp.getInstance().getMachine().getMachineID());
|
||||
// 待日後動態更改:binding.textMachineInfoNetwork.setText(getString(R.string.network) + ":" + networkDevice);
|
||||
updateMachineInfoName();
|
||||
updateMachineInfoNetwork();
|
||||
binding.textMachineInfoTemperature.setText(getString(R.string.temp) + ":" + tempStr);
|
||||
|
||||
try {
|
||||
@ -392,7 +392,7 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
case SET_NETWORK:
|
||||
getLogs().info("網路:" + message);
|
||||
binding.textNetwork.setText(message);
|
||||
// 待日後動態更改:binding.textMachineInfoNetwork.setText(message);
|
||||
updateMachineInfoNetwork();
|
||||
break;
|
||||
case RESET_SLOTNO:
|
||||
new ResetSlotNo(this).start();
|
||||
@ -642,6 +642,80 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
return -1; // 無法獲取訊號強度
|
||||
}
|
||||
|
||||
/** 取得 App 版本名稱(versionName),取不到時回 "0"。 */
|
||||
private String getAppVersionName() {
|
||||
try {
|
||||
return getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
||||
/** 機台資訊列左側:顯示「序號 + 版本號」。 */
|
||||
private void updateMachineInfoName() {
|
||||
if (binding == null) {
|
||||
return;
|
||||
}
|
||||
binding.textMachineInfoName.setText(
|
||||
MyApp.getInstance().getMachine().getMachineID() + " Ver " + getAppVersionName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 依系統/下位機回報的網路狀態,動態更新機台資訊列的網路訊號 icon 與文字。
|
||||
* WiFi 依 RSSI(dBm) 分 1~3 格與滿格;行動網路(SIM) 依 dBm 分 0~4 格;無網路顯示 0 格。
|
||||
*/
|
||||
private void updateMachineInfoNetwork() {
|
||||
if (binding == null) {
|
||||
return;
|
||||
}
|
||||
int iconRes = R.drawable.signal_cellular_0_bar_24; // 預設:無網路
|
||||
String label = getString(R.string.no_internet);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Network network = connectivityManager.getActiveNetwork();
|
||||
NetworkCapabilities capabilities = (network != null)
|
||||
? connectivityManager.getNetworkCapabilities(network) : null;
|
||||
if (capabilities != null
|
||||
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
&& capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
|
||||
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
|
||||
int rssi = 0; // 0 代表系統未提供強度
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
rssi = capabilities.getSignalStrength();
|
||||
}
|
||||
iconRes = wifiIconByRssi(rssi);
|
||||
label = getString(R.string.wireless_internet);
|
||||
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
|
||||
iconRes = cellularIconByDbm(getMobileSignalStrength());
|
||||
label = getString(R.string.mobile_network);
|
||||
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
|
||||
iconRes = R.drawable.network_wifi_24; // 有線:以滿格示意連線正常
|
||||
label = getString(R.string.wired_internet);
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.textMachineInfoNetwork.setText(label);
|
||||
binding.textMachineInfoNetwork.setCompoundDrawablesRelativeWithIntrinsicBounds(iconRes, 0, 0, 0);
|
||||
}
|
||||
|
||||
/** WiFi RSSI(dBm) → icon;數字越接近 0 越強,rssi==0 視為未提供強度回滿格。 */
|
||||
private int wifiIconByRssi(int rssi) {
|
||||
if (rssi == 0 || rssi >= -55) return R.drawable.network_wifi_24; // 滿格
|
||||
if (rssi >= -66) return R.drawable.network_wifi_3_bar_24; // 等級3
|
||||
if (rssi >= -77) return R.drawable.network_wifi_2_bar_24; // 等級2
|
||||
return R.drawable.network_wifi_1_bar_24; // 等級1
|
||||
}
|
||||
|
||||
/** 行動網路 dBm → icon;數字越接近 0 越強,-1 代表取不到訊號。 */
|
||||
private int cellularIconByDbm(int dbm) {
|
||||
if (dbm == -1) return R.drawable.signal_cellular_0_bar_24; // 無網路
|
||||
if (dbm >= -85) return R.drawable.signal_cellular_4_bar_24; // 滿格
|
||||
if (dbm >= -95) return R.drawable.signal_cellular_3_bar_24; // 等級3
|
||||
if (dbm >= -105) return R.drawable.signal_cellular_2_bar_24; // 等級2
|
||||
if (dbm >= -115) return R.drawable.signal_cellular_1_bar_24; // 等級1
|
||||
return R.drawable.signal_cellular_0_bar_24; // 無網路
|
||||
}
|
||||
|
||||
private void setBottomNavigation() {
|
||||
vmcFragment = new VmcFragment(getHandlerMain());
|
||||
activeFragment = vmcFragment;
|
||||
@ -772,8 +846,9 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
binding.btnswitchlanTW.setOnClickListener(v -> showLanguagePicker());
|
||||
// 新增:機台資訊列的語言按鈕
|
||||
binding.textMachineInfoLang.setOnClickListener(v -> showLanguagePicker());
|
||||
// 機台資訊列一動就顯示機台 ID
|
||||
binding.textMachineInfoName.setText(MyApp.getInstance().getMachine().getMachineID());
|
||||
// 機台資訊列:顯示序號 + 版本號
|
||||
updateMachineInfoName();
|
||||
updateMachineInfoNetwork();
|
||||
String currentLang = LanguageHelper.getSavedLanguage(this);
|
||||
binding.textMachineInfoLangText.setText(LanguageHelper.getDisplayName(currentLang));
|
||||
|
||||
@ -785,7 +860,8 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
finish();
|
||||
};
|
||||
|
||||
binding.textNetwork.setOnTouchListener((v, event) -> {
|
||||
// 後門已遷至機台資訊列的「序號 + 版本號」元素(舊的 textNetwork 整條系統列已隱藏,不再接收觸控)
|
||||
binding.textMachineInfoName.setOnTouchListener((v, event) -> {
|
||||
switch (event.getAction()) {
|
||||
case android.view.MotionEvent.ACTION_DOWN:
|
||||
networkHandler.postDelayed(networkRunnable, 2000); // 2秒
|
||||
@ -843,7 +919,8 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
binding.btnswitchlanJa.setVisibility(View.GONE);
|
||||
binding.btnswitchlanTW.setOnClickListener(v -> showLanguagePicker());
|
||||
binding.textMachineInfoLang.setOnClickListener(v -> showLanguagePicker());
|
||||
binding.textMachineInfoName.setText(MyApp.getInstance().getMachine().getMachineID());
|
||||
updateMachineInfoName();
|
||||
updateMachineInfoNetwork();
|
||||
String currentLang = LanguageHelper.getSavedLanguage(this);
|
||||
binding.textMachineInfoLangText.setText(LanguageHelper.getDisplayName(currentLang));
|
||||
}
|
||||
|
||||
@ -258,6 +258,10 @@ public class DispatchDialog extends DialogAbstract {
|
||||
httpAPI = new HttpAPI(getHandlerMain());
|
||||
// 初始化 Finalize Builder(在支付完成、進入出貨流程時建立)
|
||||
finalizeBuilder = new TransactionFinalizeBuilder();
|
||||
// 進入出貨流程當下 buyList 必為完整(下方即用它組 dispatchList),先擷取商品明細快照。
|
||||
// 之後結案 build() 會優先採用此快照,避免掃碼支付(玉山)等慢流程在結案前 buyList
|
||||
// 被取消/倒數路徑清空,導致 order.items 變空(無商品紀錄)但出貨其實成功。
|
||||
finalizeBuilder.captureItems();
|
||||
if (com.unibuy.smartdevice.AppEntry.isCmuh()) {
|
||||
MyApp.getInstance().getReportFlowInfoData().setFlowType(42);
|
||||
}
|
||||
|
||||
@ -111,9 +111,9 @@
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="--"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="27sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="14sp"
|
||||
android:alpha="0.7"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end" />
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user