UI PIN
This commit is contained in:
parent
810964b4be
commit
f1228db89a
@ -34,6 +34,11 @@
|
||||
android:name=".PaymentActivity"
|
||||
android:exported="false" />
|
||||
<activity android:name=".QrisResultActivity" />
|
||||
<activity
|
||||
android:name=".PinActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -121,10 +121,14 @@ public class PaymentActivity extends AppCompatActivity {
|
||||
Handler modalHandler = new Handler(Looper.getMainLooper());
|
||||
paymentModal.setOnShowListener(dialog -> {
|
||||
modalHandler.postDelayed(() -> {
|
||||
if (paymentModal.isShowing()) {
|
||||
dismissModal();
|
||||
// Simulate successful card processing
|
||||
processCardPayment();
|
||||
if (paymentModal != null && paymentModal.isShowing()) {
|
||||
// First dismiss modal, then navigate
|
||||
paymentModal.dismiss();
|
||||
|
||||
// Add small delay to ensure modal is fully dismissed
|
||||
animationHandler.postDelayed(() -> {
|
||||
navigateToPinActivity();
|
||||
}, 100);
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
@ -324,6 +328,9 @@ public class PaymentActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void showModalWithAnimation() {
|
||||
// Add debug log
|
||||
showToast("Showing card modal...");
|
||||
|
||||
paymentModal.show();
|
||||
|
||||
// Add slide-up animation
|
||||
@ -371,23 +378,47 @@ public class PaymentActivity extends AppCompatActivity {
|
||||
// This method is no longer needed since modal auto-dismisses
|
||||
}
|
||||
|
||||
private void navigateToPinActivity() {
|
||||
String amount = currentAmount.toString();
|
||||
|
||||
// Add debug log
|
||||
showToast("Navigating to PIN Activity...");
|
||||
|
||||
try {
|
||||
long amountValue = Long.parseLong(amount);
|
||||
|
||||
// Launch PIN Activity with amount data
|
||||
Intent intent = new Intent(this, PinActivity.class);
|
||||
intent.putExtra(PinActivity.EXTRA_SOURCE_ACTIVITY, "PaymentActivity");
|
||||
intent.putExtra(PinActivity.EXTRA_AMOUNT, String.valueOf(amountValue));
|
||||
startActivityForResult(intent, 100);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
showToast("Format jumlah tidak valid: " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
showToast("Error navigating to PIN: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void processCardPayment() {
|
||||
// This method is called after PIN verification is successful
|
||||
// Now process the actual payment
|
||||
String amount = currentAmount.toString();
|
||||
|
||||
try {
|
||||
long amountValue = Long.parseLong(amount);
|
||||
|
||||
// Show processing with card payment
|
||||
showToast("Memproses pembayaran dengan kartu...");
|
||||
// Show processing message
|
||||
showToast("PIN berhasil diverifikasi! Memproses pembayaran...");
|
||||
|
||||
// Process payment
|
||||
// Process the final payment
|
||||
processPayment(amountValue);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
showToast("Format jumlah tidak valid");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processPayment(long amount) {
|
||||
// Show loading state
|
||||
confirmButton.setText("Memproses...");
|
||||
@ -398,12 +429,12 @@ public class PaymentActivity extends AppCompatActivity {
|
||||
// Show success message
|
||||
showToast("Pembayaran berhasil! Jumlah: Rp " + formatCurrency(String.valueOf(amount)));
|
||||
|
||||
// Reset state and go back
|
||||
// Reset state and go back (this is final step after PIN verification)
|
||||
resetPaymentState();
|
||||
navigateBack();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
|
||||
private void resetPaymentState() {
|
||||
currentAmount = new StringBuilder();
|
||||
updateAmountDisplay();
|
||||
@ -459,6 +490,20 @@ public class PaymentActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
// Handle result from PIN Activity
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
boolean pinVerified = data.getBooleanExtra("pin_verified", false);
|
||||
if (pinVerified) {
|
||||
// PIN verification successful, process payment
|
||||
processCardPayment();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
408
app/src/main/java/com/example/bdkipoc/PinActivity.java
Normal file
408
app/src/main/java/com/example/bdkipoc/PinActivity.java
Normal file
@ -0,0 +1,408 @@
|
||||
package com.example.bdkipoc;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class PinActivity extends AppCompatActivity {
|
||||
|
||||
// Intent Extra Keys
|
||||
public static final String EXTRA_TITLE = "extra_title";
|
||||
public static final String EXTRA_SUBTITLE = "extra_subtitle";
|
||||
public static final String EXTRA_AMOUNT = "extra_amount";
|
||||
public static final String EXTRA_SOURCE_ACTIVITY = "extra_source_activity";
|
||||
|
||||
// Views
|
||||
private EditText editTextPin;
|
||||
private Button confirmButton;
|
||||
private LinearLayout backNavigation;
|
||||
private ImageView backArrow;
|
||||
private TextView backText;
|
||||
|
||||
// Numpad buttons
|
||||
private TextView btn1, btn2, btn3, btn4, btn5, btn6, btn7, btn8, btn9, btn0, btn000;
|
||||
private ImageView btnDelete;
|
||||
|
||||
// Data
|
||||
private StringBuilder currentPin = new StringBuilder();
|
||||
private static final int MAX_PIN_LENGTH = 6;
|
||||
private static final int MIN_PIN_LENGTH = 4;
|
||||
|
||||
// Extra data from intent
|
||||
private String sourceActivity;
|
||||
private String amount;
|
||||
|
||||
// Animation
|
||||
private Handler animationHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Set status bar color programmatically
|
||||
setStatusBarColor();
|
||||
|
||||
setContentView(R.layout.activity_pin);
|
||||
|
||||
// Get intent extras
|
||||
getIntentExtras();
|
||||
|
||||
initializeViews();
|
||||
setupClickListeners();
|
||||
setupInitialStates();
|
||||
}
|
||||
|
||||
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 getIntentExtras() {
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
sourceActivity = intent.getStringExtra(EXTRA_SOURCE_ACTIVITY);
|
||||
amount = intent.getStringExtra(EXTRA_AMOUNT);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeViews() {
|
||||
// Main views
|
||||
editTextPin = findViewById(R.id.editTextPin);
|
||||
confirmButton = findViewById(R.id.confirmButton);
|
||||
backNavigation = findViewById(R.id.back_navigation);
|
||||
backArrow = findViewById(R.id.backArrow);
|
||||
backText = findViewById(R.id.back_text);
|
||||
|
||||
// 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();
|
||||
});
|
||||
|
||||
// Back text (also clickable for back navigation)
|
||||
backText.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);
|
||||
handleConfirmPin();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void navigateBack() {
|
||||
finish();
|
||||
}
|
||||
|
||||
private void handleNumpadClick(View view, String digit) {
|
||||
addClickAnimation(view);
|
||||
addDigit(digit);
|
||||
}
|
||||
|
||||
private void setupInitialStates() {
|
||||
// Set initial PIN display
|
||||
editTextPin.setText("");
|
||||
|
||||
// Set initial button state
|
||||
updateButtonState();
|
||||
|
||||
// Disable EditText input (only numpad input allowed)
|
||||
editTextPin.setFocusable(false);
|
||||
editTextPin.setClickable(false);
|
||||
editTextPin.setCursorVisible(false);
|
||||
}
|
||||
|
||||
private void addDigit(String digit) {
|
||||
// Validate input length
|
||||
if (currentPin.length() >= MAX_PIN_LENGTH) {
|
||||
showToast("Maksimal " + MAX_PIN_LENGTH + " digit");
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle special case for 000
|
||||
if (digit.equals("000")) {
|
||||
if (currentPin.length() + 3 <= MAX_PIN_LENGTH) {
|
||||
currentPin.append("000");
|
||||
} else {
|
||||
int remainingLength = MAX_PIN_LENGTH - currentPin.length();
|
||||
if (remainingLength > 0) {
|
||||
currentPin.append("0".repeat(remainingLength));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentPin.append(digit);
|
||||
}
|
||||
|
||||
updatePinDisplay();
|
||||
updateButtonState();
|
||||
addInputFeedback();
|
||||
}
|
||||
|
||||
private void deleteLastDigit() {
|
||||
if (currentPin.length() > 0) {
|
||||
String current = currentPin.toString();
|
||||
|
||||
// If current ends with 000, remove all three digits
|
||||
if (current.endsWith("000") && current.length() >= 3) {
|
||||
currentPin.delete(currentPin.length() - 3, currentPin.length());
|
||||
} else {
|
||||
currentPin.deleteCharAt(currentPin.length() - 1);
|
||||
}
|
||||
|
||||
updatePinDisplay();
|
||||
updateButtonState();
|
||||
addDeleteFeedback();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePinDisplay() {
|
||||
String pin = currentPin.toString();
|
||||
|
||||
if (pin.isEmpty()) {
|
||||
editTextPin.setText("");
|
||||
} else {
|
||||
// Convert digits to asterisks for security
|
||||
String maskedPin = "*".repeat(pin.length());
|
||||
editTextPin.setText(maskedPin);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButtonState() {
|
||||
boolean hasValidPin = currentPin.length() >= MIN_PIN_LENGTH;
|
||||
|
||||
confirmButton.setEnabled(hasValidPin);
|
||||
|
||||
if (hasValidPin) {
|
||||
// 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 handleConfirmPin() {
|
||||
String pin = currentPin.toString();
|
||||
|
||||
if (TextUtils.isEmpty(pin)) {
|
||||
showToast("Masukkan PIN");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pin.length() < MIN_PIN_LENGTH) {
|
||||
showToast("PIN minimal " + MIN_PIN_LENGTH + " digit");
|
||||
return;
|
||||
}
|
||||
|
||||
// Process PIN verification
|
||||
verifyPin(pin);
|
||||
}
|
||||
|
||||
private void verifyPin(String pin) {
|
||||
// Show loading state
|
||||
confirmButton.setText("Memverifikasi...");
|
||||
confirmButton.setEnabled(false);
|
||||
|
||||
// Simulate PIN verification
|
||||
animationHandler.postDelayed(() -> {
|
||||
// For demo purposes, accept any PIN with length >= 4
|
||||
// In real implementation, this would call backend API
|
||||
|
||||
if (isValidPin(pin)) {
|
||||
showToast("PIN berhasil diverifikasi!");
|
||||
handleSuccessfulVerification();
|
||||
} else {
|
||||
showToast("PIN tidak valid. Silakan coba lagi.");
|
||||
resetPinState();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
private boolean isValidPin(String pin) {
|
||||
// Demo validation - in real app, this would validate against backend
|
||||
// For now, reject simple patterns like "1111", "1234", etc.
|
||||
return !pin.equals("1111") &&
|
||||
!pin.equals("1234") &&
|
||||
!pin.equals("0000") &&
|
||||
pin.length() >= MIN_PIN_LENGTH;
|
||||
}
|
||||
|
||||
private void handleSuccessfulVerification() {
|
||||
// Return result to calling activity
|
||||
Intent resultIntent = new Intent();
|
||||
resultIntent.putExtra("pin_verified", true);
|
||||
resultIntent.putExtra("pin_length", currentPin.length());
|
||||
|
||||
if (!TextUtils.isEmpty(amount)) {
|
||||
resultIntent.putExtra(EXTRA_AMOUNT, amount);
|
||||
}
|
||||
|
||||
setResult(RESULT_OK, resultIntent);
|
||||
|
||||
// Navigate back or to next screen based on source activity
|
||||
if ("PaymentActivity".equals(sourceActivity)) {
|
||||
// Could navigate to payment success screen
|
||||
showToast("Pembayaran berhasil diproses!");
|
||||
}
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
private void resetPinState() {
|
||||
currentPin = new StringBuilder();
|
||||
updatePinDisplay();
|
||||
updateButtonState();
|
||||
confirmButton.setText("Konfirmasi");
|
||||
confirmButton.setEnabled(false);
|
||||
}
|
||||
|
||||
// Animation methods
|
||||
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(editTextPin, "alpha", 0.7f, 1f);
|
||||
fadeIn.setDuration(200);
|
||||
fadeIn.start();
|
||||
}
|
||||
|
||||
private void addDeleteFeedback() {
|
||||
ObjectAnimator shake = ObjectAnimator.ofFloat(editTextPin, "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
|
||||
public void onBackPressed() {
|
||||
navigateBack();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (animationHandler != null) {
|
||||
animationHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Public methods for testing
|
||||
public String getCurrentPin() {
|
||||
return currentPin.toString();
|
||||
}
|
||||
|
||||
public boolean isConfirmButtonEnabled() {
|
||||
return confirmButton.isEnabled();
|
||||
}
|
||||
|
||||
// Static helper method to launch PinActivity
|
||||
public static void launch(android.content.Context context, String sourceActivity, String amount) {
|
||||
Intent intent = new Intent(context, PinActivity.class);
|
||||
intent.putExtra(EXTRA_SOURCE_ACTIVITY, sourceActivity);
|
||||
if (!TextUtils.isEmpty(amount)) {
|
||||
intent.putExtra(EXTRA_AMOUNT, amount);
|
||||
}
|
||||
|
||||
// Launch for result if context is an Activity
|
||||
if (context instanceof AppCompatActivity) {
|
||||
((AppCompatActivity) context).startActivityForResult(intent, 100);
|
||||
} else {
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
243
app/src/main/res/layout/activity_pin.xml
Normal file
243
app/src/main/res/layout/activity_pin.xml
Normal file
@ -0,0 +1,243 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none"
|
||||
android:background="#F5F5F5">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F5F5F5"
|
||||
tools:context=".PinActivity">
|
||||
|
||||
<!-- Status Bar Area -->
|
||||
<View
|
||||
android:id="@+id/status_bar_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="24dp"
|
||||
android:background="#E31937"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<!-- Header with Back Navigation -->
|
||||
<LinearLayout
|
||||
android:id="@+id/header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:background="#E31937"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/status_bar_background">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/back_navigation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingEnd="8dp"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backArrow"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_arrow_back"
|
||||
android:tint="@android:color/white"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/back_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Kembali"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="16sp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- PIN Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/pin_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
app:cardElevation="4dp"
|
||||
app:cardBackgroundColor="#4A90E2"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_container">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SILAKAN MASUKAN PIN"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<!-- PIN Input Display -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="2dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/white"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextPin"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="3"
|
||||
android:background="@android:color/transparent"
|
||||
android:textColor="@android:color/white"
|
||||
android:textColorHint="#CCFFFFFF"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:inputType="numberPassword"
|
||||
android:maxLength="6"
|
||||
android:focusable="false"
|
||||
android:clickable="false"
|
||||
android:cursorVisible="false"
|
||||
android:letterSpacing="0.5"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="2dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@android:color/white"
|
||||
android:layout_marginStart="8dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Numpad Grid -->
|
||||
<GridLayout
|
||||
android:id="@+id/numpad_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="3"
|
||||
android:rowCount="4"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginTop="32dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/pin_card">
|
||||
|
||||
<!-- Row 1: 1, 2, 3 -->
|
||||
<TextView
|
||||
android:id="@+id/btn1"
|
||||
style="@style/NumpadButton"
|
||||
android:text="1"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn2"
|
||||
style="@style/NumpadButton"
|
||||
android:text="2"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn3"
|
||||
style="@style/NumpadButton"
|
||||
android:text="3"/>
|
||||
|
||||
<!-- Row 2: 4, 5, 6 -->
|
||||
<TextView
|
||||
android:id="@+id/btn4"
|
||||
style="@style/NumpadButton"
|
||||
android:text="4"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn5"
|
||||
style="@style/NumpadButton"
|
||||
android:text="5"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn6"
|
||||
style="@style/NumpadButton"
|
||||
android:text="6"/>
|
||||
|
||||
<!-- Row 3: 7, 8, 9 -->
|
||||
<TextView
|
||||
android:id="@+id/btn7"
|
||||
style="@style/NumpadButton"
|
||||
android:text="7"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn8"
|
||||
style="@style/NumpadButton"
|
||||
android:text="8"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn9"
|
||||
style="@style/NumpadButton"
|
||||
android:text="9"/>
|
||||
|
||||
<!-- Row 4: 000, 0, Delete -->
|
||||
<TextView
|
||||
android:id="@+id/btn000"
|
||||
style="@style/NumpadButton"
|
||||
android:text="000"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn0"
|
||||
style="@style/NumpadButton"
|
||||
android:text="0"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_margin="8dp"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btnDelete"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:src="@drawable/ic_backspace"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:padding="12dp"
|
||||
android:tint="#666666"/>
|
||||
</LinearLayout>
|
||||
</GridLayout>
|
||||
|
||||
<!-- Confirmation Button -->
|
||||
<Button
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="Konfirmasi"
|
||||
android:textColor="#999999"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/button_inactive_background"
|
||||
android:enabled="false"
|
||||
android:alpha="0.6"
|
||||
app:layout_constraintTop_toBottomOf="@id/numpad_grid"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_bias="0"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
Loading…
x
Reference in New Issue
Block a user