Face ID first attemp, on waiting_for-card layout
This commit is contained in:
parent
50796a6951
commit
c6cb612c99
|
@ -1,6 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.front" />
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
|
|
@ -9,11 +9,13 @@ import android.text.Spanned;
|
|||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.TextureView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListView;
|
||||
|
||||
import androidx.lifecycle.Observer;
|
||||
|
@ -60,6 +62,9 @@ import androidx.databinding.DataBindingUtil;
|
|||
import android.widget.FrameLayout;
|
||||
import com.dspread.pos_android_app.databinding.WaitingForCardBinding; // Generated binding class
|
||||
|
||||
import android.widget.FrameLayout;
|
||||
import com.dspread.pos.utils.FaceIDHelper;
|
||||
|
||||
|
||||
public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, PaymentViewModel> implements PaymentServiceCallback {
|
||||
|
||||
|
@ -91,6 +96,9 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
|||
private boolean QRMood = false;
|
||||
private boolean FaceIDMood = false;
|
||||
|
||||
private FaceIDHelper faceIDHelper;
|
||||
private boolean isFaceIDActive = false;
|
||||
|
||||
@Override
|
||||
public void initData() {
|
||||
// Debug current locale
|
||||
|
@ -154,11 +162,103 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
|||
waitingContainer.addView(waitingBinding.getRoot());
|
||||
|
||||
// Generate QR code when needed
|
||||
// TO-DO fix M50F long time QR generated !!!
|
||||
|
||||
// waitingViewModel.generateQRCode(generatePaymentData());
|
||||
|
||||
// Observe Face ID events
|
||||
waitingViewModel.startFaceID.observe(this, start -> {
|
||||
if (start != null && start) {
|
||||
startFaceIDCamera();
|
||||
}
|
||||
});
|
||||
|
||||
waitingViewModel.faceIDSuccess.observe(this, success -> {
|
||||
if (success != null && success) {
|
||||
simulatePaymentAfterDelay();
|
||||
}
|
||||
});
|
||||
|
||||
// Set click listener for Face ID container
|
||||
waitingBinding.faceIDContainer.setOnClickListener(v -> {
|
||||
waitingViewModel.onFaceIDClicked();
|
||||
});
|
||||
|
||||
startTransaction();
|
||||
}
|
||||
|
||||
private void startFaceIDCamera() {
|
||||
if (isFaceIDActive) return;
|
||||
|
||||
isFaceIDActive = true;
|
||||
|
||||
// Show camera container - now it's inside the FrameLayout
|
||||
FrameLayout cameraContainer = waitingBinding.getRoot().findViewById(R.id.camera_container);
|
||||
if (cameraContainer != null) {
|
||||
cameraContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
// Create TextureView for camera preview
|
||||
TextureView textureView = new TextureView(this);
|
||||
textureView.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT));
|
||||
|
||||
// Add TextureView to camera container
|
||||
if (cameraContainer != null) {
|
||||
cameraContainer.addView(textureView, 0); // Add at index 0 (behind buttons)
|
||||
}
|
||||
|
||||
// Set up close button
|
||||
ImageButton btnCloseCamera = waitingBinding.getRoot().findViewById(R.id.btn_close_camera);
|
||||
if (btnCloseCamera != null) {
|
||||
btnCloseCamera.setOnClickListener(v -> {
|
||||
closeFaceIDCamera();
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize Face ID helper
|
||||
faceIDHelper = new FaceIDHelper(this, textureView, new FaceIDHelper.FaceIDCallback() {
|
||||
@Override
|
||||
public void onFaceDetected() {
|
||||
runOnUiThread(() -> {
|
||||
// Face detected - proceed with payment
|
||||
closeFaceIDCamera();
|
||||
waitingViewModel.simulateFaceIDSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraError(String error) {
|
||||
runOnUiThread(() -> {
|
||||
ToastUtils.showShort(error);
|
||||
closeFaceIDCamera();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
faceIDHelper.startBackgroundThread();
|
||||
faceIDHelper.startCamera();
|
||||
}
|
||||
|
||||
private void closeFaceIDCamera() {
|
||||
if (!isFaceIDActive) return;
|
||||
|
||||
isFaceIDActive = false;
|
||||
|
||||
// Hide camera container
|
||||
FrameLayout cameraContainer = waitingBinding.getRoot().findViewById(R.id.camera_container);
|
||||
if (cameraContainer != null) {
|
||||
cameraContainer.setVisibility(View.GONE);
|
||||
cameraContainer.removeAllViews();
|
||||
}
|
||||
|
||||
// Clean up camera resources
|
||||
if (faceIDHelper != null) {
|
||||
faceIDHelper.closeCamera();
|
||||
faceIDHelper.stopBackgroundThread();
|
||||
}
|
||||
}
|
||||
private void simulatePaymentAfterDelay() {
|
||||
boolean isTestMode = true; // Set this to false when not testing
|
||||
if (isTestMode) {
|
||||
|
@ -671,6 +771,10 @@ public class PaymentActivity extends BaseActivity<ActivityPaymentBinding, Paymen
|
|||
LogFileConfig.getInstance(this).readLog();
|
||||
QPOSCallbackManager.getInstance().unregisterPaymentCallback();
|
||||
PrinterHelper.getInstance().close();
|
||||
if (faceIDHelper != null) {
|
||||
faceIDHelper.closeCamera();
|
||||
faceIDHelper.stopBackgroundThread();
|
||||
}
|
||||
}
|
||||
|
||||
private void convertReceiptToBitmap(final BitmapReadyListener listener) {
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.util.Log;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.databinding.ObservableBoolean;
|
||||
import androidx.databinding.ObservableField;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.dspread.pos.common.manager.QPOSCallbackManager;
|
||||
import com.dspread.pos.printerAPI.PrinterHelper;
|
||||
|
@ -22,7 +23,9 @@ public class WaitingForCardViewModel extends BaseViewModel {
|
|||
|
||||
public ObservableField<String> amount = new ObservableField<>("0.00");
|
||||
public ObservableField<String> currencySymbol = new ObservableField<>("$");
|
||||
|
||||
// Add Face ID events
|
||||
public MutableLiveData<Boolean> startFaceID = new MutableLiveData<>();
|
||||
public MutableLiveData<Boolean> faceIDSuccess = new MutableLiveData<>();
|
||||
public WaitingForCardViewModel(@NonNull Application application) {
|
||||
super(application);
|
||||
}
|
||||
|
@ -60,6 +63,16 @@ public class WaitingForCardViewModel extends BaseViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
// Add Face ID methods
|
||||
public void onFaceIDClicked() {
|
||||
startFaceID.setValue(true);
|
||||
}
|
||||
|
||||
public void simulateFaceIDSuccess() {
|
||||
// This will be called when face is detected
|
||||
faceIDSuccess.setValue(true);
|
||||
}
|
||||
|
||||
public void onCancel() {
|
||||
// Handle cancel action
|
||||
Log.d("WaitingForCardViewModel", "onCancel: ");
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
package com.dspread.pos.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.SurfaceTexture;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CameraManager;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Size;
|
||||
import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FaceIDHelper implements TextureView.SurfaceTextureListener {
|
||||
|
||||
private static final int REQUEST_CAMERA_PERMISSION = 200;
|
||||
|
||||
private Context context;
|
||||
private TextureView textureView;
|
||||
private FaceIDCallback callback;
|
||||
|
||||
private CameraManager cameraManager;
|
||||
private CameraDevice cameraDevice;
|
||||
private CameraCaptureSession cameraCaptureSession;
|
||||
private CaptureRequest.Builder captureRequestBuilder;
|
||||
|
||||
private Handler backgroundHandler;
|
||||
private HandlerThread backgroundThread;
|
||||
|
||||
private String frontCameraId;
|
||||
|
||||
public interface FaceIDCallback {
|
||||
void onFaceDetected();
|
||||
void onCameraError(String error);
|
||||
}
|
||||
|
||||
public FaceIDHelper(Context context, TextureView textureView, FaceIDCallback callback) {
|
||||
this.context = context;
|
||||
this.textureView = textureView;
|
||||
this.callback = callback;
|
||||
this.cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
||||
}
|
||||
|
||||
public void startCamera() {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
callback.onCameraError("Camera permission required");
|
||||
return;
|
||||
}
|
||||
|
||||
setupCamera();
|
||||
}
|
||||
|
||||
private void setupCamera() {
|
||||
try {
|
||||
frontCameraId = getFrontCameraId();
|
||||
if (frontCameraId == null) {
|
||||
callback.onCameraError("Front camera not found");
|
||||
return;
|
||||
}
|
||||
|
||||
textureView.setSurfaceTextureListener(this);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
callback.onCameraError("Camera access error");
|
||||
}
|
||||
}
|
||||
|
||||
private String getFrontCameraId() throws CameraAccessException {
|
||||
String[] cameraIds = cameraManager.getCameraIdList();
|
||||
for (String cameraId : cameraIds) {
|
||||
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
|
||||
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
|
||||
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
|
||||
return cameraId;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
||||
openCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
|
||||
|
||||
private void openCamera() {
|
||||
try {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
cameraManager.openCamera(frontCameraId, stateCallback, backgroundHandler);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
callback.onCameraError("Failed to open camera");
|
||||
}
|
||||
}
|
||||
|
||||
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
|
||||
@Override
|
||||
public void onOpened(@NonNull CameraDevice camera) {
|
||||
cameraDevice = camera;
|
||||
createCameraPreview();
|
||||
// Simulate face detection after camera opens
|
||||
simulateFaceDetection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(@NonNull CameraDevice camera) {
|
||||
cameraDevice.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull CameraDevice camera, int error) {
|
||||
cameraDevice.close();
|
||||
cameraDevice = null;
|
||||
callback.onCameraError("Camera error: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
private void createCameraPreview() {
|
||||
try {
|
||||
SurfaceTexture texture = textureView.getSurfaceTexture();
|
||||
Surface surface = new Surface(texture);
|
||||
|
||||
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
||||
captureRequestBuilder.addTarget(surface);
|
||||
|
||||
cameraDevice.createCaptureSession(Arrays.asList(surface),
|
||||
new CameraCaptureSession.StateCallback() {
|
||||
@Override
|
||||
public void onConfigured(@NonNull CameraCaptureSession session) {
|
||||
if (cameraDevice == null) return;
|
||||
|
||||
cameraCaptureSession = session;
|
||||
try {
|
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
|
||||
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
||||
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
|
||||
CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
|
||||
|
||||
session.setRepeatingRequest(captureRequestBuilder.build(),
|
||||
null, backgroundHandler);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
|
||||
callback.onCameraError("Camera configuration failed");
|
||||
}
|
||||
}, null);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void simulateFaceDetection() {
|
||||
// Simulate face detection after 3 seconds
|
||||
new Handler().postDelayed(() -> {
|
||||
if (callback != null) {
|
||||
callback.onFaceDetected();
|
||||
}
|
||||
}, 18000);
|
||||
}
|
||||
|
||||
public void startBackgroundThread() {
|
||||
backgroundThread = new HandlerThread("CameraBackground");
|
||||
backgroundThread.start();
|
||||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
}
|
||||
|
||||
public void stopBackgroundThread() {
|
||||
if (backgroundThread != null) {
|
||||
backgroundThread.quitSafely();
|
||||
try {
|
||||
backgroundThread.join();
|
||||
backgroundThread = null;
|
||||
backgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeCamera() {
|
||||
if (cameraCaptureSession != null) {
|
||||
cameraCaptureSession.close();
|
||||
cameraCaptureSession = null;
|
||||
}
|
||||
if (cameraDevice != null) {
|
||||
cameraDevice.close();
|
||||
cameraDevice = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<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="@android:color/white"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#80000000" />
|
||||
<corners android:radius="24dp" />
|
||||
</shape>
|
|
@ -5,200 +5,226 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<data>
|
||||
<variable
|
||||
name="vm"
|
||||
type="com.dspread.pos.ui.payment.WaitingForCardViewModel" />
|
||||
<variable name="vm" type="com.dspread.pos.ui.payment.WaitingForCardViewModel" />
|
||||
</data>
|
||||
|
||||
<LinearLayout
|
||||
<!-- Use FrameLayout as root to contain both camera overlay and main content -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- Card animation GIF -->
|
||||
<!-- Main Content -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center">
|
||||
<ImageView
|
||||
android:paddingTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="300dp"
|
||||
android:src="@drawable/melberry_char_purple"
|
||||
android:scaleType="fitCenter">
|
||||
|
||||
</ImageView>
|
||||
|
||||
<!-- <pl.droidsonroids.gif.GifImageView-->
|
||||
<!-- android:layout_width="200dp"-->
|
||||
<!-- android:layout_height="200dp"-->
|
||||
<!-- android:src="@drawable/checkcard" />-->
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Instruction text -->
|
||||
<!-- <TextView-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:layout_marginTop="16dp"-->
|
||||
<!-- android:text="@string/scan_or_tap_instruction"-->
|
||||
<!-- android:textAlignment="center"-->
|
||||
<!-- android:textSize="16sp" />-->
|
||||
|
||||
<!-- Amount and currency section -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{vm.amount}"
|
||||
android:textSize="36sp"
|
||||
android:textColor="#2C2929"
|
||||
tools:text="100.00" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{vm.currencySymbol}"
|
||||
android:textSize="36sp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:textColor="#2C2929"
|
||||
tools:text="$" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Divided section for QR code and Face ID -->
|
||||
<LinearLayout
|
||||
android:id="@+id/twoCardsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="2"
|
||||
android:paddingHorizontal="1dp">
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- Left side - Face ID Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="260dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
<!-- Card animation GIF -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
|
||||
<!-- Outer Card (White Background) -->
|
||||
<LinearLayout
|
||||
android:gravity="center">
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#8c1084"
|
||||
android:padding="5dp">
|
||||
android:layout_height="@dimen/dp_300"
|
||||
android:paddingTop="10dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/melberry_char_purple" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Inner Card (Purple Background) -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="170dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/holo_purple">
|
||||
<!-- Amount and currency section -->
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_weight="1">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{vm.amount}"
|
||||
android:textSize="36sp"
|
||||
android:textColor="#2C2929"
|
||||
tools:text="100.00" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{vm.currencySymbol}"
|
||||
android:textSize="36sp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:textColor="#2C2929"
|
||||
tools:text="$" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Center the GIF Image -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<!-- Divided section for QR code and Face ID -->
|
||||
<LinearLayout
|
||||
android:id="@+id/twoCardsContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="2"
|
||||
android:paddingHorizontal="1dp">
|
||||
|
||||
<pl.droidsonroids.gif.GifImageView
|
||||
android:layout_width="98dp"
|
||||
android:layout_height="124dp"
|
||||
android:src="@drawable/faceid_180px" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<!-- Left side - Face ID Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/faceIDContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="260dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
|
||||
<!-- Text in Outer Card -->
|
||||
<!-- Outer Card (White Background) -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#8c1084"
|
||||
android:padding="5dp">
|
||||
|
||||
<!-- Left Text: "Оплатите лицом" -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Оплатить\nлицом"
|
||||
android:textSize="18sp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textStyle="normal"
|
||||
android:textColor="@color/white"
|
||||
android:layout_weight="1" />
|
||||
<!-- Inner Card (Purple Background) -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="170dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/holo_purple">
|
||||
|
||||
<!-- Right Text: ">" -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<!-- Center the GIF Image -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<pl.droidsonroids.gif.GifImageView
|
||||
android:layout_width="98dp"
|
||||
android:layout_height="124dp"
|
||||
android:src="@drawable/faceid_180px" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Text in Outer Card -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
android:text=">"
|
||||
android:textColor="@color/white" />
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<!-- Left Text: "Оплатите лицом" -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Оплатить\nлицом"
|
||||
android:textSize="18sp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textStyle="normal"
|
||||
android:textColor="@color/white"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- Right Text: ">" -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:paddingRight="10dp"
|
||||
android:text=">"
|
||||
android:textColor="@color/white" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Right side - QR Code Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="260dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
<!-- Right side - QR Code Card -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/qrCodeContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="260dp"
|
||||
android:layout_marginStart="2dp"
|
||||
android:layout_weight="1"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:cardElevation="2dp"
|
||||
app:cardUseCompatPadding="true">
|
||||
|
||||
<!-- Single Card with Purple Background -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#8c1084"
|
||||
android:padding="3dp">
|
||||
|
||||
<!-- QR Code Image -->
|
||||
<ImageView
|
||||
android:id="@+id/qr_code_image"
|
||||
<!-- Single Card with Purple Background -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="170dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/am_qr_code_mag_black"
|
||||
android:contentDescription="@string/qr_code_description"
|
||||
app:imageBitmap="@{vm.qrCodeBitmap}" />
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#8c1084"
|
||||
android:padding="3dp">
|
||||
|
||||
<!-- Text Under QR Code -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="Отсканируйте\nQR-код"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="normal"
|
||||
android:paddingBottom="5dp"
|
||||
android:gravity="left"
|
||||
android:layout_gravity="center" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<!-- QR Code Image -->
|
||||
<ImageView
|
||||
android:id="@+id/qr_code_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="170dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/am_qr_code_mag_black"
|
||||
android:contentDescription="@string/qr_code_description"
|
||||
app:imageBitmap="@{vm.qrCodeBitmap}" />
|
||||
|
||||
<!-- Text Under QR Code -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="Отсканируйте\nQR-код"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="normal"
|
||||
android:paddingBottom="5dp"
|
||||
android:gravity="left"
|
||||
android:layout_gravity="center" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Camera Container (Full Screen Overlay) -->
|
||||
<FrameLayout
|
||||
android:id="@+id/camera_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
android:background="@android:color/black">
|
||||
|
||||
<!-- Camera Preview will be added here programmatically -->
|
||||
|
||||
<!-- Close button for camera -->
|
||||
<ImageButton
|
||||
android:id="@+id/btn_close_camera"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="24dp"
|
||||
android:src="@drawable/ic_close_white"
|
||||
android:background="@drawable/rounded_bg_black_50"
|
||||
android:scaleType="center"
|
||||
android:contentDescription="Close_camera"
|
||||
android:layout_gravity="top|end" />
|
||||
|
||||
<!-- Face detection guidance -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Смотрите в камеру\nЛицо должно быть в рамке"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp"
|
||||
android:textAlignment="center"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:padding="16dp"
|
||||
android:background="@drawable/rounded_bg_black_50"
|
||||
android:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
</layout>
|
Loading…
Reference in New Issue