Merge "Fix testDensityChangeInvalidatesDrawWithCache" into androidx-main
diff --git a/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/PathEasingTest.kt b/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/PathEasingTest.kt
index 1566c9e..8f9d455 100644
--- a/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/PathEasingTest.kt
+++ b/compose/animation/animation-core/src/androidInstrumentedTest/kotlin/androidx/compose/animation/core/PathEasingTest.kt
@@ -21,7 +21,6 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
-import java.lang.IllegalStateException
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
index 86ba661..816bec4 100644
--- a/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
+++ b/compose/animation/animation-core/src/androidUnitTest/kotlin/androidx/compose/animation/core/EasingTest.kt
@@ -28,8 +28,8 @@
@RunWith(JUnit4::class)
class EasingTest {
- private val ZeroEpsilon = -(1.0f.ulp)
- private val OneEpsilon = 1.0f + 1.0f.ulp
+ private val ZeroEpsilon = -(1.0f.ulp * 2.0f)
+ private val OneEpsilon = 1.0f + 1.0f.ulp * 2.0f
@Test
fun cubicBezierStartsAt0() {
@@ -108,12 +108,49 @@
@Test
fun canSolveCubicForFractionsCloseToOne() {
- val curve = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)
+ // Only test curves defined in [0..1]
+ // For instance, EaseInOutBack is defined in a larger domain, so exclude it from the list
+ val curves =
+ listOf(
+ CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f),
+ Ease,
+ EaseIn,
+ EaseInBack,
+ EaseInCirc,
+ EaseInCubic,
+ EaseInExpo,
+ EaseInOut,
+ EaseInOutCirc,
+ EaseInOutCubic,
+ EaseInOutExpo,
+ EaseInOutQuad,
+ EaseInOutQuart,
+ EaseInOutQuint,
+ EaseInOutSine,
+ EaseInOutQuad,
+ EaseInOutQuart,
+ EaseInOutQuint,
+ EaseInSine,
+ EaseOut,
+ EaseOutCirc,
+ EaseOutCubic,
+ EaseOutExpo,
+ EaseOutQuad,
+ EaseOutQuart,
+ EaseOutQuint,
+ EaseOutSine
+ )
- // Test the last 16 ulps until 1.0f
- for (i in 0x3f7ffff0..0x3f7fffff) {
- val t = curve.transform(floatFromBits(i))
- assertTrue(t in -ZeroEpsilon..OneEpsilon)
+ for (curve in curves) {
+ // Test the last 16 ulps until 1.0f
+ for (i in 0x3f7ffff0..0x3f7fffff) {
+ val fraction = floatFromBits(i)
+ val t = curve.transform(fraction)
+ assertTrue(
+ "f($fraction) = $t out of range for $curve",
+ t in -ZeroEpsilon..OneEpsilon
+ )
+ }
}
}
}
diff --git a/compose/material3/adaptive/samples/build.gradle b/compose/material3/adaptive/samples/build.gradle
index ea8aec0..08e4e4e 100644
--- a/compose/material3/adaptive/samples/build.gradle
+++ b/compose/material3/adaptive/samples/build.gradle
@@ -38,6 +38,7 @@
implementation("androidx.compose.foundation:foundation:1.6.0-rc01")
implementation("androidx.compose.foundation:foundation-layout:1.6.0-rc01")
+ implementation("androidx.compose.material:material-icons-core:1.6.8")
implementation(project(":compose:material3:adaptive:adaptive-layout"))
implementation(project(":compose:material3:adaptive:adaptive-navigation"))
implementation(project(":compose:material3:material3"))
diff --git a/compose/material3/integration-tests/macrobenchmark-target/build.gradle b/compose/material3/integration-tests/macrobenchmark-target/build.gradle
index c19b92d..c3ee0c6 100644
--- a/compose/material3/integration-tests/macrobenchmark-target/build.gradle
+++ b/compose/material3/integration-tests/macrobenchmark-target/build.gradle
@@ -20,4 +20,5 @@
dependencies {
implementation(project(":activity:activity-compose"))
implementation(project(":compose:material3:material3"))
+ implementation("androidx.compose.material:material-icons-core:1.6.8")
}
diff --git a/compose/material3/material3-adaptive-navigation-suite/samples/build.gradle b/compose/material3/material3-adaptive-navigation-suite/samples/build.gradle
index 19ae106..d65e6a8 100644
--- a/compose/material3/material3-adaptive-navigation-suite/samples/build.gradle
+++ b/compose/material3/material3-adaptive-navigation-suite/samples/build.gradle
@@ -38,6 +38,7 @@
implementation("androidx.compose.foundation:foundation:1.6.0-rc01")
implementation("androidx.compose.foundation:foundation-layout:1.6.0-rc01")
+ implementation("androidx.compose.material:material-icons-core:1.6.8")
implementation(project(":compose:material3:adaptive:adaptive"))
implementation(project(":compose:material3:material3"))
implementation(project(":compose:material3:material3-adaptive-navigation-suite"))
diff --git a/compose/material3/material3-common/build.gradle b/compose/material3/material3-common/build.gradle
index c488a59..13b52b2 100644
--- a/compose/material3/material3-common/build.gradle
+++ b/compose/material3/material3-common/build.gradle
@@ -35,6 +35,7 @@
androidXMultiplatform {
android()
jvmStubs()
+ linuxX64Stubs()
defaultPlatform(PlatformIdentifier.ANDROID)
@@ -43,11 +44,11 @@
dependencies {
implementation(libs.kotlinStdlib)
implementation(project(":compose:ui:ui-util"))
- api("androidx.compose.foundation:foundation:1.6.0")
- api("androidx.compose.foundation:foundation-layout:1.6.0")
+ api(project(":compose:foundation:foundation"))
+ api(project(":compose:foundation:foundation-layout"))
api(project(":compose:runtime:runtime"))
- api("androidx.compose.ui:ui-graphics:1.6.0")
- api("androidx.compose.ui:ui-text:1.6.0")
+ api(project(":compose:ui:ui-graphics"))
+ api(project(":compose:ui:ui-text"))
}
}
@@ -69,10 +70,16 @@
}
}
+ commonStubsMain {
+ dependsOn(commonMain)
+ }
+
jvmStubsMain {
- dependsOn(jvmMain)
- dependencies {
- }
+ dependsOn(commonStubsMain)
+ }
+
+ linuxx64StubsMain {
+ dependsOn(commonStubsMain)
}
androidInstrumentedTest {
@@ -80,6 +87,7 @@
dependencies {
implementation(project(":compose:material3:material3"))
implementation(project(":compose:material3:material3-common"))
+ implementation("androidx.compose.material:material-icons-core:1.6.8")
implementation(project(":compose:test-utils"))
implementation(libs.testRules)
implementation(libs.junit)
diff --git a/compose/material3/material3-common/src/commonMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.kt b/compose/material3/material3-common/src/commonMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.kt
index 3f463fcf..f2bcce7 100644
--- a/compose/material3/material3-common/src/commonMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.kt
+++ b/compose/material3/material3-common/src/commonMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.kt
@@ -73,11 +73,13 @@
"interactions if the element would measure smaller"
}
- override fun hashCode(): Int = System.identityHashCode(this)
+ override fun hashCode(): Int = identifyHashCode(this)
override fun equals(other: Any?) = (other === this)
}
+internal expect inline fun identifyHashCode(value: Any): Int
+
internal class MinimumInteractiveModifierNode :
Modifier.Node(), CompositionLocalConsumerModifierNode, LayoutModifierNode {
override fun MeasureScope.measure(
diff --git a/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.commonStubs.kt b/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.commonStubs.kt
new file mode 100644
index 0000000..0332b5c
--- /dev/null
+++ b/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.commonStubs.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.common
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun identifyHashCode(value: Any): Int = implementedInJetBrainsFork()
diff --git a/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/NotImplemented.commonStubs.kt b/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/NotImplemented.commonStubs.kt
new file mode 100644
index 0000000..dfb855a
--- /dev/null
+++ b/compose/material3/material3-common/src/commonStubsMain/kotlin/androidx/compose/material3/common/NotImplemented.commonStubs.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.common
+
+@Suppress("NOTHING_TO_INLINE")
+internal inline fun implementedInJetBrainsFork(): Nothing =
+ throw NotImplementedError(
+ """
+ Implemented only in JetBrains fork.
+ Please use `org.jetbrains.compose.material3:material3-common` package instead.
+ """
+ .trimIndent()
+ )
diff --git a/compose/material3/material3-common/src/jvmMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.jvm.kt b/compose/material3/material3-common/src/jvmMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.jvm.kt
new file mode 100644
index 0000000..280a27c
--- /dev/null
+++ b/compose/material3/material3-common/src/jvmMain/kotlin/androidx/compose/material3/common/InteractiveComponentSize.jvm.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.common
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun identifyHashCode(value: Any): Int = System.identityHashCode(value)
diff --git a/compose/material3/material3-window-size-class/build.gradle b/compose/material3/material3-window-size-class/build.gradle
index f9109995..f31ae70 100644
--- a/compose/material3/material3-window-size-class/build.gradle
+++ b/compose/material3/material3-window-size-class/build.gradle
@@ -33,6 +33,7 @@
androidXMultiplatform {
android()
jvmStubs()
+ linuxX64Stubs()
defaultPlatform(PlatformIdentifier.ANDROID)
@@ -40,10 +41,10 @@
commonMain {
dependencies {
implementation(libs.kotlinStdlib)
- implementation("androidx.compose.ui:ui-util:1.6.0")
- api("androidx.compose.runtime:runtime:1.7.0-beta02")
- api("androidx.compose.ui:ui:1.6.0")
- api("androidx.compose.ui:ui-unit:1.6.0")
+ implementation(project(":compose:ui:ui-util"))
+ api(project(":compose:runtime:runtime"))
+ api(project(":compose:ui:ui"))
+ api(project(":compose:ui:ui-unit"))
}
}
@@ -66,10 +67,16 @@
}
}
+ commonStubsMain {
+ dependsOn(commonMain)
+ }
+
jvmStubsMain {
- dependsOn(jvmMain)
- dependencies {
- }
+ dependsOn(commonStubsMain)
+ }
+
+ linuxx64StubsMain {
+ dependsOn(commonStubsMain)
}
androidInstrumentedTest {
diff --git a/compose/material3/material3-window-size-class/src/commonStubsMain/kotlin/androidx/compose/material3/windowsizeclass/TestOnly.stubsCommon.kt b/compose/material3/material3-window-size-class/src/commonStubsMain/kotlin/androidx/compose/material3/windowsizeclass/TestOnly.stubsCommon.kt
new file mode 100644
index 0000000..a4e3587
--- /dev/null
+++ b/compose/material3/material3-window-size-class/src/commonStubsMain/kotlin/androidx/compose/material3/windowsizeclass/TestOnly.stubsCommon.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.windowsizeclass
+
+@MustBeDocumented actual annotation class TestOnly()
diff --git a/compose/material3/material3/build.gradle b/compose/material3/material3/build.gradle
index ea41305..1d4ba66 100644
--- a/compose/material3/material3/build.gradle
+++ b/compose/material3/material3/build.gradle
@@ -33,6 +33,7 @@
androidXMultiplatform {
android()
jvmStubs()
+ linuxX64Stubs()
defaultPlatform(PlatformIdentifier.ANDROID)
@@ -41,17 +42,16 @@
dependencies {
implementation(libs.kotlinStdlib)
// Keep pinned unless there is a need for tip of tree behavior
- implementation("androidx.collection:collection:1.4.0")
- implementation("androidx.compose.animation:animation-core:1.6.0")
- implementation("androidx.compose.ui:ui-util:1.6.0")
- api("androidx.compose.foundation:foundation:1.7.0-beta02")
- api("androidx.compose.foundation:foundation-layout:1.7.0-beta02")
- api("androidx.compose.material:material-icons-core:1.6.0")
- api("androidx.compose.material:material-ripple:1.7.0-beta02")
- api("androidx.compose.runtime:runtime:1.7.0-beta02")
- api("androidx.compose.ui:ui:1.6.0")
- api("androidx.compose.ui:ui-text:1.6.0")
- api("androidx.graphics:graphics-shapes:1.0.0-beta01")
+ implementation("androidx.collection:collection:1.4.1")
+ implementation(project(":compose:animation:animation-core"))
+ implementation(project(":compose:ui:ui-util"))
+ api(project(":compose:foundation:foundation"))
+ api(project(":compose:foundation:foundation-layout"))
+ api(project(":compose:material:material-ripple"))
+ api(project(":compose:runtime:runtime"))
+ api(project(":compose:ui:ui"))
+ api(project(":compose:ui:ui-text"))
+ api(project(":graphics:graphics-shapes"))
}
}
@@ -72,15 +72,20 @@
api("androidx.annotation:annotation:1.1.0")
api("androidx.annotation:annotation-experimental:1.4.1")
implementation("androidx.activity:activity-compose:1.8.2")
-
implementation("androidx.lifecycle:lifecycle-common-java8:2.6.1")
}
}
+ commonStubsMain {
+ dependsOn(commonMain)
+ }
+
jvmStubsMain {
- dependsOn(jvmMain)
- dependencies {
- }
+ dependsOn(commonStubsMain)
+ }
+
+ linuxx64StubsMain {
+ dependsOn(commonStubsMain)
}
androidUnitTest {
@@ -100,6 +105,7 @@
implementation(project(":compose:test-utils"))
implementation(project(':compose:foundation:foundation-layout'))
implementation(project(':compose:foundation:foundation'))
+ implementation("androidx.compose.material:material-icons-core:1.6.8")
implementation(project(":test:screenshot:screenshot"))
implementation(projectOrArtifact(":core:core"))
implementation(libs.testRules)
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DateInput.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DateInput.android.kt
new file mode 100644
index 0000000..4f33650
--- /dev/null
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DateInput.android.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3
+
+import androidx.compose.material3.internal.CalendarDate
+import androidx.compose.material3.internal.DateInputFormat
+import androidx.compose.runtime.Stable
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Stable
+internal actual class DateInputValidator
+actual constructor(
+ private val yearRange: IntRange,
+ private val selectableDates: SelectableDates,
+ private val dateInputFormat: DateInputFormat,
+ private val dateFormatter: DatePickerFormatter,
+ private val errorDatePattern: String,
+ private val errorDateOutOfYearRange: String,
+ private val errorInvalidNotAllowed: String,
+ private val errorInvalidRangeInput: String
+) {
+ /**
+ * the currently selected start date in milliseconds. Only checked against when the
+ * [InputIdentifier] is [InputIdentifier.EndDateInput].
+ */
+ actual var currentStartDateMillis: Long? = null
+
+ /**
+ * the currently selected end date in milliseconds. Only checked against when the
+ * [InputIdentifier] is [InputIdentifier.StartDateInput].
+ */
+ actual var currentEndDateMillis: Long? = null
+
+ actual fun validate(
+ dateToValidate: CalendarDate?,
+ inputIdentifier: InputIdentifier,
+ locale: CalendarLocale
+ ): String {
+ if (dateToValidate == null) {
+ return errorDatePattern.format(dateInputFormat.patternWithDelimiters.uppercase())
+ }
+ // Check that the date is within the valid range of years.
+ if (!yearRange.contains(dateToValidate.year)) {
+ return errorDateOutOfYearRange.format(
+ yearRange.first.toLocalString(),
+ yearRange.last.toLocalString()
+ )
+ }
+ // Check that the provided SelectableDates allows this date to be selected.
+ with(selectableDates) {
+ if (
+ !isSelectableYear(dateToValidate.year) ||
+ !isSelectableDate(dateToValidate.utcTimeMillis)
+ ) {
+ return errorInvalidNotAllowed.format(
+ dateFormatter.formatDate(
+ dateMillis = dateToValidate.utcTimeMillis,
+ locale = locale
+ )
+ )
+ }
+ }
+
+ // Additional validation when the InputIdentifier is for start of end dates in a range input
+ if (
+ (inputIdentifier == InputIdentifier.StartDateInput &&
+ dateToValidate.utcTimeMillis >= (currentEndDateMillis ?: Long.MAX_VALUE)) ||
+ (inputIdentifier == InputIdentifier.EndDateInput &&
+ dateToValidate.utcTimeMillis < (currentStartDateMillis ?: Long.MIN_VALUE))
+ ) {
+ // The input start date is after the end date, or the end date is before the start date.
+ return errorInvalidRangeInput
+ }
+
+ return ""
+ }
+}
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DatePicker.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DatePicker.android.kt
new file mode 100644
index 0000000..d5e94bf
--- /dev/null
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/DatePicker.android.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun formatDatePickerNavigateToYearString(
+ template: String,
+ localizedYear: String
+): String = template.format(localizedYear)
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun formatHeadlineDescription(
+ template: String,
+ verboseDateDescription: String
+): String = template.format(verboseDateDescription)
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
index 146b300..95bcbd4 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/ExposedDropdownMenu.android.kt
@@ -35,8 +35,7 @@
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.ArrowDropDown
+import androidx.compose.material3.internal.Icons
import androidx.compose.material3.internal.MenuPosition
import androidx.compose.material3.internal.Strings
import androidx.compose.material3.internal.getString
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/InteractiveComponentSize.android.kt
similarity index 63%
copy from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
copy to compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/InteractiveComponentSize.android.kt
index 02ed679..a4ebf46 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/InteractiveComponentSize.android.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,5 @@
package androidx.compose.material3
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
-
-/** Returns the default [CalendarLocale]. */
-@Composable
-@ReadOnlyComposable
-@OptIn(ExperimentalMaterial3Api::class)
-internal actual fun defaultLocale(): CalendarLocale = implementedInJetBrainsFork()
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun identityHashCode(value: Any): Int = System.identityHashCode(value)
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.android.kt
new file mode 100644
index 0000000..95a2223
--- /dev/null
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.android.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.internal
+
+import kotlinx.coroutines.CancellationException
+
+internal actual class AnchoredDragFinishedSignal actual constructor() :
+ CancellationException("Anchored drag finished") {
+ override fun fillInStackTrace(): Throwable {
+ stackTrace = emptyArray()
+ return this
+ }
+}
diff --git a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/CalendarModel.android.kt b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/CalendarModel.android.kt
index dad7b59..59ca59a 100644
--- a/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/CalendarModel.android.kt
+++ b/compose/material3/material3/src/androidMain/kotlin/androidx/compose/material3/internal/CalendarModel.android.kt
@@ -64,3 +64,38 @@
LegacyCalendarModelImpl.formatWithPattern(utcTimeMillis, pattern, locale, cache)
}
}
+
+/**
+ * Receives a given local date format string and returns a string that can be displayed to the user
+ * and parsed by the date parser.
+ *
+ * This function:
+ * - Removes all characters that don't match `d`, `M` and `y`, or any of the date format delimiters
+ * `.`, `/` and `-`.
+ * - Ensures that the format is for two digits day and month, and four digits year.
+ *
+ * The output of this cleanup is always a 10 characters string in one of the following variations:
+ * - yyyy/MM/dd
+ * - yyyy-MM-dd
+ * - yyyy.MM.dd
+ * - dd/MM/yyyy
+ * - dd-MM-yyyy
+ * - dd.MM.yyyy
+ * - MM/dd/yyyy
+ */
+internal actual fun datePatternAsInputFormat(localeFormat: String): DateInputFormat {
+ val patternWithDelimiters =
+ localeFormat
+ .replace(Regex("[^dMy/\\-.]"), "")
+ .replace(Regex("d{1,2}"), "dd")
+ .replace(Regex("M{1,2}"), "MM")
+ .replace(Regex("y{1,4}"), "yyyy")
+ .replace("My", "M/y") // Edge case for the Kako locale
+ .removeSuffix(".") // Removes a dot suffix that appears in some formats
+
+ val delimiterRegex = Regex("[/\\-.]")
+ val delimiterMatchResult = delimiterRegex.find(patternWithDelimiters)
+ val delimiterIndex = delimiterMatchResult!!.groups[0]!!.range.first
+ val delimiter = patternWithDelimiters.substring(delimiterIndex, delimiterIndex + 1)
+ return DateInputFormat(patternWithDelimiters = patternWithDelimiters, delimiter = delimiter[0])
+}
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
index a96d1d7..cd94958 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt
@@ -94,6 +94,7 @@
import androidx.compose.ui.unit.isFinite
import androidx.compose.ui.unit.isSpecified
import androidx.compose.ui.util.fastFirst
+import kotlin.jvm.JvmInline
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.roundToInt
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
index a8c9b1e..d4daf51 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/BottomSheetScaffold.kt
@@ -52,6 +52,7 @@
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastMaxOfOrNull
+import kotlin.math.max
import kotlin.math.roundToInt
import kotlinx.coroutines.launch
@@ -386,7 +387,7 @@
layout(layoutWidth, layoutHeight) {
val sheetWidth = sheetPlaceables.fastMaxOfOrNull { it.width } ?: 0
- val sheetOffsetX = Integer.max(0, (layoutWidth - sheetWidth) / 2)
+ val sheetOffsetX = max(0, (layoutWidth - sheetWidth) / 2)
val snackbarWidth = snackbarPlaceables.fastMaxOfOrNull { it.width } ?: 0
val snackbarHeight = snackbarPlaceables.fastMaxOfOrNull { it.height } ?: 0
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
index d915eb2..9065f0c 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DateInput.kt
@@ -47,6 +47,7 @@
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
+import kotlin.jvm.JvmInline
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -222,25 +223,29 @@
* @param errorInvalidRangeInput a string for displaying an error message when in a range input mode
* and one of the input dates is out of order (i.e. the user inputs a start date that is after the
* end date, or an end date that is before the start date)
- * @param currentStartDateMillis the currently selected start date in milliseconds. Only checked
- * against when the [InputIdentifier] is [InputIdentifier.EndDateInput].
- * @param currentEndDateMillis the currently selected end date in milliseconds. Only checked against
- * when the [InputIdentifier] is [InputIdentifier.StartDateInput].
*/
@OptIn(ExperimentalMaterial3Api::class)
@Stable
-internal class DateInputValidator(
- private val yearRange: IntRange,
- private val selectableDates: SelectableDates,
- private val dateInputFormat: DateInputFormat,
- private val dateFormatter: DatePickerFormatter,
- private val errorDatePattern: String,
- private val errorDateOutOfYearRange: String,
- private val errorInvalidNotAllowed: String,
- private val errorInvalidRangeInput: String,
- internal var currentStartDateMillis: Long? = null,
- internal var currentEndDateMillis: Long? = null,
+internal expect class DateInputValidator(
+ yearRange: IntRange,
+ selectableDates: SelectableDates,
+ dateInputFormat: DateInputFormat,
+ dateFormatter: DatePickerFormatter,
+ errorDatePattern: String,
+ errorDateOutOfYearRange: String,
+ errorInvalidNotAllowed: String,
+ errorInvalidRangeInput: String,
) {
+ /**
+ * the currently selected start date in milliseconds. Only checked against when the
+ * [InputIdentifier] is [InputIdentifier.EndDateInput].
+ */
+ var currentStartDateMillis: Long?
+ /**
+ * the currently selected end date in milliseconds. Only checked against when the
+ * [InputIdentifier] is [InputIdentifier.StartDateInput].
+ */
+ var currentEndDateMillis: Long?
/**
* Validates a [CalendarDate] input and returns an error string in case an issue with the given
@@ -255,45 +260,7 @@
dateToValidate: CalendarDate?,
inputIdentifier: InputIdentifier,
locale: CalendarLocale
- ): String {
- if (dateToValidate == null) {
- return errorDatePattern.format(dateInputFormat.patternWithDelimiters.uppercase())
- }
- // Check that the date is within the valid range of years.
- if (!yearRange.contains(dateToValidate.year)) {
- return errorDateOutOfYearRange.format(
- yearRange.first.toLocalString(),
- yearRange.last.toLocalString()
- )
- }
- // Check that the provided SelectableDates allows this date to be selected.
- with(selectableDates) {
- if (
- !isSelectableYear(dateToValidate.year) ||
- !isSelectableDate(dateToValidate.utcTimeMillis)
- ) {
- return errorInvalidNotAllowed.format(
- dateFormatter.formatDate(
- dateMillis = dateToValidate.utcTimeMillis,
- locale = locale
- )
- )
- }
- }
-
- // Additional validation when the InputIdentifier is for start of end dates in a range input
- if (
- (inputIdentifier == InputIdentifier.StartDateInput &&
- dateToValidate.utcTimeMillis >= (currentEndDateMillis ?: Long.MAX_VALUE)) ||
- (inputIdentifier == InputIdentifier.EndDateInput &&
- dateToValidate.utcTimeMillis < (currentStartDateMillis ?: Long.MIN_VALUE))
- ) {
- // The input start date is after the end date, or the end date is before the start date.
- return errorInvalidRangeInput
- }
-
- return ""
- }
+ ): String
}
/**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
index bf91ec5..806bf7e 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/DatePicker.kt
@@ -58,16 +58,11 @@
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
-import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
-import androidx.compose.material.icons.filled.ArrowDropDown
-import androidx.compose.material.icons.filled.DateRange
-import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.OutlinedTextFieldDefaults.defaultOutlinedTextFieldColors
import androidx.compose.material3.internal.CalendarModel
import androidx.compose.material3.internal.CalendarMonth
import androidx.compose.material3.internal.DaysInWeek
+import androidx.compose.material3.internal.Icons
import androidx.compose.material3.internal.MillisecondsIn24Hours
import androidx.compose.material3.internal.ProvideContentColorTextStyle
import androidx.compose.material3.internal.Strings
@@ -124,6 +119,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
+import kotlin.jvm.JvmInline
import kotlin.math.max
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -672,11 +668,14 @@
}
val headlineDescription =
- when (displayMode) {
- DisplayMode.Picker -> getString(Strings.DatePickerHeadlineDescription)
- DisplayMode.Input -> getString(Strings.DateInputHeadlineDescription)
- else -> ""
- }.format(verboseDateDescription)
+ formatHeadlineDescription(
+ when (displayMode) {
+ DisplayMode.Picker -> getString(Strings.DatePickerHeadlineDescription)
+ DisplayMode.Input -> getString(Strings.DateInputHeadlineDescription)
+ else -> ""
+ },
+ verboseDateDescription
+ )
Text(
text = headlineText,
@@ -748,6 +747,11 @@
const val YearMonthWeekdayDaySkeleton: String = "yMMMMEEEEd"
}
+internal expect inline fun formatHeadlineDescription(
+ template: String,
+ verboseDateDescription: String
+): String
+
/**
* Represents the colors used by the date picker.
*
@@ -2051,8 +2055,10 @@
onClick = { onYearSelected(selectedYear) },
enabled = selectableDates.isSelectableYear(selectedYear),
description =
- getString(Strings.DatePickerNavigateToYearDescription)
- .format(localizedYear),
+ formatDatePickerNavigateToYearString(
+ getString(Strings.DatePickerNavigateToYearDescription),
+ localizedYear
+ ),
colors = colors
) {
Text(
@@ -2067,6 +2073,11 @@
}
}
+internal expect inline fun formatDatePickerNavigateToYearString(
+ template: String,
+ localizedYear: String
+): String
+
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun Year(
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/InteractiveComponentSize.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/InteractiveComponentSize.kt
index a31e5e7..db9690e90 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/InteractiveComponentSize.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/InteractiveComponentSize.kt
@@ -75,11 +75,13 @@
"interactions if the element would measure smaller"
}
- override fun hashCode(): Int = System.identityHashCode(this)
+ override fun hashCode(): Int = identityHashCode(this)
override fun equals(other: Any?) = (other === this)
}
+internal expect inline fun identityHashCode(value: Any): Int
+
internal class MinimumInteractiveModifierNode :
Modifier.Node(), CompositionLocalConsumerModifierNode, LayoutModifierNode {
override fun MeasureScope.measure(
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ListItem.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ListItem.kt
index a628d71..717f48b 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ListItem.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ListItem.kt
@@ -53,6 +53,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.offset
import androidx.compose.ui.unit.sp
+import kotlin.jvm.JvmInline
import kotlin.math.max
/**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
index 300ee65..3c5d10d 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/NavigationItem.kt
@@ -70,6 +70,7 @@
import androidx.compose.ui.util.fastFirst
import androidx.compose.ui.util.fastFirstOrNull
import androidx.compose.ui.util.lerp
+import kotlin.jvm.JvmInline
import kotlin.math.max
import kotlin.math.roundToInt
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
index b6778d9..5f79700 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ProgressIndicator.kt
@@ -538,8 +538,7 @@
} else {
gapSize + strokeWidth
}
- val gapSizeSweep =
- (adjustedGapSize.value / (Math.PI * size.width.toDp().value).toFloat()) * 360f
+ val gapSizeSweep = (adjustedGapSize.value / (PI * size.width.toDp().value).toFloat()) * 360f
drawCircularIndicator(
startAngle + sweep + min(sweep, gapSizeSweep),
@@ -659,8 +658,7 @@
} else {
gapSize + strokeWidth
}
- val gapSizeSweep =
- (adjustedGapSize.value / (Math.PI * size.width.toDp().value).toFloat()) * 360f
+ val gapSizeSweep = (adjustedGapSize.value / (PI * size.width.toDp().value).toFloat()) * 360f
rotate(globalRotation.value + additionalRotation.value) {
drawCircularIndicator(
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SegmentedButton.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SegmentedButton.kt
index 554a36c..6f26f15 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SegmentedButton.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SegmentedButton.kt
@@ -43,8 +43,7 @@
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.shape.CornerBasedShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Check
+import androidx.compose.material3.internal.Icons
import androidx.compose.material3.tokens.MotionTokens
import androidx.compose.material3.tokens.OutlinedSegmentedButtonTokens
import androidx.compose.material3.tokens.OutlinedSegmentedButtonTokens.DisabledLabelTextColor
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
index a97f7c0..87200fd 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SheetDefaults.kt
@@ -54,6 +54,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp
+import kotlin.jvm.JvmName
import kotlinx.coroutines.CancellationException
/**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ShortNavigationBar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ShortNavigationBar.kt
index e0fd8eb..553c9ad 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ShortNavigationBar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/ShortNavigationBar.kt
@@ -44,6 +44,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
+import kotlin.jvm.JvmInline
import kotlin.math.roundToInt
/**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
index d373eb5..d7cb737 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Slider.kt
@@ -100,6 +100,7 @@
import androidx.compose.ui.util.packFloats
import androidx.compose.ui.util.unpackFloat1
import androidx.compose.ui.util.unpackFloat2
+import kotlin.jvm.JvmInline
import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.max
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Snackbar.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Snackbar.kt
index 06b06b7..2142d27 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Snackbar.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Snackbar.kt
@@ -23,8 +23,7 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.paddingFromBaseline
import androidx.compose.foundation.layout.widthIn
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.internal.Icons
import androidx.compose.material3.internal.Strings
import androidx.compose.material3.internal.getString
import androidx.compose.material3.tokens.SnackbarTokens
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
index aa0c01f..bde0b7e 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/TimePicker.kt
@@ -174,6 +174,7 @@
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.zIndex
+import kotlin.jvm.JvmInline
import kotlin.math.PI
import kotlin.math.atan2
import kotlin.math.cos
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WideNavigationRail.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WideNavigationRail.kt
index 6ea365c..54f7e17 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WideNavigationRail.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/WideNavigationRail.kt
@@ -60,6 +60,8 @@
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastSumBy
+import kotlin.jvm.JvmInline
+import kotlin.math.min
/**
* Material design wide navigation rail.
@@ -240,7 +242,7 @@
.constrain(
Constraints.fitPrioritizingWidth(
minWidth =
- Math.min(
+ min(
ItemMinWidth.roundToPx(),
itemMaxWidthConstraint
),
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
index 46534c4..67883b1 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/carousel/Carousel.kt
@@ -53,6 +53,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import kotlin.jvm.JvmInline
import kotlin.math.roundToInt
/**
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
index 0a4a8fc..ecacf8b 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.kt
@@ -701,12 +701,7 @@
val AnimationSpec = SpringSpec<Float>()
}
-private class AnchoredDragFinishedSignal : CancellationException() {
- override fun fillInStackTrace(): Throwable {
- stackTrace = emptyArray()
- return this
- }
-}
+internal expect class AnchoredDragFinishedSignal() : CancellationException
private suspend fun <I> restartable(inputs: () -> I, block: suspend (I) -> Unit) {
try {
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/CalendarModel.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/CalendarModel.kt
index 3d8c3c2..7ece81f 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/CalendarModel.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/CalendarModel.kt
@@ -297,22 +297,7 @@
* - dd.MM.yyyy
* - MM/dd/yyyy
*/
-internal fun datePatternAsInputFormat(localeFormat: String): DateInputFormat {
- val patternWithDelimiters =
- localeFormat
- .replace(Regex("[^dMy/\\-.]"), "")
- .replace(Regex("d{1,2}"), "dd")
- .replace(Regex("M{1,2}"), "MM")
- .replace(Regex("y{1,4}"), "yyyy")
- .replace("My", "M/y") // Edge case for the Kako locale
- .removeSuffix(".") // Removes a dot suffix that appears in some formats
-
- val delimiterRegex = Regex("[/\\-.]")
- val delimiterMatchResult = delimiterRegex.find(patternWithDelimiters)
- val delimiterIndex = delimiterMatchResult!!.groups[0]!!.range.first
- val delimiter = patternWithDelimiters.substring(delimiterIndex, delimiterIndex + 1)
- return DateInputFormat(patternWithDelimiters = patternWithDelimiters, delimiter = delimiter[0])
-}
+internal expect fun datePatternAsInputFormat(localeFormat: String): DateInputFormat
internal const val DaysInWeek: Int = 7
internal const val MillisecondsIn24Hours = 86400000L
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Icons.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Icons.kt
new file mode 100644
index 0000000..e2334af
--- /dev/null
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Icons.kt
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3.internal
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.StrokeJoin
+import androidx.compose.ui.graphics.vector.DefaultFillType
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.PathBuilder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.unit.dp
+
+internal object Icons {
+ internal object AutoMirrored {
+ internal object Filled {
+ internal val KeyboardArrowLeft: ImageVector
+ get() {
+ if (_keyboardArrowLeft != null) {
+ return _keyboardArrowLeft!!
+ }
+ _keyboardArrowLeft =
+ materialIcon(
+ name = "AutoMirrored.Filled.KeyboardArrowLeft",
+ autoMirror = true
+ ) {
+ materialPath {
+ moveTo(15.41f, 16.59f)
+ lineTo(10.83f, 12.0f)
+ lineToRelative(4.58f, -4.59f)
+ lineTo(14.0f, 6.0f)
+ lineToRelative(-6.0f, 6.0f)
+ lineToRelative(6.0f, 6.0f)
+ lineToRelative(1.41f, -1.41f)
+ close()
+ }
+ }
+ return _keyboardArrowLeft!!
+ }
+
+ private var _keyboardArrowLeft: ImageVector? = null
+
+ internal val KeyboardArrowRight: ImageVector
+ get() {
+ if (_keyboardArrowRight != null) {
+ return _keyboardArrowRight!!
+ }
+ _keyboardArrowRight =
+ materialIcon(
+ name = "AutoMirrored.Filled.KeyboardArrowRight",
+ autoMirror = true
+ ) {
+ materialPath {
+ moveTo(8.59f, 16.59f)
+ lineTo(13.17f, 12.0f)
+ lineTo(8.59f, 7.41f)
+ lineTo(10.0f, 6.0f)
+ lineToRelative(6.0f, 6.0f)
+ lineToRelative(-6.0f, 6.0f)
+ lineToRelative(-1.41f, -1.41f)
+ close()
+ }
+ }
+ return _keyboardArrowRight!!
+ }
+
+ private var _keyboardArrowRight: ImageVector? = null
+ }
+ }
+
+ internal object Filled {
+ internal val Close: ImageVector
+ get() {
+ if (_close != null) {
+ return _close!!
+ }
+ _close =
+ materialIcon(name = "Filled.Close") {
+ materialPath {
+ moveTo(19.0f, 6.41f)
+ lineTo(17.59f, 5.0f)
+ lineTo(12.0f, 10.59f)
+ lineTo(6.41f, 5.0f)
+ lineTo(5.0f, 6.41f)
+ lineTo(10.59f, 12.0f)
+ lineTo(5.0f, 17.59f)
+ lineTo(6.41f, 19.0f)
+ lineTo(12.0f, 13.41f)
+ lineTo(17.59f, 19.0f)
+ lineTo(19.0f, 17.59f)
+ lineTo(13.41f, 12.0f)
+ close()
+ }
+ }
+ return _close!!
+ }
+
+ private var _close: ImageVector? = null
+
+ internal val Check: ImageVector
+ get() {
+ if (_check != null) {
+ return _check!!
+ }
+ _check =
+ materialIcon(name = "Filled.Check") {
+ materialPath {
+ moveTo(9.0f, 16.17f)
+ lineTo(4.83f, 12.0f)
+ lineToRelative(-1.42f, 1.41f)
+ lineTo(9.0f, 19.0f)
+ lineTo(21.0f, 7.0f)
+ lineToRelative(-1.41f, -1.41f)
+ close()
+ }
+ }
+ return _check!!
+ }
+
+ private var _check: ImageVector? = null
+
+ internal val Edit: ImageVector
+ get() {
+ if (_edit != null) {
+ return _edit!!
+ }
+ _edit =
+ materialIcon(name = "Filled.Edit") {
+ materialPath {
+ moveTo(3.0f, 17.25f)
+ verticalLineTo(21.0f)
+ horizontalLineToRelative(3.75f)
+ lineTo(17.81f, 9.94f)
+ lineToRelative(-3.75f, -3.75f)
+ lineTo(3.0f, 17.25f)
+ close()
+ moveTo(20.71f, 7.04f)
+ curveToRelative(0.39f, -0.39f, 0.39f, -1.02f, 0.0f, -1.41f)
+ lineToRelative(-2.34f, -2.34f)
+ curveToRelative(-0.39f, -0.39f, -1.02f, -0.39f, -1.41f, 0.0f)
+ lineToRelative(-1.83f, 1.83f)
+ lineToRelative(3.75f, 3.75f)
+ lineToRelative(1.83f, -1.83f)
+ close()
+ }
+ }
+ return _edit!!
+ }
+
+ private var _edit: ImageVector? = null
+
+ internal val DateRange: ImageVector
+ get() {
+ if (_dateRange != null) {
+ return _dateRange!!
+ }
+ _dateRange =
+ materialIcon(name = "Filled.DateRange") {
+ materialPath {
+ moveTo(9.0f, 11.0f)
+ lineTo(7.0f, 11.0f)
+ verticalLineToRelative(2.0f)
+ horizontalLineToRelative(2.0f)
+ verticalLineToRelative(-2.0f)
+ close()
+ moveTo(13.0f, 11.0f)
+ horizontalLineToRelative(-2.0f)
+ verticalLineToRelative(2.0f)
+ horizontalLineToRelative(2.0f)
+ verticalLineToRelative(-2.0f)
+ close()
+ moveTo(17.0f, 11.0f)
+ horizontalLineToRelative(-2.0f)
+ verticalLineToRelative(2.0f)
+ horizontalLineToRelative(2.0f)
+ verticalLineToRelative(-2.0f)
+ close()
+ moveTo(19.0f, 4.0f)
+ horizontalLineToRelative(-1.0f)
+ lineTo(18.0f, 2.0f)
+ horizontalLineToRelative(-2.0f)
+ verticalLineToRelative(2.0f)
+ lineTo(8.0f, 4.0f)
+ lineTo(8.0f, 2.0f)
+ lineTo(6.0f, 2.0f)
+ verticalLineToRelative(2.0f)
+ lineTo(5.0f, 4.0f)
+ curveToRelative(-1.11f, 0.0f, -1.99f, 0.9f, -1.99f, 2.0f)
+ lineTo(3.0f, 20.0f)
+ curveToRelative(0.0f, 1.1f, 0.89f, 2.0f, 2.0f, 2.0f)
+ horizontalLineToRelative(14.0f)
+ curveToRelative(1.1f, 0.0f, 2.0f, -0.9f, 2.0f, -2.0f)
+ lineTo(21.0f, 6.0f)
+ curveToRelative(0.0f, -1.1f, -0.9f, -2.0f, -2.0f, -2.0f)
+ close()
+ moveTo(19.0f, 20.0f)
+ lineTo(5.0f, 20.0f)
+ lineTo(5.0f, 9.0f)
+ horizontalLineToRelative(14.0f)
+ verticalLineToRelative(11.0f)
+ close()
+ }
+ }
+ return _dateRange!!
+ }
+
+ private var _dateRange: ImageVector? = null
+
+ internal val ArrowDropDown: ImageVector
+ get() {
+ if (_arrowDropDown != null) {
+ return _arrowDropDown!!
+ }
+ _arrowDropDown =
+ materialIcon(name = "Filled.ArrowDropDown") {
+ materialPath {
+ moveTo(7.0f, 10.0f)
+ lineToRelative(5.0f, 5.0f)
+ lineToRelative(5.0f, -5.0f)
+ close()
+ }
+ }
+ return _arrowDropDown!!
+ }
+
+ private var _arrowDropDown: ImageVector? = null
+ }
+}
+
+private inline fun materialIcon(
+ name: String,
+ block: ImageVector.Builder.() -> ImageVector.Builder
+): ImageVector =
+ ImageVector.Builder(
+ name = name,
+ defaultWidth = MaterialIconDimension.dp,
+ defaultHeight = MaterialIconDimension.dp,
+ viewportWidth = MaterialIconDimension,
+ viewportHeight = MaterialIconDimension
+ )
+ .block()
+ .build()
+
+private inline fun materialIcon(
+ name: String,
+ autoMirror: Boolean = false,
+ block: ImageVector.Builder.() -> ImageVector.Builder
+): ImageVector =
+ ImageVector.Builder(
+ name = name,
+ defaultWidth = MaterialIconDimension.dp,
+ defaultHeight = MaterialIconDimension.dp,
+ viewportWidth = MaterialIconDimension,
+ viewportHeight = MaterialIconDimension,
+ autoMirror = autoMirror
+ )
+ .block()
+ .build()
+
+private inline fun ImageVector.Builder.materialPath(
+ fillAlpha: Float = 1f,
+ strokeAlpha: Float = 1f,
+ pathFillType: PathFillType = DefaultFillType,
+ pathBuilder: PathBuilder.() -> Unit
+) =
+ path(
+ fill = SolidColor(Color.Black),
+ fillAlpha = fillAlpha,
+ stroke = null,
+ strokeAlpha = strokeAlpha,
+ strokeLineWidth = 1f,
+ strokeLineCap = StrokeCap.Butt,
+ strokeLineJoin = StrokeJoin.Bevel,
+ strokeLineMiter = 1f,
+ pathFillType = pathFillType,
+ pathBuilder = pathBuilder
+ )
+
+// All Material icons (currently) are 24dp by 24dp, with a viewport size of 24 by 24.
+private const val MaterialIconDimension = 24f
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Strings.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Strings.kt
index 27ac520..d0e4575 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Strings.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/internal/Strings.kt
@@ -19,6 +19,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.ReadOnlyComposable
+import kotlin.jvm.JvmInline
@Immutable
@JvmInline
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/AlertDialog.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/AlertDialog.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/AlertDialog.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/AlertDialog.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/CalendarLocale.commonStubs.kt
similarity index 72%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/CalendarLocale.commonStubs.kt
index 02ed679..4639efb 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/CalendarLocale.commonStubs.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,20 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
-/** Returns the default [CalendarLocale]. */
+@ExperimentalMaterial3Api
+actual class CalendarLocale {
+ init {
+ implementedInJetBrainsFork()
+ }
+}
+
@Composable
@ReadOnlyComposable
@OptIn(ExperimentalMaterial3Api::class)
internal actual fun defaultLocale(): CalendarLocale = implementedInJetBrainsFork()
+
+internal actual fun Int.toLocalString(
+ minDigits: Int,
+ maxDigits: Int,
+ isGroupingUsed: Boolean
+): String = implementedInJetBrainsFork()
diff --git a/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DateInput.commonStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DateInput.commonStubs.kt
new file mode 100644
index 0000000..83856230
--- /dev/null
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DateInput.commonStubs.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3
+
+import androidx.compose.material3.internal.CalendarDate
+import androidx.compose.material3.internal.DateInputFormat
+import androidx.compose.runtime.Stable
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Stable
+internal actual class DateInputValidator
+actual constructor(
+ yearRange: IntRange,
+ selectableDates: SelectableDates,
+ dateInputFormat: DateInputFormat,
+ dateFormatter: DatePickerFormatter,
+ errorDatePattern: String,
+ errorDateOutOfYearRange: String,
+ errorInvalidNotAllowed: String,
+ errorInvalidRangeInput: String
+) {
+ actual var currentStartDateMillis: Long? = implementedInJetBrainsFork()
+ actual var currentEndDateMillis: Long? = implementedInJetBrainsFork()
+
+ actual fun validate(
+ dateToValidate: CalendarDate?,
+ inputIdentifier: InputIdentifier,
+ locale: CalendarLocale
+ ): String = implementedInJetBrainsFork()
+}
diff --git a/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DatePicker.commonStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DatePicker.commonStubs.kt
new file mode 100644
index 0000000..f692c5e1
--- /dev/null
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/DatePicker.commonStubs.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+package androidx.compose.material3
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun formatDatePickerNavigateToYearString(
+ template: String,
+ localizedYear: String
+): String = implementedInJetBrainsFork()
+
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun formatHeadlineDescription(
+ template: String,
+ verboseDateDescription: String
+): String = implementedInJetBrainsFork()
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/InteractiveComponentSize.commonStubs.kt
similarity index 63%
copy from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
copy to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/InteractiveComponentSize.commonStubs.kt
index 02ed679..66e32fd 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/CalendarLocale.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/InteractiveComponentSize.commonStubs.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2023 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,5 @@
package androidx.compose.material3
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ReadOnlyComposable
-
-/** Returns the default [CalendarLocale]. */
-@Composable
-@ReadOnlyComposable
-@OptIn(ExperimentalMaterial3Api::class)
-internal actual fun defaultLocale(): CalendarLocale = implementedInJetBrainsFork()
+@Suppress("NOTHING_TO_INLINE")
+internal actual inline fun identityHashCode(value: Any): Int = implementedInJetBrainsFork()
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/ModalBottomSheet.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/ModalBottomSheet.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/ModalBottomSheet.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/ModalBottomSheet.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/NavigationDrawer.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/NavigationDrawer.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/NavigationDrawer.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/NavigationDrawer.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/NotImplemented.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/NotImplemented.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/NotImplemented.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/NotImplemented.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/SkikoMenu.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/SkikoMenu.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/SkikoMenu.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/SkikoMenu.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/TimeFormat.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/TimeFormat.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/TimeFormat.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/TimeFormat.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/TimePicker.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/TimePicker.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/TimePicker.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/TimePicker.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/Tooltip.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/Tooltip.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/Tooltip.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/Tooltip.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AccessibilityServiceStateProvider.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.commonStubs.kt
similarity index 62%
copy from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
copy to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.commonStubs.kt
index ab14c60..8b75665 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/AnchoredDraggable.commonStubs.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,12 @@
package androidx.compose.material3.internal
-import androidx.compose.material3.CalendarLocale
import androidx.compose.material3.implementedInJetBrainsFork
+import kotlinx.coroutines.CancellationException
-internal actual fun createCalendarModel(locale: CalendarLocale): CalendarModel =
- implementedInJetBrainsFork()
-
-internal actual fun formatWithSkeleton(
- utcTimeMillis: Long,
- skeleton: String,
- locale: CalendarLocale,
- cache: MutableMap<String, Any>
-): String = implementedInJetBrainsFork()
+internal actual class AnchoredDragFinishedSignal actual constructor() :
+ CancellationException("Anchored drag finished") {
+ init {
+ implementedInJetBrainsFork()
+ }
+}
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/BasicTooltip.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/BasicTooltip.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/BasicTooltip.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/BasicTooltip.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.commonStubs.kt
similarity index 80%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.commonStubs.kt
index ab14c60..30bc924 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.commonStubs.kt
@@ -17,14 +17,20 @@
package androidx.compose.material3.internal
import androidx.compose.material3.CalendarLocale
+import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.implementedInJetBrainsFork
+@OptIn(ExperimentalMaterial3Api::class)
internal actual fun createCalendarModel(locale: CalendarLocale): CalendarModel =
implementedInJetBrainsFork()
+@OptIn(ExperimentalMaterial3Api::class)
internal actual fun formatWithSkeleton(
utcTimeMillis: Long,
skeleton: String,
locale: CalendarLocale,
cache: MutableMap<String, Any>
): String = implementedInJetBrainsFork()
+
+internal actual fun datePatternAsInputFormat(localeFormat: String): DateInputFormat =
+ implementedInJetBrainsFork()
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/DefaultPlatformTextStyle.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/DefaultPlatformTextStyle.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/DefaultPlatformTextStyle.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/DefaultPlatformTextStyle.commonStubs.kt
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/InternalMutatorMutex.commonStubs.kt
similarity index 61%
copy from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
copy to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/InternalMutatorMutex.commonStubs.kt
index ab14c60..0d47281 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/CalendarModel.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/InternalMutatorMutex.commonStubs.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2022 The Android Open Source Project
+ * Copyright 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,16 @@
package androidx.compose.material3.internal
-import androidx.compose.material3.CalendarLocale
import androidx.compose.material3.implementedInJetBrainsFork
-internal actual fun createCalendarModel(locale: CalendarLocale): CalendarModel =
- implementedInJetBrainsFork()
+internal actual class InternalAtomicReference<V> actual constructor(value: V) {
+ actual fun get(): V = implementedInJetBrainsFork()
-internal actual fun formatWithSkeleton(
- utcTimeMillis: Long,
- skeleton: String,
- locale: CalendarLocale,
- cache: MutableMap<String, Any>
-): String = implementedInJetBrainsFork()
+ actual fun set(value: V) {
+ implementedInJetBrainsFork()
+ }
+
+ actual fun getAndSet(value: V): V = implementedInJetBrainsFork()
+
+ actual fun compareAndSet(expect: V, newValue: V): Boolean = implementedInJetBrainsFork()
+}
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/Strings.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/Strings.commonStubs.kt
similarity index 98%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/Strings.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/Strings.commonStubs.kt
index d83be33..a2c5526 100644
--- a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/Strings.jvmStubs.kt
+++ b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/Strings.commonStubs.kt
@@ -20,6 +20,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.ReadOnlyComposable
+import kotlin.jvm.JvmInline
@Composable
@ReadOnlyComposable
diff --git a/compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/SystemBarsDefaultInsets.jvmStubs.kt b/compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/SystemBarsDefaultInsets.commonStubs.kt
similarity index 100%
rename from compose/material3/material3/src/jvmStubsMain/kotlin/androidx/compose/material3/internal/SystemBarsDefaultInsets.jvmStubs.kt
rename to compose/material3/material3/src/commonStubsMain/kotlin/androidx/compose/material3/internal/SystemBarsDefaultInsets.commonStubs.kt
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
index dd5fd27..4bd040c 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Bezier.kt
@@ -36,8 +36,9 @@
private const val Epsilon = 1e-7
// We use a fairly high epsilon here because it's post double->float conversion
// and because we use a fast approximation of cbrt(). The epsilon we use here is
-// the max error of fastCbrt() in the -1f..1f range.
-private const val FloatEpsilon = 8.3446500e-7f
+// slightly larger than the max error of fastCbrt() in the -1f..1f range
+// (8.3446500e-7f) but smaller than 1.0f.ulp * 10.
+private const val FloatEpsilon = 1e-6f
/**
* Evaluate the specified [segment] at position [t] and returns the X coordinate of the segment's
diff --git a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/UtilsTest.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/UtilsTest.kt
index 8f63be1..b6f81c1a 100644
--- a/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/UtilsTest.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/UtilsTest.kt
@@ -245,6 +245,8 @@
}
// Tests for Move Motion Event Creation <---------------
+ // Note: For tests with history, I am only checking the history count, not each history's x/y.
+ // One pointer/finger
@Test
fun createMoveMotionEvents_sixEventsOnePointerNegativeMoveDeltaWithoutHistory() {
val y = (ItemHeightPx / 2)
@@ -272,11 +274,11 @@
assertThat(moves.size).isEqualTo(numberOfEvents)
- for ((index, move) in moves.withIndex()) {
- val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
+ for ((moveIndex, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
assertThat(move.eventTime).isEqualTo(expectedTime)
- val expectedX = xMoveInitial - (abs(index * DefaultPointerInputMoveAmountPx))
+ val expectedX = xMoveInitial - (abs(moveIndex * DefaultPointerInputMoveAmountPx))
assertThat(move.x).isEqualTo(expectedX)
assertThat(move.y).isEqualTo(y)
@@ -309,11 +311,11 @@
assertThat(moves.size).isEqualTo(numberOfEvents)
- for ((index, move) in moves.withIndex()) {
- val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
+ for ((moveIndex, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
assertThat(move.eventTime).isEqualTo(expectedTime)
- val expectedX = xMoveInitial + (index * DefaultPointerInputMoveAmountPx)
+ val expectedX = xMoveInitial + (moveIndex * DefaultPointerInputMoveAmountPx)
assertThat(move.x).isEqualTo(expectedX)
assertThat(move.y).isEqualTo(y)
@@ -321,8 +323,6 @@
}
}
- // TODO(jjw): Add multi-pointer tests (next CL).
-
@Test
fun createMoveMotionEvents_sixEventsOnePointerPositiveMoveDeltaWithHistory() {
val y = (ItemHeightPx / 2)
@@ -400,6 +400,221 @@
}
}
+ // Multiple pointers/fingers
+ @Test
+ fun createMoveMotionEvents_sixEventsThreePointerNegativeMoveDeltaWithoutHistory() {
+ val y = (ItemHeightPx / 2)
+ val xMoveInitial = 0f
+ val initialTime = 100
+ val numberOfEvents = 6
+ val numberOfPointers = 3 // fingers
+ val enableFlingStyleHistory = false
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val view = View(context)
+
+ val initialPointers =
+ Array(numberOfPointers) { simpleIndex ->
+ BenchmarkSimplifiedPointerInputPointer(
+ id = simpleIndex,
+ x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
+ y = y
+ )
+ }
+
+ val moves =
+ createMoveMotionEvents(
+ initialTime = initialTime,
+ initialPointers = initialPointers,
+ rootView = view,
+ numberOfMoveEvents = numberOfEvents,
+ enableFlingStyleHistory = enableFlingStyleHistory,
+ timeDelta = 100,
+ moveDelta = -DefaultPointerInputMoveAmountPx
+ )
+
+ assertThat(moves.size).isEqualTo(numberOfEvents)
+
+ for ((index, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
+ assertThat(move.eventTime).isEqualTo(expectedTime)
+ assertThat(move.historySize).isEqualTo(0)
+
+ for (pointerIndex in 0 until move.pointerCount) {
+ val pointerId: Int = move.getPointerId(pointerIndex)
+ val localPointerCoords = MotionEvent.PointerCoords()
+ move.getPointerCoords(pointerId, localPointerCoords)
+
+ val expectedX =
+ (xMoveInitial - (abs(index * DefaultPointerInputMoveAmountPx))) +
+ (pointerIndex * DefaultPointerInputMoveAmountPx)
+ assertThat(localPointerCoords.x).isEqualTo(expectedX)
+
+ assertThat(localPointerCoords.y).isEqualTo(y)
+ }
+ }
+ }
+
+ @Test
+ fun createMoveMotionEvents_sixEventsThreePointerPositiveMoveDeltaWithoutHistory() {
+ val y = (ItemHeightPx / 2)
+ val xMoveInitial = 0f
+ val initialTime = 100
+ val numberOfEvents = 6
+ val numberOfPointers = 3 // fingers
+ val enableFlingStyleHistory = false
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val view = View(context)
+
+ val initialPointers =
+ Array(numberOfPointers) { simpleIndex ->
+ BenchmarkSimplifiedPointerInputPointer(
+ id = simpleIndex,
+ x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
+ y = y
+ )
+ }
+
+ val moves =
+ createMoveMotionEvents(
+ initialTime = initialTime,
+ initialPointers = initialPointers,
+ rootView = view,
+ numberOfMoveEvents = numberOfEvents,
+ enableFlingStyleHistory = enableFlingStyleHistory
+ )
+
+ assertThat(moves.size).isEqualTo(numberOfEvents)
+
+ for ((index, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (index * DefaultPointerInputTimeDelta)
+ assertThat(move.eventTime).isEqualTo(expectedTime)
+ assertThat(move.historySize).isEqualTo(0)
+
+ for (pointerIndex in 0 until move.pointerCount) {
+ val pointerId: Int = move.getPointerId(pointerIndex)
+ val localPointerCoords = MotionEvent.PointerCoords()
+ move.getPointerCoords(pointerId, localPointerCoords)
+
+ val expectedX =
+ (xMoveInitial + (index * DefaultPointerInputMoveAmountPx)) +
+ (pointerIndex * DefaultPointerInputMoveAmountPx)
+ assertThat(localPointerCoords.x).isEqualTo(expectedX)
+
+ assertThat(localPointerCoords.y).isEqualTo(y)
+ }
+ }
+ }
+
+ @Test
+ fun createMoveMotionEvents_sixEventsThreePointerNegativeMoveDeltaWithHistory() {
+ val y = (ItemHeightPx / 2)
+ val xMoveInitial = 0f
+ val initialTime = 100
+ val numberOfEvents = 6
+ val numberOfPointers = 3 // fingers
+ val enableFlingStyleHistory = true
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val view = View(context)
+
+ val initialPointers =
+ Array(numberOfPointers) { simpleIndex ->
+ BenchmarkSimplifiedPointerInputPointer(
+ id = simpleIndex,
+ x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
+ y = y
+ )
+ }
+
+ val moves =
+ createMoveMotionEvents(
+ initialTime = initialTime,
+ initialPointers = initialPointers,
+ rootView = view,
+ numberOfMoveEvents = numberOfEvents,
+ enableFlingStyleHistory = enableFlingStyleHistory,
+ timeDelta = 100,
+ moveDelta = -DefaultPointerInputMoveAmountPx
+ )
+
+ assertThat(moves.size).isEqualTo(numberOfEvents)
+
+ for ((moveIndex, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
+ assertThat(move.eventTime).isEqualTo(expectedTime)
+
+ assertThat(move.historySize)
+ .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
+
+ for (pointerIndex in 0 until move.pointerCount) {
+ val pointerId: Int = move.getPointerId(pointerIndex)
+ val localPointerCoords = MotionEvent.PointerCoords()
+ move.getPointerCoords(pointerId, localPointerCoords)
+
+ val expectedX =
+ (xMoveInitial - (abs(moveIndex * DefaultPointerInputMoveAmountPx))) +
+ (pointerIndex * DefaultPointerInputMoveAmountPx)
+ assertThat(localPointerCoords.x).isEqualTo(expectedX)
+ assertThat(localPointerCoords.y).isEqualTo(y)
+ }
+ }
+ }
+
+ @Test
+ fun createMoveMotionEvents_sixEventsThreePointerPositiveMoveDeltaWithHistory() {
+ val y = (ItemHeightPx / 2)
+ val xMoveInitial = 0f
+ val initialTime = 100
+ val numberOfEvents = 6
+ val numberOfPointers = 3 // fingers
+ val enableFlingStyleHistory = true
+
+ val context = ApplicationProvider.getApplicationContext<Context>()
+ val view = View(context)
+
+ val initialPointers =
+ Array(numberOfPointers) { simpleIndex ->
+ BenchmarkSimplifiedPointerInputPointer(
+ id = simpleIndex,
+ x = xMoveInitial + (simpleIndex * DefaultPointerInputMoveAmountPx),
+ y = y
+ )
+ }
+
+ val moves =
+ createMoveMotionEvents(
+ initialTime = initialTime,
+ initialPointers = initialPointers,
+ rootView = view,
+ numberOfMoveEvents = numberOfEvents,
+ enableFlingStyleHistory = enableFlingStyleHistory
+ )
+
+ assertThat(moves.size).isEqualTo(numberOfEvents)
+
+ for ((moveIndex, move) in moves.withIndex()) {
+ val expectedTime = initialTime + (moveIndex * DefaultPointerInputTimeDelta)
+ assertThat(move.eventTime).isEqualTo(expectedTime)
+
+ assertThat(move.historySize)
+ .isEqualTo(numberOfHistoricalEventsBasedOnArrayLocation(moveIndex))
+
+ for (pointerIndex in 0 until move.pointerCount) {
+ val pointerId: Int = move.getPointerId(pointerIndex)
+ val localPointerCoords = MotionEvent.PointerCoords()
+ move.getPointerCoords(pointerId, localPointerCoords)
+
+ val expectedX =
+ (xMoveInitial + (moveIndex * DefaultPointerInputMoveAmountPx)) +
+ (pointerIndex * DefaultPointerInputMoveAmountPx)
+ assertThat(localPointerCoords.x).isEqualTo(expectedX)
+ assertThat(localPointerCoords.y).isEqualTo(y)
+ }
+ }
+ }
+
@Test
fun testNumberOfHistoricalEventsBasedOnArrayLocation() {
var numberOfEvents = numberOfHistoricalEventsBasedOnArrayLocation(0)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/window/PopupTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/window/PopupTest.kt
index da69e38..84502d7 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/window/PopupTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/window/PopupTest.kt
@@ -15,6 +15,7 @@
*/
package androidx.compose.ui.window
+import android.view.KeyEvent
import android.view.View
import android.view.View.MEASURED_STATE_TOO_SMALL
import android.view.ViewGroup
@@ -282,6 +283,36 @@
}
@Test
+ fun isDismissedOnEscapePress() {
+ var showPopup by mutableStateOf(true)
+ rule.setContent {
+ Box(Modifier.fillMaxSize()) {
+ if (showPopup) {
+ Popup(
+ properties =
+ PopupProperties(
+ // Needs to be focusable to intercept key press
+ focusable = true
+ ),
+ alignment = Alignment.Center,
+ onDismissRequest = { showPopup = false }
+ ) {
+ Box(Modifier.size(50.dp).testTag(testTag))
+ }
+ }
+ }
+ }
+
+ // Popup should be visible
+ rule.onNodeWithTag(testTag).assertIsDisplayed()
+
+ UiDevice.getInstance(getInstrumentation()).pressKeyCode(KeyEvent.KEYCODE_ESCAPE)
+
+ // Popup should not exist
+ rule.onNodeWithTag(testTag).assertDoesNotExist()
+ }
+
+ @Test
fun isNotDismissedOnTapOutside_dismissOnClickOutsideFalse() {
var showPopup by mutableStateOf(true)
rule.setContent {
@@ -346,6 +377,37 @@
}
@Test
+ fun isNotDismissedOnEscapePress_dismissOnBackPressFalse() {
+ var showPopup by mutableStateOf(true)
+ rule.setContent {
+ Box(Modifier.fillMaxSize()) {
+ if (showPopup) {
+ Popup(
+ properties =
+ PopupProperties(
+ // Needs to be focusable to intercept key press
+ focusable = true,
+ dismissOnBackPress = false
+ ),
+ alignment = Alignment.Center,
+ onDismissRequest = { showPopup = false }
+ ) {
+ Box(Modifier.size(50.dp).testTag(testTag))
+ }
+ }
+ }
+ }
+
+ // Popup should be visible
+ rule.onNodeWithTag(testTag).assertIsDisplayed()
+
+ UiDevice.getInstance(getInstrumentation()).pressKeyCode(KeyEvent.KEYCODE_ESCAPE)
+
+ // Popup should still be visible
+ rule.onNodeWithTag(testTag).assertIsDisplayed()
+ }
+
+ @Test
fun canFillScreenWidth_dependingOnProperty() {
var box1Width = 0
var box2Width = 0
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
index 2269723..35431d0 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.android.kt
@@ -98,10 +98,10 @@
* @property inheritSecurePolicy Whether [WindowManager.LayoutParams.FLAG_SECURE] should be set
* according to [SecureFlagPolicy.Inherit]. Other [SecureFlagPolicy] behaviors should be set via
* [flags] directly.
- * @property dismissOnBackPress Whether the popup can be dismissed by pressing the back button. If
- * true, pressing the back button will call onDismissRequest. Note that the popup must be
- * [focusable] in order to receive key events such as the back button. If the popup is not
- * [focusable], then this property does nothing.
+ * @property dismissOnBackPress Whether the popup can be dismissed by pressing the back or escape
+ * buttons. If true, pressing the back or escape buttons will call onDismissRequest. Note that the
+ * popup must be [focusable] in order to receive key events such as the back button. If the popup
+ * is not [focusable], then this property does nothing.
* @property dismissOnClickOutside Whether the popup can be dismissed by clicking outside the
* popup's bounds. If true, clicking outside the popup will call onDismissRequest.
* @property excludeFromSystemGesture A flag to check whether to set the
@@ -157,10 +157,10 @@
*
* @param focusable Whether the popup is focusable. When true, the popup will receive IME events
* and key presses, such as when the back button is pressed.
- * @param dismissOnBackPress Whether the popup can be dismissed by pressing the back button. If
- * true, pressing the back button will call onDismissRequest. Note that [focusable] must be
- * set to true in order to receive key events such as the back button. If the popup is not
- * focusable, then this property does nothing.
+ * @param dismissOnBackPress Whether the popup can be dismissed by pressing the back or escape
+ * buttons. If true, pressing the back or escape buttons will call onDismissRequest. Note that
+ * [focusable] must be set to true in order to receive key events such as the back button. If
+ * the popup is not focusable, then this property does nothing.
* @param dismissOnClickOutside Whether the popup can be dismissed by clicking outside the
* popup's bounds. If true, clicking outside the popup will call onDismissRequest.
* @param securePolicy Policy for setting [WindowManager.LayoutParams.FLAG_SECURE] on the
@@ -625,17 +625,14 @@
/** Taken from PopupWindow */
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
- if (event.keyCode == KeyEvent.KEYCODE_BACK && properties.dismissOnBackPress) {
- if (keyDispatcherState == null) {
- return super.dispatchKeyEvent(event)
- }
+ if (!properties.dismissOnBackPress) return super.dispatchKeyEvent(event)
+ if (event.keyCode == KeyEvent.KEYCODE_BACK || event.keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ val state = keyDispatcherState ?: return super.dispatchKeyEvent(event)
if (event.action == KeyEvent.ACTION_DOWN && event.repeatCount == 0) {
- val state = keyDispatcherState
- state?.startTracking(event, this)
+ state.startTracking(event, this)
return true
} else if (event.action == KeyEvent.ACTION_UP) {
- val state = keyDispatcherState
- if (state != null && state.isTracking(event) && !event.isCanceled) {
+ if (state.isTracking(event) && !event.isCanceled) {
onDismissRequest?.invoke()
return true
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/window/Popup.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/window/Popup.kt
index c7ad7a4..2e0794b 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/window/Popup.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/window/Popup.kt
@@ -29,10 +29,10 @@
*
* @property focusable Whether the popup is focusable. When true, the popup will receive IME events
* and key presses, such as when the back button is pressed.
- * @property dismissOnBackPress Whether the popup can be dismissed by pressing the back button on
- * Android or escape key on desktop. If true, pressing the back button will call onDismissRequest.
- * Note that [focusable] must be set to true in order to receive key events such as the back
- * button - if the popup is not focusable then this property does nothing.
+ * @property dismissOnBackPress Whether the popup can be dismissed by pressing the back or escape
+ * buttons on Android or the escape key on desktop. If true, pressing the back button will call
+ * onDismissRequest. Note that [focusable] must be set to true in order to receive key events such
+ * as the back button - if the popup is not focusable then this property does nothing.
* @property dismissOnClickOutside Whether the popup can be dismissed by clicking outside the
* popup's bounds. If true, clicking outside the popup will call onDismissRequest.
* @property clippingEnabled Whether to allow the popup window to extend beyond the bounds of the
diff --git a/constraintlayout/constraintlayout-compose/build.gradle b/constraintlayout/constraintlayout-compose/build.gradle
index 5b810b4..f6ed5a1 100644
--- a/constraintlayout/constraintlayout-compose/build.gradle
+++ b/constraintlayout/constraintlayout-compose/build.gradle
@@ -35,13 +35,13 @@
sourceSets {
commonMain {
dependencies {
- implementation(project(":compose:ui:ui"))
- implementation(project(":compose:ui:ui-unit"))
- implementation(project(":compose:ui:ui-util"))
- implementation(project(":compose:foundation:foundation"))
- implementation(project(":compose:foundation:foundation-layout"))
+ implementation("androidx.compose.ui:ui:1.7.0-beta05")
+ implementation("androidx.compose.ui:ui-unit:1.7.0-beta05")
+ implementation("androidx.compose.ui:ui-util:1.7.0-beta05")
+ implementation("androidx.compose.foundation:foundation:1.7.0-beta05")
+ implementation("androidx.compose.foundation:foundation-layout:1.7.0-beta05")
implementation(project(":constraintlayout:constraintlayout-core"))
- implementation(project(":collection:collection"))
+ implementation("androidx.collection:collection:1.4.1")
}
}
diff --git a/libraryversions.toml b/libraryversions.toml
index ab0d5b3..843d843 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -12,7 +12,7 @@
BLUETOOTH = "1.0.0-alpha02"
BROWSER = "1.9.0-alpha01"
BUILDSRC_TESTS = "1.0.0-alpha01"
-CAMERA = "1.4.0-beta03"
+CAMERA = "1.4.0-rc01"
CAMERA_PIPE = "1.0.0-alpha01"
CAMERA_TESTING = "1.0.0-alpha01"
CAMERA_VIEWFINDER = "1.4.0-alpha08"
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
index 37556ae..55b194c5e 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/serialization/RouteFilledTest.kt
@@ -779,7 +779,7 @@
private fun nullableIntArgument(name: String, hasDefaultValue: Boolean = false) =
navArgument(name) {
- type = NullableIntType
+ type = IntNullableType
nullable = true
unknownDefaultValuePresent = hasDefaultValue
}
@@ -790,31 +790,3 @@
nullable = true
unknownDefaultValuePresent = hasDefaultValue
}
-
-private val NullableIntType: NavType<Int?> =
- object : NavType<Int?>(true) {
- override val name: String
- get() = "nullable_integer"
-
- override fun put(bundle: Bundle, key: String, value: Int?) {
- value?.let { bundle.putInt(key, value) }
- }
-
- @Suppress("DEPRECATION")
- override fun get(bundle: Bundle, key: String): Int? {
- val value = bundle[key]
- return value?.let { it as Int }
- }
-
- override fun parseValue(value: String): Int? {
- return if (value == "null") {
- null
- } else if (value.startsWith("0x")) {
- value.substring(2).toInt(16)
- } else {
- value.toInt()
- }
- }
-
- override fun serializeAsValue(value: Int?): String = value?.toString() ?: "null"
- }
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
index 690f73a..3a7cb68 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/serialization/NavTypeConverter.kt
@@ -28,6 +28,7 @@
/** Marker for Native Kotlin types with either full or partial built-in NavType support */
private enum class InternalType {
INT,
+ INT_NULLABLE,
BOOL,
FLOAT,
LONG,
@@ -53,6 +54,7 @@
val type =
when (this.toInternalType()) {
InternalType.INT -> NavType.IntType
+ InternalType.INT_NULLABLE -> IntNullableType
InternalType.BOOL -> NavType.BoolType
InternalType.FLOAT -> NavType.FloatType
InternalType.LONG -> NavType.LongType
@@ -90,7 +92,8 @@
private fun SerialDescriptor.toInternalType(): InternalType {
val serialName = serialName.replace("?", "")
return when {
- serialName == "kotlin.Int" -> InternalType.INT
+ serialName == "kotlin.Int" ->
+ if (isNullable) InternalType.INT_NULLABLE else InternalType.INT
serialName == "kotlin.Boolean" -> InternalType.BOOL
serialName == "kotlin.Float" -> InternalType.FLOAT
serialName == "kotlin.Long" -> InternalType.LONG
@@ -134,3 +137,33 @@
override fun parseValue(value: String): String = "null"
}
+
+internal object IntNullableType : NavType<Int?>(true) {
+ override val name: String
+ get() = "integer_nullable"
+
+ override fun put(bundle: Bundle, key: String, value: Int?) {
+ // store null as serializable inside bundle, so that decoder will use the null
+ // instead of default value
+ if (value == null) bundle.putSerializable(key, null) else bundle.putInt(key, value)
+ }
+
+ @Suppress("DEPRECATION")
+ override fun get(bundle: Bundle, key: String): Int? {
+ return bundle[key] as? Int
+ }
+
+ override fun parseValue(value: String): Int? {
+ return if (value == "null") {
+ null
+ } else if (value.startsWith("0x")) {
+ value.substring(2).toInt(16)
+ } else {
+ value.toInt()
+ }
+ }
+
+ override fun serializeAsValue(value: Int?): String {
+ return value?.toString() ?: "null"
+ }
+}
diff --git a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
index 4d1190c..45f410e 100644
--- a/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
+++ b/navigation/navigation-common/src/test/java/androidx/navigation/serialization/NavArgumentGeneratorTest.kt
@@ -53,14 +53,17 @@
}
@Test
- fun convertToIntNullableIllegal() {
+ fun convertToIntNullable() {
@Serializable class TestClass(val arg: Int?)
- val exception =
- assertFailsWith<IllegalArgumentException> {
- serializer<TestClass>().generateNavArguments()
+ val converted = serializer<TestClass>().generateNavArguments()
+ val expected =
+ navArgument("arg") {
+ type = IntNullableType
+ nullable = true
}
- assertThat(exception.message).isEqualTo("integer does not allow nullable values")
+ assertThat(converted).containsExactlyInOrder(expected)
+ assertThat(converted[0].argument.isDefaultValueUnknown).isFalse()
}
@Test
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
index bb37c66..029fe40 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerRouteTest.kt
@@ -30,6 +30,7 @@
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.navigation.NavDestination.Companion.createRoute
+import androidx.navigation.NavDestination.Companion.hasRoute
import androidx.navigation.serialization.generateHashCode
import androidx.navigation.test.R
import androidx.test.annotation.UiThreadTest
@@ -1153,6 +1154,37 @@
@UiThreadTest
@Test
+ fun testNavigateWithObjectNullableInt() {
+ @Serializable class TestClass(val arg: Int? = 10)
+ val navController = createNavController()
+ navController.graph =
+ navController.createGraph(startDestination = "start") {
+ test("start")
+ test<TestClass>()
+ }
+ assertThat(navController.currentDestination?.route).isEqualTo("start")
+
+ // passed in arg
+ navController.navigate(TestClass(15))
+ assertThat(navController.currentDestination?.hasRoute(TestClass::class)).isTrue()
+ assertThat(navController.currentBackStackEntry?.toRoute<TestClass>()?.arg).isEqualTo(15)
+ assertThat(navController.currentBackStack.value.size).isEqualTo(3)
+
+ // passed in null
+ navController.navigate(TestClass(null))
+ assertThat(navController.currentDestination?.hasRoute(TestClass::class)).isTrue()
+ assertThat(navController.currentBackStackEntry?.toRoute<TestClass>()?.arg).isNull()
+ assertThat(navController.currentBackStack.value.size).isEqualTo(4)
+
+ // use default
+ navController.navigate(TestClass())
+ assertThat(navController.currentDestination?.hasRoute(TestClass::class)).isTrue()
+ assertThat(navController.currentBackStackEntry?.toRoute<TestClass>()?.arg).isEqualTo(10)
+ assertThat(navController.currentBackStack.value.size).isEqualTo(5)
+ }
+
+ @UiThreadTest
+ @Test
fun testNavigateWithPopUpToFurthestRoute() {
val navController = createNavController()
navController.graph = nav_singleArg_graph