From 665bf1d5dfd0e0b59beaa257a942ba3ebbf91377 Mon Sep 17 00:00:00 2001 From: moon <56061215+MgKyawLay@users.noreply.github.com> Date: Wed, 1 Jul 2026 11:39:55 +0630 Subject: [PATCH] signature pad --- .../utsmyanmar/ui/navigation/AppNavGraph.kt | 4 +- .../ui/sending_to_host/SendingToHostRoute.kt | 5 +- .../ui/signature_pad/SignaturePad.kt | 68 +++++++++++-------- .../utsmyanmar/viewmodel/SharedViewModel.kt | 22 ++++-- .../baselib/db/dao/PayDetailDao.java | 7 +- .../utsmyanmar/baselib/di/DatabaseModule.java | 2 +- .../paylibs/print/printx/PrintXImpl.java | 45 +----------- 7 files changed, 69 insertions(+), 84 deletions(-) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index a024b96..8e6a986 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -55,7 +55,6 @@ import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.mob.utsmyanmar.viewmodel.TransProcessViewModel import com.utsmyanmar.paylibs.model.TradeData -import com.utsmyanmar.paylibs.model.enums.TransCVM import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType @RequiresApi(Build.VERSION_CODES.N) @@ -90,8 +89,9 @@ fun AppNavGraph( val sharedViewModel: SharedViewModel = hiltViewModel(activity) SignaturePad( onBack = { navController.popBackStack() }, - onConfirm = { _, bitmap -> + onConfirm = { _, bitmap, signatureBlob -> sharedViewModel.signBitmap = bitmap + sharedViewModel.updateSignatureBlob(signatureBlob) navController.navigate(Routes.TransactionResult.route) { popUpTo(Routes.Signature.route) { inclusive = true diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt index 9fbefed..2b50ef7 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt @@ -9,6 +9,7 @@ import com.mob.utsmyanmar.model.TransactionStatus import com.mob.utsmyanmar.ui.settlement.SettlementViewModel import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.mob.utsmyanmar.viewmodel.TransProcessViewModel +import com.utsmyanmar.paylibs.model.enums.TransCVM import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType private const val MOCK_HOST_DELAY_MS = 2000L @@ -83,6 +84,6 @@ fun ProcessingRoute( } private fun requiresSignature(payDetail: com.utsmyanmar.paylibs.model.PayDetail?): Boolean { -// return payDetail?.transCVM == TransCVM.SIGNATURE && payDetail.isFreeSign == false - return true; + return payDetail?.transCVM == TransCVM.SIGNATURE && !payDetail.isFreeSign +// return true; } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/signature_pad/SignaturePad.kt b/app/src/main/java/com/mob/utsmyanmar/ui/signature_pad/SignaturePad.kt index 6245950..ab8695b 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/signature_pad/SignaturePad.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/signature_pad/SignaturePad.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size @@ -39,8 +40,10 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.core.graphics.createBitmap import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.theme.MOBPOSTheme +import java.io.ByteArrayOutputStream import android.graphics.Canvas as AndroidCanvas import android.graphics.Path as AndroidPath import com.mob.utsmyanmar.ui.theme.Color as AppColor @@ -49,39 +52,39 @@ import com.mob.utsmyanmar.ui.theme.Color as AppColor fun SignaturePad( modifier: Modifier = Modifier, signatureColor: Color = Color.Black, - onBack: () -> Unit = {}, - onConfirm: (SignatureMode, Bitmap?) -> Unit = { _, _ -> } + // signatureBlob is null for Digital mode (using stored signature) or when nothing was drawn + onConfirm: (SignatureMode, Bitmap?, signatureBlob: ByteArray?) -> Unit = { _, _, _ -> } ) { val paths = remember { mutableStateListOf>() } val currentPath = remember { mutableStateListOf() } var selectedMode by remember { mutableStateOf(SignatureMode.Manual) } var canvasSize by remember { mutableStateOf(Size.Zero) } - var strokeWidth: Float = 8f; + var strokeWidth = 6f fun clearSignature() { paths.clear() currentPath.clear() } + fun buildBitmap(): Bitmap? { - if (selectedMode == SignatureMode.Manual) return null + if (selectedMode == SignatureMode.Digital) return null if (paths.isEmpty() && currentPath.isEmpty()) return null if (canvasSize.width <= 0f || canvasSize.height <= 0f) return null - val bitmap = Bitmap.createBitmap( - canvasSize.width.toInt(), - canvasSize.height.toInt(), - Bitmap.Config.ARGB_8888 - ) + val bitmap = + createBitmap(canvasSize.width.toInt(), canvasSize.height.toInt(), Bitmap.Config.RGB_565) val canvas = AndroidCanvas(bitmap) + canvas.drawColor(android.graphics.Color.WHITE) // fill white background first + val paint = Paint().apply { color = android.graphics.Color.BLACK style = Paint.Style.STROKE - strokeWidth = strokeWidth isAntiAlias = true strokeCap = Paint.Cap.ROUND strokeJoin = Paint.Join.ROUND + strokeWidth = 10f } fun drawStroke(points: List) { @@ -101,6 +104,13 @@ fun SignaturePad( return bitmap } + fun bitmapToBlob(bitmap: Bitmap): ByteArray { + ByteArrayOutputStream().use { stream -> + bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream) + return stream.toByteArray() + } + } + Scaffold( topBar = { AppBar( @@ -117,17 +127,18 @@ fun SignaturePad( .padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - Box( - modifier = Modifier - .weight(1f) - .fillMaxWidth() - .background(Color.White, RoundedCornerShape(16.dp)) - .padding(12.dp) - .onSizeChanged { size -> - canvasSize = Size(size.width.toFloat(), size.height.toFloat()) - } - .pointerInput(Unit) { - detectDragGestures( + Box( + modifier = Modifier + .fillMaxWidth(0.85f) // narrower than full width, adjust as needed + .height(180.dp) // fixed height instead of weight(1f) + .align(Alignment.CenterHorizontally) + .background(Color.White, RoundedCornerShape(16.dp)) + .padding(12.dp) + .onSizeChanged { size -> + canvasSize = Size(size.width.toFloat(), size.height.toFloat()) + } + .pointerInput(Unit) { + detectDragGestures( onDragStart = { startOffset -> currentPath.add(startOffset) }, @@ -175,9 +186,10 @@ fun SignaturePad( } } - Column ( - modifier = Modifier.fillMaxWidth().height(150.dp), -// horizontalArrangement = Arrangement.spacedBy(12.dp) + Column( + modifier = Modifier + .fillMaxWidth() + .height(150.dp) ) { SignatureModeOption( title = "Manual Sign", @@ -214,10 +226,12 @@ fun SignaturePad( Button( onClick = { val bitmap = buildBitmap() - if (selectedMode == SignatureMode.Digital && bitmap == null) { + if (selectedMode == SignatureMode.Manual && bitmap == null) { + // nothing drawn yet on Manual mode — block confirm return@Button } - onConfirm(selectedMode, bitmap) + val signatureBlob = bitmap?.let { bitmapToBlob(it) } + onConfirm(selectedMode, bitmap, signatureBlob) }, modifier = Modifier .weight(1f) @@ -283,4 +297,4 @@ fun SignaturePadPreview() { MOBPOSTheme { SignaturePad() } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/mob/utsmyanmar/viewmodel/SharedViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/viewmodel/SharedViewModel.kt index bf03efa..227a187 100644 --- a/app/src/main/java/com/mob/utsmyanmar/viewmodel/SharedViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/viewmodel/SharedViewModel.kt @@ -4,9 +4,9 @@ import android.graphics.Bitmap import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.mob.utsmyanmar.model.SettlementType -import com.mob.utsmyanmar.ui.processing_card.ProcessingCardState -import com.mob.utsmyanmar.ui.sending_to_host.ProcessingState +import com.utsmyanmar.baselib.db.dao.PayDetailDao import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse import com.utsmyanmar.baselib.repo.Repository @@ -21,19 +21,20 @@ import com.utsmyanmar.paylibs.utils.AccountType import com.utsmyanmar.paylibs.utils.PrintStatus import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation import com.utsmyanmar.paylibs.utils.enums.HostType -import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType import com.utsmyanmar.paylibs.utils.enums.TransMenu +import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.rxjava3.core.Observable -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import sunmi.sunmiui.utils.LogUtil import javax.inject.Inject @HiltViewModel class SharedViewModel @Inject constructor( - private val repository: Repository + private val repository: Repository, + private val payDetailDao: PayDetailDao ) : ViewModel() { companion object { @@ -666,4 +667,13 @@ class SharedViewModel @Inject constructor( SystemParamsOperation.getInstance().wavePayStatus ) } + fun updateSignatureBlob(signatureBlob: ByteArray?) { + val current = payDetail.value ?: return + current.signatureBlob = signatureBlob + payDetail.value = current + + viewModelScope.launch(Dispatchers.IO) { + payDetailDao.updateSignatureBlob(current.voucherNo, signatureBlob) + } + } } diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/db/dao/PayDetailDao.java b/baselib/src/main/java/com/utsmyanmar/baselib/db/dao/PayDetailDao.java index ec06c59..f7187cf 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/db/dao/PayDetailDao.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/db/dao/PayDetailDao.java @@ -5,13 +5,9 @@ import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; -import androidx.room.Transaction; import androidx.room.Update; import com.utsmyanmar.paylibs.model.PayDetail; -import com.utsmyanmar.paylibs.system.SingleLiveEvent; -import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType; -import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import java.util.List; @@ -157,4 +153,7 @@ public interface PayDetailDao { @Query("SELECT * FROM paydetail ORDER BY PID DESC") LiveData> getAllTrans(); + @Query("UPDATE paydetail SET signatureBlob = :blob WHERE voucherNo = :voucherNo") + void updateSignatureBlob(String voucherNo, byte[] blob); + } diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java index 2f28b53..b9416ec 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java @@ -397,7 +397,7 @@ public class DatabaseModule { @Provides @Singleton public static AppDatabase provideAppDatabase(Application application) { - return Room.databaseBuilder(application, AppDatabase.class, "yoma") + return Room.databaseBuilder(application, AppDatabase.class, "mob") // .fallbackToDestructiveMigration() .addMigrations(MIGRATION_7_8) .addMigrations(MIGRATION_8_9) diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java index de26f51..8e96aae 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java @@ -3,16 +3,8 @@ package com.utsmyanmar.paylibs.print.printx; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; import android.os.RemoteException; -import com.google.zxing.BarcodeFormat; -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitMatrix; -import com.google.zxing.qrcode.QRCodeWriter; import com.utsmyanmar.paylibs.Constant; import com.utsmyanmar.paylibs.PayLibsUtils; import com.utsmyanmar.paylibs.R; @@ -31,10 +23,8 @@ import com.utsmyanmar.paylibs.utils.enums.HostType; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmyanmar.paylibs.utils.print_utils.BitmapUtils; -import java.io.ByteArrayOutputStream; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -268,7 +258,7 @@ public class PrintXImpl extends BaseXPrint implements PrintX { if (payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_APPROVED) || payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_ACCEPT)) { printTransFooter(false,payDetail, isMerchantCopy); - printSignatureBlock(payDetail, signBitmap); +// printSignatureBlock(payDetail, signBitmap); } else { String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter(); sunmiPrinterService.printText("\n", null); @@ -293,7 +283,7 @@ public class PrintXImpl extends BaseXPrint implements PrintX { if (payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_APPROVED) || payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_ACCEPT)) { printTransFooter(false,payDetail, isMerchantCopy); - printSignatureBlock(payDetail, signBitmap); +// printSignatureBlock(payDetail, signBitmap); } else { String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter(); sunmiPrinterService.setFontSize(textSize, null); @@ -309,39 +299,10 @@ public class PrintXImpl extends BaseXPrint implements PrintX { } } - private void printSignatureBlock(PayDetail payDetail, Bitmap signBitmap) { - try { - if (payDetail.getTransCVM() != com.utsmyanmar.paylibs.model.enums.TransCVM.SIGNATURE) { - return; - } - - if (signBitmap == null) { - return; - } - - Bitmap printableBitmap = signBitmap; - if (printableBitmap.getWidth() > 130) { - double size = 1.0 * printableBitmap.getHeight() * 130 / printableBitmap.getWidth(); - int newHeight = (int) size; - printableBitmap = BitmapUtils.scale(printableBitmap, 130, newHeight); - } - - sunmiPrinterService.lineWrap(1, innerResultCallback); - sunmiPrinterService.setAlignment(1, innerResultCallback); - sunmiPrinterService.printBitmap(printableBitmap, innerResultCallback); - sunmiPrinterService.lineWrap(1, innerResultCallback); - } catch (RemoteException e) { - e.printStackTrace(); - } - } - - private void printTransDetailWave(PayDetail payDetail) { try { -// payDetail.getCustomerMobile() // as channel type - - +// payDetail.getCustomerMobile() // as channel typeိ if(payDetail.getTransactionType() == TransactionsType.WAVEPAY.value && payDetail.getQrTransStatus() == 1 ) { sunmiPrinterService.printColumnsString(new String[]{"PAYMENT TYPE ",": "+ (payDetail.getCustomerMobile() == null || payDetail.getCustomerMobile().isEmpty() ? "-": payDetail.getCustomerMobile().toUpperCase())}, new int[]{2, 2}, new int[]{0, 0}, null);