FocusState.kt 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. @file:Suppress("unused")
  2. package org.mjdev.desktop.extensions
  3. import androidx.compose.foundation.ExperimentalFoundationApi
  4. import androidx.compose.foundation.gestures.detectTapGestures
  5. import androidx.compose.foundation.relocation.BringIntoViewResponder
  6. import androidx.compose.foundation.relocation.bringIntoViewResponder
  7. import androidx.compose.runtime.Composable
  8. import androidx.compose.runtime.MutableState
  9. import androidx.compose.runtime.mutableStateOf
  10. import androidx.compose.runtime.remember
  11. import androidx.compose.runtime.rememberCoroutineScope
  12. import androidx.compose.ui.Modifier
  13. import androidx.compose.ui.composed
  14. import androidx.compose.ui.focus.FocusRequester
  15. import androidx.compose.ui.focus.FocusState
  16. import androidx.compose.ui.focus.focusRequester
  17. import androidx.compose.ui.focus.onFocusChanged
  18. import androidx.compose.ui.geometry.Offset
  19. import androidx.compose.ui.geometry.Rect
  20. import androidx.compose.ui.input.pointer.pointerInput
  21. import androidx.compose.ui.layout.onSizeChanged
  22. import androidx.compose.ui.platform.debugInspectorInfo
  23. import kotlinx.coroutines.CoroutineScope
  24. import kotlinx.coroutines.launch
  25. import org.mjdev.desktop.helpers.compose.FocusHelper
  26. object FocusState {
  27. val MutableState<FocusState>.isFocused
  28. get() = value.isFocused || value.hasFocus
  29. val MutableState<FocusState>.isNotFocused
  30. get() = !isFocused
  31. @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
  32. val FocusState.isFocused
  33. get() = this.isFocused || this.hasFocus
  34. val FocusState.isNotFocused
  35. get() = !isFocused
  36. @Composable
  37. fun rememberFocusState(
  38. initial: FocusState = FocusHelper(false)
  39. ) = remember(initial) {
  40. mutableStateOf(initial)
  41. }
  42. @Composable
  43. fun rememberFocusState(
  44. key: Any?,
  45. initial: FocusState = FocusHelper(false),
  46. ) = remember(key) {
  47. mutableStateOf(initial)
  48. }
  49. fun Modifier.focusState(
  50. focusState: MutableState<FocusState>
  51. ): Modifier = onFocusChanged { state ->
  52. focusState.value = state
  53. }
  54. @Composable
  55. fun rememberFocusRequester(
  56. key: Any? = Unit
  57. ) = remember(key) { FocusRequester() }
  58. fun Modifier.bringIntoViewIfChildrenAreFocused(): Modifier = composed(
  59. inspectorInfo = debugInspectorInfo { name = "bringIntoViewIfChildrenAreFocused" },
  60. factory = {
  61. var myRect: Rect = Rect.Zero
  62. this.onSizeChanged {
  63. myRect = Rect(Offset.Zero, Offset(it.width.toFloat(), it.height.toFloat()))
  64. }.bringIntoViewResponder(
  65. remember {
  66. object : BringIntoViewResponder {
  67. @ExperimentalFoundationApi
  68. override fun calculateRectForParent(localRect: Rect): Rect = myRect
  69. @ExperimentalFoundationApi
  70. override suspend fun bringChildIntoView(localRect: () -> Rect?) {
  71. }
  72. }
  73. }
  74. )
  75. }
  76. )
  77. @Suppress("SuspiciousModifierThen")
  78. @Composable
  79. fun Modifier.requestFocusOnTouch(
  80. focusRequester: FocusRequester,
  81. requestFocus: Boolean = true,
  82. scope: CoroutineScope = rememberCoroutineScope(),
  83. onTouch: (() -> Unit)? = null
  84. ): Modifier = this then focusRequester(
  85. focusRequester
  86. ).pointerInput(this) {
  87. detectTapGestures(
  88. onTap = {
  89. try {
  90. scope.launch {
  91. onTouch?.invoke()
  92. if (requestFocus) {
  93. focusRequester.requestFocus()
  94. }
  95. }
  96. } catch (e: Throwable) {
  97. // todo
  98. // Log.e(e)
  99. }
  100. }
  101. )
  102. }
  103. }