mirror of
https://github.com/T8RIN/ImageToolbox.git
synced 2025-05-17 13:35:58 +08:00
Create initial markup layers boilerplate
This commit is contained in:
@ -1497,4 +1497,6 @@
|
||||
<string name="enable_tonemapping">Enable Tonemapping</string>
|
||||
<string name="enter_percent">Enter %</string>
|
||||
<string name="unknown_host">Cannot access the site, try using VPN or check if the url correct</string>
|
||||
<string name="markup_layers">Markup Layers</string>
|
||||
<string name="markup_layers_sub">Layers mode with ability to freely place images, text and more</string>
|
||||
</resources>
|
@ -36,6 +36,7 @@ import androidx.compose.material.icons.outlined.FolderZip
|
||||
import androidx.compose.material.icons.outlined.GifBox
|
||||
import androidx.compose.material.icons.outlined.Gradient
|
||||
import androidx.compose.material.icons.outlined.Grain
|
||||
import androidx.compose.material.icons.outlined.Layers
|
||||
import androidx.compose.material.icons.outlined.Photo
|
||||
import androidx.compose.material.icons.outlined.PictureAsPdf
|
||||
import androidx.compose.material.icons.outlined.QrCode
|
||||
@ -125,6 +126,7 @@ sealed class Screen(
|
||||
is NoiseGeneration -> "Noise_Generation"
|
||||
is CollageMaker -> "Collage_Maker"
|
||||
is LibrariesInfo -> "Libraries_Info"
|
||||
is MarkupLayers -> "Markup Layers"
|
||||
}
|
||||
|
||||
val icon: ImageVector?
|
||||
@ -168,8 +170,16 @@ sealed class Screen(
|
||||
is WebpTools -> Icons.Rounded.WebpBox
|
||||
NoiseGeneration -> Icons.Outlined.Grain
|
||||
is CollageMaker -> Icons.Outlined.AutoAwesomeMosaic
|
||||
is MarkupLayers -> Icons.Outlined.Layers //TODO: Icons for this and stacking
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object LibrariesInfo : Screen(
|
||||
id = -4,
|
||||
title = 0,
|
||||
subtitle = 0
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data object Settings : Screen(
|
||||
id = -3,
|
||||
@ -780,10 +790,12 @@ sealed class Screen(
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data object LibrariesInfo : Screen(
|
||||
id = -4,
|
||||
title = 0,
|
||||
subtitle = 0
|
||||
data class MarkupLayers(
|
||||
val uri: KUri? = null
|
||||
) : Screen(
|
||||
id = 34,
|
||||
title = R.string.markup_layers,
|
||||
subtitle = R.string.markup_layers_sub
|
||||
)
|
||||
|
||||
companion object {
|
||||
@ -806,6 +818,7 @@ sealed class Screen(
|
||||
Filter(),
|
||||
Draw(),
|
||||
EraseBackground(),
|
||||
MarkupLayers(),
|
||||
CollageMaker(),
|
||||
ImageStitching(),
|
||||
ImageStacking(),
|
||||
|
1
feature/markup-layers/.gitignore
vendored
Normal file
1
feature/markup-layers/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
25
feature/markup-layers/build.gradle.kts
Normal file
25
feature/markup-layers/build.gradle.kts
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* ImageToolbox is an image editor for android
|
||||
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* You should have received a copy of the Apache License
|
||||
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.image.toolbox.library)
|
||||
alias(libs.plugins.image.toolbox.feature)
|
||||
alias(libs.plugins.image.toolbox.hilt)
|
||||
alias(libs.plugins.image.toolbox.compose)
|
||||
}
|
||||
|
||||
android.namespace = "ru.tech.imageresizershrinker.feature.markup_layers"
|
4
feature/markup-layers/src/main/AndroidManifest.xml
Normal file
4
feature/markup-layers/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* ImageToolbox is an image editor for android
|
||||
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* You should have received a copy of the Apache License
|
||||
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
*/
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.markup_layers.presentation
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import ru.tech.imageresizershrinker.feature.markup_layers.presentation.screenLogic.MarkupLayersComponent
|
||||
|
||||
@Composable
|
||||
fun MarkupLayersContent(
|
||||
component: MarkupLayersComponent
|
||||
) {
|
||||
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
package ru.tech.imageresizershrinker.feature.markup_layers.presentation.components
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.InfiniteTransition
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.rememberTransformableState
|
||||
import androidx.compose.foundation.gestures.transformable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.BoxWithConstraintsScope
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
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.draw.clip
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.PathEffect
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.drawOutline
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun BoxWithConstraintsScope.EditBox(
|
||||
onTap: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
state: EditBoxState = remember { EditBoxState() },
|
||||
shape: Shape = RoundedCornerShape(4.dp),
|
||||
content: @Composable BoxScope.() -> Unit
|
||||
) {
|
||||
val parentSize by remember(constraints) {
|
||||
derivedStateOf {
|
||||
IntSize(
|
||||
constraints.maxWidth,
|
||||
constraints.maxHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
EditBox(
|
||||
modifier = modifier,
|
||||
onTap = onTap,
|
||||
state = state,
|
||||
parentSize = parentSize,
|
||||
shape = shape,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditBox(
|
||||
onTap: () -> Unit,
|
||||
parentSize: IntSize,
|
||||
modifier: Modifier = Modifier,
|
||||
state: EditBoxState = remember { EditBoxState() },
|
||||
shape: Shape = RoundedCornerShape(4.dp),
|
||||
content: @Composable BoxScope.() -> Unit
|
||||
) {
|
||||
var contentSize by remember {
|
||||
mutableStateOf(IntSize.Zero)
|
||||
}
|
||||
|
||||
val parentMaxWidth = parentSize.width
|
||||
val parentMaxHeight = parentSize.height
|
||||
|
||||
SideEffect {
|
||||
state.canvasSize = parentSize
|
||||
}
|
||||
|
||||
val transformState = rememberTransformableState { zoomChange, offsetChange, rotationChange ->
|
||||
state.applyChanges(
|
||||
parentMaxWidth = parentMaxWidth,
|
||||
parentMaxHeight = parentMaxHeight,
|
||||
contentSize = contentSize,
|
||||
zoomChange = zoomChange,
|
||||
offsetChange = offsetChange,
|
||||
rotationChange = rotationChange
|
||||
)
|
||||
}
|
||||
|
||||
val tapScale = remember { Animatable(1f) }
|
||||
|
||||
LaunchedEffect(state.isActive) {
|
||||
if (state.isActive) {
|
||||
tapScale.animateTo(0.95f)
|
||||
tapScale.animateTo(1.02f)
|
||||
tapScale.animateTo(1f)
|
||||
}
|
||||
}
|
||||
|
||||
val borderAlpha by animateFloatAsState(if (state.isActive) 1f else 0f)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.onSizeChanged {
|
||||
contentSize = it
|
||||
}
|
||||
.graphicsLayer(
|
||||
scaleX = state.scale,
|
||||
scaleY = state.scale,
|
||||
rotationZ = state.rotation,
|
||||
translationX = state.offset.x,
|
||||
translationY = state.offset.y
|
||||
)
|
||||
.scale(tapScale.value)
|
||||
.clip(shape)
|
||||
.background(MaterialTheme.colorScheme.primary.copy(0.2f * borderAlpha))
|
||||
.pointerInput(onTap) {
|
||||
detectTapGestures {
|
||||
onTap()
|
||||
}
|
||||
}
|
||||
.transformable(
|
||||
state = transformState,
|
||||
enabled = state.isActive
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
content()
|
||||
AnimatedBorder(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
alpha = borderAlpha,
|
||||
scale = state.scale,
|
||||
shape = shape
|
||||
)
|
||||
Surface(
|
||||
color = Color.Transparent,
|
||||
modifier = Modifier.matchParentSize()
|
||||
) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun AnimatedBorder(
|
||||
modifier: Modifier,
|
||||
alpha: Float,
|
||||
scale: Float,
|
||||
shape: Shape
|
||||
) {
|
||||
val transition: InfiniteTransition = rememberInfiniteTransition()
|
||||
|
||||
// Infinite phase animation for PathEffect
|
||||
val phase by transition.animateFloat(
|
||||
initialValue = 0f,
|
||||
targetValue = 80f,
|
||||
animationSpec = infiniteRepeatable(
|
||||
animation = tween(
|
||||
durationMillis = 1000,
|
||||
easing = LinearEasing
|
||||
),
|
||||
repeatMode = RepeatMode.Restart
|
||||
)
|
||||
)
|
||||
|
||||
val pathEffect = PathEffect.dashPathEffect(
|
||||
intervals = floatArrayOf(20f, 20f),
|
||||
phase = phase
|
||||
)
|
||||
|
||||
val density = LocalDensity.current
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
Canvas(modifier = modifier) {
|
||||
val outline = shape.createOutline(
|
||||
size = size,
|
||||
layoutDirection = layoutDirection,
|
||||
density = density
|
||||
)
|
||||
drawOutline(
|
||||
outline = outline,
|
||||
color = colorScheme.primary.copy(alpha),
|
||||
style = Stroke(
|
||||
width = 3.dp.toPx() * (1f / scale)
|
||||
)
|
||||
)
|
||||
drawOutline(
|
||||
outline = outline,
|
||||
color = colorScheme.primaryContainer.copy(alpha),
|
||||
style = Stroke(
|
||||
width = 3.dp.toPx() * (1f / scale),
|
||||
pathEffect = pathEffect
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package ru.tech.imageresizershrinker.feature.markup_layers.presentation.components
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.util.fastCoerceIn
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
class EditBoxState(
|
||||
scale: Float = 1f,
|
||||
rotation: Float = 0f,
|
||||
offset: Offset = Offset.Companion.Zero,
|
||||
isActive: Boolean = false
|
||||
) {
|
||||
var isActive by mutableStateOf(isActive)
|
||||
internal set
|
||||
|
||||
fun activate() {
|
||||
isActive = true
|
||||
}
|
||||
|
||||
fun deactivate() {
|
||||
isActive = false
|
||||
}
|
||||
|
||||
internal fun applyChanges(
|
||||
parentMaxWidth: Int,
|
||||
parentMaxHeight: Int,
|
||||
contentSize: IntSize,
|
||||
zoomChange: Float,
|
||||
offsetChange: Offset,
|
||||
rotationChange: Float
|
||||
) {
|
||||
rotation += rotationChange
|
||||
scale = (scale * zoomChange).fastCoerceIn(0.5f, 10f)
|
||||
val panChange = (offsetChange * scale).rotateBy(rotation)
|
||||
|
||||
val extraWidth = (parentMaxWidth - contentSize.width * scale).absoluteValue
|
||||
val extraHeight = (parentMaxHeight - contentSize.height * scale).absoluteValue
|
||||
|
||||
val maxX = extraWidth / 2
|
||||
val maxY = extraHeight / 2
|
||||
|
||||
offset = Offset(
|
||||
x = (offset.x + panChange.x).coerceIn(-maxX, maxX),
|
||||
y = (offset.y + panChange.y).coerceIn(-maxY, maxY),
|
||||
)
|
||||
}
|
||||
|
||||
var scale by mutableFloatStateOf(scale)
|
||||
internal set
|
||||
|
||||
var rotation by mutableFloatStateOf(rotation)
|
||||
internal set
|
||||
|
||||
var offset by mutableStateOf(offset)
|
||||
internal set
|
||||
|
||||
private val IntSize.aspect: Float get() = width / height.toFloat()
|
||||
|
||||
private val _canvasSize = mutableStateOf(IntSize.Companion.Zero)
|
||||
|
||||
var canvasSize: IntSize
|
||||
get() = _canvasSize.value
|
||||
set(value) {
|
||||
if (_canvasSize.value != IntSize.Companion.Zero && _canvasSize.value != value) {
|
||||
val sx = value.width.toFloat() / _canvasSize.value.width
|
||||
val sy = value.height.toFloat() / _canvasSize.value.height
|
||||
if (_canvasSize.value.aspect < value.aspect) {
|
||||
scale *= minOf(sx, sy)
|
||||
offset *= minOf(sx, sy)
|
||||
} else {
|
||||
scale /= minOf(sx, sy)
|
||||
offset /= minOf(sx, sy)
|
||||
}
|
||||
}
|
||||
_canvasSize.value = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun Offset.rotateBy(
|
||||
angle: Float
|
||||
): Offset {
|
||||
val angleInRadians = ROTATION_CONST * angle
|
||||
val newX = x * cos(angleInRadians) - y * sin(angleInRadians)
|
||||
val newY = x * sin(angleInRadians) + y * cos(angleInRadians)
|
||||
return Offset(newX, newY)
|
||||
}
|
||||
|
||||
private const val ROTATION_CONST = (Math.PI / 180f).toFloat()
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* ImageToolbox is an image editor for android
|
||||
* Copyright (c) 2024 T8RIN (Malik Mukhametzyanov)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* You should have received a copy of the Apache License
|
||||
* along with this program. If not, see <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
*/
|
||||
|
||||
package ru.tech.imageresizershrinker.feature.markup_layers.presentation.screenLogic
|
||||
|
||||
import android.net.Uri
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import ru.tech.imageresizershrinker.core.domain.dispatchers.DispatchersHolder
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.BaseComponent
|
||||
import ru.tech.imageresizershrinker.core.ui.utils.navigation.Screen
|
||||
|
||||
|
||||
class MarkupLayersComponent @AssistedInject internal constructor(
|
||||
@Assisted componentContext: ComponentContext,
|
||||
@Assisted initialUri: Uri?,
|
||||
@Assisted val onGoBack: () -> Unit,
|
||||
@Assisted val onNavigate: (Screen) -> Unit,
|
||||
dispatchersHolder: DispatchersHolder
|
||||
) : BaseComponent(dispatchersHolder, componentContext) {
|
||||
|
||||
@AssistedFactory
|
||||
fun interface Factory {
|
||||
operator fun invoke(
|
||||
componentContext: ComponentContext,
|
||||
initialUri: Uri?,
|
||||
onGoBack: () -> Unit,
|
||||
onNavigate: (Screen) -> Unit,
|
||||
): MarkupLayersComponent
|
||||
}
|
||||
|
||||
}
|
@ -63,4 +63,5 @@ dependencies {
|
||||
implementation(projects.feature.noiseGeneration)
|
||||
implementation(projects.feature.colllageMaker)
|
||||
implementation(projects.feature.librariesInfo)
|
||||
implementation(projects.feature.markupLayers)
|
||||
}
|
@ -43,6 +43,7 @@ import ru.tech.imageresizershrinker.feature.libraries_info.presentation.screenLo
|
||||
import ru.tech.imageresizershrinker.feature.limits_resize.presentation.screenLogic.LimitsResizeComponent
|
||||
import ru.tech.imageresizershrinker.feature.load_net_image.presentation.screenLogic.LoadNetImageComponent
|
||||
import ru.tech.imageresizershrinker.feature.main.presentation.screenLogic.MainComponent
|
||||
import ru.tech.imageresizershrinker.feature.markup_layers.presentation.screenLogic.MarkupLayersComponent
|
||||
import ru.tech.imageresizershrinker.feature.pdf_tools.presentation.screenLogic.PdfToolsComponent
|
||||
import ru.tech.imageresizershrinker.feature.pick_color.presentation.screenLogic.PickColorFromImageComponent
|
||||
import ru.tech.imageresizershrinker.feature.recognize.text.presentation.screenLogic.RecognizeTextComponent
|
||||
@ -98,7 +99,8 @@ internal class ChildProvider @Inject constructor(
|
||||
private val easterEggComponentFactory: EasterEggComponent.Factory,
|
||||
private val colorToolsComponentFactory: ColorToolsComponent.Factory,
|
||||
private val librariesInfoComponentFactory: LibrariesInfoComponent.Factory,
|
||||
private val mainComponentFactory: MainComponent.Factory
|
||||
private val mainComponentFactory: MainComponent.Factory,
|
||||
private val markupLayersComponentFactory: MarkupLayersComponent.Factory
|
||||
) {
|
||||
fun RootComponent.createChild(
|
||||
config: Screen,
|
||||
@ -430,5 +432,14 @@ internal class ChildProvider @Inject constructor(
|
||||
onGoBack = ::navigateBack
|
||||
)
|
||||
)
|
||||
|
||||
is Screen.MarkupLayers -> NavigationChild.MarkupLayers(
|
||||
markupLayersComponentFactory(
|
||||
componentContext = componentContext,
|
||||
initialUri = config.uri,
|
||||
onGoBack = ::navigateBack,
|
||||
onNavigate = ::navigateTo
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -66,6 +66,8 @@ import ru.tech.imageresizershrinker.feature.load_net_image.presentation.LoadNetI
|
||||
import ru.tech.imageresizershrinker.feature.load_net_image.presentation.screenLogic.LoadNetImageComponent
|
||||
import ru.tech.imageresizershrinker.feature.main.presentation.MainContent
|
||||
import ru.tech.imageresizershrinker.feature.main.presentation.screenLogic.MainComponent
|
||||
import ru.tech.imageresizershrinker.feature.markup_layers.presentation.MarkupLayersContent
|
||||
import ru.tech.imageresizershrinker.feature.markup_layers.presentation.screenLogic.MarkupLayersComponent
|
||||
import ru.tech.imageresizershrinker.feature.pdf_tools.presentation.PdfToolsContent
|
||||
import ru.tech.imageresizershrinker.feature.pdf_tools.presentation.screenLogic.PdfToolsComponent
|
||||
import ru.tech.imageresizershrinker.feature.pick_color.presentation.PickColorFromImageContent
|
||||
@ -292,4 +294,9 @@ internal sealed class NavigationChild {
|
||||
override fun Content() = LibrariesInfoContent(component)
|
||||
}
|
||||
|
||||
class MarkupLayers(val component: MarkupLayersComponent) : NavigationChild() {
|
||||
@Composable
|
||||
override fun Content() = MarkupLayersContent(component)
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,8 @@ androidMinSdk = "21"
|
||||
androidTargetSdk = "35"
|
||||
androidCompileSdk = "35"
|
||||
|
||||
versionName = "3.1.0"
|
||||
versionCode = "159"
|
||||
versionName = "3.2.0-alpha01"
|
||||
versionCode = "160"
|
||||
|
||||
jvmTarget = "17"
|
||||
|
||||
@ -75,6 +75,7 @@ zxingAndroidEmbedded = "4.3.0"
|
||||
capturable = "3.0.0"
|
||||
moshi = "1.15.1"
|
||||
aboutlibraries = "11.2.3"
|
||||
junit = "4.13.2"
|
||||
|
||||
[libraries]
|
||||
aboutlibraries-m3 = { module = "com.mikepenz:aboutlibraries-compose-m3", version.ref = "aboutlibraries" }
|
||||
@ -193,6 +194,7 @@ androidx-material = { module = "androidx.compose.material:material", version.ref
|
||||
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
|
||||
|
||||
desugaring = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugaring" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
|
||||
[plugins]
|
||||
image-toolbox-library = { id = "image.toolbox.library", version = "unspecified" }
|
||||
|
@ -17,6 +17,9 @@
|
||||
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
include(":feature:markup-layers")
|
||||
|
||||
|
||||
include(":feature:libraries-info")
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user