diff --git a/app/src/main/java/com/example/bdkipoc/QrisResultActivity.java b/app/src/main/java/com/example/bdkipoc/QrisResultActivity.java index 1d7135f..c4d45c8 100644 --- a/app/src/main/java/com/example/bdkipoc/QrisResultActivity.java +++ b/app/src/main/java/com/example/bdkipoc/QrisResultActivity.java @@ -3,16 +3,23 @@ package com.example.bdkipoc; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Color; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; +import android.os.CountDownTimer; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; @@ -33,11 +40,23 @@ public class QrisResultActivity extends AppCompatActivity { private ImageView qrImageView; private TextView amountTextView; private TextView referenceTextView; + private TextView timerTextView; + private TextView qrStatusTextView; private Button downloadQrisButton; private Button checkStatusButton; + private Button cancelButton; private TextView statusTextView; private Button returnMainButton; private ProgressBar progressBar; + private LinearLayout backNavigation; + + // Timer and QR refresh + private CountDownTimer countDownTimer; + private long timeLeftInMillis = 60000; // 60 seconds + private int qrRefreshCount = 0; + private final int MAX_QR_REFRESH = 5; // Maximum 5 refreshes + + // Data variables private String orderId; private String grossAmount; private String referenceId; @@ -45,26 +64,102 @@ public class QrisResultActivity extends AppCompatActivity { private String transactionTime; private String acquirer; private String merchantId; + private String originalQrImageUrl; + private int amount; private String backendBase = "https://be-edc.msvc.app"; private String webhookUrl = "https://be-edc.msvc.app/webhooks/midtrans"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // Set status bar color programmatically + setStatusBarColor(); + setContentView(R.layout.activity_qris_result); + initializeViews(); + setupClickListeners(); + setupData(); + startTimer(); + } + + private void setStatusBarColor() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.parseColor("#E31937")); // Red color + + // Make status bar icons white (for dark red background) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + decorView.setSystemUiVisibility(0); // Clear light status bar flag + } + } + } + + private void initializeViews() { qrImageView = findViewById(R.id.qrImageView); amountTextView = findViewById(R.id.amountTextView); referenceTextView = findViewById(R.id.referenceTextView); + timerTextView = findViewById(R.id.timerTextView); + qrStatusTextView = findViewById(R.id.qrStatusTextView); downloadQrisButton = findViewById(R.id.downloadQrisButton); checkStatusButton = findViewById(R.id.checkStatusButton); + cancelButton = findViewById(R.id.cancelButton); statusTextView = findViewById(R.id.statusTextView); returnMainButton = findViewById(R.id.returnMainButton); progressBar = findViewById(R.id.progressBar); + backNavigation = findViewById(R.id.back_navigation); + } + private void setupClickListeners() { + // Back navigation + if (backNavigation != null) { + backNavigation.setOnClickListener(v -> finish()); + } + + // Cancel button + cancelButton.setOnClickListener(v -> { + if (countDownTimer != null) { + countDownTimer.cancel(); + } + finish(); + }); + + // Download QRIS button (now visible and functional) + downloadQrisButton.setOnClickListener(v -> { + qrImageView.setDrawingCacheEnabled(true); + Bitmap bitmap = qrImageView.getDrawingCache(); + if (bitmap != null) { + saveImageToGallery(bitmap, "qris_code_" + System.currentTimeMillis()); + } + qrImageView.setDrawingCacheEnabled(false); + }); + + // Check Payment Status button (now visible and functional) + checkStatusButton.setOnClickListener(v -> { + Toast.makeText(this, "Checking payment status...", Toast.LENGTH_SHORT).show(); + simulateWebhook(); + }); + + // Return to Main Screen button (now visible and functional) + returnMainButton.setOnClickListener(v -> { + if (countDownTimer != null) { + countDownTimer.cancel(); + } + Intent intent = new Intent(QrisResultActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finishAffinity(); + }); + } + + private void setupData() { Intent intent = getIntent(); String qrImageUrl = intent.getStringExtra("qrImageUrl"); - int amount = intent.getIntExtra("amount", 0); + originalQrImageUrl = qrImageUrl; // Store original URL for refresh + amount = intent.getIntExtra("amount", 0); referenceId = intent.getStringExtra("referenceId"); orderId = intent.getStringExtra("orderId"); grossAmount = intent.getStringExtra("grossAmount"); @@ -75,60 +170,131 @@ public class QrisResultActivity extends AppCompatActivity { if (orderId == null || transactionId == null) { Log.e("QrisResultFlow", "orderId or transactionId is null! Intent extras: " + intent.getExtras()); - android.widget.Toast.makeText(this, "Missing transaction details!", android.widget.Toast.LENGTH_LONG).show(); + Toast.makeText(this, "Missing transaction details!", Toast.LENGTH_LONG).show(); } - // Get the exact amount from the grossAmount string value instead of the integer - String amountStr = "Amount: " + grossAmount; - amountTextView.setText(amountStr); - referenceTextView.setText("Reference ID: " + referenceId); + // Format and display amount + if (grossAmount != null) { + String formattedAmount = "RP." + formatCurrency(grossAmount); + amountTextView.setText(formattedAmount); + } else if (amount > 0) { + String formattedAmount = "RP." + formatCurrency(String.valueOf(amount)); + amountTextView.setText(formattedAmount); + } - // Load QR image - new DownloadImageTask(qrImageView).execute(qrImageUrl); + // Set reference ID (hidden) + if (referenceId != null) { + referenceTextView.setText("Reference ID: " + referenceId); + } + + // Load initial QR image + if (qrImageUrl != null) { + loadQrCode(qrImageUrl); + } - // Disable check status button initially - checkStatusButton.setEnabled(false); // Start polling for pending payment log - pollPendingPaymentLog(orderId); + if (orderId != null) { + pollPendingPaymentLog(orderId); + } + } - // Download QRIS button - downloadQrisButton.setOnClickListener(new View.OnClickListener() { + private String formatCurrency(String amount) { + try { + long number = Long.parseLong(amount.replace(".00", "")); + return String.format("%,d", number).replace(',', '.'); + } catch (NumberFormatException e) { + return amount; + } + } + + private void startTimer() { + countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) { @Override - public void onClick(View v) { - qrImageView.setDrawingCacheEnabled(true); - Bitmap bitmap = qrImageView.getDrawingCache(); - if (bitmap != null) { - saveImageToGallery(bitmap, "qris_code_" + System.currentTimeMillis()); + public void onTick(long millisUntilFinished) { + timeLeftInMillis = millisUntilFinished; + int seconds = (int) (millisUntilFinished / 1000); + timerTextView.setText(String.valueOf(seconds)); + + // Update status text based on remaining time + if (seconds > 10) { + qrStatusTextView.setText("QR Code akan refresh dalam " + seconds + " detik"); + qrStatusTextView.setTextColor(Color.parseColor("#666666")); + } else { + qrStatusTextView.setText("QR Code akan refresh dalam " + seconds + " detik"); + qrStatusTextView.setTextColor(Color.parseColor("#E31937")); } - qrImageView.setDrawingCacheEnabled(false); } - }); - // Check Payment Status button - checkStatusButton.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - simulateWebhook(); + public void onFinish() { + timerTextView.setText("0"); + qrStatusTextView.setText("Refreshing QR Code..."); + qrStatusTextView.setTextColor(Color.parseColor("#E31937")); + + // Auto refresh QR code + refreshQrCode(); } - }); + }.start(); + } - // Return to Main Screen button - returnMainButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(QrisResultActivity.this, com.example.bdkipoc.MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - finishAffinity(); + private void refreshQrCode() { + qrRefreshCount++; + + if (qrRefreshCount >= MAX_QR_REFRESH) { + // Max refresh reached, show expired message + timerTextView.setText("Expired"); + qrStatusTextView.setText("QR Code telah expired. Silahkan generate ulang."); + qrStatusTextView.setTextColor(Color.parseColor("#E31937")); + Toast.makeText(this, "QR Code expired. Please generate new payment.", Toast.LENGTH_LONG).show(); + return; + } + + // Show loading state + progressBar.setVisibility(View.VISIBLE); + qrStatusTextView.setText("Generating new QR Code... (" + qrRefreshCount + "/" + MAX_QR_REFRESH + ")"); + + // Simulate generating new QR code + new Thread(() -> { + try { + // Simulate API call delay + Thread.sleep(2000); + + // Generate new QR code (in real app, call Midtrans API again) + generateNewQrCode(); + + } catch (InterruptedException e) { + e.printStackTrace(); } + }).start(); + } + + private void generateNewQrCode() { + new Handler(Looper.getMainLooper()).post(() -> { + progressBar.setVisibility(View.GONE); + + // In real implementation, you would call Midtrans API again + // For demo, we'll reload the same QR with a timestamp to show refresh + String refreshedUrl = originalQrImageUrl + "?refresh=" + System.currentTimeMillis(); + loadQrCode(refreshedUrl); + + // Reset timer for new 60 seconds + timeLeftInMillis = 60000; + startTimer(); + + Toast.makeText(this, "QR Code refreshed! (" + qrRefreshCount + "/" + MAX_QR_REFRESH + ")", Toast.LENGTH_SHORT).show(); }); } + private void loadQrCode(String qrImageUrl) { + new DownloadImageTask(qrImageView).execute(qrImageUrl); + } + private static class DownloadImageTask extends AsyncTask { ImageView bmImage; DownloadImageTask(ImageView bmImage) { this.bmImage = bmImage; } + protected Bitmap doInBackground(String... urls) { String urlDisplay = urls[0]; Bitmap bitmap = null; @@ -144,6 +310,7 @@ public class QrisResultActivity extends AppCompatActivity { } return bitmap; } + protected void onPostExecute(Bitmap result) { if (result != null) { bmImage.setImageBitmap(result); @@ -157,12 +324,12 @@ public class QrisResultActivity extends AppCompatActivity { String savedImageURL = android.provider.MediaStore.Images.Media.insertImage( getContentResolver(), bitmap, fileName, "QRIS Payment QR Code"); if (savedImageURL != null) { - android.widget.Toast.makeText(this, "QRIS saved to gallery", android.widget.Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "QRIS saved to gallery", Toast.LENGTH_SHORT).show(); } else { - android.widget.Toast.makeText(this, "Failed to save QRIS", android.widget.Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "Failed to save QRIS", Toast.LENGTH_SHORT).show(); } } catch (Exception e) { - android.widget.Toast.makeText(this, "Error saving QRIS: " + e.getMessage(), android.widget.Toast.LENGTH_LONG).show(); + Toast.makeText(this, "Error saving QRIS: " + e.getMessage(), Toast.LENGTH_LONG).show(); } } @@ -216,9 +383,9 @@ public class QrisResultActivity extends AppCompatActivity { progressBar.setVisibility(View.GONE); if (logFound) { checkStatusButton.setEnabled(true); - android.widget.Toast.makeText(QrisResultActivity.this, "Pending payment log found!", android.widget.Toast.LENGTH_SHORT).show(); + Toast.makeText(QrisResultActivity.this, "Pending payment log found!", Toast.LENGTH_SHORT).show(); } else { - android.widget.Toast.makeText(QrisResultActivity.this, "Pending payment log NOT found.", android.widget.Toast.LENGTH_LONG).show(); + Toast.makeText(QrisResultActivity.this, "Pending payment log NOT found.", Toast.LENGTH_LONG).show(); } }); }).start(); @@ -273,15 +440,52 @@ public class QrisResultActivity extends AppCompatActivity { } new Handler(Looper.getMainLooper()).post(() -> { progressBar.setVisibility(View.GONE); - // Proceed to show status/result - qrImageView.setVisibility(View.GONE); - amountTextView.setVisibility(View.GONE); - referenceTextView.setVisibility(View.GONE); - downloadQrisButton.setVisibility(View.GONE); - checkStatusButton.setVisibility(View.GONE); - statusTextView.setVisibility(View.VISIBLE); - returnMainButton.setVisibility(View.VISIBLE); + // Show success state + showSuccessState(); }); }).start(); } -} + + private void showSuccessState() { + // Stop timer + if (countDownTimer != null) { + countDownTimer.cancel(); + } + + // Hide QR section and show success + qrImageView.setVisibility(View.GONE); + amountTextView.setVisibility(View.GONE); + timerTextView.setVisibility(View.GONE); + qrStatusTextView.setVisibility(View.GONE); + downloadQrisButton.setVisibility(View.GONE); + checkStatusButton.setVisibility(View.GONE); + cancelButton.setVisibility(View.GONE); + + // Show success message + statusTextView.setText("Payment Successful!"); + statusTextView.setTextColor(Color.parseColor("#4CAF50")); + statusTextView.setTextSize(24); + statusTextView.setVisibility(View.VISIBLE); + returnMainButton.setVisibility(View.VISIBLE); + returnMainButton.setText("Back to Main"); + returnMainButton.setBackgroundColor(Color.parseColor("#4CAF50")); + + Toast.makeText(this, "Payment completed successfully!", Toast.LENGTH_LONG).show(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (countDownTimer != null) { + countDownTimer.cancel(); + } + } + + @Override + public void onBackPressed() { + if (countDownTimer != null) { + countDownTimer.cancel(); + } + super.onBackPressed(); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_qris_result.xml b/app/src/main/res/layout/activity_qris_result.xml index 44bc4c3..91569ec 100644 --- a/app/src/main/res/layout/activity_qris_result.xml +++ b/app/src/main/res/layout/activity_qris_result.xml @@ -1,82 +1,223 @@ + android:background="#FFFFFF"> - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +