mirror of
https://github.com/T8RIN/ImageToolbox.git
synced 2025-12-28 05:14:55 +00:00
Increase qr customization
This commit is contained in:
parent
42c11d67bc
commit
00faa3ccde
@ -48,7 +48,7 @@ class ImageToolboxApplicationPlugin : Plugin<Project> {
|
||||
apply(plugin = "kotlin-parcelize")
|
||||
apply(plugin = "com.google.gms.google-services")
|
||||
apply(plugin = "com.google.firebase.crashlytics")
|
||||
apply(plugin = "com.mikepenz.aboutlibraries.plugin")
|
||||
apply(plugin = "com.mikepenz.aboutlibraries.plugin.android")
|
||||
apply(plugin = "org.jetbrains.kotlin.plugin.compose")
|
||||
apply(plugin = "io.gitlab.arturbosch.detekt")
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ data class IconShape(
|
||||
)
|
||||
}
|
||||
|
||||
val entries: ImmutableList<IconShape> by lazy {
|
||||
val entriesNoRandom: ImmutableList<IconShape> by lazy {
|
||||
listOf(
|
||||
IconShape(SquircleShape),
|
||||
IconShape(RoundedCornerShape(15)),
|
||||
@ -127,8 +127,11 @@ data class IconShape(
|
||||
IconShape(it.toShape(), 10.dp, 20.dp)
|
||||
}
|
||||
addAll(shapes)
|
||||
add(Random)
|
||||
}.toPersistentList()
|
||||
}
|
||||
|
||||
val entries: ImmutableList<IconShape> by lazy {
|
||||
(entriesNoRandom + Random).toPersistentList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,6 +41,9 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.addOutline
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
@ -48,7 +51,9 @@ import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.min
|
||||
import androidx.core.graphics.createBitmap
|
||||
@ -57,12 +62,14 @@ import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.t8rin.imagetoolbox.core.domain.utils.runSuspendCatching
|
||||
import com.t8rin.imagetoolbox.core.settings.presentation.model.IconShape
|
||||
import com.t8rin.imagetoolbox.core.settings.presentation.provider.LocalSettingsState
|
||||
import com.t8rin.imagetoolbox.core.ui.utils.painter.centerCrop
|
||||
import com.t8rin.imagetoolbox.core.ui.utils.painter.roundCorners
|
||||
import com.t8rin.imagetoolbox.core.ui.widget.image.Picture
|
||||
import com.t8rin.imagetoolbox.core.ui.widget.modifier.shimmer
|
||||
import com.t8rin.imagetoolbox.core.utils.generateQrBitmap
|
||||
import io.github.alexzhirkevich.qrose.options.Neighbors
|
||||
import io.github.alexzhirkevich.qrose.options.QrBallShape
|
||||
import io.github.alexzhirkevich.qrose.options.QrBrush
|
||||
import io.github.alexzhirkevich.qrose.options.QrColors
|
||||
@ -223,16 +230,65 @@ data class QrCodeParams(
|
||||
val errorCorrectionLevel: ErrorCorrectionLevel = ErrorCorrectionLevel.Auto,
|
||||
val maskPattern: MaskPattern = MaskPattern.Auto
|
||||
) {
|
||||
enum class PixelShape {
|
||||
Square, RoundSquare, Circle, Vertical, Horizontal
|
||||
sealed interface PixelShape {
|
||||
sealed interface Predefined : PixelShape
|
||||
|
||||
data object Square : Predefined
|
||||
data object RoundSquare : Predefined
|
||||
data object Circle : Predefined
|
||||
data object Vertical : Predefined
|
||||
data object Horizontal : Predefined
|
||||
|
||||
data object Random : PixelShape
|
||||
data class Shaped(val shape: Shape) : PixelShape
|
||||
|
||||
companion object {
|
||||
val entries by lazy {
|
||||
listOf(
|
||||
Random,
|
||||
Square,
|
||||
RoundSquare,
|
||||
Circle,
|
||||
Vertical,
|
||||
Horizontal,
|
||||
) + (IconShape.entries - IconShape.Random).mapNotNull {
|
||||
if (it.shape is RoundedCornerShape) return@mapNotNull null
|
||||
|
||||
Shaped(it.shape)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class FrameShape {
|
||||
Square, RoundSquare, Circle
|
||||
}
|
||||
|
||||
enum class BallShape {
|
||||
Square, RoundSquare, Circle
|
||||
sealed interface BallShape {
|
||||
sealed interface Predefined : BallShape
|
||||
|
||||
data object Square : Predefined
|
||||
data object RoundSquare : Predefined
|
||||
data object Circle : Predefined
|
||||
|
||||
data object Random : BallShape
|
||||
data class Shaped(val shape: Shape) : BallShape
|
||||
|
||||
//TODO: inspect which ones cannot be read
|
||||
companion object {
|
||||
val entries by lazy {
|
||||
listOf(
|
||||
Random,
|
||||
Square,
|
||||
RoundSquare,
|
||||
Circle,
|
||||
) + (IconShape.entries - IconShape.Random).mapNotNull {
|
||||
if (it.shape is RoundedCornerShape) return@mapNotNull null
|
||||
|
||||
Shaped(it.shape)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ErrorCorrectionLevel {
|
||||
@ -322,6 +378,8 @@ fun QrCode(
|
||||
).image?.asPainter(context)?.centerCrop()
|
||||
}
|
||||
|
||||
val density = LocalDensity.current
|
||||
|
||||
val params by remember(
|
||||
width,
|
||||
height,
|
||||
@ -329,7 +387,8 @@ fun QrCode(
|
||||
foregroundColor,
|
||||
backgroundColor,
|
||||
qrParams,
|
||||
logoPainter
|
||||
logoPainter,
|
||||
density
|
||||
) {
|
||||
derivedStateOf {
|
||||
when (type) {
|
||||
@ -352,9 +411,9 @@ fun QrCode(
|
||||
)
|
||||
} ?: QrLogo(),
|
||||
shapes = QrShapes(
|
||||
darkPixel = qrParams.pixelShape.toLib(),
|
||||
darkPixel = qrParams.pixelShape.toLib(density),
|
||||
frame = qrParams.frameShape.toLib(),
|
||||
ball = qrParams.ballShape.toLib()
|
||||
ball = qrParams.ballShape.toLib(density)
|
||||
),
|
||||
errorCorrectionLevel = qrParams.errorCorrectionLevel.toLib(),
|
||||
maskPattern = qrParams.maskPattern.toLib()
|
||||
@ -421,10 +480,48 @@ fun QrCode(
|
||||
}
|
||||
}
|
||||
|
||||
private fun QrCodeParams.BallShape.toLib(): QrBallShape = when (this) {
|
||||
private fun pixelShape(
|
||||
density: Density,
|
||||
shape: () -> Shape
|
||||
) = object : QrPixelShape {
|
||||
override fun Path.path(
|
||||
size: Float,
|
||||
neighbors: Neighbors
|
||||
): Path = apply {
|
||||
addOutline(
|
||||
shape().createOutline(
|
||||
size = Size(size, size),
|
||||
layoutDirection = LayoutDirection.Ltr,
|
||||
density = density
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ballShape(
|
||||
density: Density,
|
||||
shape: () -> Shape
|
||||
) = object : QrBallShape {
|
||||
override fun Path.path(
|
||||
size: Float,
|
||||
neighbors: Neighbors
|
||||
): Path = apply {
|
||||
addOutline(
|
||||
shape().createOutline(
|
||||
size = Size(size, size),
|
||||
layoutDirection = LayoutDirection.Ltr,
|
||||
density = density
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun QrCodeParams.BallShape.toLib(density: Density): QrBallShape = when (this) {
|
||||
QrCodeParams.BallShape.Square -> QrBallShape.square()
|
||||
QrCodeParams.BallShape.RoundSquare -> QrBallShape.roundCorners(0.25f)
|
||||
QrCodeParams.BallShape.Circle -> QrBallShape.circle()
|
||||
QrCodeParams.BallShape.Random -> ballShape(density) { IconShape.entriesNoRandom.random().shape }
|
||||
is QrCodeParams.BallShape.Shaped -> ballShape(density) { shape }
|
||||
}
|
||||
|
||||
private fun QrCodeParams.FrameShape.toLib(): QrFrameShape = when (this) {
|
||||
@ -433,12 +530,14 @@ private fun QrCodeParams.FrameShape.toLib(): QrFrameShape = when (this) {
|
||||
QrCodeParams.FrameShape.Circle -> QrFrameShape.circle()
|
||||
}
|
||||
|
||||
private fun QrCodeParams.PixelShape.toLib(): QrPixelShape = when (this) {
|
||||
private fun QrCodeParams.PixelShape.toLib(density: Density): QrPixelShape = when (this) {
|
||||
QrCodeParams.PixelShape.Square -> QrPixelShape.square()
|
||||
QrCodeParams.PixelShape.RoundSquare -> QrPixelShape.roundCorners()
|
||||
QrCodeParams.PixelShape.Circle -> QrPixelShape.circle()
|
||||
QrCodeParams.PixelShape.Vertical -> QrPixelShape.verticalLines()
|
||||
QrCodeParams.PixelShape.Horizontal -> QrPixelShape.horizontalLines()
|
||||
QrCodeParams.PixelShape.Random -> pixelShape(density) { IconShape.entriesNoRandom.random().shape }
|
||||
is QrCodeParams.PixelShape.Shaped -> pixelShape(density) { shape }
|
||||
}
|
||||
|
||||
private fun QrCodeParams.ErrorCorrectionLevel.toLib(): QrErrorCorrectionLevel = when (this) {
|
||||
|
||||
@ -269,9 +269,8 @@ fun DrawLineStyleSelector(
|
||||
else MaterialStarShape
|
||||
|
||||
Column {
|
||||
val shapes = remember {
|
||||
IconShape.entries.dropLast(1)
|
||||
}
|
||||
val shapes = IconShape.entriesNoRandom
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
|
||||
@ -19,16 +19,19 @@ package com.t8rin.imagetoolbox.feature.scan_qr_code.presentation.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Code
|
||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
||||
@ -37,10 +40,12 @@ import androidx.compose.material.icons.outlined.PhotoSizeSelectLarge
|
||||
import androidx.compose.material.icons.outlined.RoundedCorner
|
||||
import androidx.compose.material.icons.rounded.Circle
|
||||
import androidx.compose.material.icons.rounded.RoundedCorner
|
||||
import androidx.compose.material.icons.rounded.Shuffle
|
||||
import androidx.compose.material.icons.rounded.TableRows
|
||||
import androidx.compose.material.icons.rounded.ViewColumn
|
||||
import androidx.compose.material.icons.sharp.Square
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -280,12 +285,7 @@ internal fun QrParamsSelector(
|
||||
),
|
||||
entries = PixelShape.entries,
|
||||
value = value.pixelShape,
|
||||
itemContent = {
|
||||
Icon(
|
||||
imageVector = it.icon,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
itemContent = { it.Content() },
|
||||
onValueChange = {
|
||||
onValueChange(
|
||||
value.copy(
|
||||
@ -330,12 +330,7 @@ internal fun QrParamsSelector(
|
||||
),
|
||||
entries = BallShape.entries,
|
||||
value = value.ballShape,
|
||||
itemContent = {
|
||||
Icon(
|
||||
imageVector = it.icon,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
itemContent = { it.Content() },
|
||||
onValueChange = {
|
||||
onValueChange(
|
||||
value.copy(
|
||||
@ -405,14 +400,43 @@ internal fun QrParamsSelector(
|
||||
}
|
||||
}
|
||||
|
||||
private val PixelShape.icon: ImageVector
|
||||
get() = when (this) {
|
||||
PixelShape.Square -> Icons.Sharp.Square
|
||||
PixelShape.RoundSquare -> Icons.Rounded.RoundedCorner
|
||||
PixelShape.Circle -> Icons.Rounded.Circle
|
||||
PixelShape.Vertical -> Icons.Rounded.ViewColumn
|
||||
PixelShape.Horizontal -> Icons.Rounded.TableRows
|
||||
@Composable
|
||||
private fun PixelShape.Content() {
|
||||
when (this) {
|
||||
is PixelShape.Predefined -> {
|
||||
Icon(
|
||||
imageVector = when (this) {
|
||||
PixelShape.Square -> Icons.Sharp.Square
|
||||
PixelShape.RoundSquare -> Icons.Rounded.RoundedCorner
|
||||
PixelShape.Circle -> Icons.Rounded.Circle
|
||||
PixelShape.Vertical -> Icons.Rounded.ViewColumn
|
||||
PixelShape.Horizontal -> Icons.Rounded.TableRows
|
||||
},
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
is PixelShape.Random -> {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Shuffle,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
is PixelShape.Shaped -> {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.background(
|
||||
color = LocalContentColor.current,
|
||||
shape = shape,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val FrameShape.icon: ImageVector
|
||||
get() = when (this) {
|
||||
@ -421,9 +445,38 @@ private val FrameShape.icon: ImageVector
|
||||
FrameShape.Circle -> Icons.Rounded.Circle
|
||||
}
|
||||
|
||||
private val BallShape.icon: ImageVector
|
||||
get() = when (this) {
|
||||
BallShape.Square -> Icons.Sharp.Square
|
||||
BallShape.RoundSquare -> Icons.Rounded.RoundedCorner
|
||||
BallShape.Circle -> Icons.Rounded.Circle
|
||||
}
|
||||
@Composable
|
||||
private fun BallShape.Content() {
|
||||
when (this) {
|
||||
is BallShape.Predefined -> {
|
||||
Icon(
|
||||
imageVector = when (this) {
|
||||
BallShape.Square -> Icons.Sharp.Square
|
||||
BallShape.RoundSquare -> Icons.Rounded.RoundedCorner
|
||||
BallShape.Circle -> Icons.Rounded.Circle
|
||||
},
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
is BallShape.Random -> {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Shuffle,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
|
||||
is BallShape.Shaped -> {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.size(20.dp)
|
||||
.background(
|
||||
color = LocalContentColor.current,
|
||||
shape = shape,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user