UI Kartu Kredit
This commit is contained in:
		
							parent
							
								
									a07e7a99ac
								
							
						
					
					
						commit
						a7fa40d60a
					
				@ -1,557 +1,372 @@
 | 
				
			|||||||
package com.example.bdkipoc;
 | 
					package com.example.bdkipoc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.content.Context;
 | 
					import android.animation.AnimatorSet;
 | 
				
			||||||
 | 
					import android.animation.ObjectAnimator;
 | 
				
			||||||
import android.content.Intent;
 | 
					import android.content.Intent;
 | 
				
			||||||
import android.graphics.Bitmap;
 | 
					import android.graphics.Color;
 | 
				
			||||||
import android.os.AsyncTask;
 | 
					import android.os.Build;
 | 
				
			||||||
import android.os.Bundle;
 | 
					import android.os.Bundle;
 | 
				
			||||||
import android.util.Log;
 | 
					import android.os.Handler;
 | 
				
			||||||
import android.view.MenuItem;
 | 
					import android.os.Looper;
 | 
				
			||||||
 | 
					import android.text.TextUtils;
 | 
				
			||||||
import android.view.View;
 | 
					import android.view.View;
 | 
				
			||||||
import android.view.inputmethod.InputMethodManager;
 | 
					import android.view.Window;
 | 
				
			||||||
 | 
					import android.view.WindowManager;
 | 
				
			||||||
 | 
					import android.view.animation.AccelerateDecelerateInterpolator;
 | 
				
			||||||
import android.widget.Button;
 | 
					import android.widget.Button;
 | 
				
			||||||
import android.widget.EditText;
 | 
					import android.widget.EditText;
 | 
				
			||||||
import android.widget.ImageView;
 | 
					import android.widget.ImageView;
 | 
				
			||||||
import android.widget.ProgressBar;
 | 
					import android.widget.LinearLayout;
 | 
				
			||||||
import android.widget.TextView;
 | 
					import android.widget.TextView;
 | 
				
			||||||
import android.widget.Toast;
 | 
					import android.widget.Toast;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import androidx.annotation.Nullable;
 | 
					 | 
				
			||||||
import androidx.appcompat.app.AppCompatActivity;
 | 
					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 PaymentActivity extends AppCompatActivity {
 | 
					public class PaymentActivity extends AppCompatActivity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ProgressBar progressBar;
 | 
					    // Views
 | 
				
			||||||
    private Button initiatePaymentButton;
 | 
					 | 
				
			||||||
    private Button simulatePaymentButton;
 | 
					 | 
				
			||||||
    private ImageView qrCodeImageView;
 | 
					 | 
				
			||||||
    private TextView statusTextView;
 | 
					 | 
				
			||||||
    private EditText editTextAmount;
 | 
					    private EditText editTextAmount;
 | 
				
			||||||
    private TextView referenceIdTextView;
 | 
					    private Button confirmButton;
 | 
				
			||||||
    private View paymentDetailsLayout;
 | 
					    private LinearLayout backNavigation;
 | 
				
			||||||
    private View paymentSuccessLayout;
 | 
					    private ImageView backArrow;
 | 
				
			||||||
    private Button returnToMainButton;
 | 
					    private TextView toolbarTitle;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private String transactionId;
 | 
					    // Numpad buttons
 | 
				
			||||||
    private String transactionUuid;
 | 
					    private TextView btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn000;
 | 
				
			||||||
    private String referenceId;
 | 
					    private ImageView btnDelete;
 | 
				
			||||||
    private int amount;
 | 
					 | 
				
			||||||
    private JSONObject midtransResponse;
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    private static final String BACKEND_BASE = "https://be-edc.msvc.app";
 | 
					    // Data
 | 
				
			||||||
    private static final String MIDTRANS_CHARGE_URL = "https://api.sandbox.midtrans.com/v2/charge";
 | 
					    private StringBuilder currentAmount = new StringBuilder();
 | 
				
			||||||
    private static final String MIDTRANS_AUTH = "Basic U0ItTWlkLXNlcnZlci1JM2RJWXdIRzVuamVMeHJCMVZ5endWMUM="; // Replace with your actual key
 | 
					    private static final int MAX_AMOUNT_LENGTH = 12;
 | 
				
			||||||
    private static final String WEBHOOK_URL = "https://be-edc.msvc.app/webhooks/midtrans";
 | 
					    
 | 
				
			||||||
 | 
					    // Animation
 | 
				
			||||||
 | 
					    private Handler animationHandler = new Handler(Looper.getMainLooper());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onCreate(@Nullable Bundle savedInstanceState) {
 | 
					    protected void onCreate(Bundle savedInstanceState) {
 | 
				
			||||||
        super.onCreate(savedInstanceState);
 | 
					        super.onCreate(savedInstanceState);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Set status bar color programmatically
 | 
				
			||||||
 | 
					        setStatusBarColor();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        setContentView(R.layout.activity_payment);
 | 
					        setContentView(R.layout.activity_payment);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Set up the toolbar
 | 
					        initializeViews();
 | 
				
			||||||
        Toolbar toolbar = findViewById(R.id.toolbar);
 | 
					        setupClickListeners();
 | 
				
			||||||
        setSupportActionBar(toolbar);
 | 
					        setupInitialStates();
 | 
				
			||||||
        if (getSupportActionBar() != null) {
 | 
					        // REMOVED: addAnimations() - No more card sliding animation
 | 
				
			||||||
            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() {
 | 
					    private void setStatusBarColor() {
 | 
				
			||||||
        progressBar.setVisibility(View.VISIBLE);
 | 
					        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 | 
				
			||||||
        initiatePaymentButton.setEnabled(false);
 | 
					            Window window = getWindow();
 | 
				
			||||||
        statusTextView.setText("Creating transaction...");
 | 
					            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
 | 
				
			||||||
 | 
					            window.setStatusBarColor(Color.parseColor("#E31937")); // Red color
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        new CreateTransactionTask().execute();
 | 
					            // Make status bar icons white (for dark red background)
 | 
				
			||||||
    }
 | 
					            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
				
			||||||
 | 
					                View decorView = window.getDecorView();
 | 
				
			||||||
    private void displayQrCode(String qrImageUrl) {
 | 
					                decorView.setSystemUiVisibility(0); // Clear light status bar flag
 | 
				
			||||||
        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) {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void initializeViews() {
 | 
				
			||||||
 | 
					        // Main views
 | 
				
			||||||
 | 
					        editTextAmount = findViewById(R.id.editTextAmount);
 | 
				
			||||||
 | 
					        confirmButton = findViewById(R.id.confirmButton);
 | 
				
			||||||
 | 
					        backNavigation = findViewById(R.id.back_navigation);
 | 
				
			||||||
 | 
					        backArrow = findViewById(R.id.backArrow);
 | 
				
			||||||
 | 
					        toolbarTitle = findViewById(R.id.toolbarTitle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Numpad buttons
 | 
				
			||||||
 | 
					        btn1 = findViewById(R.id.btn1);
 | 
				
			||||||
 | 
					        btn2 = findViewById(R.id.btn2);
 | 
				
			||||||
 | 
					        btn3 = findViewById(R.id.btn3);
 | 
				
			||||||
 | 
					        btn4 = findViewById(R.id.btn4);
 | 
				
			||||||
 | 
					        btn5 = findViewById(R.id.btn5);
 | 
				
			||||||
 | 
					        btn6 = findViewById(R.id.btn6);
 | 
				
			||||||
 | 
					        btn7 = findViewById(R.id.btn7);
 | 
				
			||||||
 | 
					        btn8 = findViewById(R.id.btn8);
 | 
				
			||||||
 | 
					        btn9 = findViewById(R.id.btn9);
 | 
				
			||||||
 | 
					        btn0 = findViewById(R.id.btn0);
 | 
				
			||||||
 | 
					        btn000 = findViewById(R.id.btn000);
 | 
				
			||||||
 | 
					        btnDelete = findViewById(R.id.btnDelete);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void setupClickListeners() {
 | 
				
			||||||
 | 
					        // Back navigation - entire LinearLayout is clickable
 | 
				
			||||||
 | 
					        backNavigation.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					            addClickAnimation(v);
 | 
				
			||||||
 | 
					            navigateBack();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Individual back arrow (for additional touch area)
 | 
				
			||||||
 | 
					        backArrow.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					            addClickAnimation(v);
 | 
				
			||||||
 | 
					            navigateBack();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Toolbar title (also clickable for back navigation)
 | 
				
			||||||
 | 
					        toolbarTitle.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					            addClickAnimation(v);
 | 
				
			||||||
 | 
					            navigateBack();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Numpad listeners
 | 
				
			||||||
 | 
					        btn1.setOnClickListener(v -> handleNumpadClick(v, "1"));
 | 
				
			||||||
 | 
					        btn2.setOnClickListener(v -> handleNumpadClick(v, "2"));
 | 
				
			||||||
 | 
					        btn3.setOnClickListener(v -> handleNumpadClick(v, "3"));
 | 
				
			||||||
 | 
					        btn4.setOnClickListener(v -> handleNumpadClick(v, "4"));
 | 
				
			||||||
 | 
					        btn5.setOnClickListener(v -> handleNumpadClick(v, "5"));
 | 
				
			||||||
 | 
					        btn6.setOnClickListener(v -> handleNumpadClick(v, "6"));
 | 
				
			||||||
 | 
					        btn7.setOnClickListener(v -> handleNumpadClick(v, "7"));
 | 
				
			||||||
 | 
					        btn8.setOnClickListener(v -> handleNumpadClick(v, "8"));
 | 
				
			||||||
 | 
					        btn9.setOnClickListener(v -> handleNumpadClick(v, "9"));
 | 
				
			||||||
 | 
					        btn0.setOnClickListener(v -> handleNumpadClick(v, "0"));
 | 
				
			||||||
 | 
					        btn000.setOnClickListener(v -> handleNumpadClick(v, "000"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delete button
 | 
				
			||||||
 | 
					        btnDelete.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					            addClickAnimation(v);
 | 
				
			||||||
 | 
					            deleteLastDigit();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Confirm button
 | 
				
			||||||
 | 
					        confirmButton.setOnClickListener(v -> {
 | 
				
			||||||
 | 
					            if (confirmButton.isEnabled()) {
 | 
				
			||||||
 | 
					                addButtonClickAnimation(v);
 | 
				
			||||||
 | 
					                handleConfirmPayment();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void navigateBack() {
 | 
				
			||||||
 | 
					        // Simple back navigation without card animation
 | 
				
			||||||
 | 
					        finish();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleNumpadClick(View view, String digit) {
 | 
				
			||||||
 | 
					        addClickAnimation(view);
 | 
				
			||||||
 | 
					        addDigit(digit);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void setupInitialStates() {
 | 
				
			||||||
 | 
					        // Set initial amount display
 | 
				
			||||||
 | 
					        editTextAmount.setText("");
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Set initial button state
 | 
				
			||||||
 | 
					        updateButtonState();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Disable EditText input (only numpad input allowed)
 | 
				
			||||||
 | 
					        editTextAmount.setFocusable(false);
 | 
				
			||||||
 | 
					        editTextAmount.setClickable(false);
 | 
				
			||||||
 | 
					        editTextAmount.setCursorVisible(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // REMOVED: addAnimations() method - No card sliding animation on startup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addDigit(String digit) {
 | 
				
			||||||
 | 
					        // Validate input length
 | 
				
			||||||
 | 
					        if (currentAmount.length() >= MAX_AMOUNT_LENGTH) {
 | 
				
			||||||
 | 
					            showToast("Maksimal " + MAX_AMOUNT_LENGTH + " digit");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Handle leading zeros
 | 
				
			||||||
 | 
					        if (currentAmount.length() == 0) {
 | 
				
			||||||
 | 
					            if (digit.equals("000")) {
 | 
				
			||||||
 | 
					                // Don't allow 000 as first input
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            currentAmount.append(digit);
 | 
				
			||||||
 | 
					        } else if (currentAmount.length() == 1 && currentAmount.toString().equals("0")) {
 | 
				
			||||||
 | 
					            if (!digit.equals("000")) {
 | 
				
			||||||
 | 
					                // Replace single 0 with new digit
 | 
				
			||||||
 | 
					                currentAmount = new StringBuilder(digit);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            currentAmount.append(digit);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        updateAmountDisplay();
 | 
				
			||||||
 | 
					        updateButtonState();
 | 
				
			||||||
 | 
					        addInputFeedback();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void deleteLastDigit() {
 | 
				
			||||||
 | 
					        if (currentAmount.length() > 0) {
 | 
				
			||||||
 | 
					            String current = currentAmount.toString();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // If current ends with 000, remove all three digits
 | 
				
			||||||
 | 
					            if (current.endsWith("000") && current.length() >= 3) {
 | 
				
			||||||
 | 
					                currentAmount.delete(currentAmount.length() - 3, currentAmount.length());
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                currentAmount.deleteCharAt(currentAmount.length() - 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            updateAmountDisplay();
 | 
				
			||||||
 | 
					            updateButtonState();
 | 
				
			||||||
 | 
					            addDeleteFeedback();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void updateAmountDisplay() {
 | 
				
			||||||
 | 
					        String amount = currentAmount.toString();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (amount.isEmpty() || amount.equals("0")) {
 | 
				
			||||||
 | 
					            editTextAmount.setText("");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            String formattedAmount = formatCurrency(amount);
 | 
				
			||||||
 | 
					            editTextAmount.setText(formattedAmount);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String formatCurrency(String amount) {
 | 
				
			||||||
 | 
					        if (TextUtils.isEmpty(amount) || amount.equals("0")) {
 | 
				
			||||||
            return "";
 | 
					            return "";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            long number = Long.parseLong(amount);
 | 
				
			||||||
 | 
					            return String.format("%,d", number).replace(',', '.');
 | 
				
			||||||
 | 
					        } catch (NumberFormatException e) {
 | 
				
			||||||
 | 
					            return amount;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void updateButtonState() {
 | 
				
			||||||
 | 
					        boolean hasValidAmount = currentAmount.length() > 0 && 
 | 
				
			||||||
 | 
					                                !currentAmount.toString().equals("0") &&
 | 
				
			||||||
 | 
					                                !currentAmount.toString().isEmpty();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        confirmButton.setEnabled(hasValidAmount);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (hasValidAmount) {
 | 
				
			||||||
 | 
					            // Active state
 | 
				
			||||||
 | 
					            confirmButton.setBackgroundResource(R.drawable.button_active_background);
 | 
				
			||||||
 | 
					            confirmButton.setTextColor(Color.WHITE);
 | 
				
			||||||
 | 
					            confirmButton.setAlpha(1.0f);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // Inactive state
 | 
				
			||||||
 | 
					            confirmButton.setBackgroundResource(R.drawable.button_inactive_background);
 | 
				
			||||||
 | 
					            confirmButton.setTextColor(Color.parseColor("#999999"));
 | 
				
			||||||
 | 
					            confirmButton.setAlpha(0.6f);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void handleConfirmPayment() {
 | 
				
			||||||
 | 
					        String amount = currentAmount.toString();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (TextUtils.isEmpty(amount) || amount.equals("0")) {
 | 
				
			||||||
 | 
					            showToast("Masukkan jumlah pembayaran");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            long amountValue = Long.parseLong(amount);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Validate minimum amount
 | 
				
			||||||
 | 
					            if (amountValue < 1000) {
 | 
				
			||||||
 | 
					                showToast("Minimal pembayaran Rp 1.000");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Validate maximum amount
 | 
				
			||||||
 | 
					            if (amountValue > 999999999L) {
 | 
				
			||||||
 | 
					                showToast("Maksimal pembayaran Rp 999.999.999");
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Process payment
 | 
				
			||||||
 | 
					            processPayment(amountValue);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        } catch (NumberFormatException e) {
 | 
				
			||||||
 | 
					            showToast("Format jumlah tidak valid");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void processPayment(long amount) {
 | 
				
			||||||
 | 
					        // Show loading state
 | 
				
			||||||
 | 
					        confirmButton.setText("Memproses...");
 | 
				
			||||||
 | 
					        confirmButton.setEnabled(false);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // Simulate payment processing
 | 
				
			||||||
 | 
					        animationHandler.postDelayed(() -> {
 | 
				
			||||||
 | 
					            // Show success message
 | 
				
			||||||
 | 
					            showToast("Pembayaran berhasil! Jumlah: Rp " + formatCurrency(String.valueOf(amount)));
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            // Reset state and go back
 | 
				
			||||||
 | 
					            resetPaymentState();
 | 
				
			||||||
 | 
					            navigateBack();
 | 
				
			||||||
 | 
					        }, 2000);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void resetPaymentState() {
 | 
				
			||||||
 | 
					        currentAmount = new StringBuilder();
 | 
				
			||||||
 | 
					        updateAmountDisplay();
 | 
				
			||||||
 | 
					        updateButtonState();
 | 
				
			||||||
 | 
					        confirmButton.setText("Konfirmasi");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Animation methods (only for numpad interactions)
 | 
				
			||||||
 | 
					    private void addClickAnimation(View view) {
 | 
				
			||||||
 | 
					        ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.95f, 1f);
 | 
				
			||||||
 | 
					        ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.95f, 1f);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        AnimatorSet animatorSet = new AnimatorSet();
 | 
				
			||||||
 | 
					        animatorSet.playTogether(scaleX, scaleY);
 | 
				
			||||||
 | 
					        animatorSet.setDuration(150);
 | 
				
			||||||
 | 
					        animatorSet.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addButtonClickAnimation(View view) {
 | 
				
			||||||
 | 
					        ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.98f, 1f);
 | 
				
			||||||
 | 
					        ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.98f, 1f);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        AnimatorSet animatorSet = new AnimatorSet();
 | 
				
			||||||
 | 
					        animatorSet.playTogether(scaleX, scaleY);
 | 
				
			||||||
 | 
					        animatorSet.setDuration(200);
 | 
				
			||||||
 | 
					        animatorSet.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addInputFeedback() {
 | 
				
			||||||
 | 
					        ObjectAnimator fadeIn = ObjectAnimator.ofFloat(editTextAmount, "alpha", 0.7f, 1f);
 | 
				
			||||||
 | 
					        fadeIn.setDuration(200);
 | 
				
			||||||
 | 
					        fadeIn.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private void addDeleteFeedback() {
 | 
				
			||||||
 | 
					        ObjectAnimator shake = ObjectAnimator.ofFloat(editTextAmount, "translationX", 0f, -10f, 10f, 0f);
 | 
				
			||||||
 | 
					        shake.setDuration(300);
 | 
				
			||||||
 | 
					        shake.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Utility methods
 | 
				
			||||||
 | 
					    private void showToast(String message) {
 | 
				
			||||||
 | 
					        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
					    public void onBackPressed() {
 | 
				
			||||||
        if (item.getItemId() == android.R.id.home) {
 | 
					        navigateBack();
 | 
				
			||||||
            finish();
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return super.onOptionsItemSelected(item);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private class CreateTransactionTask extends AsyncTask<Void, Void, Boolean> {
 | 
					    @Override
 | 
				
			||||||
        private String errorMessage;
 | 
					    protected void onDestroy() {
 | 
				
			||||||
        
 | 
					        super.onDestroy();
 | 
				
			||||||
        @Override
 | 
					        if (animationHandler != null) {
 | 
				
			||||||
        protected Boolean doInBackground(Void... voids) {
 | 
					            animationHandler.removeCallbacksAndMessages(null);
 | 
				
			||||||
            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(PaymentActivity.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(PaymentActivity.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(PaymentActivity.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(PaymentActivity.this, message, Toast.LENGTH_LONG).show();
 | 
					 | 
				
			||||||
                initiatePaymentButton.setEnabled(true);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            progressBar.setVisibility(View.GONE);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
 | 
					    // Public methods for testing
 | 
				
			||||||
        @Override
 | 
					    public String getCurrentAmount() {
 | 
				
			||||||
        protected Bitmap doInBackground(String... urls) {
 | 
					        return currentAmount.toString();
 | 
				
			||||||
            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(PaymentActivity.this, "Error loading QR code image", Toast.LENGTH_LONG).show();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private class SimulateWebhookTask extends AsyncTask<Void, Void, Boolean> {
 | 
					    public boolean isConfirmButtonEnabled() {
 | 
				
			||||||
        private String errorMessage;
 | 
					        return confirmButton.isEnabled();
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        @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(PaymentActivity.this, message, Toast.LENGTH_LONG).show();
 | 
					 | 
				
			||||||
                simulatePaymentButton.setEnabled(true);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            progressBar.setVisibility(View.GONE);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								app/src/main/res/anim/fade_in.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								app/src/main/res/anim/fade_in.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<alpha xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:duration="300"
 | 
				
			||||||
 | 
					    android:fromAlpha="0.0"
 | 
				
			||||||
 | 
					    android:toAlpha="1.0" />
 | 
				
			||||||
							
								
								
									
										4
									
								
								app/src/main/res/anim/fade_out.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								app/src/main/res/anim/fade_out.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<alpha xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:duration="300"
 | 
				
			||||||
 | 
					    android:fromAlpha="1.0"
 | 
				
			||||||
 | 
					    android:toAlpha="0.0" />
 | 
				
			||||||
							
								
								
									
										14
									
								
								app/src/main/res/anim/scale_in.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/src/main/res/anim/scale_in.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <scale
 | 
				
			||||||
 | 
					        android:duration="200"
 | 
				
			||||||
 | 
					        android:fromXScale="0.8"
 | 
				
			||||||
 | 
					        android:fromYScale="0.8"
 | 
				
			||||||
 | 
					        android:pivotX="50%"
 | 
				
			||||||
 | 
					        android:pivotY="50%"
 | 
				
			||||||
 | 
					        android:toXScale="1.0"
 | 
				
			||||||
 | 
					        android:toYScale="1.0" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="200"
 | 
				
			||||||
 | 
					        android:fromAlpha="0.0"
 | 
				
			||||||
 | 
					        android:toAlpha="1.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										14
									
								
								app/src/main/res/anim/scale_out.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/src/main/res/anim/scale_out.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <scale
 | 
				
			||||||
 | 
					        android:duration="200"
 | 
				
			||||||
 | 
					        android:fromXScale="1.0"
 | 
				
			||||||
 | 
					        android:fromYScale="1.0"
 | 
				
			||||||
 | 
					        android:pivotX="50%"
 | 
				
			||||||
 | 
					        android:pivotY="50%"
 | 
				
			||||||
 | 
					        android:toXScale="0.8"
 | 
				
			||||||
 | 
					        android:toYScale="0.8" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="200"
 | 
				
			||||||
 | 
					        android:fromAlpha="1.0"
 | 
				
			||||||
 | 
					        android:toAlpha="0.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										10
									
								
								app/src/main/res/anim/slide_in_left.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/anim/slide_in_left.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <translate
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromXDelta="-100%p"
 | 
				
			||||||
 | 
					        android:toXDelta="0" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromAlpha="0.0"
 | 
				
			||||||
 | 
					        android:toAlpha="1.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										10
									
								
								app/src/main/res/anim/slide_in_right.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/anim/slide_in_right.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <translate
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromXDelta="100%p"
 | 
				
			||||||
 | 
					        android:toXDelta="0" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromAlpha="0.0"
 | 
				
			||||||
 | 
					        android:toAlpha="1.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										10
									
								
								app/src/main/res/anim/slide_out_left.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/anim/slide_out_left.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <translate
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromXDelta="0"
 | 
				
			||||||
 | 
					        android:toXDelta="-100%p" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromAlpha="1.0"
 | 
				
			||||||
 | 
					        android:toAlpha="0.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										10
									
								
								app/src/main/res/anim/slide_out_right.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/anim/slide_out_right.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<set xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <translate
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromXDelta="0"
 | 
				
			||||||
 | 
					        android:toXDelta="100%p" />
 | 
				
			||||||
 | 
					    <alpha
 | 
				
			||||||
 | 
					        android:duration="300"
 | 
				
			||||||
 | 
					        android:fromAlpha="1.0"
 | 
				
			||||||
 | 
					        android:toAlpha="0.0" />
 | 
				
			||||||
 | 
					</set>
 | 
				
			||||||
							
								
								
									
										6
									
								
								app/src/main/res/drawable/button_active_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/res/drawable/button_active_background.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:shape="rectangle">
 | 
				
			||||||
 | 
					    <solid android:color="#DE0701" />
 | 
				
			||||||
 | 
					    <corners android:radius="8dp" />
 | 
				
			||||||
 | 
					</shape>
 | 
				
			||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/button_background_selector.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/button_background_selector.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<selector xmlns:android="http://schemas.android.com/apk/res/android">
 | 
				
			||||||
 | 
					    <item android:drawable="@drawable/button_active_background" android:state_enabled="true"/>
 | 
				
			||||||
 | 
					    <item android:drawable="@drawable/button_inactive_background" android:state_enabled="false"/>
 | 
				
			||||||
 | 
					</selector>
 | 
				
			||||||
							
								
								
									
										6
									
								
								app/src/main/res/drawable/button_inactive_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/res/drawable/button_inactive_background.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:shape="rectangle">
 | 
				
			||||||
 | 
					    <solid android:color="#ECEFF0" />
 | 
				
			||||||
 | 
					    <corners android:radius="8dp" />
 | 
				
			||||||
 | 
					</shape>
 | 
				
			||||||
							
								
								
									
										6
									
								
								app/src/main/res/drawable/card_background.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/src/main/res/drawable/card_background.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<shape xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:shape="rectangle">
 | 
				
			||||||
 | 
					    <solid android:color="#3498DB" />
 | 
				
			||||||
 | 
					    <corners android:radius="12dp" />
 | 
				
			||||||
 | 
					    <stroke android:width="0dp" />
 | 
				
			||||||
 | 
					</shape>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								app/src/main/res/drawable/ic_arrow_back.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/src/main/res/drawable/ic_arrow_back.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 220 B  | 
							
								
								
									
										10
									
								
								app/src/main/res/drawable/ic_backspace.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/src/main/res/drawable/ic_backspace.xml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					<!-- res/drawable/icons/ic_backspace.xml -->
 | 
				
			||||||
 | 
					<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
 | 
					    android:width="24dp"
 | 
				
			||||||
 | 
					    android:height="24dp"
 | 
				
			||||||
 | 
					    android:viewportWidth="24"
 | 
				
			||||||
 | 
					    android:viewportHeight="24">
 | 
				
			||||||
 | 
					    <path
 | 
				
			||||||
 | 
					        android:fillColor="#333333"
 | 
				
			||||||
 | 
					        android:pathData="M22,3H7c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.9,0.89 1.59,0.89h15c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zM19,15.59L17.59,17 14,13.41 10.41,17 9,15.59 12.59,12 9,8.41 10.41,7 14,10.59 17.59,7 19,8.41 15.41,12 19,15.59z"/>
 | 
				
			||||||
 | 
					</vector>
 | 
				
			||||||
@ -1,227 +1,268 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
					<ScrollView
 | 
				
			||||||
 | 
					    xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
					    xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
				
			||||||
 | 
					    xmlns:tools="http://schemas.android.com/tools"
 | 
				
			||||||
    android:layout_width="match_parent"
 | 
					    android:layout_width="match_parent"
 | 
				
			||||||
    android:layout_height="match_parent">
 | 
					    android:layout_height="match_parent"
 | 
				
			||||||
 | 
					    android:fillViewport="true"
 | 
				
			||||||
 | 
					    android:overScrollMode="never"
 | 
				
			||||||
 | 
					    android:scrollbars="none"
 | 
				
			||||||
 | 
					    android:background="#FFFFFF">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <com.google.android.material.appbar.AppBarLayout
 | 
					    <androidx.constraintlayout.widget.ConstraintLayout
 | 
				
			||||||
        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_width="match_parent"
 | 
				
			||||||
        android:layout_height="match_parent"
 | 
					        android:layout_height="match_parent"
 | 
				
			||||||
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
 | 
					        android:background="#FFFFFF"
 | 
				
			||||||
 | 
					        tools:context=".PaymentActivity">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <LinearLayout
 | 
					        <!-- Red Status Bar (Override purple) -->
 | 
				
			||||||
 | 
					        <View
 | 
				
			||||||
 | 
					            android:id="@+id/red_status_bar"
 | 
				
			||||||
            android:layout_width="match_parent"
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
            android:layout_height="match_parent"
 | 
					            android:layout_height="24dp"
 | 
				
			||||||
            android:orientation="vertical"
 | 
					            android:background="#E31937"
 | 
				
			||||||
            android:padding="16dp">
 | 
					            app:layout_constraintTop_toTopOf="parent"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ProgressBar
 | 
					        <!-- Red Background Header (Extended height untuk back navigation) -->
 | 
				
			||||||
                android:id="@+id/progressBar"
 | 
					        <View
 | 
				
			||||||
 | 
					            android:id="@+id/red_header_background"
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="160dp"
 | 
				
			||||||
 | 
					            android:background="#E31937"
 | 
				
			||||||
 | 
					            app:layout_constraintTop_toBottomOf="@id/red_status_bar"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Back Navigation (Positioned closer to status bar/appbar) -->
 | 
				
			||||||
 | 
					        <LinearLayout
 | 
				
			||||||
 | 
					            android:id="@+id/back_navigation"
 | 
				
			||||||
 | 
					            android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:orientation="horizontal"
 | 
				
			||||||
 | 
					            android:gravity="center_vertical"
 | 
				
			||||||
 | 
					            android:layout_marginStart="16dp"
 | 
				
			||||||
 | 
					            android:layout_marginBottom="5dp"
 | 
				
			||||||
 | 
					            android:background="?attr/selectableItemBackgroundBorderless"
 | 
				
			||||||
 | 
					            android:padding="8dp"
 | 
				
			||||||
 | 
					            app:layout_constraintStart_toStartOf="parent"
 | 
				
			||||||
 | 
					            app:layout_constraintTop_toBottomOf="@id/red_status_bar">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Back Arrow -->
 | 
				
			||||||
 | 
					            <ImageView
 | 
				
			||||||
 | 
					                android:id="@+id/backArrow"
 | 
				
			||||||
 | 
					                android:layout_width="16dp"
 | 
				
			||||||
 | 
					                android:layout_height="16dp"
 | 
				
			||||||
 | 
					                android:src="@drawable/ic_arrow_back"
 | 
				
			||||||
 | 
					                android:contentDescription="Back" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Title Text -->
 | 
				
			||||||
 | 
					            <TextView
 | 
				
			||||||
 | 
					                android:id="@+id/toolbarTitle"
 | 
				
			||||||
                android:layout_width="wrap_content"
 | 
					                android:layout_width="wrap_content"
 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					                android:layout_height="wrap_content"
 | 
				
			||||||
                android:layout_gravity="center_horizontal"
 | 
					                android:layout_marginStart="8dp"
 | 
				
			||||||
                android:visibility="gone" />
 | 
					                android:text="Kembali"
 | 
				
			||||||
 | 
					                android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					                android:textSize="12sp"
 | 
				
			||||||
 | 
					                android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					                android:textStyle="normal" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Payment Card -->
 | 
				
			||||||
 | 
					        <androidx.cardview.widget.CardView
 | 
				
			||||||
 | 
					            android:id="@+id/paymentCard"
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="191dp"
 | 
				
			||||||
 | 
					            android:layout_margin="16dp"
 | 
				
			||||||
 | 
					            android:layout_marginTop="5dp"
 | 
				
			||||||
 | 
					            app:cardBackgroundColor="#3498DB"
 | 
				
			||||||
 | 
					            app:cardCornerRadius="12dp"
 | 
				
			||||||
 | 
					            app:cardElevation="8dp"
 | 
				
			||||||
 | 
					            app:layout_constraintTop_toBottomOf="@id/back_navigation">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LinearLayout
 | 
				
			||||||
 | 
					                android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                android:layout_height="match_parent"
 | 
				
			||||||
 | 
					                android:orientation="vertical"
 | 
				
			||||||
 | 
					                android:padding="20dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Title -->
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:text="TOTAL PEMBAYARAN"
 | 
				
			||||||
 | 
					                    android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					                    android:textSize="16sp"
 | 
				
			||||||
 | 
					                    android:textStyle="bold"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="24dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Amount Input Section -->
 | 
				
			||||||
 | 
					                <LinearLayout
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:orientation="horizontal"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="8dp">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <TextView
 | 
				
			||||||
 | 
					                        android:layout_width="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:text="RP"
 | 
				
			||||||
 | 
					                        android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					                        android:textSize="20sp"
 | 
				
			||||||
 | 
					                        android:textStyle="bold"
 | 
				
			||||||
 | 
					                        android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					                        android:layout_marginEnd="8dp"
 | 
				
			||||||
 | 
					                        android:layout_gravity="bottom" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <EditText
 | 
				
			||||||
 | 
					                        android:id="@+id/editTextAmount"
 | 
				
			||||||
 | 
					                        android:layout_width="0dp"
 | 
				
			||||||
 | 
					                        android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                        android:layout_weight="1"
 | 
				
			||||||
 | 
					                        android:background="@android:color/transparent"
 | 
				
			||||||
 | 
					                        android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					                        android:textColorHint="#80FFFFFF"
 | 
				
			||||||
 | 
					                        android:textSize="20sp"
 | 
				
			||||||
 | 
					                        android:textStyle="bold"
 | 
				
			||||||
 | 
					                        android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					                        android:hint=""
 | 
				
			||||||
 | 
					                        android:inputType="none"
 | 
				
			||||||
 | 
					                        android:focusable="false"
 | 
				
			||||||
 | 
					                        android:clickable="false"
 | 
				
			||||||
 | 
					                        android:cursorVisible="false"
 | 
				
			||||||
 | 
					                        android:text=""
 | 
				
			||||||
 | 
					                        android:gravity="start"
 | 
				
			||||||
 | 
					                        android:paddingBottom="4dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- White Underline -->
 | 
				
			||||||
 | 
					                <View
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="2dp"
 | 
				
			||||||
 | 
					                    android:background="@android:color/white"
 | 
				
			||||||
 | 
					                    android:layout_marginBottom="16dp" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <!-- Description -->
 | 
				
			||||||
 | 
					                <TextView
 | 
				
			||||||
 | 
					                    android:layout_width="match_parent"
 | 
				
			||||||
 | 
					                    android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					                    android:text="Pastikan kembali nominal pembayaran pelanggan Anda"
 | 
				
			||||||
 | 
					                    android:textColor="@android:color/white"
 | 
				
			||||||
 | 
					                    android:textSize="12sp"
 | 
				
			||||||
 | 
					                    android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					                    android:alpha="0.9" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            </LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </androidx.cardview.widget.CardView>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Numpad -->
 | 
				
			||||||
 | 
					        <GridLayout
 | 
				
			||||||
 | 
					            android:id="@+id/numpad_grid"
 | 
				
			||||||
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
 | 
					            android:layout_height="wrap_content"
 | 
				
			||||||
 | 
					            android:columnCount="3"
 | 
				
			||||||
 | 
					            android:rowCount="4"
 | 
				
			||||||
 | 
					            android:layout_marginTop="24dp"
 | 
				
			||||||
 | 
					            android:layout_marginStart="16dp"
 | 
				
			||||||
 | 
					            android:layout_marginEnd="16dp"
 | 
				
			||||||
 | 
					            app:layout_constraintTop_toBottomOf="@id/paymentCard">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <!-- Row 1: 1, 2, 3 -->
 | 
				
			||||||
 | 
					            <TextView
 | 
				
			||||||
 | 
					                android:id="@+id/btn1"
 | 
				
			||||||
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
 | 
					                android:text="1" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <TextView
 | 
					            <TextView
 | 
				
			||||||
                android:id="@+id/statusTextView"
 | 
					                android:id="@+id/btn2"
 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					                android:text="2" />
 | 
				
			||||||
                android:layout_marginBottom="16dp"
 | 
					 | 
				
			||||||
                android:gravity="center"
 | 
					 | 
				
			||||||
                android:text="Ready to make a payment"
 | 
					 | 
				
			||||||
                android:textSize="18sp" />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <!-- Initial Payment Form -->
 | 
					            <TextView
 | 
				
			||||||
            <LinearLayout
 | 
					                android:id="@+id/btn3"
 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					                android:text="3" />
 | 
				
			||||||
                android:orientation="vertical">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <androidx.cardview.widget.CardView
 | 
					            <!-- Row 2: 4, 5, 6 -->
 | 
				
			||||||
                    android:layout_width="match_parent"
 | 
					            <TextView
 | 
				
			||||||
                    android:layout_height="wrap_content"
 | 
					                android:id="@+id/btn4"
 | 
				
			||||||
                    android:layout_margin="8dp"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                    app:cardBackgroundColor="@color/light_blue"
 | 
					                android:text="4" />
 | 
				
			||||||
                    app:cardCornerRadius="8dp"
 | 
					 | 
				
			||||||
                    app:cardElevation="4dp">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <LinearLayout
 | 
					            <TextView
 | 
				
			||||||
                        android:layout_width="match_parent"
 | 
					                android:id="@+id/btn5"
 | 
				
			||||||
                        android:layout_height="wrap_content"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                        android:orientation="vertical"
 | 
					                android:text="5" />
 | 
				
			||||||
                        android:padding="16dp">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <TextView
 | 
					            <TextView
 | 
				
			||||||
                            android:layout_width="wrap_content"
 | 
					                android:id="@+id/btn6"
 | 
				
			||||||
                            android:layout_height="wrap_content"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                            android:text="Amount"
 | 
					                android:text="6" />
 | 
				
			||||||
                            android:textColor="@color/primary_blue"
 | 
					 | 
				
			||||||
                            android:textSize="16sp" />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <EditText
 | 
					            <!-- Row 3: 7, 8, 9 -->
 | 
				
			||||||
                            android:id="@+id/editTextAmount"
 | 
					            <TextView
 | 
				
			||||||
                            android:layout_width="match_parent"
 | 
					                android:id="@+id/btn7"
 | 
				
			||||||
                            android:layout_height="wrap_content"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                            android:layout_marginTop="8dp"
 | 
					                android:text="7" />
 | 
				
			||||||
                            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
 | 
					            <TextView
 | 
				
			||||||
                            android:layout_width="wrap_content"
 | 
					                android:id="@+id/btn8"
 | 
				
			||||||
                            android:layout_height="wrap_content"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                            android:layout_marginTop="16dp"
 | 
					                android:text="8" />
 | 
				
			||||||
                            android:text="Reference ID"
 | 
					 | 
				
			||||||
                            android:textColor="@color/primary_blue"
 | 
					 | 
				
			||||||
                            android:textSize="16sp" />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <TextView
 | 
					            <TextView
 | 
				
			||||||
                            android:id="@+id/referenceIdTextView"
 | 
					                android:id="@+id/btn9"
 | 
				
			||||||
                            android:layout_width="match_parent"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                            android:layout_height="wrap_content"
 | 
					                android:text="9" />
 | 
				
			||||||
                            android:layout_marginTop="8dp"
 | 
					 | 
				
			||||||
                            android:text="ref-abcd1234"
 | 
					 | 
				
			||||||
                            android:textColor="@color/primary_blue"
 | 
					 | 
				
			||||||
                            android:textSize="16sp" />
 | 
					 | 
				
			||||||
                    </LinearLayout>
 | 
					 | 
				
			||||||
                </androidx.cardview.widget.CardView>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <Button
 | 
					            <!-- Row 4: 000, 0, Delete -->
 | 
				
			||||||
                    android:id="@+id/initiatePaymentButton"
 | 
					            <TextView
 | 
				
			||||||
                    android:layout_width="match_parent"
 | 
					                android:id="@+id/btn000"
 | 
				
			||||||
                    android:layout_height="wrap_content"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                    android:layout_margin="8dp"
 | 
					                android:text="000" />
 | 
				
			||||||
                    android:backgroundTint="@color/primary_blue"
 | 
					 | 
				
			||||||
                    android:text="Start Payment" />
 | 
					 | 
				
			||||||
            </LinearLayout>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <!-- QR Code and Payment Details -->
 | 
					            <TextView
 | 
				
			||||||
            <LinearLayout
 | 
					                android:id="@+id/btn0"
 | 
				
			||||||
                android:id="@+id/paymentDetailsLayout"
 | 
					                style="@style/NumpadButton"
 | 
				
			||||||
                android:layout_width="match_parent"
 | 
					                android:text="0" />
 | 
				
			||||||
                android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                android:orientation="vertical"
 | 
					 | 
				
			||||||
                android:visibility="gone">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <androidx.cardview.widget.CardView
 | 
					            <ImageView
 | 
				
			||||||
                    android:layout_width="match_parent"
 | 
					                android:id="@+id/btnDelete"
 | 
				
			||||||
                    android:layout_height="wrap_content"
 | 
					                android:layout_width="0dp"
 | 
				
			||||||
                    android:layout_margin="8dp"
 | 
					                android:layout_height="60dp"
 | 
				
			||||||
                    app:cardCornerRadius="8dp"
 | 
					                android:layout_columnWeight="1"
 | 
				
			||||||
                    app:cardElevation="4dp">
 | 
					                android:layout_margin="8dp"
 | 
				
			||||||
 | 
					                android:background="?attr/selectableItemBackgroundBorderless"
 | 
				
			||||||
 | 
					                android:src="@drawable/ic_backspace"
 | 
				
			||||||
 | 
					                android:scaleType="center"
 | 
				
			||||||
 | 
					                android:contentDescription="Delete" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <LinearLayout
 | 
					        </GridLayout>
 | 
				
			||||||
                        android:layout_width="match_parent"
 | 
					 | 
				
			||||||
                        android:layout_height="wrap_content"
 | 
					 | 
				
			||||||
                        android:gravity="center_horizontal"
 | 
					 | 
				
			||||||
                        android:orientation="vertical"
 | 
					 | 
				
			||||||
                        android:padding="16dp">
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <ImageView
 | 
					        <!-- Confirmation Button (UPDATED: Menggunakan MaterialButton) -->
 | 
				
			||||||
                            android:id="@+id/qrCodeImageView"
 | 
					        <com.google.android.material.button.MaterialButton
 | 
				
			||||||
                            android:layout_width="250dp"
 | 
					            android:id="@+id/confirmButton"
 | 
				
			||||||
                            android:layout_height="250dp"
 | 
					            android:layout_width="match_parent"
 | 
				
			||||||
                            android:contentDescription="QRIS Code"
 | 
					            android:layout_height="48dp"
 | 
				
			||||||
                            android:scaleType="fitCenter" />
 | 
					            android:text="Konfirmasi"
 | 
				
			||||||
 | 
					            android:textColor="#FFFFFF"
 | 
				
			||||||
 | 
					            android:textSize="16sp"
 | 
				
			||||||
 | 
					            android:textStyle="bold"
 | 
				
			||||||
 | 
					            android:fontFamily="@font/inter"
 | 
				
			||||||
 | 
					            android:layout_marginStart="16dp"
 | 
				
			||||||
 | 
					            android:layout_marginEnd="16dp"
 | 
				
			||||||
 | 
					            android:layout_marginTop="24dp"
 | 
				
			||||||
 | 
					            android:layout_marginBottom="24dp"
 | 
				
			||||||
 | 
					            android:enabled="false"
 | 
				
			||||||
 | 
					            app:backgroundTint="#DE0701"
 | 
				
			||||||
 | 
					            app:cornerRadius="8dp"
 | 
				
			||||||
 | 
					            app:rippleColor="#B3000000"
 | 
				
			||||||
 | 
					            app:layout_constraintTop_toBottomOf="@id/numpad_grid"
 | 
				
			||||||
 | 
					            app:layout_constraintBottom_toBottomOf="parent"
 | 
				
			||||||
 | 
					            app:layout_constraintVertical_bias="1" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <TextView
 | 
					    </androidx.constraintlayout.widget.ConstraintLayout>
 | 
				
			||||||
                            android:layout_width="match_parent"
 | 
					</ScrollView>
 | 
				
			||||||
                            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>
 | 
					 | 
				
			||||||
@ -1,12 +1,48 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<resources>
 | 
					<resources>
 | 
				
			||||||
 | 
					    <!-- Style yang sudah ada -->
 | 
				
			||||||
    <style name="MenuCardTitle">
 | 
					    <style name="MenuCardTitle">
 | 
				
			||||||
        <item name="fontFamily">@font/inter</item>
 | 
					        <item name="fontFamily">@font/inter</item>
 | 
				
			||||||
        <item name="android:textSize">12sp</item>
 | 
					        <item name="android:textSize">12sp</item>
 | 
				
			||||||
        <item name="android:textColor">#DD0701</item>
 | 
					        <item name="android:textColor">#DD0701</item>
 | 
				
			||||||
        <item name="android:textAlignment">center</item>
 | 
					        <item name="android:textAlignment">center</item>
 | 
				
			||||||
        <item name="android:lineHeight">12sp</item>
 | 
					        <item name="android:lineSpacingExtra">0dp</item>
 | 
				
			||||||
 | 
					        <item name="android:lineSpacingMultiplier">1.0</item>
 | 
				
			||||||
        <item name="android:letterSpacing">0</item>
 | 
					        <item name="android:letterSpacing">0</item>
 | 
				
			||||||
        <item name="android:textStyle">normal</item>
 | 
					        <item name="android:textStyle">normal</item>
 | 
				
			||||||
    </style>
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Style baru untuk Toolbar Title -->
 | 
				
			||||||
 | 
					    <style name="ToolbarTitleStyle">
 | 
				
			||||||
 | 
					        <item name="fontFamily">@font/inter</item>
 | 
				
			||||||
 | 
					        <item name="android:textSize">18sp</item>
 | 
				
			||||||
 | 
					        <item name="android:textStyle">bold</item>
 | 
				
			||||||
 | 
					        <item name="android:lineSpacingExtra">6dp</item>
 | 
				
			||||||
 | 
					        <item name="android:lineSpacingMultiplier">1.0</item>
 | 
				
			||||||
 | 
					        <item name="android:letterSpacing">0</item>
 | 
				
			||||||
 | 
					        <item name="android:textColor">@android:color/white</item>
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Custom Toolbar Theme -->
 | 
				
			||||||
 | 
					    <style name="CustomToolbarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
 | 
				
			||||||
 | 
					        <item name="android:textAppearance">@style/ToolbarTitleStyle</item>
 | 
				
			||||||
 | 
					        <item name="titleTextAppearance">@style/ToolbarTitleStyle</item>
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Numpad Button Style -->
 | 
				
			||||||
 | 
					    <style name="NumpadButton">
 | 
				
			||||||
 | 
					        <item name="android:layout_width">0dp</item>
 | 
				
			||||||
 | 
					        <item name="android:layout_height">60dp</item>
 | 
				
			||||||
 | 
					        <item name="android:layout_columnWeight">1</item>
 | 
				
			||||||
 | 
					        <item name="android:layout_margin">8dp</item>
 | 
				
			||||||
 | 
					        <item name="android:background">?attr/selectableItemBackgroundBorderless</item>
 | 
				
			||||||
 | 
					        <item name="android:textSize">28sp</item>
 | 
				
			||||||
 | 
					        <item name="android:textColor">#333333</item>
 | 
				
			||||||
 | 
					        <item name="android:textStyle">normal</item>
 | 
				
			||||||
 | 
					        <item name="android:fontFamily">@font/inter</item>
 | 
				
			||||||
 | 
					        <item name="android:gravity">center</item>
 | 
				
			||||||
 | 
					        <item name="android:clickable">true</item>
 | 
				
			||||||
 | 
					        <item name="android:focusable">true</item>
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</resources>
 | 
					</resources>
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user