diff --git a/core/resources/src/main/res/values/strings.xml b/core/resources/src/main/res/values/strings.xml
index a556d8e40..b65278f42 100644
--- a/core/resources/src/main/res/values/strings.xml
+++ b/core/resources/src/main/res/values/strings.xml
@@ -1497,4 +1497,6 @@
Enable Tonemapping
Enter %
Cannot access the site, try using VPN or check if the url correct
+ Markup Layers
+ Layers mode with ability to freely place images, text and more
\ No newline at end of file
diff --git a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/utils/navigation/Screen.kt b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/utils/navigation/Screen.kt
index 30e27556e..752d7c9e9 100644
--- a/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/utils/navigation/Screen.kt
+++ b/core/ui/src/main/kotlin/ru/tech/imageresizershrinker/core/ui/utils/navigation/Screen.kt
@@ -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(),
diff --git a/feature/markup-layers/.gitignore b/feature/markup-layers/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/markup-layers/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/markup-layers/build.gradle.kts b/feature/markup-layers/build.gradle.kts
new file mode 100644
index 000000000..259af43f5
--- /dev/null
+++ b/feature/markup-layers/build.gradle.kts
@@ -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 .
+ */
+
+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"
\ No newline at end of file
diff --git a/feature/markup-layers/src/main/AndroidManifest.xml b/feature/markup-layers/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..44008a433
--- /dev/null
+++ b/feature/markup-layers/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/MarkupLayersContent.kt b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/MarkupLayersContent.kt
new file mode 100644
index 000000000..917074947
--- /dev/null
+++ b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/MarkupLayersContent.kt
@@ -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 .
+ */
+
+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
+) {
+
+}
\ No newline at end of file
diff --git a/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBox.kt b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBox.kt
new file mode 100644
index 000000000..d8546a75a
--- /dev/null
+++ b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBox.kt
@@ -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
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBoxState.kt b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBoxState.kt
new file mode 100644
index 000000000..56f80e2be
--- /dev/null
+++ b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/components/EditBoxState.kt
@@ -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()
\ No newline at end of file
diff --git a/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/screenLogic/MarkupLayersComponent.kt b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/screenLogic/MarkupLayersComponent.kt
new file mode 100644
index 000000000..f4e20dbdd
--- /dev/null
+++ b/feature/markup-layers/src/main/java/ru/tech/imageresizershrinker/feature/markup_layers/presentation/screenLogic/MarkupLayersComponent.kt
@@ -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 .
+ */
+
+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
+ }
+
+}
\ No newline at end of file
diff --git a/feature/root/build.gradle.kts b/feature/root/build.gradle.kts
index d2673432d..5fd5c03f5 100644
--- a/feature/root/build.gradle.kts
+++ b/feature/root/build.gradle.kts
@@ -63,4 +63,5 @@ dependencies {
implementation(projects.feature.noiseGeneration)
implementation(projects.feature.colllageMaker)
implementation(projects.feature.librariesInfo)
+ implementation(projects.feature.markupLayers)
}
\ No newline at end of file
diff --git a/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/ChildProvider.kt b/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/ChildProvider.kt
index 3ac6e5108..a1016b0d6 100644
--- a/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/ChildProvider.kt
+++ b/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/ChildProvider.kt
@@ -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
+ )
+ )
}
}
\ No newline at end of file
diff --git a/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/NavigationChild.kt b/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/NavigationChild.kt
index 90323ad6a..321b0a7da 100644
--- a/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/NavigationChild.kt
+++ b/feature/root/src/main/java/ru/tech/imageresizershrinker/feature/root/presentation/components/navigation/NavigationChild.kt
@@ -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)
+ }
+
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 7335a1220..4e423f128 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -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" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a9e970150..773cc877c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -17,6 +17,9 @@
@file:Suppress("UnstableApiUsage")
+include(":feature:markup-layers")
+
+
include(":feature:libraries-info")