Update inline suggestions

This commit is contained in:
Aleksandras Kostarevas 2024-05-27 18:32:01 +03:00
parent 4cc53b0efa
commit 562b08883b
4 changed files with 86 additions and 30 deletions

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#14000000">
<item android:shape="rectangle">
<shape>
<corners android:radius="32dp"/>
<stroke android:color="#99FFFFFF" android:width="2dp"/>
<solid android:color="#44FFFFFF"/>
</shape>
</item>
</ripple>

View File

@ -5,6 +5,8 @@ import android.os.Build
import android.view.View import android.view.View
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -425,7 +427,8 @@ fun LazyItemScope.ActionItem(idx: Int, action: Action, onSelect: (Action) -> Uni
if (!dragging.value) { if (!dragging.value) {
it.animateItemPlacement() it.animateItemPlacement()
} else { } else {
it.zIndex(10.0f) it
.zIndex(10.0f)
.graphicsLayer { .graphicsLayer {
clip = false clip = false
translationX = offsetX.floatValue translationX = offsetX.floatValue
@ -602,6 +605,12 @@ fun ActionBar(
} }
} }
LaunchedEffect(inlineSuggestions) {
if(inlineSuggestions.isNotEmpty()) {
isActionsOpen.value = false
}
}
Surface(modifier = Modifier Surface(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(40.dp), color = MaterialTheme.colorScheme.background) .height(40.dp), color = MaterialTheme.colorScheme.background)
@ -624,9 +633,13 @@ fun ActionBar(
} }
if(!isActionsOpen.value) { if(!isActionsOpen.value) {
if (inlineSuggestions.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AnimatedVisibility(inlineSuggestions.isNotEmpty(), enter = fadeIn(), exit = fadeOut()) {
InlineSuggestions(inlineSuggestions) InlineSuggestions(inlineSuggestions)
} else if (words != null) { }
}
if (words != null && inlineSuggestions.isEmpty()) {
SuggestionItems( SuggestionItems(
words, words,
onClick = { onClick = {
@ -700,7 +713,6 @@ fun CollapsibleSuggestionsBar(
onCollapse: () -> Unit, onCollapse: () -> Unit,
words: SuggestedWords?, words: SuggestedWords?,
suggestionStripListener: SuggestionStripView.Listener, suggestionStripListener: SuggestionStripView.Listener,
inlineSuggestions: List<MutableState<View?>>,
) { ) {
Surface(modifier = Modifier Surface(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -726,9 +738,7 @@ fun CollapsibleSuggestionsBar(
) )
} }
if(inlineSuggestions.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if(words != null) {
InlineSuggestions(inlineSuggestions)
} else if(words != null) {
SuggestionItems(words, onClick = { SuggestionItems(words, onClick = {
suggestionStripListener.pickSuggestionManually( suggestionStripListener.pickSuggestionManually(
words.getInfo(it) words.getInfo(it)
@ -879,8 +889,7 @@ fun PreviewCollapsibleBar(colorScheme: ColorScheme = DarkColorScheme) {
onCollapse = { }, onCollapse = { },
onClose = { }, onClose = { },
words = exampleSuggestedWords, words = exampleSuggestedWords,
suggestionStripListener = ExampleListener(), suggestionStripListener = ExampleListener()
inlineSuggestions = listOf()
) )
} }

View File

@ -2,8 +2,10 @@ package org.futo.inputmethod.latin.uix
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import android.util.Size import android.util.Size
import android.util.TypedValue
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InlineSuggestion import android.view.inputmethod.InlineSuggestion
@ -15,20 +17,35 @@ import androidx.autofill.inline.common.ImageViewStyle
import androidx.autofill.inline.common.TextViewStyle import androidx.autofill.inline.common.TextViewStyle
import androidx.autofill.inline.common.ViewStyle import androidx.autofill.inline.common.ViewStyle
import androidx.autofill.inline.v1.InlineSuggestionUi import androidx.autofill.inline.v1.InlineSuggestionUi
import androidx.compose.foundation.clipScrollableContainer
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.ColorScheme import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import org.futo.inputmethod.latin.R
import kotlin.math.roundToInt import kotlin.math.roundToInt
private const val maxSuggestions = 5
private const val minWidthDp = 32.0f
private const val minHeightDp = 8.0f
private const val maxHeightDp = 48.0f
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
fun createInlineSuggestionsRequest( fun createInlineSuggestionsRequest(
@ -39,17 +56,24 @@ fun createInlineSuggestionsRequest(
context.fromDp(v).roundToInt() context.fromDp(v).roundToInt()
} }
val drawable = R.drawable.inline_suggestion_chip
val bgColor = activeColorScheme.secondaryContainer.toArgb()
val stylesBuilder = UiVersions.newStylesBuilder() val stylesBuilder = UiVersions.newStylesBuilder()
val suggestionStyle = InlineSuggestionUi.newStyleBuilder() val suggestionStyle = InlineSuggestionUi.newStyleBuilder()
.setSingleIconChipStyle( .setSingleIconChipStyle(
ViewStyle.Builder() ViewStyle.Builder()
.setBackgroundColor(activeColorScheme.secondaryContainer.toArgb()) .setBackground(
Icon.createWithResource(context, drawable).setTint(bgColor)
)
.setPadding(0, 0, 0, 0) .setPadding(0, 0, 0, 0)
.build() .build()
) )
.setChipStyle( .setChipStyle(
ViewStyle.Builder() ViewStyle.Builder()
.setBackgroundColor(activeColorScheme.secondaryContainer.toArgb()) .setBackground(
Icon.createWithResource(context, drawable).setTint(bgColor)
)
.setPadding( .setPadding(
fromDp(8.0f), fromDp(8.0f),
fromDp(0.0f), fromDp(0.0f),
@ -93,13 +117,23 @@ fun createInlineSuggestionsRequest(
val stylesBundle = stylesBuilder.build() val stylesBundle = stylesBuilder.build()
val displayMetrics = context.resources.displayMetrics
val maxWidthPx = displayMetrics.widthPixels * 2 / 3
val spec = InlinePresentationSpec.Builder( val spec = InlinePresentationSpec.Builder(
Size(0, 0), Size(
Size(Int.MAX_VALUE, Int.MAX_VALUE) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, minWidthDp, displayMetrics).roundToInt(),
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, minHeightDp, displayMetrics).roundToInt()
),
Size(
maxWidthPx,
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, maxHeightDp, displayMetrics).roundToInt()
),
).setStyle(stylesBundle).build() ).setStyle(stylesBundle).build()
return InlineSuggestionsRequest.Builder(listOf(spec)).let { request -> return InlineSuggestionsRequest.Builder(List(maxSuggestions) { spec }).let { request ->
request.setMaxSuggestionCount(InlineSuggestionsRequest.SUGGESTION_COUNT_UNLIMITED) request.setMaxSuggestionCount(maxSuggestions)
request.build() request.build()
} }
} }
@ -126,24 +160,26 @@ fun Context.inflateInlineSuggestion(inlineSuggestion: InlineSuggestion): Mutable
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
@Composable @Composable
fun InlineSuggestionView(inlineSuggestion: MutableState<View?>) { fun InlineSuggestionView(inlineSuggestion: MutableState<View?>) {
key(inlineSuggestion.value) {
if (inlineSuggestion.value != null) { if (inlineSuggestion.value != null) {
// TODO: For some reason this appears over top of keyboard key previews
// We should also make it animate in and round corners
AndroidView( AndroidView(
factory = { inlineSuggestion.value!! }, factory = { inlineSuggestion.value!! },
modifier = Modifier.padding(4.dp, 0.dp) modifier = Modifier.padding(4.dp, 0.dp)
) )
} }
}
} }
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
@Composable @Composable
fun RowScope.InlineSuggestions(suggestions: List<MutableState<View?>>) { fun RowScope.InlineSuggestions(suggestions: List<MutableState<View?>>) {
LazyRow(modifier = Modifier val scrollState = rememberScrollState()
Row(modifier = Modifier
.weight(1.0f) .weight(1.0f)
.padding(0.dp, 4.dp)) { .padding(0.dp, 4.dp)
items(suggestions.size) { .horizontalScroll(scrollState)
InlineSuggestionView(suggestions[it]) .clipScrollableContainer(Orientation.Horizontal)
} .clipToBounds()) {
suggestions.forEach { InlineSuggestionView(it) }
} }
} }

View File

@ -328,8 +328,7 @@ class UixManager(private val latinIME: LatinIME) {
onCollapse = { toggleExpandAction() }, onCollapse = { toggleExpandAction() },
onClose = { returnBackToMainKeyboardViewFromAction() }, onClose = { returnBackToMainKeyboardViewFromAction() },
words = suggestedWordsOrNull, words = suggestedWordsOrNull,
suggestionStripListener = latinIME.latinIMELegacy as SuggestionStripView.Listener, suggestionStripListener = latinIME.latinIMELegacy as SuggestionStripView.Listener
inlineSuggestions = inlineSuggestions
) )
} }
} }