Add meal plan editor + smaller changes
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
@file:OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
|
||||
|
||||
package dev.ulfrx.recipe.ui.keyboard
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.cinterop.DoubleVar
|
||||
import kotlinx.cinterop.allocArray
|
||||
import kotlinx.cinterop.get
|
||||
import kotlinx.cinterop.memScoped
|
||||
import kotlinx.cinterop.sizeOf
|
||||
import kotlinx.cinterop.useContents
|
||||
import platform.CoreGraphics.CGRect
|
||||
import platform.Foundation.NSNotificationCenter
|
||||
import platform.Foundation.NSNumber
|
||||
import platform.Foundation.NSOperationQueue
|
||||
import platform.Foundation.NSValue
|
||||
import platform.UIKit.UIKeyboardAnimationDurationUserInfoKey
|
||||
import platform.UIKit.UIKeyboardFrameEndUserInfoKey
|
||||
import platform.UIKit.UIKeyboardWillChangeFrameNotification
|
||||
import platform.UIKit.UIScreen
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
internal actual fun rememberKeyboardTransitionState(): KeyboardTransitionState {
|
||||
val currentInset = WindowInsets.ime.asPaddingValues().calculateBottomPadding()
|
||||
var targetInset by remember { mutableStateOf(0.dp) }
|
||||
var animationDurationMillis by remember { mutableStateOf(IosDefaultKeyboardAnimationDurationMillis) }
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
val observer =
|
||||
NSNotificationCenter.defaultCenter.addObserverForName(
|
||||
name = UIKeyboardWillChangeFrameNotification,
|
||||
`object` = null,
|
||||
queue = NSOperationQueue.mainQueue,
|
||||
usingBlock = { notification ->
|
||||
val userInfo = notification?.userInfo ?: return@addObserverForName
|
||||
val frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue
|
||||
?: return@addObserverForName
|
||||
val durationValue = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber
|
||||
|
||||
val screenHeight =
|
||||
UIScreen.mainScreen.bounds.useContents {
|
||||
size.height
|
||||
}
|
||||
val keyboardTop =
|
||||
memScoped {
|
||||
// iOS app targets are arm64; CGRect is x, y, width, height
|
||||
// as CGFloat/Double fields.
|
||||
val keyboardFrame = allocArray<DoubleVar>(CGRectDoubleFieldCount)
|
||||
frameValue.getValue(
|
||||
value = keyboardFrame,
|
||||
size = sizeOf<CGRect>().toULong(),
|
||||
)
|
||||
keyboardFrame[CGRectOriginYFieldIndex]
|
||||
}
|
||||
val targetHeight = (screenHeight - keyboardTop).coerceAtLeast(0.0)
|
||||
|
||||
targetInset = targetHeight.toFloat().dp
|
||||
animationDurationMillis =
|
||||
durationValue?.doubleValue
|
||||
?.times(MillisPerSecond)
|
||||
?.roundToInt()
|
||||
?.takeIf { it > 0 }
|
||||
?: IosDefaultKeyboardAnimationDurationMillis
|
||||
},
|
||||
)
|
||||
|
||||
onDispose {
|
||||
NSNotificationCenter.defaultCenter.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
|
||||
return KeyboardTransitionState(
|
||||
currentInset = currentInset,
|
||||
targetInset = targetInset,
|
||||
animationDurationMillis = animationDurationMillis,
|
||||
)
|
||||
}
|
||||
|
||||
private const val IosDefaultKeyboardAnimationDurationMillis = 250
|
||||
private const val MillisPerSecond = 1_000.0
|
||||
private const val CGRectDoubleFieldCount = 4
|
||||
private const val CGRectOriginYFieldIndex = 1
|
||||
Reference in New Issue
Block a user