feat: 出貨自救、登入gate、全站i18n補翻、硬幣修正、待機優化 (verPatch 40)
出貨/連線 - 出貨當下加連線閘門:送出貨指令前先確認下位機,失連則反覆自動重連 直到活著或逾時(ensureXinYuanConnectedForDispatch),再送指令 → 真正補出貨 - 保留 checkSlot 重試輪當第二道保險(出貨中途掉線) - 非現金付款進出貨前補送 inComeByIPC - PortProfile 重構:引入 DEFAULT_PROFILE 常數(通用預設 LEGACY) 後台登入 - 進 MainActivity(含長按序號後門)一律先跳登入視窗,帳密正確才進主控台, 取消則 finish() 返回前台 多國語(中/英/日) - 商品名改用 getLocalizedName:出貨中畫面、取貨確認清單、取貨碼確認清單 - 補翻取貨口提示(門未關/升降/狀態確認中/檢查中) - 補翻取貨碼頁(主提示/取消倒數/員工卡hint/驗證中/過效期/折扣類型) - 補翻出貨列狀態(已出貨數量/出貨中X件/All) - 發票方式頁「捐贈發票」→「捐贈發票/下一步」(新key,僅該卡片) 現金/硬幣 - 1元虛擬庫存封頂實體上限200(增量與載入均夾住) - 投幣測試面板解析 COIN_STOCK/NOTE_STOCK 十進位(修1元>255破版) 出貨完成 - 有待機機台出貨完成後留數秒取貨提示即跳待機(CMUH/北護無待機維持原流程) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
954d4a3716
commit
1d11367066
@ -10,7 +10,7 @@ plugins {
|
||||
// 避免不同尺寸機台間版本號產生衝突。
|
||||
// =========================================================================
|
||||
def verMinor = 2
|
||||
def verPatch = 37
|
||||
def verPatch = 40
|
||||
|
||||
|
||||
|
||||
|
||||
@ -302,6 +302,12 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
}
|
||||
});
|
||||
|
||||
// 進後台一律先登入:未登入時第一時間跳出登入視窗(不可取消),輸入正確帳密才能操作主控台;
|
||||
// 按「取消」則直接返回前台(finish)。涵蓋所有進入 MainActivity 的入口(含長按序號的隱藏後門)。
|
||||
if (MyApp.getInstance().getSuAccess().isEmpty()) {
|
||||
showLoginDialog(getCtx(), null, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ButtonQrCodeTestOnClick extends HandlerMainSchedulerOnClick {
|
||||
@ -522,10 +528,18 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
}
|
||||
|
||||
public void showLoginDialog(Context context) {
|
||||
showLoginDialog(context, null);
|
||||
showLoginDialog(context, null, false);
|
||||
}
|
||||
|
||||
public void showLoginDialog(Context context, Runnable onSuccess) {
|
||||
showLoginDialog(context, onSuccess, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mandatory true=進後台強制登入:對話框不可取消(返回鍵/點外部無效),按「取消」直接 finish 返回前台,
|
||||
* 未登入不得停留在主控台。false=一般用途(取消僅關閉視窗)。
|
||||
*/
|
||||
public void showLoginDialog(Context context, Runnable onSuccess, boolean mandatory) {
|
||||
// 使用 LayoutInflater 載入自訂佈局
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.dialog_admin_login, null);
|
||||
|
||||
@ -550,6 +564,7 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
// 建立對話框
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
.setView(view)
|
||||
.setCancelable(!mandatory) // 強制登入時不可用返回鍵/點外部關閉
|
||||
.create();
|
||||
activeLoginDialog = dialog;
|
||||
|
||||
@ -596,6 +611,10 @@ public class MainActivity extends AppCompatActivityAbstract {
|
||||
getTools().hideSystemBars((Activity) getCtx());
|
||||
dialog.dismiss();
|
||||
activeLoginDialog = null;
|
||||
if (mandatory) {
|
||||
// 強制登入下按取消 → 未登入不得進後台,直接返回前台
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
|
||||
@ -682,9 +682,15 @@ public class MyApp extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
/** 連送同步包兩次,任一次有回應即視為連線,降低偶發誤判(單次沒回不代表失連)。 */
|
||||
/**
|
||||
* 下位機是否在線。優先採信「近期任何 VMC 通訊」——下位機為輪詢式主從、持續在 POLL,
|
||||
* 只要近 4 秒收過任何 VMC 幀(POLL/ACK/廣播…)即代表在線,直接判定連線,
|
||||
* 避免脆弱的 300ms 主動 ping 在機台忙碌/送出佇列消化時收不到即時回應而誤判「尚未連線」。
|
||||
* 近期完全沒通訊時,才主動 ping 兩次(各 500ms)確認(降低偶發誤判,單次沒回不代表失連)。
|
||||
*/
|
||||
public static boolean isXinYuanAlive() {
|
||||
return pingXinYuanOnce(300) || pingXinYuanOnce(300);
|
||||
if (com.unibuy.smartdevice.controller.DevXinYuanController.isRecentlyAlive(4000)) return true;
|
||||
return pingXinYuanOnce(500) || pingXinYuanOnce(500);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -698,6 +704,33 @@ public class MyApp extends Application {
|
||||
return isXinYuanAlive(); // 重連後再確認
|
||||
}
|
||||
|
||||
/**
|
||||
* 出貨當下用:出貨前最後一道保險,確認主櫃(XinYuan)下位機連線;
|
||||
* 失連就「反覆重連並等到活著」直到成功或逾時 maxWaitMs。
|
||||
* 與進支付前的 ensureXinYuanConnected 不同:這裡會多輪重連(每輪等重開串口/重啟讀取迴圈),
|
||||
* 因為下位機常在重啟後短暫失聯,單輪重連可能還沒起來,需持續重試到真的活著才送出貨指令。
|
||||
* 回傳最終是否連線成功。注意:含 Thread.sleep,請在背景執行緒呼叫。
|
||||
*/
|
||||
public static boolean ensureXinYuanConnectedForDispatch(long maxWaitMs) {
|
||||
Logs staticLogs = new Logs(MyApp.class);
|
||||
if (isXinYuanAlive()) return true;
|
||||
long deadline = System.currentTimeMillis() + maxWaitMs;
|
||||
int round = 0;
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
round++;
|
||||
staticLogs.info("出貨前下位機失連,第 " + round + " 次自動重連...");
|
||||
checkAndReconnectDev(); // 重建 controller、重開串口、重啟讀取迴圈
|
||||
try { Thread.sleep(800); } catch (InterruptedException ignore) {}
|
||||
if (isXinYuanAlive()) {
|
||||
staticLogs.info("出貨前重連成功(第 " + round + " 輪),下位機已連線");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
boolean alive = isXinYuanAlive();
|
||||
staticLogs.info("出貨前重連結束,逾時=" + maxWaitMs + "ms,最終連線=" + alive);
|
||||
return alive;
|
||||
}
|
||||
|
||||
public void initMqtt() {
|
||||
String machineId = MyApp.getInstance().getMachine().getMachineID();
|
||||
String apiKey = MyApp.getInstance().getMachine().getApiKey();
|
||||
|
||||
@ -24,23 +24,27 @@ public final class PortProfile {
|
||||
public static final String LEGACY = "legacy"; // 舊版本 :ttyS1 / ttyS2
|
||||
public static final String STARTECH = "startech"; // 星科技版本:ttyS7 / ttyS6
|
||||
|
||||
// 未設定時的預設方案。通用版本為 LEGACY(ttyS1/ttyS2)。
|
||||
// ⚠️代樂美等星科技主板專用建置需改為 STARTECH(ttyS7/ttyS6,裝上即用免手動切),該改動勿進通用主線。
|
||||
public static final String DEFAULT_PROFILE = LEGACY;
|
||||
|
||||
private PortProfile() {}
|
||||
|
||||
private static SharedPreferences sp(Context ctx) {
|
||||
return ctx.getApplicationContext().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
/** 目前串口方案;預設 LEGACY。無 Context 版供 enum/背景使用。 */
|
||||
/** 目前串口方案;未設定時採 DEFAULT_PROFILE。無 Context 版供 enum/背景使用。 */
|
||||
public static String getProfile() {
|
||||
try {
|
||||
return sp(MyApp.getInstance()).getString(KEY_PROFILE, LEGACY);
|
||||
return sp(MyApp.getInstance()).getString(KEY_PROFILE, DEFAULT_PROFILE);
|
||||
} catch (Exception e) {
|
||||
return LEGACY;
|
||||
return DEFAULT_PROFILE;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getProfile(Context ctx) {
|
||||
return sp(ctx).getString(KEY_PROFILE, LEGACY);
|
||||
return sp(ctx).getString(KEY_PROFILE, DEFAULT_PROFILE);
|
||||
}
|
||||
|
||||
/** 是否為星科技方案(ttyS7/ttyS6)。 */
|
||||
|
||||
@ -36,6 +36,9 @@ public class SerialCashAcceptorHandler implements ICashAcceptorHandler {
|
||||
private int lastCoinReg0Val = 0;
|
||||
private int lastEscrowRegVal = 0;
|
||||
public static int virtualCoin1Count = 30;
|
||||
// 1 元料斗實體上限:1 元硬幣機構為軟體虛擬計數(硬體不回報),只增不減易飄成不合理值(曾達 362)。
|
||||
// 封頂在實體上限,投幣累加不超過此數(溢出的當作進現金箱不計),避免顯示/找零依據出現不可能的數量。
|
||||
public static final int MAX_VIRTUAL_COIN1 = 200;
|
||||
|
||||
// 庫存快取變數,避免頻繁發送真實串口指令造成 synchronized 卡頓
|
||||
private int cacheCoin1 = 30;
|
||||
@ -972,6 +975,11 @@ public class SerialCashAcceptorHandler implements ICashAcceptorHandler {
|
||||
try {
|
||||
android.content.SharedPreferences sp = context.getSharedPreferences("MDB_PREFS", Context.MODE_PRIVATE);
|
||||
virtualCoin1Count = sp.getInt("virtualCoin1Count", 30);
|
||||
// 舊資料可能已飄超過實體上限(如 362),載入時一併夾回上限,並回存修正值
|
||||
if (virtualCoin1Count > MAX_VIRTUAL_COIN1) {
|
||||
virtualCoin1Count = MAX_VIRTUAL_COIN1;
|
||||
sp.edit().putInt("virtualCoin1Count", virtualCoin1Count).apply();
|
||||
}
|
||||
cacheCoin1 = virtualCoin1Count; // 同步初始化快取
|
||||
logs.info("[庫存] 初始化1元虛擬庫存自 SharedPreferences: " + virtualCoin1Count);
|
||||
} catch (Exception e) {
|
||||
@ -1031,6 +1039,7 @@ public class SerialCashAcceptorHandler implements ICashAcceptorHandler {
|
||||
|
||||
if (count1 > 0) {
|
||||
virtualCoin1Count += count1;
|
||||
if (virtualCoin1Count > MAX_VIRTUAL_COIN1) virtualCoin1Count = MAX_VIRTUAL_COIN1; // 封頂在實體上限
|
||||
cacheCoin1 = virtualCoin1Count;
|
||||
saveVirtualCoin1Count();
|
||||
for (int i = 0; i < count1; i++) triggerCoinEvent(1);
|
||||
|
||||
@ -65,36 +65,10 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
|
||||
@Override
|
||||
public void onBuyRequested() {
|
||||
// 進支付前先確認主櫃下位機(XinYuan)連線:
|
||||
// 僅當購物清單含主櫃(VMC)商品才檢查;失連→主動重連→仍連不上則擋住不進支付。
|
||||
if (!buyListHasMainCabinetItem()) {
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
return;
|
||||
}
|
||||
// 直購路徑:若剛在「點選商品」時取貨口預檢成功(有聽到機台正常回報=下位機已在線),就跳過這裡
|
||||
// 重複的連線判斷。原因:預檢會佔用 XinYuan 串口約 9 秒,緊接著 ensureXinYuanConnected 的
|
||||
// 「清緩衝→送同步包→等 300ms」探詢窗,常因送出佇列尚在消化(sendBuffers 塞車)而收不到即時回應,
|
||||
// 誤判「未連線」並觸發不必要的 shutdown 重連(機台其實一直在回 ACK)。預檢已證明在線,直接進付款;
|
||||
// BuyDialog 內也會依同一旗標略過取貨口重驗。真正無回應(PICKUP_NO_RESPONSE 未記旗標)才走下方連線判斷。
|
||||
if (isFreshPickupPreCheck()) {
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
return;
|
||||
}
|
||||
// 顯示「連線判斷中」轉圈提示,避免客戶以為當機。
|
||||
final android.app.AlertDialog progress = buildConnectingDialog();
|
||||
try { progress.show(); } catch (Exception ignore) {}
|
||||
// ensureXinYuanConnected 內含 Thread.sleep,必須在背景執行緒跑。
|
||||
new Thread(() -> {
|
||||
boolean connected = MyApp.ensureXinYuanConnected();
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
try { if (progress.isShowing()) progress.dismiss(); } catch (Exception ignore) {}
|
||||
if (!connected) {
|
||||
showNotConnectedDialog();
|
||||
return;
|
||||
}
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
});
|
||||
}).start();
|
||||
// 下位機「連線判斷」先移除(不穩定、常誤報「未連線」):一律直接進付款,連線問題交由出貨階段處理。
|
||||
// 取貨口偵測仍保留——直購已在「點選商品」當下檢查(checkPickupOnly);其他入口(購物車/發票重開等)
|
||||
// 由 BuyDialog.checkPickupPortBeforePay 檢查取貨口(有東西/門才擋,無回應則放行)。
|
||||
new BuyDialog(context, handlerMain).show();
|
||||
}
|
||||
|
||||
/** 購物清單是否含主櫃(VMC)商品;非主櫃商品不需檢查主櫃下位機連線。 */
|
||||
@ -189,19 +163,13 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
// 單飛:已有一個檢查在進行(轉圈提示中)就忽略這次點擊,避免疊加查詢把送出佇列塞爆導致失連。
|
||||
if (pickupCheckRunning) return;
|
||||
pickupCheckRunning = true;
|
||||
final android.app.AlertDialog progress = buildProgressDialog("下位機連線檢查中......");
|
||||
final android.app.AlertDialog progress = buildProgressDialog(context.getString(R.string.pickup_checking));
|
||||
try { progress.show(); } catch (Exception ignore) {}
|
||||
new Thread(() -> {
|
||||
com.unibuy.smartdevice.exception.Logs logs = new com.unibuy.smartdevice.exception.Logs(BasicSaleFlow.class);
|
||||
int result = probePickupHasThing(slotnum);
|
||||
// 真正無回應(連近 7 秒廣播都沒有=下位機確實沒在回)才自動重連下位機後再判斷,最多 3 次。
|
||||
for (int attempt = 1; result == PICKUP_NO_RESPONSE && attempt <= 3; attempt++) {
|
||||
logs.info("點選商品-下位機無回應,自動重連並重試 (" + attempt + "/3)");
|
||||
try { MyApp.checkAndReconnectDev(); } catch (Exception ignore) {}
|
||||
result = probePickupHasThing(slotnum);
|
||||
}
|
||||
final int pickup = result;
|
||||
logs.info("點選商品-連線/取貨口檢查 pickup=" + pickup
|
||||
// 下位機連線判斷已移除:不再自動重連重試。只做一次取貨口偵測。
|
||||
final int pickup = probePickupHasThing(slotnum);
|
||||
logs.info("點選商品-取貨口檢查 pickup=" + pickup
|
||||
+ " (0=OK,1=有東西,2=門,3=升降梯,4=無通訊,5=在線但狀態未知)");
|
||||
postMain(() -> {
|
||||
pickupCheckRunning = false; // 檢查結束復位,允許下一次點擊
|
||||
@ -211,10 +179,10 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
showPickupBlockedDialog(context.getString(R.string.there_is_something_at_the_pickup_port));
|
||||
return;
|
||||
case PICKUP_DOOR:
|
||||
showPickupBlockedDialog("取貨口門未正常關閉,請先確認門已關好。");
|
||||
showPickupBlockedDialog(context.getString(R.string.pickup_door_not_closed));
|
||||
return;
|
||||
case PICKUP_ELEVATOR:
|
||||
showPickupBlockedDialog("升降梯未回到原點,請洽服務人員處理。");
|
||||
showPickupBlockedDialog(context.getString(R.string.pickup_elevator_not_home));
|
||||
return;
|
||||
case PICKUP_OK:
|
||||
// 收到「正常(01)」= 下位機在線且取貨口空 → 記旗標;
|
||||
@ -226,12 +194,12 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
// 下位機在線但此刻沒回報取貨口狀態(忙其他協定,3.5 秒內沒等到 VMC_02)。
|
||||
// 選擇「保守擋住」而非放行:寧可多擋也不漏放「取貨口有東西」。請客人稍候再點一次,
|
||||
// 屆時多半已收到取貨口狀態廣播即可正常判定。(非未連線,故不走重連提示)
|
||||
showPickupBlockedDialog("正在確認取貨口狀態,請稍候 1~2 秒再點選一次。");
|
||||
showPickupBlockedDialog(context.getString(R.string.pickup_status_confirming));
|
||||
break;
|
||||
default:
|
||||
// PICKUP_NO_RESPONSE:機台連任何 VMC 通訊都沒有+2 次重連重試仍無回應 → 判定真的斷線,
|
||||
// 擋住不開詳情頁。連線恢復後客戶重點商品即可。
|
||||
showNotConnectedDialog();
|
||||
// PICKUP_NO_RESPONSE:機台完全無 VMC 通訊。連線判斷已移除 → 不再擋「未連線」,
|
||||
// 直接放行開詳情頁;連線問題交由出貨階段處理(BuyDialog 取貨口無回應也放行)。
|
||||
onPass.run();
|
||||
}
|
||||
});
|
||||
}).start();
|
||||
@ -352,6 +320,24 @@ public class BasicSaleFlow extends SaleFlowHandler {
|
||||
return com.unibuy.smartdevice.ui.dialog.CashPayDialogGeneral.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* 語言切換時:清掉快取的購物車 fragment 並從 FragmentManager 移除舊的(它已掛在被取代的舊容器上)。
|
||||
* 否則購買後再開購物車會拿到孤兒 fragment(openFragment 因 isAdded()==true 跳過重加)→ 畫面空白。
|
||||
* 下次 onShoppingCartRequested 會建立新的並掛到新容器。
|
||||
*/
|
||||
@Override
|
||||
public void onLocaleSwitched() {
|
||||
if (cartFragment != null) {
|
||||
try {
|
||||
if (context instanceof androidx.fragment.app.FragmentActivity && cartFragment.isAdded()) {
|
||||
((androidx.fragment.app.FragmentActivity) context).getSupportFragmentManager()
|
||||
.beginTransaction().remove(cartFragment).commitNowAllowingStateLoss();
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
cartFragment = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** 購物車浮鈕:開啟多品項購物車 Fragment。 */
|
||||
@Override
|
||||
public void onShoppingCartRequested() {
|
||||
|
||||
@ -944,6 +944,10 @@ public class FontendActivity extends AppCompatActivityAbstract implements SaleFl
|
||||
|
||||
setBottomNavigation();
|
||||
startOnSwitchFragment();
|
||||
// 版面/容器已重建:清掉 saleFlowHandler 內快取的購物車 fragment(否則購買後再開會空白)
|
||||
if (saleFlowHandler != null) {
|
||||
saleFlowHandler.onLocaleSwitched();
|
||||
}
|
||||
// 重新綁定語言選單入口(重繪後 binding 已換新)
|
||||
binding.btnswitchlanEn.setVisibility(View.GONE);
|
||||
binding.btnswitchlanJa.setVisibility(View.GONE);
|
||||
|
||||
@ -79,6 +79,14 @@ public abstract class SaleFlowHandler {
|
||||
// 預設無動作
|
||||
}
|
||||
|
||||
/**
|
||||
* 語言切換時呼叫:FontendActivity 會重新 inflate 版面/容器,saleFlowHandler 內快取的 fragment
|
||||
* (如購物車)會變成掛在舊容器的孤兒 → 購買後再開會空白。子類在此清掉快取並移除舊 fragment。
|
||||
*/
|
||||
public void onLocaleSwitched() {
|
||||
// 預設無動作
|
||||
}
|
||||
|
||||
public void onPickupRequested() {
|
||||
// 預設無動作
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
} catch (LogsEmptyException e) {
|
||||
this.logs.warning(e);
|
||||
}
|
||||
holder.binding.textSlot.setText("貨道" + slot.getSlot());
|
||||
holder.binding.textSlot.setText(context.getString(R.string.slot_label) + slot.getSlot());
|
||||
// 多國語的判斷(統一由 ProductStructure 處理,英/日未翻譯自動 fallback 中文)
|
||||
holder.binding.textProductName.setText(slot.getProduct().getLocalizedName(context));
|
||||
|
||||
@ -96,14 +96,14 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
holder.binding.textPrice.setText("NT$ " + price);
|
||||
|
||||
// 綁定庫存數量顯示
|
||||
holder.binding.textStock.setText("庫存" + count);
|
||||
holder.binding.textStock.setText(context.getString(R.string.stock_label) + count);
|
||||
|
||||
holder.binding.mask.setVisibility(View.GONE);
|
||||
holder.binding.textMask.setText("");
|
||||
|
||||
if (count <= 0) {
|
||||
holder.binding.mask.setVisibility(View.VISIBLE);
|
||||
holder.binding.textMask.setText("售完");
|
||||
holder.binding.textMask.setText(context.getString(R.string.sold_out));
|
||||
}
|
||||
|
||||
// 效期過期:顯示「暫不販售」遮罩,並一律禁止購買(蓋過售完顯示,主要情境是有貨但過效期)
|
||||
@ -114,7 +114,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
|
||||
if (isLock) {
|
||||
holder.binding.mask.setVisibility(View.VISIBLE);
|
||||
holder.binding.textMask.setText("暫停販售");
|
||||
holder.binding.textMask.setText(context.getString(R.string.suspended_sales));
|
||||
}
|
||||
|
||||
if (count > 0 && !isLock && !isExpired) {
|
||||
|
||||
@ -338,7 +338,7 @@ public class BuyDialog extends DialogAbstract {
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
|
||||
final String message = doorError
|
||||
? "取貨口門未正常關閉,請先確認門已關好。"
|
||||
? BuyDialog.this.getContext().getString(R.string.pickup_door_not_closed)
|
||||
: BuyDialog.this.getContext().getString(R.string.there_is_something_at_the_pickup_port);
|
||||
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
@ -459,6 +459,17 @@ public class BuyDialog extends DialogAbstract {
|
||||
closeDialogCountdown.shutdown();
|
||||
int flowType = MyApp.getInstance().getReportFlowInfoData().getFlowType();
|
||||
getLogs().debug("buy flowType:" + flowType);
|
||||
// 非現金付款(flowType != 9):此刻機台剛進收款模式、還在 POLL,立即送 inComeByIPC 給足額 credit
|
||||
// (沿用開機已驗證的 0x08/9999),讓「收款式」下位機結束收款、後續正常出貨;
|
||||
// 否則機台會卡在等錢(狂送 VMC_29 金錢開關)、不送 POLL → checkSlot 送不出去 → 出貨失敗。
|
||||
// 現金(9)不送:由現金流程依實收金額自行送 inComeByIPC,避免預付 credit 造成免費出貨。
|
||||
if (flowType != 9) {
|
||||
try {
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().inComeByIPC((byte) 0x08, 9999));
|
||||
getLogs().info("非現金付款(flowType=" + flowType + ") → 送 inComeByIPC 給下位機收款 credit");
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
// if (flowType == 5 || flowType == 7 || flowType == 30) {
|
||||
if (flowType == 5 || flowType == 7) {
|
||||
changeCheckout();
|
||||
|
||||
@ -352,7 +352,7 @@ public class CheckoutAccessCodeDialog extends DialogAbstract {
|
||||
String number = binding.editTextNumber.getText().toString().trim();
|
||||
// 長度檢查
|
||||
if (number.isEmpty() || number.length() < 8) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), "通行碼長度不能少於 8 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), getCtx().getString(R.string.passcode_min_8));
|
||||
return;
|
||||
}
|
||||
submitPassCode(number);
|
||||
@ -369,11 +369,11 @@ public class CheckoutAccessCodeDialog extends DialogAbstract {
|
||||
// 防護:通行碼從屬「取貨模組」,任一關閉即不開放呼叫 B670(即使 UI 漏出入口也擋下)
|
||||
if (!(MyApp.getInstance().getDevSet().isPickupModule() && MyApp.getInstance().getDevSet().isPassCode())) {
|
||||
openBarcode = true;
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "通行碼功能未開放");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.passcode_not_enabled));
|
||||
return;
|
||||
}
|
||||
// 送出前顯示「驗證中…」,避免使用者以為沒反應
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "驗證中…");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.verifying));
|
||||
new com.unibuy.smartdevice.external.StarCloudAPI(getHandlerMain(), getHandlerMain())
|
||||
.verifyPassCode(code, new com.unibuy.smartdevice.external.StarCloudAPI.VerificationCallback() {
|
||||
@Override
|
||||
|
||||
@ -637,7 +637,7 @@ public class CheckoutCashDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消("+countdown+")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"("+countdown+")");
|
||||
}
|
||||
|
||||
public static class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -327,7 +327,7 @@ public class CheckoutFreeGiftCodeDialog extends DialogAbstract {
|
||||
public void changeOk() {
|
||||
String number = binding.editTextNumber.getText().toString().trim();
|
||||
if (number.isEmpty() || number.length() < 8) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "來店禮代碼需 8 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.gift_code_min_8));
|
||||
return;
|
||||
}
|
||||
submitWelcomeGift(number);
|
||||
@ -341,10 +341,10 @@ public class CheckoutFreeGiftCodeDialog extends DialogAbstract {
|
||||
// 防護:來店禮關閉即不開放呼叫 B690(即使 UI 漏出入口也擋下)
|
||||
if (!MyApp.getInstance().getDevSet().isWelcomeGift()) {
|
||||
openBarcode = true;
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "來店禮功能未開放");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.gift_not_enabled));
|
||||
return;
|
||||
}
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "驗證中…");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.verifying));
|
||||
new com.unibuy.smartdevice.external.StarCloudAPI(getHandlerMain(), getHandlerMain())
|
||||
.verifyWelcomeGift(code, new com.unibuy.smartdevice.external.StarCloudAPI.WelcomeGiftCallback() {
|
||||
@Override
|
||||
@ -364,7 +364,7 @@ public class CheckoutFreeGiftCodeDialog extends DialogAbstract {
|
||||
.setDiscountPercentage((100 - discountValue) / 100f);
|
||||
} else {
|
||||
openBarcode = true;
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "不支援的折扣類型");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getContext().getString(R.string.unsupported_discount_type));
|
||||
return;
|
||||
}
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.CHANGE_BUY.getOption(), "change buy");
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
package com.unibuy.smartdevice.ui.dialog;
|
||||
import com.unibuy.smartdevice.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
@ -209,7 +210,7 @@ public class CheckoutNfcCardDialog extends DialogAbstract {
|
||||
closeDialogCountdown.start(30);
|
||||
|
||||
binding.textPrice.setText(String.valueOf(getTotalPrice()));
|
||||
binding.textStatus.setText("交易讀取中,請將卡片/手機停留片刻,\n勿快速移動,系統完成後會自動返回。");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.reading_transaction));
|
||||
|
||||
ProductStructure buyProduct = MyApp.getInstance().getBuyList().get(0).getProduct();
|
||||
MyApp.getInstance().getReportFlowInfoData().setProductId(buyProduct.getProductID());
|
||||
@ -259,7 +260,7 @@ public class CheckoutNfcCardDialog extends DialogAbstract {
|
||||
nfcPayController.start(1, getTotalPrice());
|
||||
} catch (LogsIOException e) {
|
||||
getLogs().warning(e);
|
||||
binding.textStatus.setText("刷卡機無法開啟");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.card_reader_cannot_open));
|
||||
getHandlerMain().getHandler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -348,7 +349,7 @@ public class CheckoutNfcCardDialog extends DialogAbstract {
|
||||
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消("+countdown+")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"("+countdown+")");
|
||||
}
|
||||
|
||||
public class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
package com.unibuy.smartdevice.ui.dialog;
|
||||
import com.unibuy.smartdevice.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
@ -213,7 +214,7 @@ public class CheckoutNfcPhoneDialog extends DialogAbstract {
|
||||
|
||||
binding.textPrice.setText(String.valueOf(getTotalPrice()));
|
||||
|
||||
binding.textStatus.setText("交易讀取中,請將卡片/手機停留片刻,\n勿快速移動,系統完成後會自動返回。");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.reading_transaction));
|
||||
|
||||
ProductStructure buyProduct = MyApp.getInstance().getBuyList().get(0).getProduct();
|
||||
MyApp.getInstance().getReportFlowInfoData().setProductId(buyProduct.getProductID());
|
||||
@ -263,7 +264,7 @@ public class CheckoutNfcPhoneDialog extends DialogAbstract {
|
||||
nfcPayController.start(4, getTotalPrice());
|
||||
} catch (LogsIOException e) {
|
||||
getLogs().warning(e);
|
||||
binding.textStatus.setText("刷卡機無法開啟");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.card_reader_cannot_open));
|
||||
getHandlerMain().getHandler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -352,7 +353,7 @@ public class CheckoutNfcPhoneDialog extends DialogAbstract {
|
||||
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消("+countdown+")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"("+countdown+")");
|
||||
}
|
||||
|
||||
public class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
package com.unibuy.smartdevice.ui.dialog;
|
||||
import com.unibuy.smartdevice.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
@ -210,7 +211,7 @@ public class CheckoutNfcRechargeDialog extends DialogAbstract {
|
||||
|
||||
binding.textPrice.setText(String.valueOf(getTotalPrice()));
|
||||
|
||||
binding.textStatus.setText("交易讀取中,請將卡片/手機停留片刻,\n勿快速移動,系統完成後會自動返回。");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.reading_transaction));
|
||||
|
||||
ProductStructure buyProduct = MyApp.getInstance().getBuyList().get(0).getProduct();
|
||||
MyApp.getInstance().getReportFlowInfoData().setProductId(buyProduct.getProductID());
|
||||
@ -260,7 +261,7 @@ public class CheckoutNfcRechargeDialog extends DialogAbstract {
|
||||
nfcPayController.start(2, getTotalPrice());
|
||||
} catch (LogsIOException e) {
|
||||
getLogs().warning(e);
|
||||
binding.textStatus.setText("刷卡機無法開啟");
|
||||
binding.textStatus.setText(getCtx().getString(R.string.card_reader_cannot_open));
|
||||
getHandlerMain().getHandler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@ -349,7 +350,7 @@ public class CheckoutNfcRechargeDialog extends DialogAbstract {
|
||||
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消("+countdown+")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"("+countdown+")");
|
||||
}
|
||||
|
||||
public class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -594,7 +594,7 @@ public class CheckoutTapPayDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消("+countdown+")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"("+countdown+")");
|
||||
}
|
||||
|
||||
public class ReadBarCodeOnScheduler extends HandlerMainScheduler {
|
||||
|
||||
@ -99,8 +99,8 @@ public class DialogProductDetail extends DialogAbstract {
|
||||
|
||||
// 商品名稱(多語)、貨道、庫存
|
||||
binding.textProductName.setText(slot.getProduct().getLocalizedName(context));
|
||||
binding.slotNumber.setText("貨道" + slot.getSlot());
|
||||
binding.inventoryNumber.setText("庫存" + slot.getCount());
|
||||
binding.slotNumber.setText(context.getString(R.string.slot_label) + slot.getSlot());
|
||||
binding.inventoryNumber.setText(context.getString(R.string.stock_label) + slot.getCount());
|
||||
|
||||
// 商品規格/描述(多語,純文字含換行;後台空白則隱藏整塊)。
|
||||
// setText 原樣呈現換行與空格/縮排;版面已設 gravity=start,故縮排不會被置中打亂。
|
||||
|
||||
@ -465,8 +465,8 @@ public class DispatchDialog extends DialogAbstract {
|
||||
} catch (Exception e) {
|
||||
getLogs().warning(e);
|
||||
}
|
||||
// 找不到替換檔(或解碼失敗)→ 用內建預設圖(此版專給代樂美,預設為 qrcode_msg_dailemei)
|
||||
binding.imgDeliveryFailed.setImageResource(R.drawable.qrcode_msg_dailemei);
|
||||
// 找不到替換檔(或解碼失敗)→ 用內建預設圖
|
||||
binding.imgDeliveryFailed.setImageResource(R.drawable.qrcode_msg);
|
||||
}
|
||||
|
||||
/** 依螢幕尺寸做降採樣解碼,避免大圖 OOM。 */
|
||||
@ -490,11 +490,11 @@ public class DispatchDialog extends DialogAbstract {
|
||||
countDownTimer = new CountDownTimer(15_000, 1_000) { // 10 秒,每秒 tick 一次
|
||||
public void onTick(long millisUntilFinished) {
|
||||
int seconds = (int) (millisUntilFinished / 1000);
|
||||
tvCountdown.setText("(" + seconds + "s)後關閉");
|
||||
tvCountdown.setText(getCtx().getString(R.string.close_after_seconds, seconds));
|
||||
}
|
||||
|
||||
public void onFinish() {
|
||||
tvCountdown.setText("(0s)後關閉");
|
||||
tvCountdown.setText(getCtx().getString(R.string.close_after_seconds, 0));
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
@ -540,9 +540,35 @@ public class DispatchDialog extends DialogAbstract {
|
||||
cancel();
|
||||
}
|
||||
|
||||
// 有待機畫面機台:出貨完成後停留幾秒取貨提示再跳待機畫面(可調)。
|
||||
private static final int STANDBY_PICKUP_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* 出貨完成後跳「待機畫面」(僅有待機的機台,即 !AppEntry.isCmuh)。
|
||||
* 交易已於出貨成功處 publishFinalize 結案;此處收掉本對話框計時器並導向 AppEntry.initialActivity()
|
||||
* (有待機機台即 HomeActivity)。取貨門已開,跳待機不影響客人取貨,只是縮短等待感。
|
||||
*/
|
||||
private void goToStandby() {
|
||||
try { closeDialogCountdown.shutdown(); } catch (Exception ignore) {}
|
||||
try { if (countDownTimer != null) countDownTimer.cancel(); } catch (Exception ignore) {}
|
||||
MyApp.getInstance().getBuyList().clear();
|
||||
try {
|
||||
Intent intent = new Intent(getCtx(), com.unibuy.smartdevice.AppEntry.initialActivity());
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
getCtx().startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
getLogs().warning(e);
|
||||
}
|
||||
cancel(); // 關閉本對話框
|
||||
}
|
||||
|
||||
private boolean isDispatchingNext = false;
|
||||
private boolean isCheckSlotByVMC = false;
|
||||
private int checkSlotRunCount = 0;
|
||||
// 非 Cmuh 出貨遇「下位機未連線」時,做一輪「重連→重新出貨」的計數(限一輪,避免無限迴圈)。
|
||||
// 機台一旦有回應(isCMD)即歸零,讓後續若再度失聯能再救一輪。
|
||||
private int dispatchReconnectRound = 0;
|
||||
|
||||
public class DevCheckSlotByVMC extends DevController.ReadBufferOnScheduler {
|
||||
private int slot;
|
||||
@ -594,9 +620,10 @@ public class DispatchDialog extends DialogAbstract {
|
||||
getLogs().info("vmc isCMD:" + isCMD + " isStatus:" + isStatus);
|
||||
|
||||
if (isCMD) {
|
||||
dispatchReconnectRound = 0; // 機台有回應=已連線,重置重連輪數
|
||||
if (isStatus) {
|
||||
getLogs().info("-----------------商品出貨中-----------------");
|
||||
setTextViewCountdown("商品出貨中", 65);
|
||||
setTextViewCountdown(getCtx().getString(R.string.dispensing_product), 65);
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.getReadBufferByNow(new DevGetProductByVMC(handlerMain, slot), 5000);
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
@ -612,6 +639,7 @@ public class DispatchDialog extends DialogAbstract {
|
||||
}
|
||||
} else {
|
||||
boolean isCmuh = com.unibuy.smartdevice.AppEntry.isCmuh();
|
||||
// 非 Cmuh 重試 3 次仍無回應就進入下方「重連→重新出貨」那一輪(give-up 分支),早點救援較快。
|
||||
int maxRetries = isCmuh ? 10 : 3;
|
||||
if (checkSlotRunCount >= maxRetries) {
|
||||
buttonControlCountdown.shutdown();
|
||||
@ -623,12 +651,29 @@ public class DispatchDialog extends DialogAbstract {
|
||||
}
|
||||
getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(),
|
||||
"領藥有問題 請等3秒後再重掃");
|
||||
checkSlotRunCount = 0;
|
||||
} else if (dispatchReconnectRound < 1) {
|
||||
// 非 Cmuh:重試用盡仍「下位機未連線」→ 重連救活控制器後「重新出貨一輪」(限一輪,避免無限迴圈)。
|
||||
dispatchReconnectRound++;
|
||||
getLogs().info("下位機未連線 → 重連後重新出貨 (第 " + dispatchReconnectRound + " 輪)");
|
||||
try { MyApp.checkAndReconnectDev(); } catch (Exception ignore) {}
|
||||
checkSlotRunCount = 0;
|
||||
isCheckSlotByVMC = false;
|
||||
// 給重連後的控制器時間重開串口/重啟讀取迴圈,再重跑一次出貨
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (!isFinalizing) {
|
||||
try { currentlyProcessingGoods(); } catch (Exception e) { getLogs().warning(e); }
|
||||
}
|
||||
}, 2500);
|
||||
} else {
|
||||
// 已重連重試一輪仍未回應 → 真的失敗
|
||||
getLogs().info("重連後下位機仍未回應,出貨作業中止");
|
||||
getSrcHandlerMain().start(getClass().getSimpleName(), Option.ERROR_PROCESS_GOODS.getOption(),
|
||||
getCtx().getString(R.string.slave_computer_did_not_respond_wait_3_seconds_try_again));
|
||||
MyApp.getInstance().getDevXinYuanController().start();
|
||||
checkSlotRunCount = 0;
|
||||
dispatchReconnectRound = 0;
|
||||
}
|
||||
checkSlotRunCount = 0;
|
||||
} else {
|
||||
getLogs().info("機台未回應,第 " + (checkSlotRunCount + 1) + " 次重試 checkSlot..."
|
||||
+ (isCmuh ? " (溫和模式,不發送指令)" : ""));
|
||||
@ -814,7 +859,7 @@ public class DispatchDialog extends DialogAbstract {
|
||||
if (isShipped) { // 正在要出貨的話
|
||||
if (count < quantity) { // count 目前出了多少貨 Quantity 總貨物數量
|
||||
// 設定商品名稱和圖片
|
||||
binding.textProductName.setText(product.getProductName());
|
||||
binding.textProductName.setText(product.getLocalizedName(getContext()));
|
||||
|
||||
try {
|
||||
new ImageGlide(getContext()).fileload(product.getProductImg(), binding.imageProductPicture);
|
||||
@ -1033,7 +1078,7 @@ public class DispatchDialog extends DialogAbstract {
|
||||
if (com.unibuy.smartdevice.AppEntry.isCmuh()) {
|
||||
insertDrgnoToMemo();
|
||||
}
|
||||
publishFinalizeUnlessPassCode();
|
||||
publishFinalize();
|
||||
getSrcHandlerMain().send(getClass().getSimpleName(), FontendActivity.Option.RESET_DATA.getOption(),
|
||||
"update data");
|
||||
saveData();
|
||||
@ -1061,24 +1106,33 @@ public class DispatchDialog extends DialogAbstract {
|
||||
binding.buttonOk.setTextColor(Color.BLACK);
|
||||
setButtonOkText(0); // 顯示「取貨確認」不帶倒數
|
||||
|
||||
// 顯示取貨倒數 15 秒後自動關閉對話框
|
||||
// 顯示取貨倒數後自動結束:
|
||||
// - 有待機畫面的機台(!isCmuh):縮短取貨提示秒數(STANDBY_PICKUP_SECONDS)後「跳待機畫面」,
|
||||
// 減少客人等待感(取貨門已開,跳待機不影響取貨)。
|
||||
// - 無待機(中國醫/台大北護等 pickup_sheet=isCmuh):維持原本 15 秒→關閉回原流程。
|
||||
isChangeStatus = true;
|
||||
// 💡 統一都有括號,消除初始與倒數的格式不一致閃爍
|
||||
final boolean hasStandby = !com.unibuy.smartdevice.AppEntry.isCmuh();
|
||||
final int pickupSeconds = hasStandby ? STANDBY_PICKUP_SECONDS : 15;
|
||||
setTextViewCountdown(
|
||||
getCtx().getString(R.string.pickup_port_open) + "(15)"
|
||||
getCtx().getString(R.string.pickup_port_open) + "(" + pickupSeconds + ")"
|
||||
+ getCtx().getString(R.string.pick_up_within),
|
||||
65);
|
||||
countDownTimer = new CountDownTimer(15_000, 1_000) {
|
||||
countDownTimer = new CountDownTimer(pickupSeconds * 1000L, 1_000) {
|
||||
public void onTick(long millisUntilFinished) {
|
||||
int seconds = (int) (millisUntilFinished / 1000);
|
||||
setTextViewCountdown(seconds);
|
||||
}
|
||||
|
||||
public void onFinish() {
|
||||
dialogCancel();
|
||||
if (hasStandby) {
|
||||
goToStandby();
|
||||
} else {
|
||||
dialogCancel();
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
getLogs().info("📢 出貨完畢,取貨倒數 15 秒後關閉對話框");
|
||||
getLogs().info("📢 出貨完畢,取貨倒數 " + pickupSeconds + " 秒後"
|
||||
+ (hasStandby ? "跳待機畫面" : "關閉對話框"));
|
||||
|
||||
isDispatchingNext = false;
|
||||
isGetProductByVMC = false;
|
||||
@ -1149,21 +1203,20 @@ public class DispatchDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
getLogs().info("出貨失敗,發送 MQTT Finalize 結案訊息: " + message);
|
||||
publishFinalizeUnlessPassCode();
|
||||
publishFinalize();
|
||||
getSrcHandlerMain().send(getClass().getSimpleName(), FontendActivity.Option.RESET_DATA.getOption(),
|
||||
"update data");
|
||||
saveData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 發送 MQTT 交易結案;但 flowType 5(通行碼)為工程師/內部硬體測試,不上報交易
|
||||
* (B670 驗證已於後台記 log;避免污染銷售/營收,且不扣減雲端庫存)。
|
||||
* 發送 MQTT 交易結案。
|
||||
* 通行碼(flowType 5)現在也一併上報:依需求「完整交易進銷售紀錄」,與一般銷售相同處理
|
||||
* (會建立訂單、記出貨明細/貨道、扣雲端庫存、計入交易筆數)。單次通行碼在 B670 驗證時已消耗,
|
||||
* 後台結案 case 5 只記 log,不會雙扣。
|
||||
*/
|
||||
private void publishFinalizeUnlessPassCode() {
|
||||
// 用 finalizeBuilder 在進入出貨當下擷取的快照判斷,而非結案當下的全域即時值;
|
||||
// 防止出貨中途全域 flowType 被洗回 0(如殘留加購倒數彈出 BuyDialog)而導致通行碼被誤報。
|
||||
if (finalizeBuilder != null && finalizeBuilder.getOrderFlowType() == 5) {
|
||||
getLogs().info("通行碼(payment_type=5) 為內部測試出貨,略過 MQTT 交易結案上報。");
|
||||
private void publishFinalize() {
|
||||
if (finalizeBuilder == null) {
|
||||
return;
|
||||
}
|
||||
MqttManager.getInstance().publishTransactionFinalize(finalizeBuilder.build());
|
||||
@ -1236,12 +1289,26 @@ public class DispatchDialog extends DialogAbstract {
|
||||
buttonControlCountdown.setCountdown(25);
|
||||
}
|
||||
|
||||
getLogs().info("11111");
|
||||
MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new DevCheckSlotByVMC(getHandlerMain(), slot));
|
||||
getLogs().info("22222");
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slot));
|
||||
getLogs().info("33333");
|
||||
// ── 出貨前最後一道保險:確認下位機連線,失連就先自動重連並等到活著,再送出貨指令 ──
|
||||
// 這是「百分百在出貨當下遇失連可自動補出貨」的關鍵。ensure 內含 ping/重連的 Thread.sleep,
|
||||
// 必須背景執行;完成後回主執行緒才送 checkSlot。(檢查放這裡而非按下直接購買時,因為付款到
|
||||
// 出貨可能隔數十秒,當時連著不代表出貨時還連著;下位機常在重啟後短暫失聯。)
|
||||
setTextViewCountdown(getCtx().getString(R.string.device_initializing), 65);
|
||||
new Thread(() -> {
|
||||
boolean alive = MyApp.ensureXinYuanConnectedForDispatch(8000);
|
||||
getLogs().info("出貨前確認下位機連線結果: " + alive);
|
||||
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
|
||||
if (isFinalizing)
|
||||
return;
|
||||
getLogs().info("11111");
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.getReadBufferByNow(new DevCheckSlotByVMC(getHandlerMain(), slot));
|
||||
getLogs().info("22222");
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slot));
|
||||
getLogs().info("33333");
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void devRunElectric(int field, int slot, int increase)
|
||||
|
||||
@ -186,6 +186,14 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
|
||||
MyApp.getInstance().initialReportData();
|
||||
|
||||
// 【防呆】取貨碼對話框開啟時先清空 BuyList,避免「之前殘留、未清掉的購物車品項」
|
||||
// 被取貨碼流程誤當取貨碼 0 元出貨。只有本對話框「掃碼→驗證成功回傳」的品項才可進 BuyList 出貨。
|
||||
if (MyApp.getInstance().getBuyList() != null && MyApp.getInstance().getBuyList().size() > 0) {
|
||||
getLogs().info("開啟取貨碼對話框時偵測到殘留 BuyList " + MyApp.getInstance().getBuyList().size()
|
||||
+ " 筆,已清空以防誤出貨(避免取消鍵白拿/假取貨碼紀錄)");
|
||||
MyApp.getInstance().getBuyList().clear();
|
||||
}
|
||||
|
||||
setInputMode(true);
|
||||
|
||||
binding.btnModeKeypad.setOnClickListener(v -> {
|
||||
@ -203,7 +211,9 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
httpAPI = new HttpAPI(getHandlerMain());
|
||||
|
||||
binding.buttonFinish.setOnClickListener(v -> changeOk());
|
||||
binding.buttonCancel.setOnClickListener(v -> changeBuy());
|
||||
// 【修正】取消鍵只「關閉對話框並清空 BuyList」,絕不可呼叫 changeBuy() 出貨。
|
||||
// 原本寫成 changeBuy():BuyList 若有殘留品項,按取消會被 0 元出貨、還誤記成取貨碼(payment_type=6)。
|
||||
binding.buttonCancel.setOnClickListener(v -> dialogCancel());
|
||||
|
||||
closeDialogCountdown = new CloseDialogOnThreadHandler(getHandlerMain());
|
||||
closeDialogCountdown.start(40);
|
||||
@ -398,7 +408,7 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
}
|
||||
// 長度檢查
|
||||
if (number.isEmpty() || number.length() < 8) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), "取貨碼長度不能少於 8 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), getCtx().getString(R.string.pickup_code_min_8));
|
||||
return;
|
||||
}
|
||||
submitPickupCode(number);
|
||||
@ -426,11 +436,11 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
// 防護:取貨碼從屬「取貨模組」,任一關閉即不開放呼叫 B660(即使 UI 漏出入口也擋下)
|
||||
if (!(MyApp.getInstance().getDevSet().isPickupModule() && MyApp.getInstance().getDevSet().isPickupCode())) {
|
||||
openBarcode = true;
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "取貨碼功能未開放");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.pickup_code_not_enabled));
|
||||
return;
|
||||
}
|
||||
// 送出前顯示「驗證中…」,避免使用者以為沒反應
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), "驗證中…");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.SET_STATUS_TEXT.getOption(), getCtx().getString(R.string.verifying));
|
||||
new com.unibuy.smartdevice.external.StarCloudAPI(getHandlerMain(), getHandlerMain())
|
||||
.verifyPickupCode(code, new com.unibuy.smartdevice.external.StarCloudAPI.PickupVerificationCallback() {
|
||||
@Override
|
||||
@ -513,7 +523,7 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消 " + countdown + "秒");
|
||||
binding.buttonCancel.setText(getContext().getString(R.string.cancel_seconds_format, countdown));
|
||||
}
|
||||
|
||||
public void setStatusText(String message) {
|
||||
@ -671,12 +681,12 @@ public class FontendPickupCodeDialog extends DialogAbstract {
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
|
||||
// 取貨口門未關閉,提示使用者並阻止後續購買流程
|
||||
handlerMain.start("FontendPickupCodeDialog", "取貨口門未正常關閉,請先確認門已關好");
|
||||
handlerMain.start("FontendPickupCodeDialog", getContext().getString(R.string.pickup_door_not_closed));
|
||||
// 使用主執行緒顯示 AlertDialog
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
AlertDialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.abnormal_reminder)
|
||||
.setMessage("取貨口門未正常關閉,請先確認門已關好。")
|
||||
.setMessage(R.string.pickup_door_not_closed)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.i_knew, (d, which) -> {
|
||||
d.dismiss();
|
||||
|
||||
@ -333,14 +333,14 @@ public class InvoiceCustomerIdentifierDialog extends DialogAbstract {
|
||||
public void changeNextStep() {
|
||||
String number = binding.editTextNumber.getText().toString();
|
||||
if (number.length() < 8) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), "統一編號長度不能少於 8 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), getCtx().getString(R.string.tax_id_min_8));
|
||||
return;
|
||||
}
|
||||
binding.linearStep1.setVisibility(View.GONE);
|
||||
binding.linearStep2.setVisibility(View.VISIBLE);
|
||||
binding.buttonNextStep.setVisibility(View.GONE);
|
||||
binding.buttonFinish.setVisibility(View.VISIBLE);
|
||||
binding.textInvoiceCarrier.setText("輸入電話號碼");
|
||||
binding.textInvoiceCarrier.setText(getCtx().getString(R.string.enter_phone_number));
|
||||
closeDialogCountdown.setCountdown(40);
|
||||
}
|
||||
|
||||
@ -351,12 +351,12 @@ public class InvoiceCustomerIdentifierDialog extends DialogAbstract {
|
||||
|
||||
// 長度檢查
|
||||
if (number.length() < 8) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), "統一編號長度不能少於 8 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), getCtx().getString(R.string.tax_id_min_8));
|
||||
return;
|
||||
}
|
||||
|
||||
if (phone.length() < 10) {
|
||||
getHandlerMain().start(getClass().getSimpleName(), "電話號碼長度不能少於 10 碼");
|
||||
getHandlerMain().start(getClass().getSimpleName(), getCtx().getString(R.string.phone_min_10));
|
||||
return;
|
||||
}
|
||||
MyApp.getInstance().getInvoiceData().setCustomerIdentifier(number);
|
||||
|
||||
@ -244,14 +244,14 @@ public class InvoiceDonationDialog extends DialogAbstract {
|
||||
public void changeOk() {
|
||||
int selectedPosition = donationAdapter.getSelectedPosition();
|
||||
if (selectedPosition < 0) {
|
||||
Toast.makeText(getCtx(), "請選擇捐贈機構", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getCtx(), getCtx().getString(R.string.select_charity), Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
String selectedName = organizationNames.get(selectedPosition);
|
||||
String loveCode = donationMap.get(selectedName);
|
||||
MyApp.getInstance().getInvoiceData().setLoveCode(loveCode);
|
||||
MyApp.getInstance().getReportFlowInfoData().setInvoiceInfo("loveCode:" + loveCode);
|
||||
Toast.makeText(getCtx(), "選擇:" + selectedName, Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getCtx(), getCtx().getString(R.string.choose) + ":" + selectedName, Toast.LENGTH_SHORT).show();
|
||||
changeCheckout();
|
||||
}
|
||||
|
||||
@ -302,7 +302,7 @@ public class InvoiceDonationDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("返回發票選擇(" + countdown + ")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.back_to_invoice) + "(" + countdown + ")");
|
||||
}
|
||||
|
||||
public static class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -4,6 +4,7 @@ import android.content.Context;
|
||||
|
||||
import com.unibuy.smartdevice.DialogAbstract;
|
||||
import com.unibuy.smartdevice.MyApp;
|
||||
import com.unibuy.smartdevice.R;
|
||||
import com.unibuy.smartdevice.databinding.DialogInvoiceTypeBinding;
|
||||
import com.unibuy.smartdevice.tools.HandlerMain;
|
||||
import com.unibuy.smartdevice.tools.HandlerMainCountdown;
|
||||
@ -146,7 +147,7 @@ public class InvoiceTypeDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("返回" + countdown + "秒");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.return_to) + countdown + getCtx().getString(R.string.second));
|
||||
}
|
||||
|
||||
public static class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
package com.unibuy.smartdevice.ui.dialog;
|
||||
import com.unibuy.smartdevice.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
@ -185,7 +186,7 @@ public class MemberCardPickupDialog extends DialogAbstract {
|
||||
private void handleCardDetected(String cardNo) {
|
||||
if (!cardNo.isEmpty()) {
|
||||
getLogs().info("MemberCardPickupDialog - Card Detected: " + cardNo);
|
||||
binding.editCardNo.setHint("正在驗證卡片...");
|
||||
binding.editCardNo.setHint(getContext().getString(R.string.verifying_card));
|
||||
binding.editCardNo.setText("");
|
||||
|
||||
// 呼叫 B680 遠端驗證
|
||||
@ -201,13 +202,13 @@ public class MemberCardPickupDialog extends DialogAbstract {
|
||||
MyApp.getInstance().getSlotData(buy.getField(), buy.getSlot());
|
||||
if (liveSlot != null && liveSlot.getCount() <= 0) {
|
||||
getLogs().info("庫存已歸零 slot=" + buy.getSlot() + ",取消出貨,返回銷售平台。");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.TOAST.getOption(), "商品已售罄,請重新選擇");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.TOAST.getOption(), getCtx().getString(R.string.product_sold_out_reselect));
|
||||
dialogCancel(); // 內部已清空 BuyList + dismiss
|
||||
return;
|
||||
}
|
||||
if (liveSlot != null && liveSlot.isExpired()) {
|
||||
getLogs().info("商品已過效期 slot=" + buy.getSlot() + ",取消出貨,返回銷售平台。");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.TOAST.getOption(), "商品已過效期,暫不販售");
|
||||
getHandlerMain().start(getClass().getSimpleName(), Option.TOAST.getOption(), getContext().getString(R.string.product_expired_not_for_sale));
|
||||
dialogCancel(); // 內部已清空 BuyList + dismiss
|
||||
return;
|
||||
}
|
||||
@ -266,7 +267,7 @@ public class MemberCardPickupDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonCancelText(long countdown) {
|
||||
binding.buttonCancel.setText("取消(" + countdown + ")");
|
||||
binding.buttonCancel.setText(getCtx().getString(R.string.cancel)+"(" + countdown + ")");
|
||||
}
|
||||
|
||||
public class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
package com.unibuy.smartdevice.ui.dialog;
|
||||
import com.unibuy.smartdevice.R;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
@ -86,7 +87,7 @@ public class PickupSuccessDialog extends DialogAbstract {
|
||||
this.laneNumber = laneNumber;
|
||||
if (binding != null) {
|
||||
binding.tvLaneNumber.setText(laneNumber);
|
||||
binding.tvSubtitle.setText("請至" + laneNumber + "號櫃門拿取您的商品");
|
||||
binding.tvSubtitle.setText(getCtx().getString(R.string.go_to_cabinet_format, laneNumber));
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +118,7 @@ public class PickupSuccessDialog extends DialogAbstract {
|
||||
}
|
||||
|
||||
public void setButtonConfirmText(long countdown) {
|
||||
binding.btnConfirm.setText("確認已取貨(" + countdown + "秒)");
|
||||
binding.btnConfirm.setText(getCtx().getString(R.string.confirm_taken_format, countdown));
|
||||
}
|
||||
|
||||
public static class CloseDialogOnThreadHandler extends HandlerMainCountdown {
|
||||
|
||||
@ -60,7 +60,7 @@ public class RecyclerDialogDispatchListAdpter extends RecyclerView.Adapter<Recyc
|
||||
|
||||
String productID = dispatchProduct.getProduct().getProductID();
|
||||
if (!productID.isEmpty() && !productID.equals("?")) {
|
||||
holder.binding.textProductName.setText(dispatchProduct.getProduct().getProductName());
|
||||
holder.binding.textProductName.setText(dispatchProduct.getProduct().getLocalizedName(context));
|
||||
} else {
|
||||
holder.binding.textProductName.setText(context.getString(R.string.click_select_product));//點我選擇商品
|
||||
}
|
||||
@ -84,7 +84,7 @@ public class RecyclerDialogDispatchListAdpter extends RecyclerView.Adapter<Recyc
|
||||
|
||||
int price = machinePrice > 0? machinePrice: sellingPrice;
|
||||
|
||||
holder.binding.textCount.setText(String.format("已出貨數量(%d / %d)", count, quantity));
|
||||
holder.binding.textCount.setText(context.getString(R.string.shipped_quantity_format, count, quantity));
|
||||
|
||||
logs.info("isShipped:" + dispatchProduct.isShipped());
|
||||
|
||||
@ -95,12 +95,12 @@ public class RecyclerDialogDispatchListAdpter extends RecyclerView.Adapter<Recyc
|
||||
} else if (dispatchProduct.isShipped()) {
|
||||
try {
|
||||
if (SlotField.getSlotField(dispatchProduct.getField()).isCanOneShipped()) {
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping)+"("+(count+1)+"件)");//出貨中
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping_count_format, count + 1));//出貨中
|
||||
} else {
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping)+"(All)");//出貨中
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping_all));//出貨中
|
||||
}
|
||||
} catch (LogsEmptyException e) {
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping)+"("+(count+1)+"件)");//出貨中
|
||||
holder.binding.textDispatchStatus.setText(context.getString(R.string.shipping_count_format, count + 1));//出貨中
|
||||
}
|
||||
|
||||
holder.binding.textDispatchStatus.setTextColor(ContextCompat.getColor(context, R.color.onPrimary));
|
||||
|
||||
@ -63,7 +63,7 @@ public class RecyclerDialogPickupCodeBuyListAdpter extends RecyclerView.Adapter<
|
||||
holder.binding.textPosition.setText(String.valueOf(position));
|
||||
String productID = buyProduct.getProduct().getProductID();
|
||||
if (!productID.isEmpty() && !productID.equals("?")) {
|
||||
holder.binding.textProductName.setText(buyProduct.getProduct().getProductName());
|
||||
holder.binding.textProductName.setText(buyProduct.getProduct().getLocalizedName(context));
|
||||
} else {
|
||||
holder.binding.textProductName.setText(context.getString(R.string.click_select_product));//
|
||||
}
|
||||
@ -84,7 +84,7 @@ public class RecyclerDialogPickupCodeBuyListAdpter extends RecyclerView.Adapter<
|
||||
int price = machinePrice > 0? machinePrice: sellingPrice;
|
||||
|
||||
holder.binding.textPrice.setText("$"+price);
|
||||
holder.binding.textCount.setText("出貨數量:" + count + "件");
|
||||
holder.binding.textCount.setText(context.getString(R.string.dispatch_quantity_format, count));
|
||||
|
||||
logs.info("field:" + buyProduct.getField());
|
||||
}
|
||||
|
||||
@ -510,6 +510,40 @@ public class CashMachineSettings extends AppCompatActivity implements View.OnCli
|
||||
|
||||
// 將收到的原始事件印到畫面 Debug 區(取代原本每則跳 Toast 的干擾)
|
||||
appendDebugLog("[事件] " + event);
|
||||
|
||||
if (event == null) return;
|
||||
|
||||
// MDB 轉換盒(SerialCashAcceptorHandler)的十進位格式,優先處理。
|
||||
// 舊的 19 段 hex 格式每段限 2 位(0~255),當某面額數量>255(如 1元虛擬庫存)時 %02X 會變 3 位,
|
||||
// 使整包被「每段須 2 字元」驗證丟棄→四種硬幣全部顯示不出來。改吃這個十進位格式即無此限制。
|
||||
if (event.startsWith("COIN_STOCK:")) {
|
||||
try {
|
||||
String[] v = event.substring("COIN_STOCK:".length()).split(",");
|
||||
if (v.length >= 4) {
|
||||
coin1_count = Integer.parseInt(v[0].trim());
|
||||
coin5_count = Integer.parseInt(v[1].trim());
|
||||
coin10_count = Integer.parseInt(v[2].trim());
|
||||
coin50_count = Integer.parseInt(v[3].trim());
|
||||
tvCoin50Count.setText("50元數量:" + coin50_count);
|
||||
tvCoin10Count.setText("10元數量:" + coin10_count);
|
||||
tvCoin5Count.setText("5元數量:" + coin5_count);
|
||||
tvCoin1Count.setText("1元數量:" + coin1_count);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e("MDB_EVENT", "COIN_STOCK 解析失敗: " + e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.startsWith("NOTE_STOCK:")) {
|
||||
try {
|
||||
note100_count = Integer.parseInt(event.substring("NOTE_STOCK:".length()).trim());
|
||||
tvBillStatusDisplay.setText("循環區裡面百鈔數量" + note100_count);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e("MDB_EVENT", "NOTE_STOCK 解析失敗: " + e.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.length() >= 5) {
|
||||
String code = event.substring(0, 5);
|
||||
switch (code) {
|
||||
|
||||
@ -36,7 +36,7 @@ class CartOperationAdapter(layoutResId: Int, data: MutableList<SlotStructure>) :
|
||||
|
||||
holder.setText(R.id.textProductName, name)
|
||||
.setText(R.id.totalPriceTextView, "NT$ ${result.currentItemPrice}")
|
||||
.setText(R.id.textStock, String.format("庫存%02d件", item.count))
|
||||
.setText(R.id.textStock, ctx.getString(R.string.stock_pieces_format, item.count))
|
||||
.setText(R.id.textQuantity, "${result.currentItemCount}")
|
||||
.setText(R.id.textPrice, "NT$ ${item.product.realPrice}")
|
||||
|
||||
|
||||
@ -385,7 +385,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="取貨碼"
|
||||
android:text="@string/pickup_code"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
|
||||
@ -83,12 +83,12 @@
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeKeypad"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="鍵盤輸入" />
|
||||
android:text="@string/keyboard_input" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeScan"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="掃描條碼" />
|
||||
android:text="@string/scan_barcode" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="請選擇支付方式"
|
||||
android:text="@string/select_payment_method"
|
||||
android:textSize="30sp"
|
||||
android:textColor="@color/primary"
|
||||
android:padding="10dp"
|
||||
@ -122,7 +122,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:gravity="center"
|
||||
android:text="信用卡"
|
||||
android:text="@string/credit_card"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
<ImageView
|
||||
@ -155,7 +155,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:gravity="center"
|
||||
android:text="電子票證"
|
||||
android:text="@string/e_ticket"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp"/>
|
||||
<ImageView
|
||||
@ -188,7 +188,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:gravity="center"
|
||||
android:text="手機NFC"
|
||||
android:text="@string/phone_nfc"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
<ImageView
|
||||
@ -223,7 +223,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center"
|
||||
android:text="掃碼支付-玉山"
|
||||
android:text="@string/qr_pay_esun"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
<ImageView
|
||||
@ -256,7 +256,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center"
|
||||
android:text="掃碼支付-TapPay"
|
||||
android:text="@string/qr_pay_tappay"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
<ImageView
|
||||
@ -289,7 +289,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center"
|
||||
android:text="現金支付"
|
||||
android:text="@string/cash_payment"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp"/>
|
||||
<ImageView
|
||||
@ -322,7 +322,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Line Pay 支付"
|
||||
android:text="@string/line_pay"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
</LinearLayout>
|
||||
@ -349,7 +349,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="通行碼"
|
||||
android:text="@string/passcode"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
</LinearLayout>
|
||||
@ -377,7 +377,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="來店禮"
|
||||
android:text="@string/gifts"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="25sp" />
|
||||
</LinearLayout>
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
android:layout_height="60dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:text="現金支付"
|
||||
android:text="@string/cash_payment"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
@ -47,7 +47,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -86,7 +86,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="已投入:"
|
||||
android:text="@string/label_inserted"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -124,7 +124,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="start|center_vertical"
|
||||
android:text="未投入:"
|
||||
android:text="@string/label_not_inserted"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -168,7 +168,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:gravity="center"
|
||||
android:text="請投入硬幣或紙鈔"
|
||||
android:text="@string/please_insert_cash"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -228,7 +228,7 @@
|
||||
android:layout_weight="1"
|
||||
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消並退幣(45秒)"
|
||||
android:text="@string/cancel_and_refund"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -258,7 +258,7 @@
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="嘗試退鈔並重試"
|
||||
android:text="@string/retry_refund"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將付款條碼對準掃描器"
|
||||
android:text="@string/align_barcode_to_scanner"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -145,7 +145,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消支付(40秒)"
|
||||
android:text="@string/cancel_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -160,7 +160,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/infoContainer"
|
||||
android:text="修改支付方式"
|
||||
android:text="@string/change_payment_method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將付款條碼對準掃描器"
|
||||
android:text="@string/align_barcode_to_scanner"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -143,7 +143,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消支付(40秒)"
|
||||
android:text="@string/cancel_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -158,7 +158,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/infoContainer"
|
||||
android:text="修改支付方式"
|
||||
android:text="@string/change_payment_method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將卡片靠近感應區"
|
||||
android:text="@string/tap_card_to_reader"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -143,7 +143,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消支付(40秒)"
|
||||
android:text="@string/cancel_payment"
|
||||
android:textColor="@color/onWarning"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -158,7 +158,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/gray"
|
||||
android:text="修改支付方式"
|
||||
android:text="@string/change_payment_method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將付款條碼對準掃描器"
|
||||
android:text="@string/align_barcode_to_scanner"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -143,7 +143,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消支付(40秒)"
|
||||
android:text="@string/cancel_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -158,7 +158,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/infoContainer"
|
||||
android:text="修改支付方式"
|
||||
android:text="@string/change_payment_method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將卡片靠近感應區"
|
||||
android:text="@string/tap_card_to_reader"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -143,7 +143,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="取消支付(40秒)"
|
||||
android:text="@string/cancel_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
@ -158,7 +158,7 @@
|
||||
android:layout_weight="1"
|
||||
android:paddingHorizontal="0dp"
|
||||
android:backgroundTint="@color/infoContainer"
|
||||
android:text="修改支付方式"
|
||||
android:text="@string/change_payment_method"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
app:elevation="4dp"
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1.10"
|
||||
android:gravity="center|end"
|
||||
android:text="交易金額:"
|
||||
android:text="@string/transaction_amount"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
@ -74,7 +74,7 @@
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="0.90"
|
||||
android:gravity="center"
|
||||
android:text="QRCode產生中,請等待片刻"
|
||||
android:text="@string/generating_qrcode"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
@ -158,7 +158,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:backgroundTint="@color/white"
|
||||
android:text="更換支付"
|
||||
android:text="@string/replacement_payment"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/black" />
|
||||
</LinearLayout>
|
||||
|
||||
@ -106,7 +106,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="公司統編"
|
||||
android:text="@string/company_tax_id"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
@ -142,7 +142,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="電話號碼"
|
||||
android:text="@string/phone_number"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
@ -162,7 +162,7 @@
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="輸入公司統編"
|
||||
android:text="@string/enter_company_tax_id"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
@ -182,7 +182,7 @@
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="公司統編"
|
||||
android:hint="@string/company_tax_id"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusBottomStart="8dp"
|
||||
@ -391,7 +391,7 @@
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="電話號碼"
|
||||
android:hint="@string/phone_number"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxCornerRadiusBottomEnd="8dp"
|
||||
app:boxCornerRadiusBottomStart="8dp"
|
||||
@ -600,7 +600,7 @@
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="返回支付方式"
|
||||
android:text="@string/back_to_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
@ -612,7 +612,7 @@
|
||||
android:layout_height="64dp"
|
||||
android:layout_weight="1"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:text="下一步"
|
||||
android:text="@string/next_step"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
|
||||
@ -149,14 +149,14 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/qrcode_msg_dailemei"
|
||||
android:src="@drawable/qrcode_msg"
|
||||
android:scaleType="fitXY" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvCountdown"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="(15s)後關閉"
|
||||
android:text=""
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="30sp"
|
||||
android:visibility="gone"
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="請選擇捐贈機構"
|
||||
android:text="@string/select_charity"
|
||||
android:textColor="?attr/colorPrimary"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
@ -147,7 +147,7 @@
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="返回支付方式"
|
||||
android:text="@string/back_to_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
@ -159,7 +159,7 @@
|
||||
android:layout_height="64dp"
|
||||
android:layout_weight="1"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:text="確定"
|
||||
android:text="@string/sure"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
|
||||
@ -83,12 +83,12 @@
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeKeypad"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="鍵盤輸入" />
|
||||
android:text="@string/keyboard_input" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeScan"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="掃描條碼" />
|
||||
android:text="@string/scan_barcode" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@ -152,7 +152,7 @@
|
||||
android:layout_height="64dp"
|
||||
android:layout_weight="1"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="返回支付方式"
|
||||
android:text="@string/back_to_payment"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
@ -166,7 +166,7 @@
|
||||
android:layout_marginStart="16dp"
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:enabled="false"
|
||||
android:text="確認"
|
||||
android:text="@string/confirm"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請選擇發票開立方式"
|
||||
android:text="@string/select_invoice_type"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold"
|
||||
@ -70,7 +70,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="輸入載具"
|
||||
android:text="@string/input_vehicle"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
@ -102,7 +102,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="捐贈發票"
|
||||
android:text="@string/donation_invoice_next"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
@ -133,7 +133,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="公司統編"
|
||||
android:text="@string/company_tax_id"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
@ -160,7 +160,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:backgroundTint="@color/warning"
|
||||
android:text="返回40秒"
|
||||
android:text="@string/return_to"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="無需付款"
|
||||
android:text="@string/no_payment_needed"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="40sp"
|
||||
android:textStyle="bold" />
|
||||
@ -49,7 +49,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="請將員工卡靠近讀卡機"
|
||||
android:text="@string/please_tap_member_card"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
@ -60,7 +60,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:text="交易狀態:等待感應"
|
||||
android:text="@string/waiting_for_tap"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="15sp" />
|
||||
|
||||
@ -78,7 +78,7 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="卡號資訊:"
|
||||
android:text="@string/card_number_info"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@color/black" />
|
||||
|
||||
@ -89,7 +89,7 @@
|
||||
android:layout_marginTop="10dp"
|
||||
android:background="@drawable/textview_border"
|
||||
android:gravity="center"
|
||||
android:hint="請感應卡片"
|
||||
android:hint="@string/tap_card_hint"
|
||||
android:inputType="text"
|
||||
android:textSize="30sp"
|
||||
android:textColor="@color/primary"
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
android:layout_height="60dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="center"
|
||||
android:text="請確認您的商品是否正確"
|
||||
android:text="@string/confirm_product_correct"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold" />
|
||||
@ -73,7 +73,7 @@
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="16dp"
|
||||
android:backgroundTint="@color/primary"
|
||||
android:text="確認"
|
||||
android:text="@string/confirm"
|
||||
android:textColor="@color/onPrimary"
|
||||
android:textSize="20sp"
|
||||
app:cornerRadius="8dp" />
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="65dp"
|
||||
android:gravity="center"
|
||||
android:text="請輸入取貨碼"
|
||||
android:text="@string/enter_pickup_code"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="36sp"
|
||||
android:textStyle="bold" />
|
||||
@ -50,7 +50,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="請輸入取貨碼 或 掃描QRCode"
|
||||
android:text="@string/enter_pickup_code_or_scan"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
@ -83,12 +83,12 @@
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeKeypad"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="鍵盤輸入" />
|
||||
android:text="@string/keyboard_input" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnModeScan"
|
||||
style="@style/Widget.App.InputModeButton"
|
||||
android:text="掃描條碼" />
|
||||
android:text="@string/scan_barcode" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -103,7 +103,7 @@
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="60dp"
|
||||
android:textSize="28sp"
|
||||
android:hint="請輸入取貨碼"
|
||||
android:hint="@string/enter_pickup_code"
|
||||
android:background="@drawable/bg_input_outline"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
@ -269,7 +269,7 @@
|
||||
android:insetLeft="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="取消"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="26sp"
|
||||
app:cornerRadius="12dp"
|
||||
android:textColor="@color/white" />
|
||||
@ -289,7 +289,7 @@
|
||||
android:insetLeft="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:padding="0dp"
|
||||
android:text="確認"
|
||||
android:text="@string/confirm"
|
||||
android:textSize="26sp"
|
||||
app:cornerRadius="12dp"
|
||||
android:textColor="@color/white" />
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="關閉"
|
||||
android:text="@string/close"
|
||||
android:textColor="@color/onWarning"
|
||||
android:textSize="@dimen/text_size_title_small"
|
||||
android:textStyle="bold" />
|
||||
@ -161,7 +161,7 @@
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="商品描述"
|
||||
android:text="@string/product_description"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="@dimen/text_size_title_small"
|
||||
android:textStyle="bold" />
|
||||
@ -202,7 +202,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="數量"
|
||||
android:text="@string/amount"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="@dimen/text_size_title_small" />
|
||||
|
||||
@ -258,7 +258,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="金額小計"
|
||||
android:text="@string/subtotal"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="@dimen/text_size_title_small" />
|
||||
|
||||
@ -300,7 +300,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="4dp"
|
||||
android:text="加入購物車"
|
||||
android:text="@string/add_to_shopping_cart"
|
||||
android:textColor="@color/primary"
|
||||
android:textSize="@dimen/text_size_label_large"
|
||||
android:textStyle="bold" />
|
||||
@ -324,7 +324,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="4dp"
|
||||
android:text="直接購買"
|
||||
android:text="@string/buy_now"
|
||||
android:textColor="@color/onPrimary"
|
||||
android:textSize="@dimen/text_size_label_large"
|
||||
android:textStyle="bold" />
|
||||
|
||||
@ -141,7 +141,7 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="付款金額"
|
||||
android:text="@string/payment_amount"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:text="商品"
|
||||
android:text="@string/product_label"
|
||||
style="@style/TextAppearance.App.QuickCart.Medium"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="normal" />
|
||||
@ -72,7 +72,7 @@
|
||||
android:id="@+id/textStock"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="庫存00件"
|
||||
android:text="@string/stock_label"
|
||||
android:layout_marginStart="16dp"
|
||||
style="@style/TextAppearance.App.QuickCart.Medium"
|
||||
android:textColor="@color/gray"
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:background="@drawable/bg_rounded_primary"
|
||||
android:text="貨道01"
|
||||
android:text="@string/slot_label"
|
||||
android:textColor="@color/onPrimary"
|
||||
android:textSize="@dimen/text_size_label"
|
||||
android:textStyle="bold" />
|
||||
@ -75,7 +75,7 @@
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:background="@drawable/bg_rounded_light_gray"
|
||||
android:text="庫存0"
|
||||
android:text="@string/stock_label"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="@dimen/text_size_label"
|
||||
android:textStyle="bold" />
|
||||
@ -151,7 +151,7 @@
|
||||
android:id="@+id/textMask"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="售完"
|
||||
android:text="@string/sold_out"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold"
|
||||
|
||||
@ -204,6 +204,9 @@
|
||||
<!-- ui/recycler/RecyclerDialogDispatchListAdpter.java -->
|
||||
<string name="shipped">Shipped</string>
|
||||
<string name="shipping">Shipping</string>
|
||||
<string name="shipped_quantity_format">Shipped (%1$d / %2$d)</string>
|
||||
<string name="shipping_count_format">Shipping (%1$d)</string>
|
||||
<string name="shipping_all">Shipping (All)</string>
|
||||
<string name="waiting">Waiting</string>
|
||||
<!-- ui/recycler/RecyclerProductListAdpter.java -->
|
||||
<!-- ui/recycler/RecyclerProductSearchAdpter.java -->
|
||||
@ -271,6 +274,7 @@
|
||||
<string name="unified_number">Unified number</string>
|
||||
<string name="phone_number">Phone number</string>
|
||||
<string name="donation_invoice">Donation Invoice</string>
|
||||
<string name="donation_invoice_next">Donation Invoice / Next</string>
|
||||
<string name="input_complete">Input Complete</string>
|
||||
<!-- dialog_dispatch.xml -->
|
||||
<string name="shipping_goods">Shipping goods</string>
|
||||
@ -391,6 +395,18 @@
|
||||
<string name="product_delivery_issues_contact_the_counter_window">For product delivery issues, please contact the counter window!</string>
|
||||
<string name="abnormal_reminder">Abnormal reminder</string>
|
||||
<string name="there_is_something_at_the_pickup_port">There is something at the pickup port, please remove it first</string>
|
||||
<string name="pickup_door_not_closed">The pickup port door is not properly closed. Please make sure it is shut.</string>
|
||||
<string name="pickup_elevator_not_home">The lift has not returned to its home position. Please contact staff.</string>
|
||||
<string name="pickup_status_confirming">Confirming pickup port status. Please wait 1-2 seconds and tap again.</string>
|
||||
<string name="pickup_checking">Checking pickup port...</string>
|
||||
<string name="enter_pickup_code_or_scan">Enter pickup code or scan QR code</string>
|
||||
<string name="tap_card_hint">Please tap your card</string>
|
||||
<string name="cancel_seconds_format">Cancel %1$ds</string>
|
||||
<string name="verifying_card">Verifying card...</string>
|
||||
<string name="product_expired_not_for_sale">This product has expired and is not available for sale.</string>
|
||||
<string name="unsupported_discount_type">Unsupported discount type</string>
|
||||
<string name="confirm_product_correct">Please confirm your product is correct</string>
|
||||
<string name="dispatch_quantity_format">Quantity: %1$d</string>
|
||||
<string name="i_knew">knew</string>
|
||||
<string name="input_vehicle">Input Vehicle</string>
|
||||
<string name="sync_product">Reload Products</string>
|
||||
@ -435,4 +451,70 @@
|
||||
<string name="please_go_to_cabinet_to_pick_up_goods">Please collect your item from cabinet No. 99</string>
|
||||
<string name="confirm_goods_taken_hardcoded">Confirm item taken (15s)</string>
|
||||
<string name="system_inspection_in_progress">Machine inspection in progress, please wait</string>
|
||||
|
||||
<!-- ===== i18n backfill: sale / product detail / cart / payment / invoice (2026-07) ===== -->
|
||||
<string name="slot_label">Slot</string>
|
||||
<string name="stock_label">Stock</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="product_description">Description</string>
|
||||
<string name="subtotal">Subtotal</string>
|
||||
<string name="add_to_shopping_cart">Add to Cart</string>
|
||||
<string name="buy_now">Buy Now</string>
|
||||
<string name="payment_amount">Amount</string>
|
||||
<string name="product_label">Product</string>
|
||||
<string name="stock_pieces_format">Stock: %1$02d</string>
|
||||
<string name="select_payment_method">Select Payment Method</string>
|
||||
<string name="credit_card">Credit Card</string>
|
||||
<string name="e_ticket">Stored-Value Card</string>
|
||||
<string name="phone_nfc">Phone NFC</string>
|
||||
<string name="qr_pay_esun">QR Pay - E.SUN</string>
|
||||
<string name="qr_pay_tappay">QR Pay - TapPay</string>
|
||||
<string name="line_pay">Line Pay</string>
|
||||
<string name="select_invoice_type">Select Invoice Type</string>
|
||||
<string name="company_tax_id">Company Tax ID</string>
|
||||
<string name="select_charity">Select a Charity</string>
|
||||
<string name="back_to_payment">Back to Payment</string>
|
||||
<string name="back_to_invoice">Back to Invoice</string>
|
||||
<string name="enter_company_tax_id">Enter Company Tax ID</string>
|
||||
<string name="next_step">Next</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="tax_id_min_8">Tax ID must be at least 8 digits</string>
|
||||
<string name="phone_min_10">Phone number must be at least 10 digits</string>
|
||||
<string name="enter_phone_number">Enter Phone Number</string>
|
||||
<string name="pay_item_count">Quantity: %d item(s)</string>
|
||||
<string name="pay_payable_amount">Amount Due</string>
|
||||
<string name="pay_discounted_format">Saved NT$%d</string>
|
||||
<!-- ===== i18n backfill batch2 ===== -->
|
||||
<string name="change_payment_method">Change Payment Method</string>
|
||||
<string name="cancel_payment">Cancel Payment</string>
|
||||
<string name="align_barcode_to_scanner">Align the payment barcode with the scanner</string>
|
||||
<string name="tap_card_to_reader">Tap your card on the reader</string>
|
||||
<string name="generating_qrcode">Generating QR code, please wait</string>
|
||||
<string name="card_reader_cannot_open">Cannot start card reader</string>
|
||||
<string name="reading_transaction">Reading transaction. Keep your card/phone steady,\ndo not move quickly; it will return automatically when done.</string>
|
||||
<string name="dispensing_product">Dispensing product</string>
|
||||
<string name="close_after_seconds">Close in (%1$ds)</string>
|
||||
<string name="keyboard_input">Keyboard</string>
|
||||
<string name="scan_barcode">Scan Barcode</string>
|
||||
<string name="verifying">Verifying…</string>
|
||||
<string name="pickup_code_min_8">Pickup code must be at least 8 digits</string>
|
||||
<string name="passcode_min_8">Passcode must be at least 8 digits</string>
|
||||
<string name="gift_code_min_8">Gift code must be 8 digits</string>
|
||||
<string name="enter_pickup_code">Enter pickup code</string>
|
||||
<string name="pickup_code_not_enabled">Pickup code is not enabled</string>
|
||||
<string name="passcode_not_enabled">Passcode is not enabled</string>
|
||||
<string name="gift_not_enabled">Gift function is not enabled</string>
|
||||
<string name="no_payment_needed">No payment required</string>
|
||||
<string name="card_number_info">Card No.:</string>
|
||||
<string name="product_sold_out_reselect">Product sold out, please choose again</string>
|
||||
<string name="waiting_for_tap">Status: waiting for tap</string>
|
||||
<string name="label_inserted">Inserted</string>
|
||||
<string name="label_not_inserted">Remaining</string>
|
||||
<string name="please_insert_cash">Please insert coins or bills</string>
|
||||
<string name="cancel_and_refund">Cancel & Refund</string>
|
||||
<string name="retry_refund">Try refund again</string>
|
||||
<string name="hint_title">Notice!</string>
|
||||
<string name="device_initializing">Initializing device, please wait...</string>
|
||||
<string name="go_to_cabinet_format">Please collect your item at cabinet No. %1$s</string>
|
||||
<string name="confirm_taken_format">Confirm item taken (%1$ds)</string>
|
||||
</resources>
|
||||
|
||||
@ -204,6 +204,9 @@
|
||||
<!-- ui/recycler/RecyclerDialogDispatchListAdpter.java -->
|
||||
<string name="shipped">発送済み</string>
|
||||
<string name="shipping">配送</string>
|
||||
<string name="shipped_quantity_format">出荷済み(%1$d / %2$d)</string>
|
||||
<string name="shipping_count_format">出荷中(%1$d点)</string>
|
||||
<string name="shipping_all">出荷中(All)</string>
|
||||
<string name="waiting">待っている</string>
|
||||
<!-- ui/recycler/RecyclerProductListAdpter.java -->
|
||||
<!-- ui/recycler/RecyclerProductSearchAdpter.java -->
|
||||
@ -271,6 +274,7 @@
|
||||
<string name="unified_number">統一番号</string>
|
||||
<string name="phone_number">電話番号</string>
|
||||
<string name="donation_invoice">寄付金請求書</string>
|
||||
<string name="donation_invoice_next">寄付金請求書/次へ</string>
|
||||
<string name="input_complete">入力完了</string>
|
||||
<!-- dialog_dispatch.xml -->
|
||||
<string name="shipping_goods">商品の発送</string>
|
||||
@ -391,6 +395,18 @@
|
||||
<string name="product_delivery_issues_contact_the_counter_window">商品配送に関するトラブルはカウンター窓口までお問い合わせください!</string>
|
||||
<string name="abnormal_reminder">異常なリマインダー</string>
|
||||
<string name="there_is_something_at_the_pickup_port">受取口に物があります、先に取り出してください</string>
|
||||
<string name="pickup_door_not_closed">受取口の扉が正しく閉まっていません。扉が閉まっているか確認してください。</string>
|
||||
<string name="pickup_elevator_not_home">リフトが元の位置に戻っていません。係員にお問い合わせください。</string>
|
||||
<string name="pickup_status_confirming">受取口の状態を確認中です。1〜2秒待ってからもう一度タップしてください。</string>
|
||||
<string name="pickup_checking">受取口を確認中......</string>
|
||||
<string name="enter_pickup_code_or_scan">受取コードを入力、またはQRコードをスキャン</string>
|
||||
<string name="tap_card_hint">カードをかざしてください</string>
|
||||
<string name="cancel_seconds_format">キャンセル %1$d秒</string>
|
||||
<string name="verifying_card">カードを確認中...</string>
|
||||
<string name="product_expired_not_for_sale">商品は有効期限切れのため、販売しておりません。</string>
|
||||
<string name="unsupported_discount_type">サポートされていない割引タイプ</string>
|
||||
<string name="confirm_product_correct">商品が正しいかご確認ください</string>
|
||||
<string name="dispatch_quantity_format">出荷数量:%1$d点</string>
|
||||
<string name="i_knew">知っていた</string>
|
||||
<string name="input_vehicle">スマホバーコード への入力</string>
|
||||
<string name="sync_product">商品データを同期</string>
|
||||
@ -434,4 +450,70 @@
|
||||
<string name="please_go_to_cabinet_to_pick_up_goods">99番の扉から商品をお受け取りください</string>
|
||||
<string name="confirm_goods_taken_hardcoded">受け取り確認(15秒)</string>
|
||||
<string name="system_inspection_in_progress">機器点検中です。しばらくお待ちください</string>
|
||||
|
||||
<!-- ===== i18n backfill: sale / product detail / cart / payment / invoice (2026-07) ===== -->
|
||||
<string name="slot_label">レーン</string>
|
||||
<string name="stock_label">在庫</string>
|
||||
<string name="close">閉じる</string>
|
||||
<string name="product_description">商品説明</string>
|
||||
<string name="subtotal">小計</string>
|
||||
<string name="add_to_shopping_cart">カートに追加</string>
|
||||
<string name="buy_now">今すぐ購入</string>
|
||||
<string name="payment_amount">お支払金額</string>
|
||||
<string name="product_label">商品</string>
|
||||
<string name="stock_pieces_format">在庫%1$02d個</string>
|
||||
<string name="select_payment_method">お支払方法を選択</string>
|
||||
<string name="credit_card">クレジットカード</string>
|
||||
<string name="e_ticket">電子マネー</string>
|
||||
<string name="phone_nfc">スマホNFC</string>
|
||||
<string name="qr_pay_esun">QR決済-玉山</string>
|
||||
<string name="qr_pay_tappay">QR決済-TapPay</string>
|
||||
<string name="line_pay">Line Pay</string>
|
||||
<string name="select_invoice_type">請求書の発行方法を選択</string>
|
||||
<string name="company_tax_id">法人統一番号</string>
|
||||
<string name="select_charity">寄付先を選択してください</string>
|
||||
<string name="back_to_payment">お支払方法に戻る</string>
|
||||
<string name="back_to_invoice">請求書選択に戻る</string>
|
||||
<string name="enter_company_tax_id">法人統一番号を入力</string>
|
||||
<string name="next_step">次へ</string>
|
||||
<string name="confirm">確認</string>
|
||||
<string name="tax_id_min_8">統一番号は8桁以上必要です</string>
|
||||
<string name="phone_min_10">電話番号は10桁以上必要です</string>
|
||||
<string name="enter_phone_number">電話番号を入力</string>
|
||||
<string name="pay_item_count">商品数量:計 %d 点</string>
|
||||
<string name="pay_payable_amount">お支払金額</string>
|
||||
<string name="pay_discounted_format">NT$%d 割引</string>
|
||||
<!-- ===== i18n backfill batch2 ===== -->
|
||||
<string name="change_payment_method">お支払方法を変更</string>
|
||||
<string name="cancel_payment">支払いをキャンセル</string>
|
||||
<string name="align_barcode_to_scanner">決済バーコードをスキャナーに合わせてください</string>
|
||||
<string name="tap_card_to_reader">カードをリーダーにかざしてください</string>
|
||||
<string name="generating_qrcode">QRコードを生成中です。お待ちください</string>
|
||||
<string name="card_reader_cannot_open">カードリーダーを起動できません</string>
|
||||
<string name="reading_transaction">取引を読み取り中です。カード/スマホを動かさず、\n完了後は自動的に戻ります。</string>
|
||||
<string name="dispensing_product">商品を排出中</string>
|
||||
<string name="close_after_seconds">(%1$d秒)後に閉じる</string>
|
||||
<string name="keyboard_input">キーボード入力</string>
|
||||
<string name="scan_barcode">バーコードをスキャン</string>
|
||||
<string name="verifying">確認中…</string>
|
||||
<string name="pickup_code_min_8">受取コードは8桁以上必要です</string>
|
||||
<string name="passcode_min_8">通行コードは8桁以上必要です</string>
|
||||
<string name="gift_code_min_8">来店特典コードは8桁必要です</string>
|
||||
<string name="enter_pickup_code">受取コードを入力</string>
|
||||
<string name="pickup_code_not_enabled">受取コード機能は未開放です</string>
|
||||
<string name="passcode_not_enabled">通行コード機能は未開放です</string>
|
||||
<string name="gift_not_enabled">来店特典機能は未開放です</string>
|
||||
<string name="no_payment_needed">お支払い不要</string>
|
||||
<string name="card_number_info">カード番号:</string>
|
||||
<string name="product_sold_out_reselect">商品は完売しました。もう一度お選びください</string>
|
||||
<string name="waiting_for_tap">状態:タッチ待ち</string>
|
||||
<string name="label_inserted">投入済み</string>
|
||||
<string name="label_not_inserted">未投入</string>
|
||||
<string name="please_insert_cash">硬貨または紙幣を投入してください</string>
|
||||
<string name="cancel_and_refund">キャンセルして返金</string>
|
||||
<string name="retry_refund">返金を再試行</string>
|
||||
<string name="hint_title">お知らせ!</string>
|
||||
<string name="device_initializing">機器を初期化中です。お待ちください...</string>
|
||||
<string name="go_to_cabinet_format">%1$s番の扉から商品をお取りください</string>
|
||||
<string name="confirm_taken_format">受取確認(%1$d秒)</string>
|
||||
</resources>
|
||||
|
||||
@ -126,6 +126,9 @@
|
||||
<!-- ui/recycler/RecyclerDialogDispatchListAdpter.java -->
|
||||
<string name="shipped">已出貨</string>
|
||||
<string name="shipping">出貨中</string>
|
||||
<string name="shipped_quantity_format">已出貨數量(%1$d / %2$d)</string>
|
||||
<string name="shipping_count_format">出貨中(%1$d件)</string>
|
||||
<string name="shipping_all">出貨中(All)</string>
|
||||
<string name="waiting">等待中</string>
|
||||
<!-- ui/recycler/RecyclerProductSearchAdpter.java -->
|
||||
<string name="click_on_product">點選商品</string>
|
||||
@ -182,6 +185,7 @@
|
||||
<string name="unified_number">統一編號</string>
|
||||
<string name="phone_number">電話號碼</string>
|
||||
<string name="donation_invoice">捐贈發票</string>
|
||||
<string name="donation_invoice_next">捐贈發票/下一步</string>
|
||||
<string name="input_complete">輸入完成</string>
|
||||
<!-- dialog_dispatch.xml -->
|
||||
<string name="shipping_goods">出貨商品</string>
|
||||
@ -302,6 +306,18 @@
|
||||
<string name="product_delivery_issues_contact_the_counter_window">商品出貨問題,請洽櫃台窗口!</string>
|
||||
<string name="abnormal_reminder">異常提醒</string>
|
||||
<string name="there_is_something_at_the_pickup_port">取貨口有東西,請先取出</string>
|
||||
<string name="pickup_door_not_closed">取貨口門未正常關閉,請先確認門已關好。</string>
|
||||
<string name="pickup_elevator_not_home">升降梯未回到原點,請洽服務人員處理。</string>
|
||||
<string name="pickup_status_confirming">正在確認取貨口狀態,請稍候 1~2 秒再點選一次。</string>
|
||||
<string name="pickup_checking">取貨口檢查中......</string>
|
||||
<string name="enter_pickup_code_or_scan">請輸入取貨碼 或 掃描QRCode</string>
|
||||
<string name="tap_card_hint">請感應卡片</string>
|
||||
<string name="cancel_seconds_format">取消 %1$d秒</string>
|
||||
<string name="verifying_card">正在驗證卡片...</string>
|
||||
<string name="product_expired_not_for_sale">商品已過效期,暫不販售</string>
|
||||
<string name="unsupported_discount_type">不支援的折扣類型</string>
|
||||
<string name="confirm_product_correct">請確認您的商品是否正確</string>
|
||||
<string name="dispatch_quantity_format">出貨數量:%1$d件</string>
|
||||
<string name="i_knew">知道了</string>
|
||||
<string name="input_vehicle">輸入載具</string>
|
||||
<string name="member_card_pickup_title">員工卡支付</string>
|
||||
@ -348,4 +364,67 @@
|
||||
<string name="please_go_to_cabinet_to_pick_up_goods">請至99號櫃門拿取您的商品</string>
|
||||
<string name="confirm_goods_taken_hardcoded">確認已取貨(15秒)</string>
|
||||
<string name="system_inspection_in_progress">機器巡檢中請稍後</string>
|
||||
|
||||
<!-- ===== i18n 補齊:銷售/商品詳情/購物車/支付/發票流程 硬編字改資源 (2026-07) ===== -->
|
||||
<string name="slot_label">貨道</string>
|
||||
<string name="stock_label">庫存</string>
|
||||
<string name="close">關閉</string>
|
||||
<string name="product_description">商品描述</string>
|
||||
<string name="subtotal">金額小計</string>
|
||||
<string name="add_to_shopping_cart">加入購物車</string>
|
||||
<string name="buy_now">直接購買</string>
|
||||
<string name="payment_amount">付款金額</string>
|
||||
<string name="product_label">商品</string>
|
||||
<string name="stock_pieces_format">庫存%1$02d件</string>
|
||||
<string name="select_payment_method">請選擇支付方式</string>
|
||||
<string name="credit_card">信用卡</string>
|
||||
<string name="e_ticket">電子票證</string>
|
||||
<string name="phone_nfc">手機NFC</string>
|
||||
<string name="qr_pay_esun">掃碼支付-玉山</string>
|
||||
<string name="qr_pay_tappay">掃碼支付-TapPay</string>
|
||||
<string name="line_pay">Line Pay 支付</string>
|
||||
<string name="select_invoice_type">請選擇發票開立方式</string>
|
||||
<string name="company_tax_id">公司統編</string>
|
||||
<string name="select_charity">請選擇捐贈機構</string>
|
||||
<string name="back_to_payment">返回支付方式</string>
|
||||
<string name="back_to_invoice">返回發票選擇</string>
|
||||
<string name="enter_company_tax_id">輸入公司統編</string>
|
||||
<string name="next_step">下一步</string>
|
||||
<string name="confirm">確認</string>
|
||||
<string name="tax_id_min_8">統一編號長度不能少於 8 碼</string>
|
||||
<string name="phone_min_10">電話號碼長度不能少於 10 碼</string>
|
||||
<string name="enter_phone_number">輸入電話號碼</string>
|
||||
<!-- ===== i18n 補齊 batch2:支付對話框/出貨/碼輸入/員工卡/取貨成功 (2026-07) ===== -->
|
||||
<string name="change_payment_method">修改支付方式</string>
|
||||
<string name="cancel_payment">取消支付</string>
|
||||
<string name="align_barcode_to_scanner">請將付款條碼對準掃描器</string>
|
||||
<string name="tap_card_to_reader">請將卡片靠近感應區</string>
|
||||
<string name="generating_qrcode">QRCode產生中,請等待片刻</string>
|
||||
<string name="card_reader_cannot_open">刷卡機無法開啟</string>
|
||||
<string name="reading_transaction">交易讀取中,請將卡片/手機停留片刻,\n勿快速移動,系統完成後會自動返回。</string>
|
||||
<string name="dispensing_product">商品出貨中</string>
|
||||
<string name="close_after_seconds">(%1$ds)後關閉</string>
|
||||
<string name="keyboard_input">鍵盤輸入</string>
|
||||
<string name="scan_barcode">掃描條碼</string>
|
||||
<string name="verifying">驗證中…</string>
|
||||
<string name="pickup_code_min_8">取貨碼長度不能少於 8 碼</string>
|
||||
<string name="passcode_min_8">通行碼長度不能少於 8 碼</string>
|
||||
<string name="gift_code_min_8">來店禮代碼需 8 碼</string>
|
||||
<string name="enter_pickup_code">請輸入取貨碼</string>
|
||||
<string name="pickup_code_not_enabled">取貨碼功能未開放</string>
|
||||
<string name="passcode_not_enabled">通行碼功能未開放</string>
|
||||
<string name="gift_not_enabled">來店禮功能未開放</string>
|
||||
<string name="no_payment_needed">無需付款</string>
|
||||
<string name="card_number_info">卡號資訊:</string>
|
||||
<string name="product_sold_out_reselect">商品已售罄,請重新選擇</string>
|
||||
<string name="waiting_for_tap">交易狀態:等待感應</string>
|
||||
<string name="label_inserted">已投入</string>
|
||||
<string name="label_not_inserted">未投入</string>
|
||||
<string name="please_insert_cash">請投入硬幣或紙鈔</string>
|
||||
<string name="cancel_and_refund">取消並退幣</string>
|
||||
<string name="retry_refund">嘗試退鈔並重試</string>
|
||||
<string name="hint_title">提示!</string>
|
||||
<string name="device_initializing">設備初始化中,請稍候...</string>
|
||||
<string name="go_to_cabinet_format">請至%1$s號櫃門拿取您的商品</string>
|
||||
<string name="confirm_taken_format">確認已取貨(%1$d秒)</string>
|
||||
</resources>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user