-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from Lilytreasure/pdfgendev
added signature functionality
- Loading branch information
Showing
11 changed files
with
584 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import android.graphics.Bitmap | ||
import android.graphics.BitmapFactory | ||
import androidx.compose.ui.graphics.ImageBitmap | ||
import androidx.compose.ui.graphics.asAndroidBitmap | ||
import androidx.compose.ui.graphics.asImageBitmap | ||
import java.io.ByteArrayOutputStream | ||
|
||
/** | ||
* Converts [ImageBitmap] to image with desired [format] and returns its bytes. | ||
* | ||
* */ | ||
|
||
actual typealias ImageFormat = Bitmap.CompressFormat | ||
actual fun ImageBitmap.toByteArray(format: ImageFormat): ByteArray { | ||
return ByteArrayOutputStream().use { | ||
asAndroidBitmap().compress(format, 100, it) | ||
it.toByteArray() | ||
} | ||
} | ||
|
||
actual fun ByteArray.toImageBitmap(): ImageBitmap { | ||
// Decode the ByteArray into a Bitmap | ||
val bitmap = BitmapFactory.decodeByteArray(this, 0, this.size) | ||
// Convert the Bitmap to ImageBitmap | ||
return bitmap.asImageBitmap() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
|
||
|
||
import androidx.compose.ui.geometry.Size | ||
import androidx.compose.ui.graphics.Canvas | ||
import androidx.compose.ui.graphics.ColorFilter | ||
import androidx.compose.ui.graphics.ImageBitmap | ||
import androidx.compose.ui.graphics.drawscope.CanvasDrawScope | ||
import androidx.compose.ui.graphics.painter.Painter | ||
import androidx.compose.ui.unit.Density | ||
import androidx.compose.ui.unit.LayoutDirection | ||
|
||
expect enum class ImageFormat { | ||
PNG, JPEG, WEBP | ||
} | ||
|
||
/** | ||
* Converts [ImageBitmap] to image with desired [format] and returns its bytes. | ||
* */ | ||
expect fun ImageBitmap.toByteArray(format: ImageFormat = ImageFormat.PNG) : ByteArray | ||
|
||
/** | ||
* Converts [Painter] to image with desired [width], [height] and [format] and returns its bytes. | ||
* */ | ||
fun Painter.toByteArray(width : Int, height: Int, format : ImageFormat = ImageFormat.PNG) : ByteArray = | ||
toImageBitmap(width, height).toByteArray(format) | ||
|
||
/** | ||
* Converts [Painter] to [ImageBitmap] with desired [width], [height], [alpha] and [colorFilter] | ||
* */ | ||
fun Painter.toImageBitmap( | ||
width : Int, | ||
height : Int, | ||
alpha : Float = 1f, | ||
colorFilter: ColorFilter? = null | ||
) : ImageBitmap { | ||
|
||
val bmp = ImageBitmap(width, height) | ||
val canvas = Canvas(bmp) | ||
|
||
CanvasDrawScope().draw( | ||
density = Density(1f, 1f), | ||
layoutDirection = LayoutDirection.Ltr, | ||
canvas = canvas, | ||
size = Size(width.toFloat(), height.toFloat()) | ||
) { | ||
draw(this@draw.size, alpha, colorFilter) | ||
} | ||
|
||
return bmp | ||
} | ||
|
||
expect fun ByteArray.toImageBitmap(): ImageBitmap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package composables | ||
|
||
import androidx.compose.foundation.layout.fillMaxHeight | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.material.Text | ||
import androidx.compose.material3.AlertDialog | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.TextButton | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.ImageBitmap | ||
import androidx.compose.ui.graphics.vector.ImageVector | ||
|
||
@Composable | ||
fun AlertDialogExample( | ||
onDismissRequest: () -> Unit, | ||
onConfirmation: (ImageBitmap?) -> Unit, | ||
dialogTitle: String, | ||
icon: ImageVector, | ||
) { | ||
var capturedSignature by remember { mutableStateOf<ImageBitmap?>(null) } | ||
AlertDialog( | ||
icon = { | ||
Icon(icon, contentDescription = "Example Icon") | ||
}, | ||
title = { | ||
Text(text = dialogTitle) | ||
}, | ||
text = { | ||
SignatureContainer( | ||
onSignatureCaptured = { signature -> | ||
capturedSignature = signature // Capture the result | ||
} | ||
) | ||
}, | ||
onDismissRequest = { | ||
onDismissRequest() | ||
}, | ||
confirmButton = { | ||
TextButton( | ||
onClick = { | ||
onConfirmation(capturedSignature) | ||
} | ||
) { | ||
Text("Confirm") | ||
} | ||
}, | ||
dismissButton = { | ||
TextButton( | ||
onClick = { | ||
onDismissRequest() | ||
} | ||
) { | ||
Text("Dismiss") | ||
} | ||
}, | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.fillMaxHeight(0.5f) | ||
) | ||
} |
71 changes: 71 additions & 0 deletions
71
composeApp/src/commonMain/kotlin/composables/PdFViewCard.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package composables | ||
|
||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.MoreVert | ||
import androidx.compose.material.icons.outlined.PictureAsPdf | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.unit.dp | ||
import androidx.compose.ui.unit.sp | ||
import theme.backArrowColor | ||
|
||
@Composable | ||
fun PdfViewCard(label: String, description: String? = null, onClickContainer: () -> Unit){ | ||
Box(modifier = Modifier | ||
.background(color = MaterialTheme.colorScheme.inverseOnSurface) | ||
.clickable { | ||
onClickContainer() | ||
}) { | ||
Row( | ||
modifier = Modifier.padding(top = 9.dp, bottom = 9.dp) | ||
.fillMaxWidth(), | ||
verticalAlignment = Alignment.CenterVertically){ | ||
Row(verticalAlignment = Alignment.CenterVertically){ | ||
Icon( | ||
Icons.Outlined.PictureAsPdf, | ||
contentDescription = null | ||
) | ||
Column { | ||
Text( | ||
text = label, | ||
modifier = Modifier.padding(start = 15.dp), | ||
fontSize = 14.sp, | ||
color= MaterialTheme.colorScheme.onBackground, | ||
style = MaterialTheme.typography.bodyMedium | ||
) | ||
|
||
if (description != null) { | ||
Text( | ||
text = description, | ||
modifier = Modifier.padding(start = 15.dp), | ||
color= MaterialTheme.colorScheme.outline, | ||
style = MaterialTheme.typography.bodyMedium | ||
) | ||
} | ||
|
||
} | ||
} | ||
Row { | ||
Spacer(modifier = Modifier.weight(1f)) | ||
Icon( | ||
Icons.Filled.MoreVert, | ||
contentDescription = "share file", | ||
tint = backArrowColor | ||
) | ||
Spacer(modifier = Modifier.padding(end = 15.dp)) | ||
} | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
composeApp/src/commonMain/kotlin/composables/SignatureAction.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package composables | ||
|
||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.Spacer | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.outlined.Draw | ||
import androidx.compose.material3.ElevatedCard | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.unit.dp | ||
import androidx.compose.ui.unit.sp | ||
import theme.backArrowColor | ||
|
||
@Composable | ||
fun SignAction(label: String, description: String? = null, onClickContainer: () -> Unit) { | ||
ElevatedCard( | ||
onClick = onClickContainer, | ||
modifier = Modifier.fillMaxWidth() | ||
.background(color = MaterialTheme.colorScheme.background) | ||
) { | ||
Box(modifier = Modifier.background(color = MaterialTheme.colorScheme.inverseOnSurface)) { | ||
Row( | ||
modifier = Modifier.padding(top = 12.dp, bottom = 12.dp) | ||
.fillMaxWidth(), | ||
verticalAlignment = Alignment.CenterVertically | ||
) { | ||
Column { | ||
Text( | ||
text = label, | ||
modifier = Modifier.padding(start = 15.dp), | ||
fontSize = 14.sp, | ||
color = MaterialTheme.colorScheme.onBackground, | ||
style = MaterialTheme.typography.bodyMedium | ||
) | ||
|
||
if (description != null) { | ||
Text( | ||
text = description, | ||
modifier = Modifier.padding(start = 15.dp), | ||
color = MaterialTheme.colorScheme.outline, | ||
style = MaterialTheme.typography.bodyMedium | ||
) | ||
} | ||
|
||
} | ||
Row { | ||
Spacer(modifier = Modifier.weight(1f)) | ||
Icon( | ||
Icons.Outlined.Draw, | ||
contentDescription = "sign", | ||
tint = backArrowColor | ||
) | ||
Spacer(modifier = Modifier.padding(end = 15.dp)) | ||
} | ||
} | ||
} | ||
} | ||
} |
101 changes: 101 additions & 0 deletions
101
composeApp/src/commonMain/kotlin/composables/SignatureContainer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package composables | ||
|
||
import androidx.compose.foundation.BorderStroke | ||
import androidx.compose.foundation.border | ||
import androidx.compose.foundation.gestures.detectDragGestures | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.saveable.rememberSaveable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.drawWithContent | ||
import androidx.compose.ui.graphics.Color | ||
import androidx.compose.ui.graphics.ImageBitmap | ||
import androidx.compose.ui.graphics.StrokeCap | ||
import androidx.compose.ui.input.pointer.pointerInput | ||
import androidx.compose.ui.unit.dp | ||
import utils.SignatureLine | ||
import utils.SignatureState | ||
import utils.toImageBitmap | ||
|
||
@Composable | ||
fun SignatureContainer( | ||
onSignatureCaptured: (ImageBitmap) -> Unit // Callback to pass the result | ||
) { | ||
val state = rememberSignatureState() | ||
Column() { | ||
Box( | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.height(250.dp) | ||
.border( | ||
BorderStroke( | ||
width = 0.5.dp, | ||
color = MaterialTheme.colorScheme.primary, | ||
), | ||
shape = RoundedCornerShape(8.dp), | ||
) | ||
.pointerInput(Unit) { | ||
detectDragGestures { change, dragAmount -> | ||
change.consume() | ||
val signatureLine = SignatureLine( | ||
start = change.position - dragAmount, | ||
end = change.position, | ||
) | ||
state.addSignatureLine(signatureLine) | ||
} | ||
} | ||
.drawWithContent { | ||
drawContent() | ||
state.updateSignature( | ||
toImageBitmap( | ||
width = size.width.toInt(), | ||
height = size.height.toInt(), | ||
signatureColor = Color.Black, | ||
signatureSize = 5.dp, | ||
signatureSignatureLines = state.signatureLines, | ||
), | ||
) | ||
} | ||
) { | ||
androidx.compose.foundation.Canvas(modifier = Modifier.fillMaxSize()) { // Draw all the signature lines in real time | ||
state.signatureLines.forEach { line -> | ||
drawLine( | ||
color = Color.Black, | ||
start = line.start, | ||
end = line.end, | ||
strokeWidth = 4.dp.toPx(), | ||
cap = StrokeCap.Round | ||
) | ||
} | ||
} | ||
} | ||
state.signature.let { | ||
if (it != null) { | ||
// it.toByteArray(ImageFormat.PNG) convert for storage | ||
onSignatureCaptured(it) | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
@Composable | ||
fun rememberSignatureState(): SignatureState { | ||
return rememberSaveable(saver = SignatureState.Saver) { | ||
SignatureState() | ||
} | ||
} | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
Oops, something went wrong.