implement menu debit dan qris

This commit is contained in:
riz081 2025-05-30 19:27:43 +07:00
parent 459d9ab0f1
commit 2a24016637
5 changed files with 819 additions and 13 deletions

View File

@ -33,7 +33,6 @@
<activity
android:name=".PaymentActivity"
android:exported="false" />
<activity android:name=".QrisResultActivity" />
<activity
android:name=".PinActivity"
android:screenOrientation="portrait"
@ -42,6 +41,10 @@
<activity
android:name=".ReceiptActivity"
android:exported="false" />
<activity
android:name=".QrisActivity"
android:exported="false" />
<activity android:name=".QrisResultActivity" />
</application>
</manifest>

View File

@ -86,11 +86,11 @@ public class MainActivity extends AppCompatActivity {
if (cardId == R.id.card_kartu_kredit) {
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_kartu_debit) {
Toast.makeText(this, "Kartu Debit Diklik", Toast.LENGTH_SHORT).show();
startActivity(new Intent(MainActivity.this, PaymentActivity.class));
} else if (cardId == R.id.card_qris) {
startActivity(new Intent(MainActivity.this, TransactionActivity.class));
startActivity(new Intent(MainActivity.this, QrisActivity.class));
} else if (cardId == R.id.card_bantuan) {
Toast.makeText(this, "Bantuan Diklik", Toast.LENGTH_SHORT).show();
startActivity(new Intent(MainActivity.this, TransactionActivity.class));
} else if (cardId == R.id.card_info_toko) {
Toast.makeText(this, "Info Toko Diklik", Toast.LENGTH_SHORT).show();
} else {

View File

@ -0,0 +1,557 @@
package com.example.bdkipoc;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Random;
import java.util.UUID;
public class QrisActivity extends AppCompatActivity {
private ProgressBar progressBar;
private Button initiatePaymentButton;
private Button simulatePaymentButton;
private ImageView qrCodeImageView;
private TextView statusTextView;
private EditText editTextAmount;
private TextView referenceIdTextView;
private View paymentDetailsLayout;
private View paymentSuccessLayout;
private Button returnToMainButton;
private String transactionId;
private String transactionUuid;
private String referenceId;
private int amount;
private JSONObject midtransResponse;
private static final String BACKEND_BASE = "https://be-edc.msvc.app";
private static final String MIDTRANS_CHARGE_URL = "https://api.sandbox.midtrans.com/v2/charge";
private static final String MIDTRANS_AUTH = "Basic U0ItTWlkLXNlcnZlci1JM2RJWXdIRzVuamVMeHJCMVZ5endWMUM="; // Replace with your actual key
private static final String WEBHOOK_URL = "https://be-edc.msvc.app/webhooks/midtrans";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qris);
// Set up the toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setTitle("QRIS Payment");
}
// Initialize views
progressBar = findViewById(R.id.progressBar);
initiatePaymentButton = findViewById(R.id.initiatePaymentButton);
simulatePaymentButton = findViewById(R.id.simulatePaymentButton);
qrCodeImageView = findViewById(R.id.qrCodeImageView);
statusTextView = findViewById(R.id.statusTextView);
editTextAmount = findViewById(R.id.editTextAmount);
referenceIdTextView = findViewById(R.id.referenceIdTextView);
paymentDetailsLayout = findViewById(R.id.paymentDetailsLayout);
paymentSuccessLayout = findViewById(R.id.paymentSuccessLayout);
returnToMainButton = findViewById(R.id.returnToMainButton);
// Generate a random amount between 100,000 and 999,999
amount = new Random().nextInt(900000) + 100000;
// Format and display the amount
editTextAmount.setText("");
editTextAmount.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(editTextAmount, InputMethodManager.SHOW_IMPLICIT);
}
// Generate reference ID
referenceId = "ref-" + generateRandomString(8);
referenceIdTextView.setText(referenceId);
// Set up click listeners
initiatePaymentButton.setOnClickListener(v -> createTransaction());
simulatePaymentButton.setOnClickListener(v -> simulateWebhook());
returnToMainButton.setOnClickListener(v -> finish());
// Initially hide the QR code and payment success views
paymentDetailsLayout.setVisibility(View.GONE);
paymentSuccessLayout.setVisibility(View.GONE);
simulatePaymentButton.setVisibility(View.GONE);
}
private void createTransaction() {
progressBar.setVisibility(View.VISIBLE);
initiatePaymentButton.setEnabled(false);
statusTextView.setText("Creating transaction...");
new CreateTransactionTask().execute();
}
private void displayQrCode(String qrImageUrl) {
new DownloadImageTask().execute(qrImageUrl);
}
private void simulateWebhook() {
progressBar.setVisibility(View.VISIBLE);
simulatePaymentButton.setEnabled(false);
statusTextView.setText("Processing payment...");
new SimulateWebhookTask().execute();
}
private void showSuccessScreen() {
paymentDetailsLayout.setVisibility(View.GONE);
paymentSuccessLayout.setVisibility(View.VISIBLE);
statusTextView.setText("Payment successful!");
progressBar.setVisibility(View.GONE);
}
private String generateRandomString(int length) {
String chars = "abcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder sb = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
int index = random.nextInt(chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
private String getServerKey() {
// MIDTRANS_AUTH = 'Basic base64string'
String base64 = MIDTRANS_AUTH.replace("Basic ", "");
String decoded = android.util.Base64.decode(base64, android.util.Base64.DEFAULT).toString();
// Format is usually 'SB-Mid-server-xxxx:'. Remove trailing colon if present.
return decoded.replace(":\n", "");
}
private String generateSignature(String orderId, String statusCode, String grossAmount, String serverKey) {
String input = orderId + statusCode + grossAmount + serverKey;
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-512");
byte[] messageDigest = md.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (java.security.NoSuchAlgorithmException e) {
return "";
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private class CreateTransactionTask extends AsyncTask<Void, Void, Boolean> {
private String errorMessage;
@Override
protected Boolean doInBackground(Void... voids) {
try {
// Generate a UUID for the transaction
transactionUuid = UUID.randomUUID().toString();
// Create transaction JSON payload
JSONObject payload = new JSONObject();
payload.put("type", "PAYMENT");
payload.put("channel_category", "RETAIL_OUTLET");
payload.put("channel_code", "QRIS");
payload.put("reference_id", referenceId);
// Read amount from EditText and log it
String amountText = editTextAmount.getText().toString().trim();
Log.d("MidtransCharge", "Raw amount text: " + amountText);
try {
// Parse amount - expecting integer in lowest denomination (Indonesian Rupiah)
amount = Integer.parseInt(amountText);
Log.d("MidtransCharge", "Parsed amount: " + amount);
} catch (NumberFormatException e) {
Log.e("MidtransCharge", "Amount parsing error: " + e.getMessage());
errorMessage = "Invalid amount format";
return false;
}
payload.put("amount", amount);
payload.put("cashflow", "MONEY_IN");
payload.put("status", "INIT");
payload.put("device_id", 1);
payload.put("transaction_uuid", transactionUuid);
payload.put("transaction_time_seconds", 0.0);
payload.put("device_code", "PB4K252T00021");
payload.put("merchant_name", "Marcel Panjaitan");
payload.put("mid", "71000026521");
payload.put("tid", "73001500");
// Make the API call
URL url = new URI(BACKEND_BASE + "/transactions").toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
// Read the response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// Parse the response to get transaction ID
JSONObject jsonResponse = new JSONObject(response.toString());
JSONObject data = jsonResponse.getJSONObject("data");
transactionId = String.valueOf(data.getInt("id"));
// Now generate QRIS via Midtrans
return generateQris(amount);
} else {
// Read error response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
errorMessage = "Error creating transaction: " + response.toString();
return false;
}
} catch (Exception e) {
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
errorMessage = "Unexpected error: " + e.getMessage();
return false;
}
}
private boolean generateQris(int amount) {
try {
// Create QRIS charge JSON payload
JSONObject payload = new JSONObject();
payload.put("payment_type", "qris");
JSONObject transactionDetails = new JSONObject();
transactionDetails.put("order_id", transactionUuid);
transactionDetails.put("gross_amount", amount);
payload.put("transaction_details", transactionDetails);
// Log the request details
Log.d("MidtransCharge", "URL: " + MIDTRANS_CHARGE_URL);
Log.d("MidtransCharge", "Authorization: " + MIDTRANS_AUTH);
Log.d("MidtransCharge", "Accept: application/json");
Log.d("MidtransCharge", "Content-Type: application/json");
Log.d("MidtransCharge", "X-Override-Notification: " + WEBHOOK_URL);
Log.d("MidtransCharge", "Payload: " + payload.toString());
// Make the API call to Midtrans
URL url = new URI(MIDTRANS_CHARGE_URL).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", MIDTRANS_AUTH);
conn.setRequestProperty("X-Override-Notification", WEBHOOK_URL);
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
InputStream inputStream = conn.getInputStream();
if (inputStream != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// Parse the response
midtransResponse = new JSONObject(response.toString());
return true;
} else {
Log.e("MidtransCharge", "HTTP " + responseCode + ": No input stream available");
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No input stream available";
return false;
}
} else {
InputStream errorStream = conn.getErrorStream();
if (errorStream != null) {
BufferedReader br = new BufferedReader(new InputStreamReader(errorStream, "utf-8"));
StringBuilder errorResponse = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
errorResponse.append(responseLine.trim());
}
Log.e("MidtransCharge", "HTTP " + responseCode + ": " + errorResponse.toString());
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": " + errorResponse.toString();
} else {
Log.e("MidtransCharge", "HTTP " + responseCode + ": No error stream available");
errorMessage = "Error generating QRIS: HTTP " + responseCode + ": No error stream available";
}
return false;
}
} catch (Exception e) {
Log.e("MidtransCharge", "Exception: " + e.getMessage(), e);
errorMessage = "Unexpected error: " + e.getMessage();
return false;
}
}
@Override
protected void onPostExecute(Boolean success) {
if (success && midtransResponse != null) {
try {
// Extract needed values from midtransResponse
JSONObject actions = midtransResponse.getJSONArray("actions").getJSONObject(0);
String qrImageUrl = actions.getString("url");
// Extract transaction_id
String transactionId = midtransResponse.getString("transaction_id");
String transactionTime = midtransResponse.getString("transaction_time");
String acquirer = midtransResponse.getString("acquirer");
String merchantId = midtransResponse.getString("merchant_id");
String exactGrossAmount = midtransResponse.getString("gross_amount");
// Log everything before launching activity
Log.d("MidtransCharge", "Creating QrisResultActivity intent with:");
Log.d("MidtransCharge", "qrImageUrl: " + qrImageUrl);
Log.d("MidtransCharge", "amount: " + amount);
Log.d("MidtransCharge", "referenceId: " + referenceId);
Log.d("MidtransCharge", "transactionUuid (orderId): " + transactionUuid);
Log.d("MidtransCharge", "transaction_id: " + transactionId);
Log.d("MidtransCharge", "exactGrossAmount: " + exactGrossAmount);
// Instead of showing QR inline, launch QrisResultActivity
Intent intent = new Intent(QrisActivity.this, QrisResultActivity.class);
intent.putExtra("qrImageUrl", qrImageUrl);
intent.putExtra("amount", amount);
intent.putExtra("referenceId", referenceId);
intent.putExtra("orderId", transactionUuid); // Order ID
intent.putExtra("transactionId", transactionId); // Actual Midtrans transaction_id
intent.putExtra("grossAmount", exactGrossAmount); // Exact gross amount from response
intent.putExtra("transactionTime", transactionTime); // For timestamp
intent.putExtra("acquirer", acquirer);
intent.putExtra("merchantId", merchantId);
try {
startActivity(intent);
} catch (Exception e) {
Log.e("MidtransCharge", "Failed to start QrisResultActivity: " + e.getMessage(), e);
Toast.makeText(QrisActivity.this, "Error launching QR display: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
return;
} catch (JSONException e) {
Log.e("MidtransCharge", "QRIS response JSON error: " + e.getMessage(), e);
Toast.makeText(QrisActivity.this, "Error processing QRIS response", Toast.LENGTH_LONG).show();
}
} else {
String message = (errorMessage != null && !errorMessage.isEmpty()) ? errorMessage : "Unknown error occurred. Please check Logcat for details.";
Toast.makeText(QrisActivity.this, message, Toast.LENGTH_LONG).show();
initiatePaymentButton.setEnabled(true);
}
progressBar.setVisibility(View.GONE);
}
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... urls) {
String urlDisplay = urls[0];
Bitmap bitmap = null;
try {
URL url = new URI(urlDisplay).toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
java.io.InputStream input = connection.getInputStream();
bitmap = android.graphics.BitmapFactory.decodeStream(input);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
qrCodeImageView.setImageBitmap(result);
} else {
Toast.makeText(QrisActivity.this, "Error loading QR code image", Toast.LENGTH_LONG).show();
}
}
}
private class SimulateWebhookTask extends AsyncTask<Void, Void, Boolean> {
private String errorMessage;
@Override
protected Boolean doInBackground(Void... voids) {
try {
// Wait a moment to simulate real-world timing
Thread.sleep(1500);
// Get server key and prepare signature
String serverKey = getServerKey();
String grossAmount = String.valueOf(amount) + ".00";
String signatureKey = generateSignature(
transactionUuid,
"200",
grossAmount,
serverKey
);
// Create webhook payload
JSONObject payload = new JSONObject();
payload.put("transaction_type", "on-us");
payload.put("transaction_time", midtransResponse.getString("transaction_time"));
payload.put("transaction_status", "settlement");
payload.put("transaction_id", midtransResponse.getString("transaction_id"));
payload.put("status_message", "midtrans payment notification");
payload.put("status_code", "200");
payload.put("signature_key", signatureKey);
payload.put("settlement_time", midtransResponse.getString("transaction_time"));
payload.put("payment_type", "qris");
payload.put("order_id", transactionUuid);
payload.put("merchant_id", midtransResponse.getString("merchant_id"));
payload.put("issuer", midtransResponse.getString("acquirer"));
payload.put("gross_amount", grossAmount);
payload.put("fraud_status", "accept");
payload.put("currency", "IDR");
payload.put("acquirer", midtransResponse.getString("acquirer"));
payload.put("shopeepay_reference_number", "");
payload.put("reference_id", referenceId);
// Call the webhook URL
URL url = new URI(WEBHOOK_URL).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
byte[] input = payload.toString().getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
if (responseCode == 200 || responseCode == 201) {
// Wait briefly to allow the backend to process
Thread.sleep(2000);
return checkTransactionStatus();
} else {
// Read error response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
errorMessage = "Error simulating payment: " + response.toString();
return false;
}
} catch (Exception e) {
errorMessage = "Error: " + e.getMessage();
return false;
}
}
private boolean checkTransactionStatus() {
try {
// Check transaction status
URL url = new URI(BACKEND_BASE + "/transactions/" + transactionId).toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
// Read the response
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// Parse the response
JSONObject jsonResponse = new JSONObject(response.toString());
JSONObject data = jsonResponse.getJSONObject("data");
String status = data.getString("status");
return status.equalsIgnoreCase("SUCCESS");
} else {
errorMessage = "Error checking transaction status. HTTP response code: " + responseCode;
return false;
}
} catch (Exception e) {
errorMessage = "Error checking transaction status: " + e.getMessage();
return false;
}
}
@Override
protected void onPostExecute(Boolean success) {
if (success) {
showSuccessScreen();
} else {
String message = (errorMessage != null && !errorMessage.isEmpty()) ? errorMessage : "Unknown error occurred. Please check Logcat for details.";
Toast.makeText(QrisActivity.this, message, Toast.LENGTH_LONG).show();
simulatePaymentButton.setEnabled(true);
}
progressBar.setVisibility(View.GONE);
}
}
}

View File

@ -95,10 +95,10 @@ public class ReceiptActivity extends AppCompatActivity {
}
private void setupClickListeners() {
// Back navigation
backNavigation.setOnClickListener(v -> navigateBack());
backArrow.setOnClickListener(v -> navigateBack());
toolbarTitle.setOnClickListener(v -> navigateBack());
// Back navigation - Goes back to previous activity (PaymentActivity)
backNavigation.setOnClickListener(v -> navigateBackToPrevious());
backArrow.setOnClickListener(v -> navigateBackToPrevious());
toolbarTitle.setOnClickListener(v -> navigateBackToPrevious());
// Action buttons
printButton.setOnClickListener(v -> handlePrintReceipt());
@ -191,24 +191,43 @@ public class ReceiptActivity extends AppCompatActivity {
}
private void handleFinish() {
// Finish and return to main screen
navigateBack();
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
navigateToHomePage();
}
private void navigateBack() {
// You can navigate back to main activity or finish
private void navigateBackToPrevious() {
// Navigate back to PaymentActivity (previous activity)
Intent intent = new Intent(this, PaymentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
}
private void navigateToHomePage() {
// Navigate to MainActivity/Home Page when "Selesai" button is pressed
Intent intent = new Intent(this, MainActivity.class);
// Clear all previous activities from the stack and start fresh
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
// Optional: Add success message to show in MainActivity
intent.putExtra("transaction_completed", true);
intent.putExtra("transaction_amount", getIntent().getStringExtra("transaction_amount"));
startActivity(intent);
finish();
// Show success message
showToast("Transaksi berhasil diselesaikan!");
}
private void showToast(String message) {
android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
navigateBack();
// Back button behavior - goes back to previous activity
navigateBackToPrevious();
}
}

View File

@ -0,0 +1,227 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:title="QRIS Payment" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone" />
<TextView
android:id="@+id/statusTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="Ready to make a payment"
android:textSize="18sp" />
<!-- Initial Payment Form -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardBackgroundColor="@color/light_blue"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Amount"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
<EditText
android:id="@+id/editTextAmount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="Enter amount"
android:inputType="number"
android:maxLength="12"
android:importantForAutofill="no"
android:singleLine="true"
android:textColor="@color/primary_blue"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="end" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Reference ID"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
<TextView
android:id="@+id/referenceIdTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="ref-abcd1234"
android:textColor="@color/primary_blue"
android:textSize="16sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/initiatePaymentButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary_blue"
android:text="Start Payment" />
</LinearLayout>
<!-- QR Code and Payment Details -->
<LinearLayout
android:id="@+id/paymentDetailsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:id="@+id/qrCodeImageView"
android:layout_width="250dp"
android:layout_height="250dp"
android:contentDescription="QRIS Code"
android:scaleType="fitCenter" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Scan with your banking app or e-wallet to pay"
android:textSize="14sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/simulatePaymentButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/accent_green"
android:text="Confirm Payment" />
</LinearLayout>
<!-- Payment Success -->
<LinearLayout
android:id="@+id/paymentSuccessLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:cardBackgroundColor="@color/light_gray"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:contentDescription="Success Icon"
android:src="@android:drawable/ic_dialog_info"
android:tint="@color/accent_green" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Payment Successful!"
android:textColor="@color/accent_green"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="Your transaction has been completed successfully."
android:textSize="14sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<Button
android:id="@+id/returnToMainButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:backgroundTint="@color/primary_blue"
android:text="Return to Main" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>