diff --git a/.idea/runConfigurations/kmmutils__dokkaHtml_.xml b/.idea/runConfigurations/kmmutils__dokkaHtml_.xml
deleted file mode 100644
index cfb3025..0000000
--- a/.idea/runConfigurations/kmmutils__dokkaHtml_.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- true
- true
- false
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/kmmutils__publishAllPublicationsToSonatypeRepository_.xml b/.idea/runConfigurations/kmmutils__publishAllPublicationsToSonatypeRepository_.xml
deleted file mode 100644
index 8f18692..0000000
--- a/.idea/runConfigurations/kmmutils__publishAllPublicationsToSonatypeRepository_.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
- true
- false
- false
-
-
-
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 8fa3f19..365aac2 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,6 +4,7 @@ import nl.littlerobots.vcu.plugin.versionCatalogUpdate
import nl.littlerobots.vcu.plugin.versionSelector
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradleSubplugin
+import org.jetbrains.kotlin.compose.compiler.gradle.ComposeFeatureFlag.Companion.OptimizeNonSkippingGroups
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnLockMismatchReport
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
@@ -37,6 +38,7 @@ buildscript {
allprojects {
group = Config.artifactId
version = Config.versionName
+
tasks.withType().configureEach {
compilerOptions {
jvmTarget.set(Config.jvmTarget)
@@ -77,9 +79,7 @@ subprojects {
}
plugins.withType().configureEach {
the().apply {
- enableIntrinsicRemember = true
- enableNonSkippingGroupOptimization = true
- enableStrongSkippingMode = true
+ featureFlags.addAll(OptimizeNonSkippingGroups)
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_definitions.txt")
if (properties["enableComposeCompilerReports"] == "true") {
val metricsDir = layout.buildDirectory.dir("compose_metrics")
diff --git a/buildSrc/src/main/kotlin/Config.kt b/buildSrc/src/main/kotlin/Config.kt
index 83feaf5..1e0ca07 100644
--- a/buildSrc/src/main/kotlin/Config.kt
+++ b/buildSrc/src/main/kotlin/Config.kt
@@ -18,7 +18,7 @@ object Config {
const val majorRelease = 1
const val minorRelease = 4
- const val patch = 3
+ const val patch = 4
const val postfix = ""
const val versionName = "$majorRelease.$minorRelease.$patch$postfix"
@@ -42,12 +42,12 @@ object Config {
"kotlin.contracts.ExperimentalContracts"
)
val compilerArgs = listOf(
- "-Xbackend-threads=0", // parallel IR compilation
+ "-Xconsistent-data-class-copy-visibility",
)
val jvmCompilerArgs = buildList {
- addAll(compilerArgs)
add("-Xjvm-default=all") // enable all jvm optimizations
add("-Xstring-concat=inline")
+ add("-Xbackend-threads=0") // parallel IR compilation
addAll(optIns.map { "-opt-in=$it" })
}
diff --git a/buildSrc/src/main/kotlin/ConfigureMultiplatform.kt b/buildSrc/src/main/kotlin/ConfigureMultiplatform.kt
index f4eb6ff..f7c01f8 100644
--- a/buildSrc/src/main/kotlin/ConfigureMultiplatform.kt
+++ b/buildSrc/src/main/kotlin/ConfigureMultiplatform.kt
@@ -4,9 +4,9 @@ import org.gradle.api.Project
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.getting
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinHierarchyBuilder
-import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
@OptIn(ExperimentalWasmDsl::class, ExperimentalKotlinGradlePluginApi::class)
fun Project.configureMultiplatform(
@@ -29,6 +29,11 @@ fun Project.configureMultiplatform(
applyDefaultHierarchyTemplate(configure)
withSourcesJar(true)
+ compilerOptions {
+ freeCompilerArgs.addAll(Config.compilerArgs)
+ optIn.addAll(Config.optIns)
+ }
+
if (linux) {
linuxX64()
linuxArm64()
@@ -91,7 +96,6 @@ fun Project.configureMultiplatform(
all {
languageSettings {
progressiveMode = true
- Config.optIns.forEach { optIn(it) }
}
}
}
diff --git a/compose/build.gradle.kts b/compose/build.gradle.kts
index 8229369..4d70443 100644
--- a/compose/build.gradle.kts
+++ b/compose/build.gradle.kts
@@ -44,6 +44,8 @@ kotlin {
api(compose.components.resources)
api(libs.lifecycle.runtime)
+ api(libs.lifecycle.compose)
+ implementation(libs.compose.window.size)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.animationGraphics)
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Annotations.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Annotations.kt
index ac39d53..bb0cfd5 100644
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Annotations.kt
+++ b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Annotations.kt
@@ -4,6 +4,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
@@ -129,12 +130,15 @@ public fun String.shadow(
*/
public fun String.font(fontFamily: FontFamily): AnnotatedString = annotate(SpanStyle(fontFamily = fontFamily))
-// TODO: Waiting for compose update
-
-// public fun String.clickable(onClick: () -> Unit): AnnotatedString = annotate {
-// pushLink(LinkAnnotation.Clickable("clickable") { onClick() })
-// pushStyle(SpanStyle(textDecoration = TextDecoration.Underline))
-// append(this@clickable)
-// pop()
-// pop()
-// }
+/**
+ * Makes this string clickable. When clicked, the [onClick] lambda is invoked
+ *
+ * @return the [AnnotatedString] created
+ */
+public fun String.clickable(onClick: () -> Unit): AnnotatedString = annotate {
+ pushLink(LinkAnnotation.Clickable("clickable") { onClick() })
+ pushStyle(SpanStyle(textDecoration = TextDecoration.Underline))
+ append(this@clickable)
+ pop()
+ pop()
+}
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/ScreenModifiers.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/ScreenModifiers.kt
index 946c8c0..676a55b 100644
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/ScreenModifiers.kt
+++ b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/ScreenModifiers.kt
@@ -4,9 +4,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.compose.LocalLifecycleOwner
/**
* Registers a new lifecycle observer for the lifetime of the composition of this function, then clears it.
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/TypeCrossfade.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/TypeCrossfade.kt
index 55b80bb..7530cb0 100644
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/TypeCrossfade.kt
+++ b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/TypeCrossfade.kt
@@ -53,7 +53,7 @@ public inline fun TypeCrossfade(
@PublishedApi
internal fun Transition.Crossfade(
modifier: Modifier = Modifier,
- contentAlignment: Alignment,
+ contentAlignment: Alignment = Alignment.Center,
animationSpec: FiniteAnimationSpec = tween(),
contentKey: (targetState: T) -> Any? = { it },
content: @Composable BoxScope.(targetState: T) -> Unit
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Utils.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Utils.kt
deleted file mode 100644
index 65a80e5..0000000
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/Utils.kt
+++ /dev/null
@@ -1 +0,0 @@
-package pro.respawn.kmmutils.compose
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/resources/ResourcesExt.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/resources/ResourcesExt.kt
index ae568eb..48c3337 100644
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/resources/ResourcesExt.kt
+++ b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/resources/ResourcesExt.kt
@@ -1,3 +1,5 @@
+@file:Suppress("TooManyFunctions")
+
package pro.respawn.kmmutils.compose.resources
import androidx.compose.runtime.Composable
@@ -39,7 +41,10 @@ public fun StringArrayResource.strings(): List = stringArrayResource(thi
@Composable
@NonSkippableComposable
-public fun StringResource.string(vararg args: Any): String = stringResource(this, formatArgs = args)
+public fun StringResource.string(
+ vararg args: Any,
+ trim: Boolean = true
+): String = stringResource(this, formatArgs = args).let { if (trim) it.trim() else it }
@Composable
@NonSkippableComposable
@@ -64,3 +69,8 @@ public fun FontResource.font(
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): Font = Font(this, weight, style)
+
+public suspend fun StringResource.getString(
+ vararg args: Any,
+ trim: Boolean = true
+): String = org.jetbrains.compose.resources.getString(this, formatArgs = args).let { if (trim) it.trim() else it }
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeClass.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeClass.kt
deleted file mode 100644
index ad79a6b..0000000
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeClass.kt
+++ /dev/null
@@ -1,297 +0,0 @@
-package pro.respawn.kmmutils.compose.windowsize
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.ReadOnlyComposable
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpSize
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.toSize
-
-/**
- * Calculates the window's [WindowSizeClass].
- *
- * A new [WindowSizeClass] will be returned whenever a change causes the width or
- * height of the window to cross a breakpoint, such as when the device is rotated or the window
- * is resized.
- */
-@Composable
-@ReadOnlyComposable
-public fun calculateWindowSizeClass(): WindowSizeClass = WindowSizeClass.calculateFromSize(
- size = windowSizePx.toSize(),
- density = LocalDensity.current
-)
-
-/**
- * Window size classes are a set of opinionated viewport breakpoints to design, develop, and test
- * responsive application layouts against.
- * For more details check Support different screen sizes documentation.
- *
- * WindowSizeClass contains a [WindowWidthSizeClass] and [WindowHeightSizeClass], representing the
- * window size classes for this window's width and height respectively.
- *
- * See [calculateWindowSizeClass] to calculate the WindowSizeClass.
- *
- * @property widthSizeClass width-based window size class ([WindowWidthSizeClass])
- * @property heightSizeClass height-based window size class ([WindowHeightSizeClass])
- */
-@Immutable
-public class WindowSizeClass private constructor(
- public val widthSizeClass: WindowWidthSizeClass,
- public val heightSizeClass: WindowHeightSizeClass,
-) {
-
- public companion object {
-
- internal fun calculateFromSize(size: DpSize): WindowSizeClass {
- val windowWidthSizeClass = WindowWidthSizeClass.fromWidth(size.width)
- val windowHeightSizeClass = WindowHeightSizeClass.fromHeight(size.height)
- return WindowSizeClass(windowWidthSizeClass, windowHeightSizeClass)
- }
-
- /**
- * Calculates the best matched [WindowSizeClass] for a given [size] and [Density] according
- * to the provided [supportedWidthSizeClasses] and [supportedHeightSizeClasses].
- *
- * @param size of the window
- * @param density of the window
- * @param supportedWidthSizeClasses the set of width size classes that are supported
- * @param supportedHeightSizeClasses the set of height size classes that are supported
- * @return [WindowSizeClass] corresponding to the given width and height
- */
- public fun calculateFromSize(
- size: Size,
- density: Density,
- supportedWidthSizeClasses: Set =
- WindowWidthSizeClass.DefaultSizeClasses,
- supportedHeightSizeClasses: Set =
- WindowHeightSizeClass.DefaultSizeClasses,
- ): WindowSizeClass {
- val windowWidthSizeClass =
- WindowWidthSizeClass.fromWidth(size.width, density, supportedWidthSizeClasses)
- val windowHeightSizeClass =
- WindowHeightSizeClass.fromHeight(size.height, density, supportedHeightSizeClasses)
- return WindowSizeClass(windowWidthSizeClass, windowHeightSizeClass)
- }
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (other == null || this::class != other::class) return false
-
- other as WindowSizeClass
-
- if (widthSizeClass != other.widthSizeClass) return false
- if (heightSizeClass != other.heightSizeClass) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = widthSizeClass.hashCode()
- result = 31 * result + heightSizeClass.hashCode()
- return result
- }
-
- override fun toString(): String = "WindowSizeClass($widthSizeClass, $heightSizeClass)"
-}
-
-/**
- * Width-based window size class.
- *
- * A window size class represents a breakpoint that can be used to build responsive layouts. Each
- * window size class breakpoint represents a majority case for typical device scenarios so your
- * layouts will work well on most devices and configurations.
- *
- * For more details see Window size classes documentation.
- */
-@Immutable
-@kotlin.jvm.JvmInline
-public value class WindowWidthSizeClass private constructor(private val value: Int) :
- Comparable {
-
- override operator fun compareTo(other: WindowWidthSizeClass): Int =
- breakpoint().compareTo(other.breakpoint())
-
- override fun toString(): String = "WindowWidthSizeClass." + when (this) {
- Compact -> "Compact"
- Medium -> "Medium"
- Expanded -> "Expanded"
- else -> ""
- }
-
- public companion object {
-
- /** Represents the majority of phones in portrait. */
- public val Compact: WindowWidthSizeClass = WindowWidthSizeClass(0)
-
- /**
- * Represents the majority of tablets in portrait and large unfolded inner displays in
- * portrait.
- */
- public val Medium: WindowWidthSizeClass = WindowWidthSizeClass(1)
-
- /**
- * Represents the majority of tablets in landscape and large unfolded inner displays in
- * landscape.
- */
- public val Expanded: WindowWidthSizeClass = WindowWidthSizeClass(2)
-
- /**
- * The default set of size classes that includes [Compact], [Medium], and [Expanded] size
- * classes. Should never expand to ensure behavioral consistency.
- */
- public val DefaultSizeClasses: Set = setOf(Compact, Medium, Expanded)
-
- /**
- * The standard set of size classes. It's supposed to include all size classes and will be
- * expanded whenever a new size class is defined. By default
- * [WindowSizeClass.calculateFromSize] will only return size classes in [DefaultSizeClasses]
- * in order to avoid behavioral changes when new size classes are added. You can opt in to
- * support all available size classes by doing:
- * ```
- * WindowSizeClass.calculateFromSize(
- * size = size,
- * density = density,
- * supportedWidthSizeClasses = WindowWidthSizeClass.StandardSizeClasses,
- * supportedHeightSizeClasses = WindowHeightSizeClass.StandardSizeClasses
- * )
- * ```
- */
- public val StandardSizeClasses: Set get() = DefaultSizeClasses
-
- private fun WindowWidthSizeClass.breakpoint(): Dp = when {
- this == Expanded -> 840.dp
- this == Medium -> 600.dp
- else -> 0.dp
- }
-
- /** Calculates the [WindowWidthSizeClass] for a given [width] */
- internal fun fromWidth(width: Dp): WindowWidthSizeClass = fromWidth(
- with(defaultDensity) { width.toPx() },
- defaultDensity,
- DefaultSizeClasses,
- )
-
- /**
- * Calculates the best matched [WindowWidthSizeClass] for a given [width] in Pixels and
- * a given [Density] from [supportedSizeClasses].
- */
- internal fun fromWidth(
- width: Float,
- density: Density,
- supportedSizeClasses: Set,
- ): WindowWidthSizeClass {
- require(width >= 0) { "Width must not be negative" }
- require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
- val sortedSizeClasses = supportedSizeClasses.sortedDescending()
- // Find the largest supported size class that matches the width
- sortedSizeClasses.forEach {
- if (width >= with(density) { it.breakpoint().toPx() }) {
- return it
- }
- }
- // If none of the size classes matches, return the smallest one.
- return sortedSizeClasses.last()
- }
- }
-}
-
-/**
- * Height-based window size class.
- *
- * A window size class represents a breakpoint that can be used to build responsive layouts. Each
- * window size class breakpoint represents a majority case for typical device scenarios so your
- * layouts will work well on most devices and configurations.
- *
- * For more details see Window size classes documentation.
- */
-@Immutable
-@kotlin.jvm.JvmInline
-public value class WindowHeightSizeClass private constructor(private val value: Int) :
- Comparable {
-
- override operator fun compareTo(other: WindowHeightSizeClass): Int = breakpoint().compareTo(other.breakpoint())
-
- override fun toString(): String = "WindowHeightSizeClass." + when (this) {
- Compact -> "Compact"
- Medium -> "Medium"
- Expanded -> "Expanded"
- else -> ""
- }
-
- public companion object {
-
- /** Represents the majority of phones in landscape */
- public val Compact: WindowHeightSizeClass = WindowHeightSizeClass(0)
-
- /** Represents the majority of tablets in landscape and majority of phones in portrait */
- public val Medium: WindowHeightSizeClass = WindowHeightSizeClass(1)
-
- /** Represents the majority of tablets in portrait */
- public val Expanded: WindowHeightSizeClass = WindowHeightSizeClass(2)
-
- /**
- * The default set of size classes that includes [Compact], [Medium], and [Expanded] size
- * classes. Should never expand to ensure behavioral consistency.
- */
- public val DefaultSizeClasses: Set = setOf(Compact, Medium, Expanded)
-
- /**
- * The standard set of size classes. It's supposed to include all size classes and will be
- * expanded whenever a new size class is defined. By default
- * [WindowSizeClass.calculateFromSize] will only return size classes in [DefaultSizeClasses]
- * in order to avoid behavioral changes when new size classes are added. You can opt in to
- * support all available size classes by doing:
- * ```
- * WindowSizeClass.calculateFromSize(
- * size = size,
- * density = density,
- * supportedWidthSizeClasses = WindowWidthSizeClass.StandardSizeClasses,
- * supportedHeightSizeClasses = WindowHeightSizeClass.StandardSizeClasses
- * )
- * ```
- */
- public val StandardSizeClasses: Set get() = DefaultSizeClasses
-
- private fun WindowHeightSizeClass.breakpoint(): Dp = when {
- this == Expanded -> 900.dp
- this == Medium -> 480.dp
- else -> 0.dp
- }
-
- /** Calculates the [WindowHeightSizeClass] for a given [height] */
- internal fun fromHeight(height: Dp) = fromHeight(
- with(defaultDensity) { height.toPx() },
- defaultDensity,
- DefaultSizeClasses,
- )
-
- /**
- * Calculates the best matched [WindowHeightSizeClass] for a given [height] in Pixels and
- * a given [Density] from [supportedSizeClasses].
- */
- internal fun fromHeight(
- height: Float,
- density: Density,
- supportedSizeClasses: Set,
- ): WindowHeightSizeClass {
- require(height >= 0) { "Width must not be negative" }
- require(supportedSizeClasses.isNotEmpty()) { "Must support at least one size class" }
- val sortedSizeClasses = supportedSizeClasses.sortedDescending()
- // Find the largest supported size class that matches the width
- sortedSizeClasses.forEach {
- if (height >= with(density) { it.breakpoint().toPx() }) {
- return it
- }
- }
- // If none of the size classes matches, return the smallest one.
- return sortedSizeClasses.last()
- }
- }
-}
-
-private val defaultDensity = Density(1F, 1F)
diff --git a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeExt.kt b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeExt.kt
index 56d561d..54d193a 100644
--- a/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeExt.kt
+++ b/compose/src/commonMain/kotlin/pro/respawn/kmmutils/compose/windowsize/WindowSizeExt.kt
@@ -1,5 +1,9 @@
package pro.respawn.kmmutils.compose.windowsize
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.platform.LocalDensity
@@ -8,6 +12,18 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.toSize
+/**
+ * Calculates the window's [WindowSizeClass].
+ *
+ * A new [WindowSizeClass] will be returned whenever a change causes the width or
+ * height of the window to cross a breakpoint, such as when the device is rotated or the window
+ * is resized.
+ */
+@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
+@Composable
+@ReadOnlyComposable
+public fun calculateWindowSizeClass(): WindowSizeClass = WindowSizeClass.calculateFromSize(size = windowSize)
+
/**
* Whether the window width is long (longer than most phones **in portrait**).
*
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 8d6c39c..1869a3a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,10 +1,10 @@
[versions]
androidx-activity = "1.9.1"
androidx-core = "1.13.1"
-compose = "1.7.0-alpha02"
-composeDetektPlugin = "1.3.0"
-coroutines = "1.9.0-RC"
-datetime = "0.6.0"
+compose = "1.7.0-alpha03"
+composeDetektPlugin = "1.4.0"
+coroutines = "1.9.0-RC.2"
+datetime = "0.6.1"
dependencyAnalysisPlugin = "1.32.0"
detekt = "1.23.6"
dokka = "1.9.20"
@@ -13,7 +13,7 @@ gradleDoctorPlugin = "0.10.0"
junit = "4.13.2"
kotest = "5.9.1"
# @pin
-kotlin = "2.0.10"
+kotlin = "2.0.20"
kotlinx-atomicfu = "0.25.0"
lifecycle = "2.8.0"
maven-publish-plugin = "0.29.0"
@@ -45,6 +45,8 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
lifecycle-runtime = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycle" }
lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycle" }
+lifecycle-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
+compose-window-size = { module = "org.jetbrains.compose.material3:material3-window-size-class", version.ref = "compose" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }
[bundles]