Safepoint Modal Scan Card

This commit is contained in:
riz081 2025-06-23 09:20:26 +07:00
parent d43c4bad0c
commit f403358554
3 changed files with 149 additions and 286 deletions

View File

@ -8,7 +8,9 @@ import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.Button; import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -45,17 +47,15 @@ import java.util.regex.Pattern;
public class EmvTransactionActivity extends AppCompatActivity { public class EmvTransactionActivity extends AppCompatActivity {
private static final String TAG = "EmvTransaction"; private static final String TAG = "EmvTransaction";
// UI Components // UI Components - SIMPLIFIED
private TextView tvStatus; private TextView tvStatus;
private TextView tvAmountDisplay; private ProgressBar progressBar;
private Button btnAction; private ImageView ivCardReader;
private Button btnCancel;
// Transaction Data // Transaction Data
private String transactionAmount; private String transactionAmount;
private boolean isEMVMode; private boolean isEMVMode;
private boolean isProcessing = false; private boolean isProcessing = false;
private boolean isButtonProcessing = false; // ADD THIS MISSING FIELD
// EMV Components // EMV Components
private EMVOptV2 mEMVOptV2; private EMVOptV2 mEMVOptV2;
@ -197,8 +197,9 @@ public class EmvTransactionActivity extends AppCompatActivity {
} }
} }
// ====== UPDATED INIT VIEWS METHOD ======
private void initViews() { private void initViews() {
// Setup Toolbar // Setup Toolbar with back navigation
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
@ -206,13 +207,21 @@ public class EmvTransactionActivity extends AppCompatActivity {
getSupportActionBar().setTitle("Scan Kartu"); getSupportActionBar().setTitle("Scan Kartu");
} }
// Initialize UI components
tvStatus = findViewById(R.id.tv_status); tvStatus = findViewById(R.id.tv_status);
tvAmountDisplay = findViewById(R.id.tv_amount_display); progressBar = findViewById(R.id.progress_bar);
btnAction = findViewById(R.id.btn_action); ivCardReader = findViewById(R.id.iv_card_reader);
btnCancel = findViewById(R.id.btn_cancel);
btnAction.setOnClickListener(v -> handleActionClick()); // Set initial state
btnCancel.setOnClickListener(v -> finish()); updateStatusUI("Initializing scanner...", true);
}
// ====== NEW METHOD TO UPDATE STATUS UI ======
private void updateStatusUI(String statusText, boolean showProgress) {
runOnUiThread(() -> {
tvStatus.setText(statusText);
progressBar.setVisibility(showProgress ? View.VISIBLE : View.GONE);
});
} }
private void initEMVComponents() { private void initEMVComponents() {
@ -294,7 +303,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
} }
} }
// ====== AUTO-SCAN METHODS ====== // ====== UPDATED AUTO-START SCANNING METHOD ======
private void autoStartScanning() { private void autoStartScanning() {
Log.d(TAG, "Auto-starting card scanning..."); Log.d(TAG, "Auto-starting card scanning...");
@ -303,11 +312,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
return; return;
} }
runOnUiThread(() -> { updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card\n\nScanning will start automatically", true);
tvStatus.setText("Ready for card...\n\nPlease insert, swipe, or tap your card\n\nScanning will start automatically");
btnAction.setText("CANCEL");
btnAction.setEnabled(true);
});
// Start scanning automatically // Start scanning automatically
startCardCheck(); startCardCheck();
@ -324,87 +329,8 @@ public class EmvTransactionActivity extends AppCompatActivity {
}, 2000); // 2 second delay before restart }, 2000); // 2 second delay before restart
} }
// ====== CARD SCANNING METHODS ====== // ====== UPDATED CARD CHECK METHODS ======
private void updateUI() {
long amountCents = Long.parseLong(transactionAmount);
double amountRupiah = amountCents / 100.0;
NumberFormat formatter = NumberFormat.getCurrencyInstance(new Locale("id", "ID"));
String formattedAmount = formatter.format(amountRupiah);
tvAmountDisplay.setText("Nominal: " + formattedAmount);
String mode = isEMVMode ? "EMV Mode (Full Card Data)" : "Simple Mode (Basic Detection)";
String status = "Auto-scanning active...\n" +
"Mode: " + mode + "\n\n" +
"Please insert, swipe, or tap your card\n" +
"Processing will start automatically";
tvStatus.setText(status);
btnAction.setText("CANCEL");
}
private void handleActionClick() {
// Prevent multiple rapid clicks
if (isButtonProcessing) {
Log.d(TAG, "Button click ignored - already processing");
return;
}
isButtonProcessing = true;
Log.d(TAG, "handleActionClick - mProcessStep: " + mProcessStep + ", isProcessing: " + isProcessing);
// Reset button processing flag after delay
btnAction.postDelayed(() -> isButtonProcessing = false, 1000);
if (mProcessStep == 0) {
// Only handle cancel in auto-scan mode
if (isProcessing) {
cancelScanning();
} else {
// If not processing, this becomes cancel to go back
finish();
}
} else if (mProcessStep == EMV_CONFIRM_CARD_NO) {
android.util.Log.d(TAG, "User confirmed card number");
btnAction.setText("Processing...");
importCardNoStatus(0);
} else if (mProcessStep == EMV_CERT_VERIFY) {
android.util.Log.d(TAG, "User confirmed certificate");
btnAction.setText("Processing...");
importCertStatus(0);
}
}
private void cancelScanning() {
Log.d(TAG, "User cancelled scanning");
try {
// Cancel current operations
if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
MyApplication.app.readCardOptV2.cancelCheckCard();
}
// Reset EMV process
if (mEMVOptV2 != null) {
mEMVOptV2.initEmvProcess();
}
// Reset state
isProcessing = false;
mProcessStep = 0;
// Go back to previous activity
finish();
} catch (Exception e) {
Log.e(TAG, "Error cancelling scan: " + e.getMessage(), e);
finish();
}
}
private void startCardCheck() { private void startCardCheck() {
// Prevent multiple calls
if (isProcessing) { if (isProcessing) {
Log.d(TAG, "Card check already in progress - ignoring call"); Log.d(TAG, "Card check already in progress - ignoring call");
return; return;
@ -413,21 +339,15 @@ public class EmvTransactionActivity extends AppCompatActivity {
Log.d(TAG, "Starting auto card check - setting isProcessing = true"); Log.d(TAG, "Starting auto card check - setting isProcessing = true");
isProcessing = true; isProcessing = true;
runOnUiThread(() -> { updateStatusUI("Initializing scanner...\n\nPlease wait...", true);
tvStatus.setText("Initializing scanner...\n\nPlease wait...");
btnAction.setText("CANCEL");
btnAction.setEnabled(true);
});
try { try {
// Force EMV reset before any operation
if (mEMVOptV2 != null) { if (mEMVOptV2 != null) {
Log.d(TAG, "Forcing EMV reset before card check"); Log.d(TAG, "Forcing EMV reset before card check");
mEMVOptV2.initEmvProcess(); mEMVOptV2.initEmvProcess();
// Wait a bit before continuing
new Handler(Looper.getMainLooper()).postDelayed(() -> { new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (isProcessing && !isFinishing()) { // Double check we're still processing if (isProcessing && !isFinishing()) {
continueCardCheck(); continueCardCheck();
} }
}, 500); }, 500);
@ -451,12 +371,8 @@ public class EmvTransactionActivity extends AppCompatActivity {
return; return;
} }
runOnUiThread(() -> { String mode = isEMVMode ? "EMV Mode" : "Simple Mode";
String mode = isEMVMode ? "EMV Mode" : "Simple Mode"; updateStatusUI("Scanning for card...\n\nMode: " + mode + "\n\nPlease insert, swipe, or tap your card", true);
tvStatus.setText("Scanning for card...\n\nMode: " + mode + "\n\nPlease insert, swipe, or tap your card");
btnAction.setText("CANCEL");
btnAction.setEnabled(true);
});
if (isEMVMode) { if (isEMVMode) {
startEMVCardCheck(); startEMVCardCheck();
@ -470,21 +386,18 @@ public class EmvTransactionActivity extends AppCompatActivity {
} }
} }
// ====== UPDATED HANDLE SCAN ERROR ======
private void handleScanError(String errorMessage) { private void handleScanError(String errorMessage) {
Log.e(TAG, "Scan error: " + errorMessage); Log.e(TAG, "Scan error: " + errorMessage);
runOnUiThread(() -> { isProcessing = false;
isProcessing = false; mProcessStep = 0;
mProcessStep = 0;
updateStatusUI("Scan error: " + errorMessage + "\n\nRetrying in 2 seconds...", false);
tvStatus.setText("Scan error: " + errorMessage + "\n\nRetrying in 2 seconds..."); showToast(errorMessage);
btnAction.setText("CANCEL");
// Auto-restart scanning after error
showToast(errorMessage); restartAutoScanning();
// Auto-restart scanning after error
restartAutoScanning();
});
} }
private void startEMVCardCheck() { private void startEMVCardCheck() {
@ -497,7 +410,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
mEMVOptV2.initEmvProcess(); mEMVOptV2.initEmvProcess();
initEmvTlvData(); initEmvTlvData();
tvStatus.setText("EMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card"); updateStatusUI("EMV Mode: Starting card scan...\nPlease insert, swipe, or tap your card", true);
int cardType = AidlConstantsV2.CardType.NFC.getValue() | AidlConstantsV2.CardType.IC.getValue(); int cardType = AidlConstantsV2.CardType.NFC.getValue() | AidlConstantsV2.CardType.IC.getValue();
android.util.Log.d(TAG, "Starting EMV checkCard with cardType: " + cardType); android.util.Log.d(TAG, "Starting EMV checkCard with cardType: " + cardType);
@ -514,13 +427,13 @@ public class EmvTransactionActivity extends AppCompatActivity {
private void startSimpleCardCheck() { private void startSimpleCardCheck() {
try { try {
if (!MyApplication.app.isConnectPaySDK()) { if (!MyApplication.app.isConnectPaySDK()) {
tvStatus.setText("Connecting to PaySDK..."); updateStatusUI("Connecting to PaySDK...", true);
MyApplication.app.bindPaySDKService(); MyApplication.app.bindPaySDKService();
return; return;
} }
int cardType = CardType.MAGNETIC.getValue() | CardType.IC.getValue() | CardType.NFC.getValue(); int cardType = CardType.MAGNETIC.getValue() | CardType.IC.getValue() | CardType.NFC.getValue();
tvStatus.setText("Simple Mode: Starting card scan...\nPlease insert, swipe, or tap your card"); updateStatusUI("Simple Mode: Starting card scan...\nPlease insert, swipe, or tap your card", true);
MyApplication.app.readCardOptV2.checkCard(cardType, mSimpleCheckCardCallback, 60); MyApplication.app.readCardOptV2.checkCard(cardType, mSimpleCheckCardCallback, 60);
@ -536,8 +449,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
MyApplication.app.readCardOptV2.cancelCheckCard(); MyApplication.app.readCardOptV2.cancelCheckCard();
} }
isProcessing = false; isProcessing = false;
btnAction.setText("Start Scanning"); updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card", true);
updateUI();
} catch (Exception e) { } catch (Exception e) {
android.util.Log.e(TAG, "Error stopping card check: " + e.getMessage()); android.util.Log.e(TAG, "Error stopping card check: " + e.getMessage());
} }
@ -688,7 +600,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
} }
bundle.putInt("cardType", mCardType); bundle.putInt("cardType", mCardType);
tvStatus.setText("EMV processing started...\nReading card data..."); updateStatusUI("EMV processing started...\nReading card data...", true);
Log.d(TAG, "Starting transactProcessEx with reset EMV"); Log.d(TAG, "Starting transactProcessEx with reset EMV");
mEMVOptV2.transactProcessEx(bundle, mEMVListener); mEMVOptV2.transactProcessEx(bundle, mEMVListener);
@ -833,16 +745,16 @@ public class EmvTransactionActivity extends AppCompatActivity {
mAppSelectDialog.show(); mAppSelectDialog.show();
} }
// ====== UPDATED EMV DIALOG HANDLERS ======
private void showCardNumberConfirmation() { private void showCardNumberConfirmation() {
runOnUiThread(() -> { runOnUiThread(() -> {
String displayText = "Card Number: " + maskCardNumber(mCardNo) + String displayText = "Card Number Detected:\n" + maskCardNumber(mCardNo) +
"\n\nConfirming card number automatically..."; "\n\nConfirming automatically...";
tvStatus.setText(displayText); updateStatusUI(displayText, true);
// Auto-confirm after short delay to avoid manual interaction // Auto-confirm after short delay
btnAction.postDelayed(() -> { new Handler(Looper.getMainLooper()).postDelayed(() -> {
Log.d(TAG, "Auto-confirming card number"); Log.d(TAG, "Auto-confirming card number");
btnAction.setText("Processing...");
importCardNoStatus(0); importCardNoStatus(0);
}, 1500); }, 1500);
@ -852,14 +764,13 @@ public class EmvTransactionActivity extends AppCompatActivity {
private void showCertificateVerification() { private void showCertificateVerification() {
runOnUiThread(() -> { runOnUiThread(() -> {
String displayText = "Certificate Information:\n" + mCertInfo + String displayText = "Certificate Verification:\n" + mCertInfo +
"\n\nConfirming certificate automatically..."; "\n\nProcessing automatically...";
tvStatus.setText(displayText); updateStatusUI(displayText, true);
// Auto-confirm after short delay // Auto-confirm after short delay
btnAction.postDelayed(() -> { new Handler(Looper.getMainLooper()).postDelayed(() -> {
Log.d(TAG, "Auto-confirming certificate"); Log.d(TAG, "Auto-confirming certificate");
btnAction.setText("Processing...");
importCertStatus(0); importCertStatus(0);
}, 1500); }, 1500);
@ -867,7 +778,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
}); });
} }
// ====== PIN PAD METHODS ====== // ====== UPDATED PIN PAD METHODS ======
private void initPinPad() { private void initPinPad() {
android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION =========="); android.util.Log.e(TAG, "========== PIN PAD INITIALIZATION ==========");
try { try {
@ -882,7 +793,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
PinPadConfigV2 pinPadConfig = new PinPadConfigV2(); PinPadConfigV2 pinPadConfig = new PinPadConfigV2();
pinPadConfig.setPinPadType(0); pinPadConfig.setPinPadType(0);
pinPadConfig.setPinType(mPinType); pinPadConfig.setPinType(mPinType);
pinPadConfig.setOrderNumKey(false); pinPadConfig.setOrderNumKey(true);
String panForPin = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1); String panForPin = mCardNo.substring(mCardNo.length() - 13, mCardNo.length() - 1);
byte[] panBytes = panForPin.getBytes("US-ASCII"); byte[] panBytes = panForPin.getBytes("US-ASCII");
@ -895,11 +806,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
pinPadConfig.setKeySystem(0); pinPadConfig.setKeySystem(0);
pinPadConfig.setAlgorithmType(0); pinPadConfig.setAlgorithmType(0);
runOnUiThread(() -> { updateStatusUI("PIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device", true);
tvStatus.setText("PIN Input Required\n\nPIN pad is ready\nPlease enter your PIN on the device");
btnAction.setText("PIN Pad Active");
btnAction.setEnabled(false);
});
mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener); mPinPadOptV2.initPinPad(pinPadConfig, mPinPadListener);
@ -910,6 +817,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
} }
} }
// ====== UPDATED PIN PAD LISTENER ======
private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() { private final PinPadListenerV2 mPinPadListener = new PinPadListenerV2.Stub() {
@Override @Override
public void onPinLength(int len) throws RemoteException { public void onPinLength(int len) throws RemoteException {
@ -919,7 +827,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
dots += ""; dots += "";
} }
tvStatus.setText("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)"); updateStatusUI("PIN Input: " + dots + "\n\nEntering PIN... (" + len + " digits)", true);
}); });
} }
@ -928,9 +836,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
android.util.Log.d(TAG, "PIN input confirmed"); android.util.Log.d(TAG, "PIN input confirmed");
runOnUiThread(() -> { runOnUiThread(() -> {
btnAction.setEnabled(true); updateStatusUI("PIN confirmed, processing...", true);
btnAction.setText("Processing...");
tvStatus.setText("PIN confirmed, processing...");
}); });
if (pinBlock != null) { if (pinBlock != null) {
@ -948,9 +854,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
android.util.Log.d(TAG, "PIN input cancelled by user"); android.util.Log.d(TAG, "PIN input cancelled by user");
runOnUiThread(() -> { runOnUiThread(() -> {
btnAction.setEnabled(true); updateStatusUI("PIN input cancelled", false);
btnAction.setText("Start Scanning");
tvStatus.setText("PIN input cancelled");
}); });
mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget(); mHandler.obtainMessage(PIN_CLICK_CANCEL).sendToTarget();
@ -962,9 +866,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
String msg = AidlErrorCodeV2.valueOf(code).getMsg(); String msg = AidlErrorCodeV2.valueOf(code).getMsg();
runOnUiThread(() -> { runOnUiThread(() -> {
btnAction.setEnabled(true); updateStatusUI("PIN error: " + msg, false);
btnAction.setText("Start Scanning");
tvStatus.setText("PIN error: " + msg);
}); });
mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget(); mHandler.obtainMessage(PIN_ERROR, code, code, msg).sendToTarget();
@ -1001,7 +903,7 @@ public class EmvTransactionActivity extends AppCompatActivity {
isProcessing = false; isProcessing = false;
mProcessStep = 0; mProcessStep = 0;
tvStatus.setText("EMV reset complete\n\nRestarting auto-scan..."); updateStatusUI("EMV reset complete\n\nRestarting auto-scan...", true);
showToast("EMV reset - restarting scan"); showToast("EMV reset - restarting scan");
// Auto-restart scanning // Auto-restart scanning
@ -1017,17 +919,13 @@ public class EmvTransactionActivity extends AppCompatActivity {
}).start(); }).start();
} }
// ====== UPDATED RESET SCANNING STATE ======
private void resetScanningState() { private void resetScanningState() {
Log.d(TAG, "Resetting scanning state for auto-scan mode"); Log.d(TAG, "Resetting scanning state for auto-scan mode");
isProcessing = false; isProcessing = false;
isButtonProcessing = false;
mProcessStep = 0; mProcessStep = 0;
runOnUiThread(() -> { updateStatusUI("Ready for card...\n\nPlease insert, swipe, or tap your card", true);
btnAction.setText("CANCEL");
btnAction.setEnabled(true);
updateUI();
});
} }
// ====== HELPER METHODS ====== // ====== HELPER METHODS ======
@ -1041,10 +939,11 @@ public class EmvTransactionActivity extends AppCompatActivity {
finish(); finish();
} }
// ====== UPDATED MOCK ONLINE PROCESS ======
private void mockOnlineProcess() { private void mockOnlineProcess() {
new Thread(() -> { new Thread(() -> {
try { try {
runOnUiThread(() -> tvStatus.setText("Processing online authorization...")); runOnUiThread(() -> updateStatusUI("Processing online authorization...", true));
Thread.sleep(2000); Thread.sleep(2000);
try { try {
@ -1149,9 +1048,29 @@ public class EmvTransactionActivity extends AppCompatActivity {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
} }
// ====== UPDATED ON SUPPORT NAVIGATE UP ======
@Override @Override
public boolean onSupportNavigateUp() { public boolean onSupportNavigateUp() {
onBackPressed(); // Handle back button press - clean up and go back
try {
// Cancel any ongoing operations
if (MyApplication.app != null && MyApplication.app.readCardOptV2 != null) {
MyApplication.app.readCardOptV2.cancelCheckCard();
}
// Reset EMV process
if (mEMVOptV2 != null) {
mEMVOptV2.initEmvProcess();
}
isProcessing = false;
mProcessStep = 0;
} catch (Exception e) {
Log.e(TAG, "Error cleaning up on back press: " + e.getMessage());
}
finish();
return true; return true;
} }

View File

@ -1,4 +1,4 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android" <alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300" android:duration="300"
android:fromAlpha="0.0" android:fromAlpha="0.0"
android:toAlpha="1.0" /> android:toAlpha="1.0" />

View File

@ -17,147 +17,91 @@
android:theme="@style/CustomToolbarTheme" android:theme="@style/CustomToolbarTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<!-- Content Container --> <!-- Main Content Container with Center Alignment -->
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:padding="16dp"> android:gravity="center"
android:padding="24dp">
<!-- Amount Display Card --> <!-- Status Modal Card - Centered and Compact -->
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="24dp" android:layout_gravity="center"
app:cardCornerRadius="12dp" app:cardCornerRadius="16dp"
app:cardElevation="4dp" app:cardElevation="8dp"
app:cardBackgroundColor="@color/primary_blue"> app:cardBackgroundColor="@android:color/white">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="20dp"> android:padding="32dp"
android:gravity="center">
<!-- Header Title -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Card Scanner"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#2E3A47"
android:gravity="center"
android:fontFamily="@font/inter"
android:layout_marginBottom="24dp" />
<!-- Card Reader Animation/Icon -->
<ImageView <ImageView
android:id="@+id/iv_card_reader"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:layout_marginBottom="24dp"
android:src="@drawable/ic_card_insert"
android:scaleType="centerInside"
app:tint="@color/primary_blue" />
<!-- Status Text -->
<TextView
android:id="@+id/tv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Ready for card scanning..."
android:textSize="16sp"
android:textColor="#5A6C7D"
android:gravity="center"
android:lineSpacingExtra="4dp"
android:fontFamily="@font/inter"
android:layout_marginBottom="24dp" />
<!-- Progress Indicator -->
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginBottom="12dp" android:visibility="visible"
android:src="@drawable/ic_credit_card" android:indeterminateTint="@color/primary_blue"
app:tint="@android:color/white" /> android:layout_marginBottom="16dp" />
<!-- Instructions Text -->
<TextView <TextView
android:id="@+id/tv_amount_display"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Nominal: Rp 0,00" android:text="Please insert, tap, or swipe your card\nScanning will start automatically"
android:textSize="20sp" android:textSize="14sp"
android:textStyle="bold" android:textColor="#8A9BAE"
android:textColor="@color/white" android:gravity="center"
android:fontFamily="@font/inter" android:lineSpacingExtra="2dp"
android:gravity="center" /> android:fontFamily="@font/inter" />
</LinearLayout> </LinearLayout>
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<!-- Status Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginBottom="24dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Status Transaksi"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#333333"
android:gravity="center"
android:layout_marginBottom="16dp" />
<!-- Card Reader Animation/Icon -->
<ImageView
android:id="@+id/iv_card_reader"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_card_insert"
android:scaleType="centerInside"
app:tint="#666666" />
<!-- Auto-Scan Status Text -->
<TextView
android:id="@+id/tv_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Auto-scanning active..."
style="@style/StatusTextStyle"
android:layout_marginBottom="16dp" />
<!-- Progress Indicator (Initially Visible for Auto-Scan) -->
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:visibility="visible"
android:indeterminateTint="@color/primary_blue" />
</LinearLayout>
</ScrollView>
</androidx.cardview.widget.CardView>
<!-- Action Buttons -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="16dp">
<!-- Cancel Button (Primary Action) -->
<Button
android:id="@+id/btn_action"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="CANCEL"
style="@style/OutlineButton"
android:layout_marginBottom="12dp" />
<!-- Secondary Cancel Button -->
<Button
android:id="@+id/btn_cancel"
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="BACK TO AMOUNT"
style="@style/OutlineButton" />
</LinearLayout>
<!-- Auto-Scan Instructions -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="• Scanning starts automatically when you enter\n• Card will be detected and processed immediately\n• No need to press any buttons - just present your card"
style="@style/HintTextStyle" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>