diff --git a/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/UploadDocsViewmodel.kt b/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/UploadDocsViewmodel.kt index a145d1fa5..15a15e99c 100644 --- a/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/UploadDocsViewmodel.kt +++ b/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/UploadDocsViewmodel.kt @@ -29,6 +29,8 @@ import org.mifos.mobile.core.ui.utils.BaseViewModel import org.mifos.mobile.feature.loan.application.component.DocumentType import org.mifos.mobile.feature.loan.application.component.SignatureUploadType import kotlin.io.encoding.ExperimentalEncodingApi +import kotlin.time.Clock +import kotlin.time.ExperimentalTime /** * `ViewModel` for the Upload Documents screen. @@ -88,10 +90,9 @@ internal class UploadDocsViewModel : mutableStateFlow.update { it.copy( dialogState = null, - signatureDocumentFile = action.image, - // TODO:: Generate Unique Name & Calculate Size - signatureFileName = "signature.png", - signatureSize = "100 KB", + signatureDocumentFile = action.imageArray.toBase64DataUri(), + signatureFileName = generateUniqueFileName("signature", "png"), + signatureSize = formatFileSize(action.imageArray.size.toLong()), ) } } @@ -172,19 +173,11 @@ internal class UploadDocsViewModel : try { val image = FileKit.openFilePicker(type = FileKitType.Image) image?.let { file -> - val sizeInKB = file.size() / 1024 - val sizeInMb = sizeInKB / 1024 - val showFileSize = if (sizeInMb >= 1) { - "$sizeInMb MB" - } else { - "$sizeInKB KB" - } - mutableStateFlow.update { it.copy( propertyDocumentsFile = file.readBytes().toBase64DataUri(), propertyDocumentFileName = file.name, - propertyDocumentsSize = showFileSize, + propertyDocumentsSize = formatFileSize(file.size()), ) } } @@ -204,19 +197,11 @@ internal class UploadDocsViewModel : try { val image = FileKit.openFilePicker(type = FileKitType.Image) image?.let { file -> - val sizeInKB = file.size() / 1024 - val sizeInMb = sizeInKB / 1024 - val showFileSize = if (sizeInMb >= 1) { - "$sizeInMb MB" - } else { - "$sizeInKB KB" - } - mutableStateFlow.update { it.copy( bankStatementFile = file.readBytes().toBase64DataUri(), bankStatementFileName = file.name, - bankStatementSize = showFileSize, + bankStatementSize = formatFileSize(file.size()), ) } } @@ -252,20 +237,12 @@ internal class UploadDocsViewModel : val image = FileKit.openFilePicker(type = FileKitType.Image) image?.let { file -> - val sizeInKB = file.size() / 1024 - val sizeInMb = sizeInKB / 1024 - val showFileSize = if (sizeInMb >= 1) { - "$sizeInMb MB" - } else { - "$sizeInKB KB" - } - mutableStateFlow.update { it.copy( dialogState = null, signatureDocumentFile = file.readBytes().toBase64DataUri(), signatureFileName = file.name, - signatureSize = showFileSize, + signatureSize = formatFileSize(file.size()), ) } } @@ -342,6 +319,34 @@ internal class UploadDocsViewModel : private fun handleUploadDocumentResult(action: UploadDocsAction.Internal.UploadDocumentResultReceived) { // TODO: Implement logic to handle the upload result, e.g., show a toast or update state. } + + /** + * Calculates and formats the file size from bytes to a human-readable string. + * + * @param bytes The size in bytes. + * @return A formatted string showing size in MB or KB. + */ + private fun formatFileSize(bytes: Long): String { + val sizeInKB = bytes / 1024 + val sizeInMb = sizeInKB / 1024 + return if (sizeInMb >= 1) { + "$sizeInMb MB" + } else { + "$sizeInKB KB" + } + } + + /** + * Generates a unique filename with a timestamp. + * + * @param prefix The prefix for the filename . + * @param extension The file extension without the dot. + * @return A unique filename in the format "prefix_timestamp.extension". + */ + @OptIn(ExperimentalTime::class) + private fun generateUniqueFileName(prefix: String, extension: String): String { + return "${prefix}_${Clock.System.now().toEpochMilliseconds()}.$extension" + } } /** @@ -441,9 +446,9 @@ internal sealed interface UploadDocsAction { /** * User action to upload a signed image. - * @property image The base64-encoded string of the signature image. + * `@property` imageArray Raw bytes of the signature image. */ - data class UploadSign(val image: String) : UploadDocsAction + data class UploadSign(val imageArray: ByteArray) : UploadDocsAction /** * User action to initiate the upload of a document. diff --git a/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/component/BottomSheetContent.kt b/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/component/BottomSheetContent.kt index b7873c965..9e5f4c1ca 100644 --- a/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/component/BottomSheetContent.kt +++ b/feature/loan-application/src/commonMain/kotlin/org/mifos/mobile/feature/loan/application/uploadDocs/component/BottomSheetContent.kt @@ -59,7 +59,6 @@ import mifos_mobile.feature.loan_application.generated.resources.sign import mifos_mobile.feature.loan_application.generated.resources.sign_here import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.stringResource -import org.mifos.mobile.core.common.toBase64DataUri import org.mifos.mobile.core.designsystem.component.CardVariant import org.mifos.mobile.core.designsystem.component.MifosButton import org.mifos.mobile.core.designsystem.component.MifosCustomCard @@ -291,7 +290,7 @@ private fun SignatureContent( backgroundColor = Color.White, ) if (data != null) { - val data = data.encodeToByteArray().toBase64DataUri() + val data = data.encodeToByteArray() onAction(UploadDocsAction.UploadSign(data)) } }