From 409831636dfccd509ac11fe6d1c92fcfc763c4e6 Mon Sep 17 00:00:00 2001 From: Saad Nadeem Date: Sat, 29 Aug 2026 02:18:21 -0400 Subject: [PATCH] fix(ui): reopen smoothly during close animation --- .../ui/compose/impls/HudEditorUIScreen.kt | 20 +++++++++---- .../ui/compose/impls/OneConfigUIScreen.kt | 30 +++++++++++++++---- .../internal/ui/OneConfigInterface.kt | 3 ++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/HudEditorUIScreen.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/HudEditorUIScreen.kt index fbd1f7a33..9ddbc01cc 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/HudEditorUIScreen.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/HudEditorUIScreen.kt @@ -45,9 +45,18 @@ class HudEditorUIScreen : ComposeScreen() { UiSounds.play(UiSoundEvent.CLOSE) } + private fun cancelClose(): Boolean { + if (!closeRequested) return false + closeRequested = false + requestOpenCallback?.invoke() + UiSounds.play(UiSoundEvent.OPEN) + return true + } + @Volatile private var returningToOneConfig = false private var requestCloseCallback: (() -> Unit)? = null + private var requestOpenCallback: (() -> Unit)? = null override val scrollSpeed: Float get() = 0.5f @@ -79,12 +88,11 @@ class HudEditorUIScreen : ComposeScreen() { } val toggleKey = OneConfigConfig.oneConfigKeybind.keyCodes?.firstOrNull() if (toggleKey != null && key == toggleKey && !KeybindRecordingBus.isRecording) { + if (closeRequested) return cancelClose() if (OneConfigConfig.keybindClosesGui) { - if (!closeRequested) { - OneConfigConfig.notifyKeybindClosedGui() - beginClose() - requestCloseCallback?.invoke() - } + OneConfigConfig.notifyKeybindClosedGui() + beginClose() + requestCloseCallback?.invoke() } else { returningToOneConfig = true Platform.screen().display(OneConfigUIScreen()) @@ -131,8 +139,10 @@ class HudEditorUIScreen : ComposeScreen() { LaunchedEffect(Unit) { visible = true } val requestClose: () -> Unit = { visible = false } + val requestOpen: () -> Unit = { visible = true } SideEffect { requestCloseCallback = requestClose + requestOpenCallback = requestOpen } val exitMs = guiCloseAnimationMillis().toInt() diff --git a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt index 0085d39a8..59d06f9de 100644 --- a/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt +++ b/minecraft/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/compose/impls/OneConfigUIScreen.kt @@ -94,10 +94,24 @@ class OneConfigUIScreen @JvmOverloads constructor( closeRequested = true closeRequestedAt = System.currentTimeMillis() closeAnimationMs = guiCloseAnimationMillis() - markClosed() UiSounds.play(UiSoundEvent.CLOSE) } + private fun cancelClose(): Boolean { + if (!closeRequested) return false + + // Resume the opening blur animation from current blur intensity + val now = System.currentTimeMillis() + val blurProgress = if (closeAnimationMs <= 0L) 0f + else 1f - easeOutExpo((now - closeRequestedAt).toFloat() / closeAnimationMs) + openedAt = now - (blurProgress.coerceIn(0f, 1f) * OPEN_ANIMATION_MS).toLong() + + closeRequested = false + requestOpenCallback?.invoke() + UiSounds.play(UiSoundEvent.OPEN) + return true + } + /** The page this screen is showing which survives the scene being disposed and rebuilt */ private var route: Any? = null @@ -225,12 +239,11 @@ class OneConfigUIScreen @JvmOverloads constructor( } val toggleKey = OneConfigConfig.oneConfigKeybind.keyCodes?.firstOrNull() if (toggleKey != null && key == toggleKey && !KeybindRecordingBus.isRecording) { + if (closeRequested) return cancelClose() if (OneConfigConfig.keybindClosesGui) { - if (!closeRequested) { - OneConfigConfig.notifyKeybindClosedGui() - beginClose() - requestCloseCallback?.invoke() - } + OneConfigConfig.notifyKeybindClosedGui() + beginClose() + requestCloseCallback?.invoke() } else { HudManager.openEditor() } @@ -264,6 +277,7 @@ class OneConfigUIScreen @JvmOverloads constructor( // and that would queue a fullscreen blur which smears over the popup so bail unless we are current if (Platform.screen().current() !== this) return if (closeRequested && System.currentTimeMillis() - closeRequestedAt >= closeAnimationMs) { + markClosed() //? if < 1.21.8 //renderBackground(ctx, mouseX, mouseY, tickDelta) Platform.screen().close() @@ -321,6 +335,7 @@ class OneConfigUIScreen @JvmOverloads constructor( /** Holds a reference to the close-animation trigger from Compose */ private var requestCloseCallback: (() -> Unit)? = null + private var requestOpenCallback: (() -> Unit)? = null @Composable override fun compose() { @@ -337,6 +352,9 @@ class OneConfigUIScreen @JvmOverloads constructor( onCloseReady = { closeRequest -> requestCloseCallback = closeRequest }, + onOpenReady = { openRequest -> + requestOpenCallback = openRequest + }, ) { } } } diff --git a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigInterface.kt b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigInterface.kt index 21f118acc..1edd13195 100644 --- a/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigInterface.kt +++ b/modules/internal/src/main/kotlin/org/polyfrost/oneconfig/internal/ui/OneConfigInterface.kt @@ -75,6 +75,7 @@ fun OneConfigInterface( restoring: Boolean = false, onCloseRequest: () -> Unit = {}, onCloseReady: ((requestClose: () -> Unit) -> Unit)? = null, + onOpenReady: ((requestOpen: () -> Unit) -> Unit)? = null, shellBackdrop: DrawScope.(Offset) -> Unit = {} ) { ThemeRegistry.init() @@ -139,9 +140,11 @@ fun OneConfigInterface( } val requestClose: () -> Unit = { visible = false } + val requestOpen: () -> Unit = { visible = true } SideEffect { onCloseReady?.invoke(requestClose) + onOpenReady?.invoke(requestOpen) } CompositionLocalProvider(LocalCloseRequest provides requestClose) {