Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions example/src/commonMain/kotlin/UITest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import top.yukonga.miuix.kmp.icon.icons.useful.NavigatorSwitch
import top.yukonga.miuix.kmp.icon.icons.useful.Order
import top.yukonga.miuix.kmp.icon.icons.useful.Settings
import top.yukonga.miuix.kmp.theme.MiuixTheme
import top.yukonga.miuix.kmp.utils.WindowSize
import top.yukonga.miuix.kmp.utils.getWindowSize
import top.yukonga.miuix.kmp.utils.overScrollVertical
import top.yukonga.miuix.kmp.utils.scrollEndHaptic
Expand Down Expand Up @@ -229,7 +230,7 @@ private fun WideScreenLayout(
pagerState: PagerState,
topAppBarScrollBehaviorList: List<ScrollBehavior>,
currentScrollBehavior: ScrollBehavior,
windowSize: Any,
windowSize: WindowSize,
colorMode: MutableState<Int>
) {
val layoutDirection = LocalLayoutDirection.current
Expand Down Expand Up @@ -274,7 +275,7 @@ private fun WideScreenPanel(
onPageSelected: (Int) -> Unit,
barScrollBehavior: ScrollBehavior,
uiState: UIState,
windowSize: Any,
windowSize: WindowSize,
layoutDirection: LayoutDirection
) {
Scaffold(
Expand Down
2 changes: 1 addition & 1 deletion iosApp/iosApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0.4</string>
<key>CFBundleVersion</key>
<string>500</string>
<string>501</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>CADisableMinimumFrameDurationOnPhone</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fun Button(
content: @Composable RowScope.() -> Unit
) {
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
val color by rememberUpdatedState(if (enabled) colors.color else colors.disabledColor)
val color = if (enabled) colors.color else colors.disabledColor
Surface(
onClick = onClick,
enabled = enabled,
Expand Down Expand Up @@ -96,8 +96,8 @@ fun TextButton(
insideMargin: PaddingValues = ButtonDefaults.InsideMargin
) {
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
val color by rememberUpdatedState(if (enabled) colors.color else colors.disabledColor)
val textColor by rememberUpdatedState(if (enabled) colors.textColor else colors.disabledTextColor)
val color = if (enabled) colors.color else colors.disabledColor
val textColor = if (enabled) colors.textColor else colors.disabledTextColor
Surface(
onClick = onClick,
enabled = enabled,
Expand Down
18 changes: 9 additions & 9 deletions miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/Card.kt
Original file line number Diff line number Diff line change
Expand Up @@ -102,21 +102,21 @@ fun Card(
content: @Composable ColumnScope.() -> Unit,
) {
val interactionSource = remember { MutableInteractionSource() }
val currentOnClick by rememberUpdatedState(onClick)
val currentOnLongPress by rememberUpdatedState(onLongPress)

val pressFeedbackModifier = when (pressFeedbackType) {
PressFeedbackType.None -> Modifier
PressFeedbackType.Sink -> Modifier.pressSink(interactionSource)
PressFeedbackType.Tilt -> Modifier.pressTilt(interactionSource)
val pressFeedbackModifier = remember(pressFeedbackType, interactionSource) {
when (pressFeedbackType) {
PressFeedbackType.None -> Modifier
PressFeedbackType.Sink -> Modifier.pressSink(interactionSource)
PressFeedbackType.Tilt -> Modifier.pressTilt(interactionSource)
}
}

BasicCard(
modifier = modifier
.pointerInput(Unit) {
.pointerInput(onClick, onLongPress) {
detectTapGestures(
onTap = { currentOnClick?.invoke() },
onLongPress = { currentOnLongPress?.invoke() }
onTap = { onClick?.invoke() },
onLongPress = { onLongPress?.invoke() }
)
}
.pointerInput(interactionSource) {
Expand Down
27 changes: 12 additions & 15 deletions miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/Checkbox.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -65,46 +64,44 @@ fun Checkbox(
colors: CheckboxColors = CheckboxDefaults.checkboxColors(),
enabled: Boolean = true,
) {
val isChecked by rememberUpdatedState(checked)
val currentOnCheckedChange by rememberUpdatedState(onCheckedChange)

val hapticFeedback = LocalHapticFeedback.current

val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val isDragged by interactionSource.collectIsDraggedAsState()
val isHovered by interactionSource.collectIsHoveredAsState()

val springSpec = spring<Float>(
dampingRatio = Spring.DampingRatioLowBouncy,
stiffness = Spring.StiffnessMedium
)
val springSpec = remember {
spring<Float>(
dampingRatio = Spring.DampingRatioLowBouncy,
stiffness = Spring.StiffnessMedium
)
}

val size by animateFloatAsState(
targetValue = if (!enabled) 1f else if (isPressed || isDragged || isHovered) 0.95f else 1f,
animationSpec = springSpec
)

val backgroundColor by animateColorAsState(
targetValue = if (isChecked) colors.checkedBackgroundColor(enabled) else colors.uncheckedBackgroundColor(enabled),
targetValue = if (checked) colors.checkedBackgroundColor(enabled) else colors.uncheckedBackgroundColor(enabled),
animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing)
)

val foregroundColor by animateColorAsState(
targetValue = if (isChecked) colors.checkedForegroundColor(enabled) else colors.uncheckedForegroundColor(enabled),
targetValue = if (checked) colors.checkedForegroundColor(enabled) else colors.uncheckedForegroundColor(enabled),
animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing)
)

val checkmarkAnim = rememberCheckmarkAnimationState(isChecked)
val checkmarkAnim = rememberCheckmarkAnimationState(checked)

val finalModifier = if (onCheckedChange != null) {
Modifier.toggleable(
value = isChecked,
value = checked,
onValueChange = {
if (currentOnCheckedChange == null) return@toggleable
currentOnCheckedChange?.invoke(!isChecked)
onCheckedChange.invoke(!checked)
hapticFeedback.performHapticFeedback(
if (isChecked) HapticFeedbackType.ToggleOn else HapticFeedbackType.ToggleOff
if (checked) HapticFeedbackType.ToggleOn else HapticFeedbackType.ToggleOff
)
},
enabled = enabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ fun BasicComponent(
) {
@Suppress("NAME_SHADOWING")
val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
val indication = LocalIndication.current

val holdDown = remember { mutableStateOf<HoldDownInteraction.HoldDown?>(null) }
LaunchedEffect(holdDownState) {
Expand All @@ -76,19 +77,21 @@ fun BasicComponent(
}
}

val clickableModifier = remember(onClick, enabled, interactionSource) {
if (onClick != null && enabled) {
Modifier.clickable(
indication = indication,
interactionSource = interactionSource,
onClick = onClick
)
} else Modifier
}

SubcomposeLayout(
modifier = modifier
.heightIn(min = 56.dp)
.fillMaxWidth()
.then(
if (onClick != null && enabled) {
Modifier.clickable(
indication = LocalIndication.current,
interactionSource = interactionSource,
onClick = { onClick.invoke() }
)
} else Modifier
)
.then(clickableModifier)
.padding(insideMargin)
) { constraints ->
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ fun IconButton(
minWidth: Dp = IconButtonDefaults.MinWidth,
content: @Composable () -> Unit
) {
val currentOnClick by rememberUpdatedState(onClick)
val shape = remember(cornerRadius) { SmoothRoundedCornerShape(cornerRadius) }
val interactionSource = remember { MutableInteractionSource() }
val holdDown = remember { mutableStateOf<HoldDownInteraction.HoldDown?>(null) }
Expand Down Expand Up @@ -81,7 +80,7 @@ fun IconButton(
role = Role.Button,
indication = LocalIndication.current,
interactionSource = interactionSource,
onClick = currentOnClick
onClick = onClick
),
contentAlignment = Alignment.Center
) {
Expand Down
134 changes: 69 additions & 65 deletions miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/ListPopup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import top.yukonga.miuix.kmp.theme.MiuixTheme
import top.yukonga.miuix.kmp.utils.BackHandler
import top.yukonga.miuix.kmp.utils.MiuixPopupUtils.Companion.PopupLayout
import top.yukonga.miuix.kmp.utils.SmoothRoundedCornerShape
import top.yukonga.miuix.kmp.utils.WindowSize
import top.yukonga.miuix.kmp.utils.getWindowSize
import kotlin.math.min

Expand Down Expand Up @@ -76,9 +75,6 @@ fun ListPopup(
) {
if (!show.value) return

val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current

val windowSize by rememberUpdatedState(getWindowSize())
var parentBounds by remember { mutableStateOf(IntRect.Zero) }

Expand All @@ -96,8 +92,16 @@ fun ListPopup(
}
}
) { _, _ -> layout(0, 0) {} }
if (parentBounds == IntRect.Zero) return

val popupMargin = remember {
val density = LocalDensity.current
val layoutDirection = LocalLayoutDirection.current
val displayCutout = WindowInsets.displayCutout.asPaddingValues()
val statusBars = WindowInsets.statusBars.asPaddingValues()
val navigationBars = WindowInsets.navigationBars.asPaddingValues()
val captionBar = WindowInsets.captionBar.asPaddingValues()

val popupMargin = remember(windowSize, density) {
with(density) {
IntRect(
left = popupPositionProvider.getMargins().calculateLeftPadding(layoutDirection).roundToPx(),
Expand All @@ -108,17 +112,19 @@ fun ListPopup(
}
}

val windowBounds = with(density) {
IntRect(
left = WindowInsets.displayCutout.asPaddingValues().calculateLeftPadding(layoutDirection).roundToPx(),
top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding().roundToPx(),
right = windowSize.width - WindowInsets.displayCutout.asPaddingValues().calculateRightPadding(layoutDirection).roundToPx(),
bottom = windowSize.height - WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
.roundToPx() - WindowInsets.captionBar.asPaddingValues().calculateBottomPadding().roundToPx()
)
val windowBounds = remember(windowSize, density) {
with(density) {
IntRect(
left = displayCutout.calculateLeftPadding(layoutDirection).roundToPx(),
top = statusBars.calculateTopPadding().roundToPx(),
right = windowSize.width - displayCutout.calculateRightPadding(layoutDirection).roundToPx(),
bottom = windowSize.height - navigationBars.calculateBottomPadding()
.roundToPx() - captionBar.calculateBottomPadding().roundToPx()
)
}
}

val transformOrigin = remember(parentBounds, popupMargin, windowSize, alignment, density) {
val transformOrigin = remember(windowSize, alignment, density) {
val xInWindow = when (alignment) {
PopupPositionProvider.Align.Right,
PopupPositionProvider.Align.TopRight,
Expand All @@ -133,63 +139,61 @@ fun ListPopup(
)
}

if (parentBounds != IntRect.Zero && windowSize != WindowSize(0, 0)) {
PopupLayout(
visible = show,
enableWindowDim = enableWindowDim,
transformOrigin = { transformOrigin },
) {
val shape = remember { SmoothRoundedCornerShape(16.dp) }
val elevationPx = with(density) { shadowElevation.toPx() }
PopupLayout(
visible = show,
enableWindowDim = enableWindowDim,
transformOrigin = { transformOrigin },
) {
val shape = remember { SmoothRoundedCornerShape(16.dp) }
val elevationPx = with(density) { shadowElevation.toPx() }

Box(
modifier = popupModifier
.pointerInput(onDismissRequest) {
detectTapGestures(
onTap = { onDismissRequest?.invoke() }
)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
constraints.copy(
minWidth = if (minWidth.roundToPx() <= windowSize.width) minWidth.roundToPx() else windowSize.width,
minHeight = if (50.dp.roundToPx() <= windowSize.height) 50.dp.roundToPx() else windowSize.height,
maxHeight = maxHeight?.roundToPx()?.coerceAtLeast(50.dp.roundToPx())
?: (windowBounds.height - popupMargin.top - popupMargin.bottom).coerceAtLeast(
50.dp.roundToPx()
),
maxWidth = if (minWidth.roundToPx() <= windowSize.width) windowSize.width else minWidth.roundToPx()
)
Box(
modifier = popupModifier
.pointerInput(onDismissRequest) {
detectTapGestures(
onTap = { onDismissRequest?.invoke() }
)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
constraints.copy(
minWidth = if (minWidth.roundToPx() <= windowSize.width) minWidth.roundToPx() else windowSize.width,
minHeight = if (50.dp.roundToPx() <= windowSize.height) 50.dp.roundToPx() else windowSize.height,
maxHeight = maxHeight?.roundToPx()?.coerceAtLeast(50.dp.roundToPx())
?: (windowBounds.height - popupMargin.top - popupMargin.bottom).coerceAtLeast(
50.dp.roundToPx()
),
maxWidth = if (minWidth.roundToPx() <= windowSize.width) windowSize.width else minWidth.roundToPx()
)
val measuredSize = IntSize(placeable.width, placeable.height)
)
val measuredSize = IntSize(placeable.width, placeable.height)

val calculatedOffset = popupPositionProvider.calculatePosition(
parentBounds,
windowBounds,
layoutDirection,
measuredSize,
popupMargin,
alignment
)
val calculatedOffset = popupPositionProvider.calculatePosition(
parentBounds,
windowBounds,
layoutDirection,
measuredSize,
popupMargin,
alignment
)

layout(constraints.maxWidth, constraints.maxHeight) {
placeable.place(calculatedOffset)
}
layout(constraints.maxWidth, constraints.maxHeight) {
placeable.place(calculatedOffset)
}
) {
Box(
modifier = Modifier
.graphicsLayer(
clip = true,
shape = shape,
shadowElevation = elevationPx,
ambientShadowColor = MiuixTheme.colorScheme.windowDimming,
spotShadowColor = MiuixTheme.colorScheme.windowDimming
)
.background(MiuixTheme.colorScheme.surface)
) {
content()
}
) {
Box(
modifier = Modifier
.graphicsLayer(
clip = true,
shape = shape,
shadowElevation = elevationPx,
ambientShadowColor = MiuixTheme.colorScheme.windowDimming,
spotShadowColor = MiuixTheme.colorScheme.windowDimming
)
.background(MiuixTheme.colorScheme.surface)
) {
content()
}
}
}
Expand Down
Loading
Loading