Separate some compose UI components to make things more understandable

This commit is contained in:
Aleksandras Kostarevas 2024-09-27 20:20:18 +03:00
parent 2e2bba2ac2
commit 112b7a291a

View File

@ -4,6 +4,7 @@ import android.app.Activity
import android.content.ClipDescription import android.content.ClipDescription
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Rect
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.VibrationEffect import android.os.VibrationEffect
@ -57,12 +58,14 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
@ -107,6 +110,7 @@ import org.futo.inputmethod.updates.deferManualUpdate
import org.futo.inputmethod.updates.isManualUpdateTimeExpired import org.futo.inputmethod.updates.isManualUpdateTimeExpired
import org.futo.inputmethod.updates.openManualUpdateCheck import org.futo.inputmethod.updates.openManualUpdateCheck
import org.futo.inputmethod.updates.retrieveSavedLastUpdateCheckResult import org.futo.inputmethod.updates.retrieveSavedLastUpdateCheckResult
import org.futo.inputmethod.v2keyboard.ComputedKeyboardSize
import org.futo.inputmethod.v2keyboard.FloatingKeyboardSize import org.futo.inputmethod.v2keyboard.FloatingKeyboardSize
import org.futo.inputmethod.v2keyboard.KeyboardSizingCalculator import org.futo.inputmethod.v2keyboard.KeyboardSizingCalculator
import org.futo.inputmethod.v2keyboard.OneHandedDirection import org.futo.inputmethod.v2keyboard.OneHandedDirection
@ -659,165 +663,218 @@ class UixManager(private val latinIME: LatinIME) {
} }
@Composable @Composable
fun SizePositionerSurface(content: @Composable BoxScope.(actionBarGap: Dp) -> Unit) { private fun OffsetPositioner(offset: Offset, content: @Composable () -> Unit) {
Column(modifier = Modifier.fillMaxHeight().absoluteOffset { IntOffset(offset.x.toInt(), 0) }) {
Spacer(Modifier.weight(1.0f))
content()
Spacer(Modifier.height(with(LocalDensity.current) { offset.y.toDp() }))
}
}
@Composable
private fun KeyboardSurface(
requiredWidthPx: Int,
backgroundColor: Color,
modifier: Modifier = Modifier,
shape: Shape = RectangleShape,
padding: Rect = Rect(),
content: @Composable BoxScope.() -> Unit
) = with(LocalDensity.current) {
Box(modifier
.onSizeChanged { measuredTouchableHeight = it.height}
.background(backgroundColor, shape)
.requiredWidth(requiredWidthPx.toDp())
.absolutePadding(
left = padding.left.toDp(),
top = padding.top.toDp(),
right = padding.right.toDp(),
bottom = padding.bottom.toDp(),
)
.clipToBounds()
) {
CompositionLocalProvider(LocalContentColor provides contentColorFor(backgroundColor)) {
content()
}
}
}
@Composable
private fun FloatingKeyboardContents(
pointerInputKey: Any?,
onDragged: (Offset) -> Unit,
onDragEnd: () -> Unit,
content: @Composable BoxScope.(actionBarGap: Dp) -> Unit
) {
// Content
Box(Modifier.fillMaxWidth()) {
content(4.dp)
}
// Bottom drag bar
Spacer(modifier = Modifier.height(24.dp))
Box(modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.pointerInput(pointerInputKey) {
detectDragGestures(
onDrag = { _, dragAmount -> onDragged(dragAmount)},
onDragEnd = { onDragEnd() })
}) {
Box(
modifier = Modifier.fillMaxWidth(0.6f).height(4.dp)
.align(Alignment.TopCenter).background(
MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f),
RoundedCornerShape(100)
)
)
}
}
@Composable
private fun FloatingKeyboardWindow(
size: FloatingKeyboardSize,
content: @Composable BoxScope.(actionBarGap: Dp) -> Unit
) = with(LocalDensity.current) {
val offset = remember(size) { mutableStateOf(Offset(size.bottomOrigin.first.toFloat(), size.bottomOrigin.second.toFloat())) }
OffsetPositioner(offset.value) {
KeyboardSurface(
requiredWidthPx = size.width,
backgroundColor = latinIME.keyboardColor,
shape = RoundedCornerShape(16.dp),
padding = size.decorationPadding
) {
Column {
FloatingKeyboardContents(
pointerInputKey = size,
onDragged = { dragAmount ->
var newOffset = offset.value.copy(
x = offset.value.x + dragAmount.x,
y = offset.value.y - dragAmount.y
)
// Ensure we are not out of bounds
newOffset = newOffset.copy(
newOffset.x.coerceAtLeast(0.0f),
newOffset.y.coerceAtLeast(0.0f)
)
newOffset = newOffset.copy(
newOffset.x.coerceAtMost(
latinIME.getViewWidth().toFloat() - size.width
),
newOffset.y.coerceAtMost(
latinIME.getViewHeight().toFloat() - measuredTouchableHeight
)
)
offset.value = newOffset
},
onDragEnd = {
latinIME.sizingCalculator.editSavedSettings { settings ->
settings.copy(
floatingBottomOriginDp = Pair(
offset.value.x.toDp().value,
offset.value.y.toDp().value
)
)
}
},
content = content
)
}
}
}
}
@Composable
private fun NonFloatingKeyboardWindow(
size: ComputedKeyboardSize,
content: @Composable BoxScope.(actionBarGap: Dp) -> Unit
) = with(LocalDensity.current) {
OffsetPositioner(Offset(0.0f, 0.0f)) {
KeyboardSurface(
requiredWidthPx = size.getWidth(),
backgroundColor = latinIME.keyboardColor,
padding = size.getPadding()
) {
val actionBarGap = 4.dp
when(size) {
is OneHandedKeyboardSize -> {
Box(modifier = Modifier.width(size.layoutWidth.toDp()).align(
when(size.direction) {
OneHandedDirection.Left -> Alignment.CenterStart
OneHandedDirection.Right -> Alignment.CenterEnd
}
)) {
content(actionBarGap)
}
}
else -> {
content(actionBarGap)
}
}
}
}
}
@Composable
fun KeyboardWindowSelector(content: @Composable BoxScope.(actionBarGap: Dp) -> Unit) {
val size = latinIME.size.value val size = latinIME.size.value
when(size) { when(size) {
is FloatingKeyboardSize -> { is FloatingKeyboardSize -> FloatingKeyboardWindow(size, content)
val offset = remember(size) { mutableStateOf(Offset(size.bottomOrigin.first.toFloat(), size.bottomOrigin.second.toFloat())) }
val configuration = LocalConfiguration.current
with(LocalDensity.current) {
Column(modifier = Modifier.fillMaxHeight().absoluteOffset { IntOffset(offset.value.x.toInt(), 0) }) {
Spacer(Modifier.weight(1.0f))
Column(Modifier
.background(latinIME.keyboardColor, RoundedCornerShape(8.dp))
.requiredWidth(size.width.toDp())
.onSizeChanged {
measuredTouchableHeight = it.height
}
.absolutePadding(
left = size.decorationPadding.left.toDp(),
top = 0.dp,
right = size.decorationPadding.right.toDp(),
bottom = 0.dp,
)
) {
Box(Modifier.fillMaxWidth()) {
CompositionLocalProvider(
LocalContentColor provides contentColorFor(
latinIME.keyboardColor
)
) {
content(4.dp)
}
}
Spacer(modifier = Modifier.height(24.dp))
Box(modifier = Modifier
.fillMaxWidth()
.height(20.dp)
.pointerInput(size) {
detectDragGestures(onDrag = { change, dragAmount ->
var newOffset = offset.value.copy(
x = offset.value.x + dragAmount.x,
y = offset.value.y - dragAmount.y
)
// Ensure we are not out of bounds
newOffset = newOffset.copy(
newOffset.x.coerceAtLeast(0.0f),
newOffset.y.coerceAtLeast(0.0f)
)
newOffset = newOffset.copy(
newOffset.x.coerceAtMost(latinIME.getViewWidth().toFloat() - size.width),
newOffset.y.coerceAtMost(latinIME.getViewHeight().toFloat() - measuredTouchableHeight)
)
offset.value = newOffset
}, onDragEnd = {
latinIME.sizingCalculator.editSavedSettings { settings ->
settings.copy(
floatingBottomOriginDp = Pair(
offset.value.x.toDp().value,
offset.value.y.toDp().value
)
)
}
})
}) {
Box(modifier = Modifier.fillMaxWidth(0.6f).height(4.dp).align(Alignment.TopCenter).background(
MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), RoundedCornerShape(100)
))
}
}
Spacer(Modifier.height(offset.value.y.toDp()))
}
}
}
is OneHandedKeyboardSize, is OneHandedKeyboardSize,
is RegularKeyboardSize, is RegularKeyboardSize,
is SplitKeyboardSize -> { is SplitKeyboardSize -> NonFloatingKeyboardWindow(size, content)
Column {
Spacer(modifier = Modifier.weight(1.0f))
Surface(modifier = Modifier.onSizeChanged {
measuredTouchableHeight = it.height
}, color = latinIME.keyboardColor) {
with(LocalDensity.current) {
val actionBarGap = (size.getPadding().top / 2).toDp()
Box(Modifier.absolutePadding(
left = size.getPadding().left.toDp(),
top = actionBarGap,
right = size.getPadding().right.toDp(),
bottom = size.getPadding().bottom.toDp(),
).width(
(size.getWidth() - size.getPadding().left - size.getPadding().right).toDp()
)) {
when(size) {
is OneHandedKeyboardSize -> {
Box(modifier = Modifier.width(size.layoutWidth.toDp()).align(
when(size.direction) {
OneHandedDirection.Left -> Alignment.CenterStart
OneHandedDirection.Right -> Alignment.CenterEnd
}
)) {
content(actionBarGap)
}
}
is RegularKeyboardSize -> {
content(actionBarGap)
}
is SplitKeyboardSize -> {
content(actionBarGap)
}
else -> throw IllegalStateException()
}
}
null -> return
}
}
@Composable
private fun ProvidersAndWrapper(content: @Composable () -> Unit) {
UixThemeWrapper(latinIME.colorScheme) {
DataStoreCacheProvider {
CompositionLocalProvider(LocalManager provides keyboardManagerForAction) {
CompositionLocalProvider(LocalThemeProvider provides latinIME.getDrawableProvider()) {
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
CompositionLocalProvider(LocalFoldingState provides foldingOptions.value) {
content()
}
} }
} }
} }
} }
null -> return
} }
} }
fun setContent() { fun setContent() {
composeView?.setContent { composeView?.setContent {
UixThemeWrapper(latinIME.colorScheme) { ProvidersAndWrapper {
DataStoreCacheProvider { InputDarkener(isInputOverridden.value || isShowingActionEditor.value) {
CompositionLocalProvider(LocalManager provides keyboardManagerForAction) { closeActionWindow()
CompositionLocalProvider(LocalThemeProvider provides latinIME.getDrawableProvider()) { isShowingActionEditor.value = false
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
CompositionLocalProvider(LocalFoldingState provides foldingOptions.value) {
InputDarkener(isInputOverridden.value || isShowingActionEditor.value) {
closeActionWindow()
isShowingActionEditor.value = false
}
SizePositionerSurface { gap ->
Column {
when {
currWindowActionWindow != null -> ActionViewWithHeader(
currWindowActionWindow!!
)
else -> MainKeyboardViewWithActionBar()
}
Spacer(modifier = Modifier.height(gap))
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
}
ForgetWordDialog()
}
ActionEditorHost()
}
}
}
}
} }
KeyboardWindowSelector { gap ->
Column {
when {
currWindowActionWindow != null -> ActionViewWithHeader(
currWindowActionWindow!!
)
else -> MainKeyboardViewWithActionBar()
}
Spacer(modifier = Modifier.height(gap))
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
}
ForgetWordDialog()
}
ActionEditorHost()
} }
} }
} }