Merge "Remove multiple passes of drag." into androidx-master-dev
diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index 27801a3b4..15e5c1e 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -1,6 +1,8 @@
name: AndroidX Presubmits
on:
push:
+ pull_request_target:
+ types: [opened, synchronize, reopened]
pull_request:
types: [opened, synchronize, reopened]
pull_request_review:
diff --git a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
index 93ea754..f289076 100644
--- a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
+++ b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
@@ -165,6 +165,7 @@
Bundle optionsBundle = null;
if (intent.hasExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE)) {
optionsBundle = intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE);
+ intent.removeExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE);
} else if (options != null) {
optionsBundle = options.toBundle();
}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentReceiveResultTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentReceiveResultTest.kt
index c786445..be97a16 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentReceiveResultTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentReceiveResultTest.kt
@@ -19,6 +19,7 @@
import android.app.PendingIntent
import android.content.Intent
import android.content.IntentSender
+import android.os.Bundle
import androidx.fragment.app.test.FragmentResultActivity
import androidx.fragment.app.test.FragmentTestActivity
import androidx.fragment.test.R
@@ -119,6 +120,16 @@
}
@Test
+ fun testStartIntentSenderForResultWithOptionsOk() {
+ startIntentSenderForResult(30, Activity.RESULT_OK, "content 30", Bundle())
+
+ assertWithMessage("Fragment should receive result").that(fragment.hasResult[0]).isTrue()
+ assertThat(fragment.requestCode[0]).isEqualTo(30)
+ assertThat(fragment.resultCode[0]).isEqualTo(Activity.RESULT_OK)
+ assertThat(fragment.resultContent[0]).isEqualTo("content 30")
+ }
+
+ @Test
fun testStartIntentSenderForResultCanceled() {
startIntentSenderForResult(40, Activity.RESULT_CANCELED, "content 40")
@@ -163,7 +174,8 @@
private fun startIntentSenderForResult(
requestCode: Int,
resultCode: Int,
- content: String
+ content: String,
+ options: Bundle? = null
) {
activityRule.runOnUiThread {
val intent = Intent(activity, FragmentResultActivity::class.java)
@@ -175,7 +187,7 @@
try {
fragment.startIntentSenderForResult(
pendingIntent.intentSender,
- requestCode, null, 0, 0, 0, null
+ requestCode, null, 0, 0, 0, options
)
} catch (e: IntentSender.SendIntentException) {
fail("IntentSender failed")
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index d98909d..9d98e62 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1440,6 +1440,11 @@
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "Fragment " + this + " received the following in "
+ + "startIntentSenderForResult() requestCode: " + requestCode + " IntentSender: "
+ + intent + " fillInIntent: " + fillInIntent + " options: " + options);
+ }
getParentFragmentManager().launchStartIntentSenderForResult(this, intent, requestCode,
fillInIntent, flagsMask, flagsValues, extraFlags, options);
}
@@ -1466,6 +1471,11 @@
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(FragmentManager.TAG, "Fragment " + this + " received the following in "
+ + "onActivityResult(): requestCode: " + requestCode + " resultCode: "
+ + resultCode + " data: " + data);
+ }
}
/**
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 1d5007f..01bf8c3 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -493,15 +493,15 @@
}
};
- // Key to retrieve the request code from any intents that are started
- private static final String EXTRA_KEY_REQUEST_CODE = "activity.result.requestCode";
-
private ActivityResultLauncher<Intent> mStartActivityForResult;
private ActivityResultLauncher<IntentSenderRequest> mStartIntentSenderForResult;
private ActivityResultLauncher<String[]> mRequestPermissions;
ArrayDeque<LaunchedFragmentInfo> mLaunchedFragments = new ArrayDeque<>();
+ private static final String EXTRA_CREATED_FILLIN_INTENT = "androidx.fragment"
+ + ".extra.ACTIVITY_OPTIONS_BUNDLE";
+
private boolean mNeedMenuInvalidate;
private boolean mStateSaved;
private boolean mStopped;
@@ -2906,8 +2906,7 @@
// fragment transactions was committed immediately after the for
// result call
if (fragment == null) {
- Log.w(TAG,
- "Intent Sender result delivered for unknown Fragment "
+ Log.w(TAG, "Intent Sender result delivered for unknown Fragment "
+ fragmentWho);
return;
}
@@ -2976,7 +2975,7 @@
if (mStartActivityForResult != null) {
LaunchedFragmentInfo info = new LaunchedFragmentInfo(f.mWho, requestCode);
mLaunchedFragments.addLast(info);
- if (options != null) {
+ if (intent != null && options != null) {
intent.putExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE, options);
}
mStartActivityForResult.launch(intent);
@@ -2994,6 +2993,11 @@
if (options != null) {
if (fillInIntent == null) {
fillInIntent = new Intent();
+ fillInIntent.putExtra(EXTRA_CREATED_FILLIN_INTENT, true);
+ }
+ if (isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(TAG, "ActivityOptions " + options + " were added to fillInIntent "
+ + fillInIntent + " for fragment " + f);
}
fillInIntent.putExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE, options);
}
@@ -3002,6 +3006,9 @@
.setFlags(flagsValues, flagsMask).build();
LaunchedFragmentInfo info = new LaunchedFragmentInfo(f.mWho, requestCode);
mLaunchedFragments.addLast(info);
+ if (isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(TAG, "Fragment " + f + "is launching an IntentSender for result ");
+ }
mStartIntentSenderForResult.launch(request);
} else {
mHost.onStartIntentSenderFromFragment(f, intent, requestCode, fillInIntent,
@@ -3628,17 +3635,24 @@
@Override
public Intent createIntent(@NonNull Context context, IntentSenderRequest input) {
Intent result = new Intent(ACTION_INTENT_SENDER_REQUEST);
- if (input.getFillInIntent() != null) {
- Bundle activityOptions =
- input.getFillInIntent().getBundleExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE);
- int requestCode =
- input.getFillInIntent().getIntExtra(EXTRA_KEY_REQUEST_CODE, -1);
+ Intent fillInIntent = input.getFillInIntent();
+ if (fillInIntent != null) {
+ Bundle activityOptions = fillInIntent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE);
if (activityOptions != null) {
- result.putExtra(EXTRA_KEY_REQUEST_CODE, requestCode);
result.putExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE, activityOptions);
+ fillInIntent.removeExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE);
+ if (fillInIntent.getBooleanExtra(EXTRA_CREATED_FILLIN_INTENT, false)) {
+ input = new IntentSenderRequest.Builder(input.getIntentSender())
+ .setFillInIntent(null)
+ .setFlags(input.getFlagsValues(), input.getFlagsMask())
+ .build();
+ }
}
}
result.putExtra(EXTRA_INTENT_SENDER_REQUEST, input);
+ if (isLoggingEnabled(Log.VERBOSE)) {
+ Log.v(TAG, "CreateIntent created the following intent: " + result);
+ }
return result;
}
diff --git a/ui/ui-material/api/current.txt b/ui/ui-material/api/current.txt
index 6acb362..4c4a03d 100644
--- a/ui/ui-material/api/current.txt
+++ b/ui/ui-material/api/current.txt
@@ -202,11 +202,22 @@
@kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialApi {
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
+ }
+
public final class FloatingActionButtonKt {
method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-NLuz2VQ(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit>? icon = null, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp);
method @androidx.compose.runtime.Composable public static void FloatingActionButton-NGcTDU4(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
+ ctor public FractionalThreshold(@FloatRange(from=null, to=null) float fraction);
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FractionalThreshold copy(float fraction);
+ }
+
public final class IconButtonKt {
method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, boolean enabled = true, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
@@ -351,14 +362,12 @@
}
public final class SwipeToDismissKt {
- method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissDirection,? extends androidx.compose.material.ThresholdConfig> dismissThresholds = { return <init>(0.5) }, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.DismissState rememberDismissState(androidx.compose.material.DismissValue initialValue = androidx.compose.material.DismissValue.Default, kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissValue,java.lang.Boolean> confirmStateChange = { return true });
}
public final class SwipeableKt {
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fixedThresholds-0680j_4(float offset);
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fractionalThresholds(@FloatRange(from=0.0, to=1.0) float fraction);
- method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function3<? super androidx.compose.ui.unit.Density,? super java.lang.Float,? super java.lang.Float,java.lang.Float> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
+ method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
var varf5a37bc5: <ErrorType> = anchors.keys.<anonymous class>()
if (varf5a37bc5 != null) varf5a37bc5 else Float.NEGATIVE_INFINITY
}, float maxValue = elvis {
@@ -433,6 +442,10 @@
method @androidx.compose.runtime.Composable public static void TextField-pcAQjko(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, kotlin.jvm.functions.Function0<kotlin.Unit> label, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onFocusChanged = {}, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ }
+
@androidx.compose.runtime.Immutable public final class Typography {
ctor public Typography(androidx.compose.ui.text.font.FontFamily defaultFontFamily, androidx.compose.ui.text.TextStyle h1, androidx.compose.ui.text.TextStyle h2, androidx.compose.ui.text.TextStyle h3, androidx.compose.ui.text.TextStyle h4, androidx.compose.ui.text.TextStyle h5, androidx.compose.ui.text.TextStyle h6, androidx.compose.ui.text.TextStyle subtitle1, androidx.compose.ui.text.TextStyle subtitle2, androidx.compose.ui.text.TextStyle body1, androidx.compose.ui.text.TextStyle body2, androidx.compose.ui.text.TextStyle button, androidx.compose.ui.text.TextStyle caption, androidx.compose.ui.text.TextStyle overline);
method public androidx.compose.ui.text.TextStyle component1();
diff --git a/ui/ui-material/api/public_plus_experimental_current.txt b/ui/ui-material/api/public_plus_experimental_current.txt
index 6acb362..4c4a03d 100644
--- a/ui/ui-material/api/public_plus_experimental_current.txt
+++ b/ui/ui-material/api/public_plus_experimental_current.txt
@@ -202,11 +202,22 @@
@kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialApi {
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
+ }
+
public final class FloatingActionButtonKt {
method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-NLuz2VQ(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit>? icon = null, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp);
method @androidx.compose.runtime.Composable public static void FloatingActionButton-NGcTDU4(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
+ ctor public FractionalThreshold(@FloatRange(from=null, to=null) float fraction);
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FractionalThreshold copy(float fraction);
+ }
+
public final class IconButtonKt {
method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, boolean enabled = true, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
@@ -351,14 +362,12 @@
}
public final class SwipeToDismissKt {
- method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissDirection,? extends androidx.compose.material.ThresholdConfig> dismissThresholds = { return <init>(0.5) }, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.DismissState rememberDismissState(androidx.compose.material.DismissValue initialValue = androidx.compose.material.DismissValue.Default, kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissValue,java.lang.Boolean> confirmStateChange = { return true });
}
public final class SwipeableKt {
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fixedThresholds-0680j_4(float offset);
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fractionalThresholds(@FloatRange(from=0.0, to=1.0) float fraction);
- method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function3<? super androidx.compose.ui.unit.Density,? super java.lang.Float,? super java.lang.Float,java.lang.Float> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
+ method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
var varf5a37bc5: <ErrorType> = anchors.keys.<anonymous class>()
if (varf5a37bc5 != null) varf5a37bc5 else Float.NEGATIVE_INFINITY
}, float maxValue = elvis {
@@ -433,6 +442,10 @@
method @androidx.compose.runtime.Composable public static void TextField-pcAQjko(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, kotlin.jvm.functions.Function0<kotlin.Unit> label, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onFocusChanged = {}, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ }
+
@androidx.compose.runtime.Immutable public final class Typography {
ctor public Typography(androidx.compose.ui.text.font.FontFamily defaultFontFamily, androidx.compose.ui.text.TextStyle h1, androidx.compose.ui.text.TextStyle h2, androidx.compose.ui.text.TextStyle h3, androidx.compose.ui.text.TextStyle h4, androidx.compose.ui.text.TextStyle h5, androidx.compose.ui.text.TextStyle h6, androidx.compose.ui.text.TextStyle subtitle1, androidx.compose.ui.text.TextStyle subtitle2, androidx.compose.ui.text.TextStyle body1, androidx.compose.ui.text.TextStyle body2, androidx.compose.ui.text.TextStyle button, androidx.compose.ui.text.TextStyle caption, androidx.compose.ui.text.TextStyle overline);
method public androidx.compose.ui.text.TextStyle component1();
diff --git a/ui/ui-material/api/restricted_current.txt b/ui/ui-material/api/restricted_current.txt
index 6acb362..4c4a03d 100644
--- a/ui/ui-material/api/restricted_current.txt
+++ b/ui/ui-material/api/restricted_current.txt
@@ -202,11 +202,22 @@
@kotlin.RequiresOptIn(message="This material API is experimental and is likely to change or to be removed in" + " the future.") public @interface ExperimentalMaterialApi {
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FixedThreshold implements androidx.compose.material.ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FixedThreshold copy-0680j_4(float offset);
+ }
+
public final class FloatingActionButtonKt {
method @androidx.compose.runtime.Composable public static void ExtendedFloatingActionButton-NLuz2VQ(kotlin.jvm.functions.Function0<kotlin.Unit> text, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit>? icon = null, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp);
method @androidx.compose.runtime.Composable public static void FloatingActionButton-NGcTDU4(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(CornerSize(50)), long backgroundColor = MaterialTheme.colors.secondary, long contentColor = contentColorFor(backgroundColor), float elevation = 6.dp, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public final class FractionalThreshold implements androidx.compose.material.ThresholdConfig {
+ ctor public FractionalThreshold(@FloatRange(from=null, to=null) float fraction);
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Immutable public androidx.compose.material.FractionalThreshold copy(float fraction);
+ }
+
public final class IconButtonKt {
method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, boolean enabled = true, androidx.compose.ui.Modifier modifier = Modifier, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
@@ -351,14 +362,12 @@
}
public final class SwipeToDismissKt {
- method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
+ method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material.DismissState state, androidx.compose.ui.Modifier modifier = Modifier, java.util.Set<? extends androidx.compose.material.DismissDirection> directions = setOf(EndToStart, StartToEnd), kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissDirection,? extends androidx.compose.material.ThresholdConfig> dismissThresholds = { return <init>(0.5) }, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> background, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> dismissContent);
method @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Composable public static androidx.compose.material.DismissState rememberDismissState(androidx.compose.material.DismissValue initialValue = androidx.compose.material.DismissValue.Default, kotlin.jvm.functions.Function1<? super androidx.compose.material.DismissValue,java.lang.Boolean> confirmStateChange = { return true });
}
public final class SwipeableKt {
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fixedThresholds-0680j_4(float offset);
- method @androidx.compose.material.ExperimentalMaterialApi public static kotlin.jvm.functions.Function3<androidx.compose.ui.unit.Density,java.lang.Float,java.lang.Float,java.lang.Float> fractionalThresholds(@FloatRange(from=0.0, to=1.0) float fraction);
- method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function3<? super androidx.compose.ui.unit.Density,? super java.lang.Float,? super java.lang.Float,java.lang.Float> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
+ method @androidx.compose.material.ExperimentalMaterialApi public static <T> androidx.compose.ui.Modifier swipeable(androidx.compose.ui.Modifier, androidx.compose.material.SwipeableState<T> state, java.util.Map<java.lang.Float,? extends T> anchors, kotlin.jvm.functions.Function2<? super T,? super T,? extends androidx.compose.material.ThresholdConfig> thresholds, androidx.compose.ui.gesture.scrollorientationlocking.Orientation orientation, boolean enabled = true, boolean reverseDirection = false, float minValue = elvis {
var varf5a37bc5: <ErrorType> = anchors.keys.<anonymous class>()
if (varf5a37bc5 != null) varf5a37bc5 else Float.NEGATIVE_INFINITY
}, float maxValue = elvis {
@@ -433,6 +442,10 @@
method @androidx.compose.runtime.Composable public static void TextField-pcAQjko(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, kotlin.jvm.functions.Function0<kotlin.Unit> label, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ -> }, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onFocusChanged = {}, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface, androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
}
+ @androidx.compose.material.ExperimentalMaterialApi @androidx.compose.runtime.Stable public interface ThresholdConfig {
+ method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
+ }
+
@androidx.compose.runtime.Immutable public final class Typography {
ctor public Typography(androidx.compose.ui.text.font.FontFamily defaultFontFamily, androidx.compose.ui.text.TextStyle h1, androidx.compose.ui.text.TextStyle h2, androidx.compose.ui.text.TextStyle h3, androidx.compose.ui.text.TextStyle h4, androidx.compose.ui.text.TextStyle h5, androidx.compose.ui.text.TextStyle h6, androidx.compose.ui.text.TextStyle subtitle1, androidx.compose.ui.text.TextStyle subtitle2, androidx.compose.ui.text.TextStyle body1, androidx.compose.ui.text.TextStyle body2, androidx.compose.ui.text.TextStyle button, androidx.compose.ui.text.TextStyle caption, androidx.compose.ui.text.TextStyle overline);
method public androidx.compose.ui.text.TextStyle component1();
diff --git a/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt b/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
index 27fdafb..f628627 100644
--- a/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
+++ b/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeToDismissSamples.kt
@@ -32,6 +32,7 @@
import androidx.compose.material.DismissValue.DismissedToEnd
import androidx.compose.material.DismissValue.DismissedToStart
import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.FractionalThreshold
import androidx.compose.material.ListItem
import androidx.compose.material.SwipeToDismiss
import androidx.compose.material.icons.Icons
@@ -71,6 +72,9 @@
state = dismissState,
modifier = Modifier.padding(vertical = 4.dp),
directions = setOf(StartToEnd, EndToStart),
+ dismissThresholds = { direction ->
+ FractionalThreshold(if (direction == StartToEnd) 0.25f else 0.5f)
+ },
background = {
val direction = dismissState.dismissDirection ?: return@SwipeToDismiss
val color = animate(when (dismissState.swipeTarget) {
diff --git a/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt b/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
index 76287e5..3cd2cc0 100644
--- a/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
+++ b/ui/ui-material/samples/src/main/java/androidx/compose/material/samples/SwipeableSamples.kt
@@ -25,8 +25,8 @@
import androidx.compose.foundation.layout.preferredSize
import androidx.compose.foundation.layout.preferredWidth
import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.FractionalThreshold
import androidx.compose.material.SwipeableState
-import androidx.compose.material.fractionalThresholds
import androidx.compose.material.swipeable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@@ -61,7 +61,7 @@
.swipeable(
state = swipeableState,
anchors = anchors,
- thresholds = fractionalThresholds(0.5f),
+ thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal
),
backgroundColor = Color.Black
diff --git a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
index 12bfe4c..edc1c2a 100644
--- a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
+++ b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Drawer.kt
@@ -306,7 +306,7 @@
Modifier.swipeable(
state = drawerState,
anchors = anchors,
- thresholds = fractionalThresholds(0.5f),
+ thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal,
enabled = gesturesEnabled,
reverseDirection = isRtl
@@ -417,7 +417,7 @@
Modifier.swipeable(
state = drawerState,
anchors = anchors,
- thresholds = fixedThresholds(BottomDrawerThreshold),
+ thresholds = { _, _ -> FixedThreshold(BottomDrawerThreshold) },
orientation = Orientation.Vertical,
enabled = gesturesEnabled
)
diff --git a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
index 34d1d66..0a81e25 100644
--- a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
+++ b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/SwipeToDismiss.kt
@@ -90,26 +90,7 @@
* change the background of the [SwipeToDismiss] if you want different actions on each side.
*/
val dismissDirection: DismissDirection?
- get() {
- val (from, to, _) = swipeProgress
- return when {
- // settled at the default state
- from == to && from == Default -> null
- // has been dismissed to the end
- from == to && from == DismissedToEnd -> StartToEnd
- // has been dismissed to the start
- from == to && from == DismissedToStart -> EndToStart
- // is currently being dismissed to the end
- from == Default && to == DismissedToEnd -> StartToEnd
- // is currently being dismissed to the start
- from == Default && to == DismissedToStart -> EndToStart
- // has been dismissed to the end but is now animated back to default
- from == DismissedToEnd && to == Default -> StartToEnd
- // has been dismissed to the start but is now animated back to default
- from == DismissedToStart && to == Default -> EndToStart
- else -> null
- }
- }
+ get() = getDismissDirection(swipeProgress.from, swipeProgress.to)
/**
* Whether the component has been dismissed in the given [direction].
@@ -173,6 +154,7 @@
* @param state The state of this component.
* @param modifier Optional [Modifier] for this component.
* @param directions The set of directions in which the component can be dismissed.
+ * @param dismissThresholds The thresholds the item needs to be swiped in order to be dismissed.
* @param background A composable that is stacked behind the content and is exposed when the
* content is swiped. You can/should use the [state] to have different backgrounds on each side.
* @param dismissContent The content that can be dismissed.
@@ -183,6 +165,7 @@
state: DismissState,
modifier: Modifier = Modifier,
directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
+ dismissThresholds: (DismissDirection) -> ThresholdConfig = { FractionalThreshold(0.5f) },
background: @Composable RowScope.() -> Unit,
dismissContent: @Composable RowScope.() -> Unit
) = WithConstraints(modifier) {
@@ -193,10 +176,14 @@
if (StartToEnd in directions) anchors += width to DismissedToEnd
if (EndToStart in directions) anchors += -width to DismissedToStart
+ val thresholds = { from: DismissValue, to: DismissValue ->
+ dismissThresholds(getDismissDirection(from, to)!!)
+ }
+
Stack(Modifier.swipeable(
state = state,
anchors = anchors,
- thresholds = fractionalThresholds(0.25f),
+ thresholds = thresholds,
orientation = Orientation.Horizontal,
enabled = state.value == Default,
reverseDirection = isRtl
@@ -210,4 +197,24 @@
modifier = Modifier.offsetPx(x = state.offset)
)
}
+}
+
+private fun getDismissDirection(from: DismissValue, to: DismissValue): DismissDirection? {
+ return when {
+ // settled at the default state
+ from == to && from == Default -> null
+ // has been dismissed to the end
+ from == to && from == DismissedToEnd -> StartToEnd
+ // has been dismissed to the start
+ from == to && from == DismissedToStart -> EndToStart
+ // is currently being dismissed to the end
+ from == Default && to == DismissedToEnd -> StartToEnd
+ // is currently being dismissed to the start
+ from == Default && to == DismissedToStart -> EndToStart
+ // has been dismissed to the end but is now animated back to default
+ from == DismissedToEnd && to == Default -> StartToEnd
+ // has been dismissed to the start but is now animated back to default
+ from == DismissedToStart && to == Default -> EndToStart
+ else -> null
+ }
}
\ No newline at end of file
diff --git a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
index 256f408..8d5d7ec 100644
--- a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
+++ b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
@@ -291,10 +291,10 @@
* @param T The type of the state.
* @param state The state of the [swipeable].
* @param anchors Pairs of anchors and states, used to map anchors to states and vice versa.
- * @param thresholds The thresholds between anchors that determine which anchor to animate to
- * when the user stops swiping, represented as a lambda that takes a pair of anchors and returns
- * a value between them. Note the order of the anchors matters as it indicates the swipe direction.
- * An easy way to define these thresholds is using [fixedThresholds] or [fractionalThresholds].
+ * @param thresholds Specifies where the thresholds between the states are. The thresholds will be
+ * used to determine which state to animate to when swiping stops. This is represented as a lambda
+ * that takes two states and returns the threshold between them in the form of a [ThresholdConfig].
+ * Note that the order of the states corresponds to the swipe direction.
* @param orientation The orientation in which the [swipeable] can be swiped.
* @param enabled Whether this [swipeable] is enabled and should react to the user's input.
* @param reverseDirection Whether to reverse the direction of the swipe, so a top to bottom
@@ -308,7 +308,7 @@
fun <T> Modifier.swipeable(
state: SwipeableState<T>,
anchors: Map<Float, T>,
- thresholds: SwipeableThresholds,
+ thresholds: (from: T, to: T) -> ThresholdConfig,
orientation: Orientation,
enabled: Boolean = true,
reverseDirection: Boolean = false,
@@ -324,7 +324,11 @@
}
val density = DensityAmbient.current
state.anchors = anchors
- state.thresholds = { a, b -> density.thresholds(a, b) }
+ state.thresholds = { a, b ->
+ val from = anchors.getValue(a)
+ val to = anchors.getValue(b)
+ with(thresholds(from, to)) { density.computeThreshold(a, b) }
+ }
state.animatedFloat.setBounds(minValue, maxValue)
val lastAnchor = anchors.getOffset(state.value)!!
@@ -343,7 +347,7 @@
adjustTarget = { target ->
val adjusted = adjustTarget(
anchors = anchors.keys,
- thresholds = { a, b -> density.thresholds(a, b) },
+ thresholds = state.thresholds,
target = target,
lastAnchor = lastAnchor
)
@@ -366,29 +370,46 @@
}
/**
- * Type alias for the lambda that will be invoked to compute the thresholds between anchors in
- * [Modifier.swipeable]. This takes two anchors, whose the order indicates the swipe direction.
+ * Interface to compute a threshold between two anchors/states in a [swipeable].
+ *
+ * To define a [ThresholdConfig], consider using [FixedThreshold] and [FractionalThreshold].
*/
-typealias SwipeableThresholds = Density.(fromAnchor: Float, toAnchor: Float) -> Float
+@Stable
+@ExperimentalMaterialApi
+interface ThresholdConfig {
+ /**
+ * Compute the value of the threshold (in pixels), once the values of the anchors are known.
+ */
+ fun Density.computeThreshold(fromValue: Float, toValue: Float): Float
+}
/**
- * Constructor for fixed thresholds between anchors.
+ * A fixed threshold will be at an [offset] away from the first anchor.
*
- * @param offset Each threshold will be at this offset (in dp) away from the first anchor.
+ * @param offset The offset (in dp) that the threshold will be at.
*/
+@Immutable
@ExperimentalMaterialApi
-fun fixedThresholds(offset: Dp): SwipeableThresholds =
- { fromAnchor, toAnchor -> fromAnchor + offset.toPx() * sign(toAnchor - fromAnchor) }
+data class FixedThreshold(private val offset: Dp) : ThresholdConfig {
+ override fun Density.computeThreshold(fromValue: Float, toValue: Float): Float {
+ return fromValue + offset.toPx() * sign(toValue - fromValue)
+ }
+}
/**
- * Constructor for fractional thresholds between anchors.
+ * A fractional threshold will be at a [fraction] of the way between the two anchors.
*
- * @param fraction Each threshold will be at this fraction of the way between the two anchors.
+ * @param fraction The fraction (between 0 and 1) that the threshold will be at.
*/
+@Immutable
@ExperimentalMaterialApi
-fun fractionalThresholds(
- @FloatRange(from = 0.0, to = 1.0) fraction: Float
-): SwipeableThresholds = { fromAnchor, toAnchor -> lerp(fromAnchor, toAnchor, fraction) }
+data class FractionalThreshold(
+ @FloatRange(from = 0.0, to = 1.0) private val fraction: Float
+) : ThresholdConfig {
+ override fun Density.computeThreshold(fromValue: Float, toValue: Float): Float {
+ return lerp(fromValue, toValue, fraction)
+ }
+}
@Stable
private class AnimatedFloatByState(
diff --git a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Switch.kt b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
index 94757fd..ad4db4b 100644
--- a/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
+++ b/ui/ui-material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
@@ -83,7 +83,7 @@
.swipeable(
state = swipeableState,
anchors = mapOf(minBound to false, maxBound to true),
- thresholds = fractionalThresholds(0.5f),
+ thresholds = { _, _ -> FractionalThreshold(0.5f) },
orientation = Orientation.Horizontal,
enabled = enabled,
reverseDirection = isRtl,