Skip to content

Commit 958ad9c

Browse files
committed
library: Support multiple pop-up windows to dim layer by layer
1 parent 9b08f38 commit 958ad9c

File tree

1 file changed

+56
-38
lines changed

1 file changed

+56
-38
lines changed

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/utils/MiuixPopupUtils.kt

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,23 @@ class MiuixPopupUtils {
4343
private data class PopupState(
4444
val content: @Composable () -> Unit,
4545
val transformOrigin: () -> TransformOrigin,
46-
val windowDimming: Boolean
46+
val windowDimming: Boolean,
47+
val zIndex: Float
4748
)
4849

4950
@Immutable
5051
private data class DialogState(
51-
val content: @Composable () -> Unit
52+
val content: @Composable () -> Unit,
53+
val zIndex: Float
5254
)
5355

5456
companion object {
5557
private val popupStates = mutableStateMapOf<MutableState<Boolean>, PopupState>()
5658
private val dialogStates = mutableStateMapOf<MutableState<Boolean>, DialogState>()
59+
private var nextZIndex = 1f
5760

5861
private val isAnyPopupShowing by derivedStateOf { popupStates.keys.any { it.value } }
5962
private val isAnyDialogShowing by derivedStateOf { dialogStates.keys.any { it.value } }
60-
private val isWindowDimmingNeeded by derivedStateOf {
61-
popupStates.entries.any { it.key.value && it.value.windowDimming }
62-
}
6363

6464
/**
6565
* Show a dialog.
@@ -75,7 +75,12 @@ class MiuixPopupUtils {
7575
dismissDialog(show)
7676
return
7777
}
78-
dialogStates[show] = DialogState(content)
78+
val currentZIndex = if (!show.value) {
79+
nextZIndex++
80+
} else {
81+
dialogStates[show]?.zIndex ?: nextZIndex++
82+
}
83+
dialogStates[show] = DialogState(content, currentZIndex)
7984
if (!show.value) show.value = true
8085
}
8186

@@ -110,7 +115,12 @@ class MiuixPopupUtils {
110115
dismissPopup(show)
111116
return
112117
}
113-
popupStates[show] = PopupState(content, transformOrigin, windowDimming)
118+
val currentZIndex = if (!show.value) {
119+
nextZIndex++
120+
} else {
121+
popupStates[show]?.zIndex ?: nextZIndex++
122+
}
123+
popupStates[show] = PopupState(content, transformOrigin, windowDimming, currentZIndex)
114124
if (!show.value) show.value = true
115125
}
116126

@@ -152,21 +162,6 @@ class MiuixPopupUtils {
152162
}
153163
}
154164

155-
// Dimming Layer (zIndex 1f)
156-
AnimatedVisibility(
157-
visible = isAnyDialogShowing || isWindowDimmingNeeded,
158-
modifier = Modifier.zIndex(1f).fillMaxSize(),
159-
enter = fadeIn(animationSpec = tween(dimEnterDuration, easing = DecelerateEasing(1.5f))),
160-
exit = fadeOut(animationSpec = tween(dimExitDuration, easing = DecelerateEasing(1.5f)))
161-
) {
162-
Box(
163-
modifier = Modifier
164-
.fillMaxSize()
165-
.background(MiuixTheme.colorScheme.windowDimming)
166-
)
167-
}
168-
169-
// Dialogs Layer (zIndex 2f)
170165
dialogStates.entries.forEach { (showState, dialogState) ->
171166
key(showState) {
172167
var internalVisible by remember { mutableStateOf(false) }
@@ -175,9 +170,24 @@ class MiuixPopupUtils {
175170
internalVisible = showState.value
176171
}
177172

173+
// Dimming layer for the dialog
178174
AnimatedVisibility(
179175
visible = internalVisible,
180-
modifier = Modifier.zIndex(2f).fillMaxSize(),
176+
modifier = Modifier.zIndex(dialogState.zIndex).fillMaxSize(),
177+
enter = fadeIn(animationSpec = tween(dimEnterDuration, easing = DecelerateEasing(1.5f))),
178+
exit = fadeOut(animationSpec = tween(dimExitDuration, easing = DecelerateEasing(1.5f)))
179+
) {
180+
Box(
181+
modifier = Modifier
182+
.fillMaxSize()
183+
.background(MiuixTheme.colorScheme.windowDimming)
184+
)
185+
}
186+
187+
// Content layer for the dialog
188+
AnimatedVisibility(
189+
visible = internalVisible,
190+
modifier = Modifier.zIndex(dialogState.zIndex).fillMaxSize(),
181191
enter = if (largeScreen) {
182192
fadeIn(
183193
animationSpec = spring(0.9f, 900f)
@@ -210,19 +220,6 @@ class MiuixPopupUtils {
210220
) {
211221
dialogState.content()
212222
}
213-
val shouldDimForPopup = popupStates.entries.any { it.key.value && it.value.windowDimming }
214-
AnimatedVisibility(
215-
visible = shouldDimForPopup,
216-
modifier = Modifier.zIndex(1f).fillMaxSize(),
217-
enter = fadeIn(animationSpec = tween(150, easing = DecelerateEasing(1.5f))),
218-
exit = fadeOut(animationSpec = tween(150, easing = DecelerateEasing(1.5f)))
219-
) {
220-
Box(
221-
modifier = Modifier
222-
.fillMaxSize()
223-
.background(MiuixTheme.colorScheme.windowDimming.copy(alpha = 0.5f))
224-
)
225-
}
226223

227224
DisposableEffect(showState) {
228225
onDispose {
@@ -235,7 +232,6 @@ class MiuixPopupUtils {
235232
}
236233
}
237234

238-
// Popups Layer (zIndex 3f)
239235
popupStates.entries.forEach { (showState, popupState) ->
240236
key(showState) {
241237
var internalVisible by remember { mutableStateOf(false) }
@@ -244,9 +240,31 @@ class MiuixPopupUtils {
244240
internalVisible = showState.value
245241
}
246242

243+
// Dimming layer for the popup
244+
if (popupState.windowDimming) {
245+
AnimatedVisibility(
246+
visible = internalVisible,
247+
modifier = Modifier.zIndex(popupState.zIndex).fillMaxSize(),
248+
enter = fadeIn(
249+
animationSpec = tween(
250+
durationMillis = dimEnterDuration,
251+
easing = DecelerateEasing(1.5f)
252+
)
253+
),
254+
exit = fadeOut(animationSpec = tween(dimExitDuration, easing = DecelerateEasing(1.5f)))
255+
) {
256+
Box(
257+
modifier = Modifier
258+
.fillMaxSize()
259+
.background(MiuixTheme.colorScheme.windowDimming)
260+
)
261+
}
262+
}
263+
264+
// Content layer for the popup
247265
AnimatedVisibility(
248266
visible = internalVisible,
249-
modifier = Modifier.zIndex(3f).fillMaxSize(),
267+
modifier = Modifier.zIndex(popupState.zIndex).fillMaxSize(),
250268
enter = fadeIn(
251269
animationSpec = tween(150, easing = DecelerateEasing(1.5f))
252270
) + scaleIn(

0 commit comments

Comments
 (0)