Force LTR in some UI, update actions autoclose

This commit is contained in:
Aleksandras Kostarevas 2024-06-15 16:12:26 +03:00
parent b74e977b6a
commit 494e27f482
4 changed files with 185 additions and 128 deletions

View File

@ -61,6 +61,7 @@ import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
@ -403,6 +404,7 @@ fun LazyItemScope.ActionItem(idx: Int, action: Action, onSelect: (Action) -> Uni
context.setSetting(
ExpandableActionItems, ActionRegistry.moveElement(
context.getSetting(ExpandableActionItems, DefaultActionsString),
DefaultActions,
action,
1
)
@ -414,6 +416,7 @@ fun LazyItemScope.ActionItem(idx: Int, action: Action, onSelect: (Action) -> Uni
context.setSetting(
ExpandableActionItems, ActionRegistry.moveElement(
context.getSetting(ExpandableActionItems, DefaultActionsString),
DefaultActions,
action,
-1
)
@ -486,13 +489,11 @@ fun ActionItemSmall(action: Action, onSelect: (Action) -> Unit) {
fun ActionItems(onSelect: (Action) -> Unit) {
val actions = useDataStoreValueBlocking(key = ExpandableActionItems, default = DefaultActionsString)
if(actions != null) {
val actionItems = ActionRegistry.stringToActions(actions, DefaultActions)
val actionItems = ActionRegistry.stringToActions(actions, DefaultActions)
LazyRow {
items(actionItems.size, key = { actionItems[it].name }) {
ActionItem(it, actionItems[it], onSelect)
}
LazyRow {
items(actionItems.size, key = { actionItems[it].name }) {
ActionItem(it, actionItems[it], onSelect)
}
}
}
@ -588,7 +589,8 @@ fun ActionBar(
inlineSuggestions: List<MutableState<View?>>,
forceOpenActionsInitially: Boolean = false,
importantNotice: ImportantNotice? = null,
keyboardManagerForAction: KeyboardManagerForAction? = null
keyboardManagerForAction: KeyboardManagerForAction? = null,
actionsForcedOpenByUser: MutableState<Boolean> = mutableStateOf(false)
) {
val view = LocalView.current
val context = LocalContext.current
@ -600,14 +602,16 @@ fun ActionBar(
}
LaunchedEffect(words) {
if(words != null && !words.isEmpty) {
if(words != null && !words.isEmpty && !actionsForcedOpenByUser.value) {
isActionsOpen.value = false
actionsForcedOpenByUser.value = false
}
}
LaunchedEffect(inlineSuggestions) {
if(inlineSuggestions.isNotEmpty()) {
isActionsOpen.value = false
actionsForcedOpenByUser.value = false
}
}
@ -618,6 +622,8 @@ fun ActionBar(
Row {
ExpandActionsButton(isActionsOpen.value) {
isActionsOpen.value = !isActionsOpen.value
actionsForcedOpenByUser.value = isActionsOpen.value
if(isActionsOpen.value && importantNotice != null) {
importantNotice.onDismiss(context)
}

View File

@ -44,8 +44,10 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
@ -259,6 +261,8 @@ class UixManager(private val latinIME: LatinIME) {
private var numSuggestionsSinceNotice = 0
private var currentNotice: MutableState<ImportantNotice?> = mutableStateOf(null)
private val actionsForcedOpenByUser = mutableStateOf(false)
var currWindowActionWindow: ActionWindow? = null
val isMainKeyboardHidden get() = mainKeyboardHidden
@ -295,7 +299,8 @@ class UixManager(private val latinIME: LatinIME) {
inlineSuggestions = inlineSuggestions,
onActionActivated = { onActionActivated(it) },
importantNotice = currentNotice.value,
keyboardManagerForAction = keyboardManagerForAction
keyboardManagerForAction = keyboardManagerForAction,
actionsForcedOpenByUser = actionsForcedOpenByUser
)
}
}
@ -319,6 +324,7 @@ class UixManager(private val latinIME: LatinIME) {
setContent()
actionsForcedOpenByUser.value = false
keyboardManagerForAction.announce("${latinIME.resources.getString(action.name)} mode")
}
@ -340,6 +346,7 @@ class UixManager(private val latinIME: LatinIME) {
setContent()
actionsForcedOpenByUser.value = false
keyboardManagerForAction.announce("$name closed")
}
@ -491,25 +498,27 @@ class UixManager(private val latinIME: LatinIME) {
composeView?.setContent {
UixThemeWrapper(latinIME.colorScheme) {
CompositionLocalProvider(LocalManager provides keyboardManagerForAction) {
Column {
Spacer(modifier = Modifier.weight(1.0f))
Surface(modifier = Modifier.onSizeChanged {
latinIME.updateTouchableHeight(it.height)
}, color = latinIME.keyboardColor) {
Box {
Column {
when {
currWindowActionWindow != null -> ActionViewWithHeader(
currWindowActionWindow!!
)
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr ) {
Column {
Spacer(modifier = Modifier.weight(1.0f))
Surface(modifier = Modifier.onSizeChanged {
latinIME.updateTouchableHeight(it.height)
}, color = latinIME.keyboardColor) {
Box {
Column {
when {
currWindowActionWindow != null -> ActionViewWithHeader(
currWindowActionWindow!!
)
else -> MainKeyboardViewWithActionBar()
else -> MainKeyboardViewWithActionBar()
}
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
}
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
ForgetWordDialog()
}
ForgetWordDialog()
}
}
}
@ -606,6 +615,7 @@ class UixManager(private val latinIME: LatinIME) {
fun onInputFinishing() {
closeActionWindow()
actionsForcedOpenByUser.value = false
languageSwitcherDialog?.dismiss()
}

View File

@ -45,11 +45,13 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
@ -75,6 +77,8 @@ import org.futo.inputmethod.latin.uix.settings.ScrollableList
import org.futo.inputmethod.latin.uix.settings.useDataStore
import org.futo.inputmethod.latin.uix.settings.useDataStoreValueBlocking
import org.futo.inputmethod.latin.uix.theme.Typography
import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
import org.futo.inputmethod.latin.uix.theme.presets.DynamicDarkTheme
import org.futo.inputmethod.updates.dismissedMigrateUpdateNotice
import org.futo.inputmethod.updates.openURI
import kotlin.math.absoluteValue
@ -151,35 +155,37 @@ fun IconText(icon: Painter, title: String, body: String) {
fun PaymentText(verbose: Boolean) {
val numDaysInstalled = useNumberOfDaysInstalled()
// Doesn't make sense to say "You've been using for ... days" if it's less than seven days
if(numDaysInstalled.intValue >= 7) {
ParagraphText(stringResource(R.string.payment_text_1, numDaysInstalled.value))
} else {
ParagraphText(stringResource(R.string.payment_text_1_alt))
}
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
// Doesn't make sense to say "You've been using for ... days" if it's less than seven days
if (numDaysInstalled.intValue >= 7) {
ParagraphText(stringResource(R.string.payment_text_1, numDaysInstalled.value))
} else {
ParagraphText(stringResource(R.string.payment_text_1_alt))
}
if(verbose) {
IconText(
icon = painterResource(id = R.drawable.activity),
title = "Sustainable Development",
body = "FUTO's mission is for open-source software and non-malicious software business practices to become a sustainable income source for projects and their developers. For this reason, we are in favor of users actually paying for software."
)
if (verbose) {
IconText(
icon = painterResource(id = R.drawable.activity),
title = "Sustainable Development",
body = "FUTO's mission is for open-source software and non-malicious software business practices to become a sustainable income source for projects and their developers. For this reason, we are in favor of users actually paying for software."
)
IconText(
icon = painterResource(id = R.drawable.unlock),
title = "Commitment to Privacy",
body = "This app will never serve you ads or sell your data. We are not in the business of doing that."
)
IconText(
icon = painterResource(id = R.drawable.unlock),
title = "Commitment to Privacy",
body = "This app will never serve you ads or sell your data. We are not in the business of doing that."
)
/*
/*
IconText(
icon = painterResource(id = R.drawable.code),
title = "Ongoing Work",
body = "Creating and maintaining great software requires significant resources. Your support will help us keep development going."
)
*/
} else {
ParagraphText(stringResource(R.string.payment_text_2))
} else {
ParagraphText(stringResource(R.string.payment_text_2))
}
}
}
@ -427,7 +433,7 @@ fun PaymentSurface(isPrimary: Boolean, title: String, onClick: (() -> Unit)? = n
}
@Composable
@Preview(showBackground = true, heightDp = 10000)
@Preview(showBackground = true, heightDp = 2048)
fun PaymentScreen(
navController: NavHostController = rememberNavController(),
onExit: () -> Unit = { }
@ -515,39 +521,41 @@ fun PaymentScreen(
val lastValidRemindValue = remember { mutableFloatStateOf(5.0f) }
val remindDays = remember { mutableStateOf("5") }
val coroutineScope = rememberCoroutineScope()
Button(
onClick = {
coroutineScope.launch {
pushNoticeReminderTime(context, lastValidRemindValue.floatValue)
}
onExit()
},
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
),
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Text(stringResource(R.string.remind_me_in_x))
BasicTextField(
value = remindDays.value,
onValueChange = {
remindDays.value = it
it.toFloatOrNull()
?.let { lastValidRemindValue.floatValue = it }
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
Button(
onClick = {
coroutineScope.launch {
pushNoticeReminderTime(context, lastValidRemindValue.floatValue)
}
onExit()
},
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer
),
modifier = Modifier
.width(32.dp)
.border(Dp.Hairline, LocalContentColor.current)
.padding(4.dp),
textStyle = Typography.bodyMedium.copy(color = LocalContentColor.current),
cursorBrush = SolidColor(LocalContentColor.current),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
)
Text(stringResource(R.string.in_x_days))
.fillMaxWidth()
.padding(8.dp)
) {
Text(stringResource(R.string.remind_me_in_x))
BasicTextField(
value = remindDays.value,
onValueChange = {
remindDays.value = it
it.toFloatOrNull()
?.let { lastValidRemindValue.floatValue = it }
},
modifier = Modifier
.width(32.dp)
.border(Dp.Hairline, LocalContentColor.current)
.padding(4.dp),
textStyle = Typography.bodyMedium.copy(color = LocalContentColor.current),
cursorBrush = SolidColor(LocalContentColor.current),
keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
)
Text(stringResource(R.string.in_x_days))
}
}
}
}
@ -558,6 +566,17 @@ fun PaymentScreen(
}
}
@Composable
@Preview(heightDp = 2048)
private fun PaymentScreenDark() {
val context = LocalContext.current
UixThemeWrapper(colorScheme = DynamicDarkTheme.obtainColors(context)) {
Surface(color = MaterialTheme.colorScheme.background) {
PaymentScreen()
}
}
}
@Composable
fun PaymentScreenSwitch(

View File

@ -4,6 +4,7 @@ import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
@ -24,6 +25,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -31,10 +33,12 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import org.futo.inputmethod.latin.uix.KeyBordersSetting
import org.futo.inputmethod.latin.uix.KeyHintsSetting
@ -234,65 +238,83 @@ fun ThemePicker(onSelected: (ThemeOption) -> Unit) {
}
}
val originalDirection = LocalLayoutDirection.current
Column {
LazyVerticalGrid(
modifier = Modifier.fillMaxWidth(),
columns = GridCells.Adaptive(minSize = 172.dp)
) {
items(availableThemeOptions.count()) {
val themeOption = availableThemeOptions[it].second
ThemePreview(themeOption, isSelected = themeOption.key == currentTheme) {
onSelected(themeOption)
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
LazyVerticalGrid(
modifier = Modifier.fillMaxWidth(),
columns = GridCells.Adaptive(minSize = 172.dp),
horizontalArrangement = if (LocalLayoutDirection.current == LayoutDirection.Rtl) {
Arrangement.End
} else {
Arrangement.Start
}
}
) {
items(availableThemeOptions.count()) {
val themeOption = availableThemeOptions[it].second
item {
AddCustomThemeButton {
// TODO: Custom themes
val toast = Toast.makeText(
context,
"Custom themes coming eventually",
Toast.LENGTH_SHORT
)
toast.show()
ThemePreview(themeOption, isSelected = themeOption.key == currentTheme) {
onSelected(themeOption)
}
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) { }
item {
AddCustomThemeButton {
// TODO: Custom themes
val toast = Toast.makeText(
context,
"Custom themes coming eventually",
Toast.LENGTH_SHORT
)
toast.show()
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Key borders",
setting = KeyBordersSetting
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Show symbol hints",
setting = KeyHintsSetting
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) { }
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingSlider(
title = "Keyboard Height",
setting = KeyboardHeightMultiplierSetting,
range = 0.33f .. 1.75f, transform = { it },
indicator = { "${(it * 100.0f).roundToInt()}%" },
steps = 16
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingSlider(
title = "Keyboard Offset",
setting = KeyboardBottomOffsetSetting,
range = 0.0f .. 50.0f,
hardRange = 0.0f .. 250.0f,
transform = { it },
indicator = { "${String.format("%.1f", it)} dp" },
steps = 9
)
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
CompositionLocalProvider(LocalLayoutDirection provides originalDirection) {
SettingToggleDataStore(
title = "Key borders",
setting = KeyBordersSetting
)
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
CompositionLocalProvider(LocalLayoutDirection provides originalDirection) {
SettingToggleDataStore(
title = "Show symbol hints",
setting = KeyHintsSetting
)
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
CompositionLocalProvider(LocalLayoutDirection provides originalDirection) {
SettingSlider(
title = "Keyboard Height",
setting = KeyboardHeightMultiplierSetting,
range = 0.33f..1.75f, transform = { it },
indicator = { "${(it * 100.0f).roundToInt()}%" },
steps = 16
)
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
CompositionLocalProvider(LocalLayoutDirection provides originalDirection) {
SettingSlider(
title = "Keyboard Offset",
setting = KeyboardBottomOffsetSetting,
range = 0.0f..50.0f,
hardRange = 0.0f..250.0f,
transform = { it },
indicator = { "${String.format("%.1f", it)} dp" },
steps = 9
)
}
}
}
}
}