mirror of
https://gitlab.futo.org/keyboard/latinime.git
synced 2024-09-28 14:54:30 +01:00
Update keyboard sizing and add floating mode
This commit is contained in:
parent
32b27b84c0
commit
3d8233be92
@ -16,6 +16,11 @@
|
||||
<string name="more_actions_action_title">All Actions</string>
|
||||
<string name="bug_viewer_action_title">Bug Viewer</string>
|
||||
|
||||
<string name="left_handed_keyboard_action_title">Left-Handed Keyboard</string>
|
||||
<string name="right_handed_keyboard_action_title">Right-Handed Keyboard</string>
|
||||
<string name="split_keyboard_action_title">Split Keyboard</string>
|
||||
<string name="floating_keyboard_action_title">Floating Keyboard</string>
|
||||
|
||||
<string name="action_kind_action_key">Action Key</string>
|
||||
<string name="action_kind_pinned_key">Pinned Action(s)</string>
|
||||
<string name="action_kind_favorites">Favorite Actions</string>
|
||||
|
@ -140,40 +140,16 @@ public final class KeyboardSwitcher implements SwitchActions {
|
||||
}
|
||||
|
||||
|
||||
final KeyboardSizingCalculator sizingCalculator = new KeyboardSizingCalculator(mLatinIMELegacy.getInputMethodService());
|
||||
final KeyboardSizingCalculator sizingCalculator = ((LatinIME)mLatinIMELegacy.getInputMethodService()).getSizingCalculator();
|
||||
final ComputedKeyboardSize computedSize = sizingCalculator.calculate(layoutSetName, settingsValues.mIsNumberRowEnabled);
|
||||
|
||||
int keyboardWidth = 0;
|
||||
int keyboardHeight = 0;
|
||||
|
||||
int splitLayoutWidth = 0;
|
||||
|
||||
Rect padding = new Rect();
|
||||
|
||||
Window window = mLatinIMELegacy.getInputMethodService().getWindow().getWindow();
|
||||
|
||||
if(computedSize instanceof SplitKeyboardSize) {
|
||||
keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(window, res);
|
||||
keyboardHeight = ((SplitKeyboardSize) computedSize).getHeight();
|
||||
splitLayoutWidth = ((SplitKeyboardSize) computedSize).getSplitLayoutWidth();
|
||||
padding = ((SplitKeyboardSize) computedSize).getPadding();
|
||||
}else if(computedSize instanceof RegularKeyboardSize) {
|
||||
keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(window, res);
|
||||
keyboardHeight = ((RegularKeyboardSize) computedSize).getHeight();
|
||||
padding = ((RegularKeyboardSize) computedSize).getPadding();
|
||||
}
|
||||
|
||||
final KeyboardLayoutSetV2Params params = new KeyboardLayoutSetV2Params(
|
||||
keyboardWidth,
|
||||
keyboardHeight,
|
||||
padding,
|
||||
computedSize,
|
||||
layoutSetName,
|
||||
subtype.getLocale(),
|
||||
editorInfo == null ? new EditorInfo() : editorInfo,
|
||||
settingsValues.mIsNumberRowEnabled,
|
||||
sizingCalculator.calculateGap(),
|
||||
splitLayoutWidth != 0,
|
||||
splitLayoutWidth,
|
||||
settingsValues.mShowsActionKey ? settingsValues.mActionKeyId : null,
|
||||
LongPressKeySettings.load(mThemeContext)
|
||||
);
|
||||
|
@ -132,16 +132,8 @@ public final class KeyPreviewChoreographer {
|
||||
final int keyPreviewPosition;
|
||||
int previewX = key.getDrawX() - (previewWidth - keyDrawWidth) / 2
|
||||
+ CoordinateUtils.x(originCoords);
|
||||
if (previewX < 0) {
|
||||
previewX = 0;
|
||||
keyPreviewPosition = KeyPreviewView.POSITION_LEFT;
|
||||
} else if (previewX > keyboardViewWidth - previewWidth) {
|
||||
previewX = keyboardViewWidth - previewWidth;
|
||||
keyPreviewPosition = KeyPreviewView.POSITION_RIGHT;
|
||||
} else {
|
||||
keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE;
|
||||
}
|
||||
final boolean hasMoreKeys = (key.getMoreKeys() != null);
|
||||
keyPreviewPosition = KeyPreviewView.POSITION_MIDDLE;
|
||||
final boolean hasMoreKeys = !key.getMoreKeys().isEmpty();
|
||||
keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition);
|
||||
// The key preview is placed vertically above the top edge of the parent key with an
|
||||
// arbitrary offset.
|
||||
|
@ -21,10 +21,14 @@ import android.view.inputmethod.InputMethodSubtype
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@ -75,28 +79,27 @@ import org.futo.inputmethod.latin.uix.theme.applyWindowColors
|
||||
import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
|
||||
import org.futo.inputmethod.latin.xlm.LanguageModelFacilitator
|
||||
import org.futo.inputmethod.updates.scheduleUpdateCheckingJob
|
||||
import org.futo.inputmethod.v2keyboard.ComputedKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.FloatingKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSettings
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSizeSettingKind
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSizeStateProvider
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSizingCalculator
|
||||
import org.futo.inputmethod.v2keyboard.getHeight
|
||||
|
||||
private class UnlockedBroadcastReceiver(val onDeviceUnlocked: () -> Unit) : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
println("Unlocked Broadcast Receiver: ${intent?.action}")
|
||||
if (intent?.action == Intent.ACTION_USER_UNLOCKED) {
|
||||
onDeviceUnlocked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner,
|
||||
LatinIMELegacy.SuggestionStripController, DynamicThemeProviderOwner, FoldStateProvider,
|
||||
KeyboardSizeStateProvider {
|
||||
|
||||
open class InputMethodServiceCompose : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {
|
||||
private lateinit var mLifecycleRegistry: LifecycleRegistry
|
||||
private lateinit var mViewModelStore: ViewModelStore
|
||||
private lateinit var mSavedStateRegistryController: SavedStateRegistryController
|
||||
|
||||
|
||||
|
||||
fun setOwners() {
|
||||
val decorView = window.window?.decorView
|
||||
if (decorView?.findViewTreeLifecycleOwner() == null) {
|
||||
@ -110,11 +113,59 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
mLifecycleRegistry = LifecycleRegistry(this)
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
|
||||
|
||||
mViewModelStore = ViewModelStore()
|
||||
|
||||
mSavedStateRegistryController = SavedStateRegistryController.create(this)
|
||||
mSavedStateRegistryController.performRestore(null)
|
||||
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.CREATED
|
||||
}
|
||||
|
||||
override fun onStartInputView(editorInfo: EditorInfo?, restarting: Boolean) {
|
||||
super.onStartInputView(editorInfo, restarting)
|
||||
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.STARTED
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||
}
|
||||
|
||||
override val lifecycle: Lifecycle
|
||||
get() = mLifecycleRegistry
|
||||
override val savedStateRegistry: SavedStateRegistry
|
||||
get() = mSavedStateRegistryController.savedStateRegistry
|
||||
override val viewModelStore: ViewModelStore
|
||||
get() = mViewModelStore
|
||||
|
||||
internal var composeView: ComposeView? = null
|
||||
|
||||
override fun onCreateInputView(): View =
|
||||
ComposeView(this).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setParentCompositionContext(null)
|
||||
|
||||
setOwners()
|
||||
|
||||
composeView = this
|
||||
}
|
||||
}
|
||||
|
||||
class LatinIME : InputMethodServiceCompose(), LatinIMELegacy.SuggestionStripController,
|
||||
DynamicThemeProviderOwner, FoldStateProvider, KeyboardSizeStateProvider {
|
||||
val latinIMELegacy = LatinIMELegacy(
|
||||
this as InputMethodService,
|
||||
this as LatinIMELegacy.SuggestionStripController
|
||||
)
|
||||
|
||||
|
||||
val inputLogic get() = latinIMELegacy.mInputLogic
|
||||
|
||||
lateinit var languageModelFacilitator: LanguageModelFacilitator
|
||||
@ -122,6 +173,8 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
val uixManager = UixManager(this)
|
||||
lateinit var suggestionBlacklist: SuggestionBlacklist
|
||||
|
||||
val sizingCalculator = KeyboardSizingCalculator(this, uixManager)
|
||||
|
||||
private var activeThemeOption: ThemeOption? = null
|
||||
private var activeColorScheme = VoiceInputTheme.obtainColors(this)
|
||||
private var pendingRecreateKeyboard: Boolean = false
|
||||
@ -130,6 +183,13 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
val colorScheme get() = activeColorScheme
|
||||
val keyboardColor get() = drawableProvider?.primaryKeyboardColor?.let { androidx.compose.ui.graphics.Color(it) } ?: colorScheme.surface
|
||||
|
||||
val size: MutableState<ComputedKeyboardSize?> = mutableStateOf(null)
|
||||
private fun calculateSize(): ComputedKeyboardSize
|
||||
= sizingCalculator.calculate(
|
||||
latinIMELegacy.mKeyboardSwitcher.keyboard?.mId?.mKeyboardLayoutSetName ?: "qwerty",
|
||||
latinIMELegacy.mKeyboardSwitcher.keyboard?.mId?.mNumberRow ?: false
|
||||
)
|
||||
|
||||
private var drawableProvider: DynamicThemeProvider? = null
|
||||
|
||||
private var lastEditorInfo: EditorInfo? = null
|
||||
@ -204,7 +264,26 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSizeUpdated() {
|
||||
val newSize = calculateSize()
|
||||
val shouldInvalidateKeyboard = size.value?.let { oldSize ->
|
||||
when {
|
||||
oldSize is FloatingKeyboardSize && newSize is FloatingKeyboardSize -> {
|
||||
oldSize.width != newSize.width || oldSize.height != newSize.height
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
} ?: true
|
||||
|
||||
size.value = newSize
|
||||
|
||||
if(shouldInvalidateKeyboard) {
|
||||
invalidateKeyboard(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun invalidateKeyboard(refreshSettings: Boolean = false) {
|
||||
size.value = calculateSize()
|
||||
settingsRefreshRequired = settingsRefreshRequired || refreshSettings
|
||||
|
||||
if(!uixManager.isMainKeyboardHidden) {
|
||||
@ -256,16 +335,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
val filter = IntentFilter(Intent.ACTION_USER_UNLOCKED)
|
||||
registerReceiver(unlockReceiver, filter)
|
||||
|
||||
mLifecycleRegistry = LifecycleRegistry(this)
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
|
||||
|
||||
mViewModelStore = ViewModelStore()
|
||||
|
||||
mSavedStateRegistryController = SavedStateRegistryController.create(this)
|
||||
mSavedStateRegistryController.performRestore(null)
|
||||
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.CREATED
|
||||
|
||||
suggestionBlacklist = SuggestionBlacklist(latinIMELegacy.mSettings, this, lifecycleScope)
|
||||
|
||||
Subtypes.addDefaultSubtypesIfNecessary(this)
|
||||
@ -348,6 +417,21 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
}
|
||||
|
||||
// Listen to size changes
|
||||
launchJob {
|
||||
val prev: MutableMap<KeyboardSizeSettingKind, String?> =
|
||||
KeyboardSizeSettingKind.entries.associateWith { null }.toMutableMap()
|
||||
|
||||
dataStore.data.collect { data ->
|
||||
prev.keys.toList().forEach {
|
||||
if(data[KeyboardSettings[it]!!.key] != prev[it]) {
|
||||
prev[it] = data[KeyboardSettings[it]!!.key]
|
||||
onSizeUpdated()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uixManager.onCreate()
|
||||
|
||||
Settings.getInstance().settingsChangedListeners.add { oldSettings, newSettings ->
|
||||
@ -364,7 +448,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
unregisterReceiver(unlockReceiver)
|
||||
|
||||
stopJobs()
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||
viewModelStore.clear()
|
||||
|
||||
languageModelFacilitator.saveHistoryLog()
|
||||
@ -381,6 +464,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
Log.w("LatinIME", "Configuration changed")
|
||||
size.value = calculateSize()
|
||||
latinIMELegacy.onConfigurationChanged(newConfig)
|
||||
super.onConfigurationChanged(newConfig)
|
||||
}
|
||||
@ -390,22 +474,21 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
|
||||
private var legacyInputView: View? = null
|
||||
private var touchableHeight: Int = 0
|
||||
override fun onCreateInputView(): View {
|
||||
Log.w("LatinIME", "Create input view")
|
||||
legacyInputView = latinIMELegacy.onCreateInputView()
|
||||
val composeView = super.onCreateInputView()
|
||||
|
||||
val composeView = uixManager.createComposeView()
|
||||
legacyInputView = latinIMELegacy.onCreateInputView()
|
||||
latinIMELegacy.setComposeInputView(composeView)
|
||||
|
||||
uixManager.setContent()
|
||||
|
||||
return composeView
|
||||
}
|
||||
|
||||
private var inputViewHeight: Int = -1
|
||||
|
||||
// Both called by UixManager
|
||||
fun updateTouchableHeight(to: Int) { touchableHeight = to }
|
||||
fun getInputViewHeight(): Int = inputViewHeight
|
||||
fun getViewHeight(): Int = composeView?.height ?: resources.displayMetrics.heightPixels
|
||||
|
||||
private var isInputModal = false
|
||||
fun setInputModal(to: Boolean) {
|
||||
@ -426,8 +509,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
key(legacyInputView) {
|
||||
AndroidView(factory = {
|
||||
legacyInputView!!
|
||||
@ -445,7 +526,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
legacyInputView = newView
|
||||
|
||||
uixManager.setContent()
|
||||
uixManager.getComposeView()?.let {
|
||||
composeView?.let {
|
||||
latinIMELegacy.setComposeInputView(it)
|
||||
}
|
||||
|
||||
@ -455,7 +536,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
override fun setInputView(view: View?) {
|
||||
super.setInputView(view)
|
||||
|
||||
uixManager.getComposeView()?.let {
|
||||
composeView?.let {
|
||||
latinIMELegacy.setComposeInputView(it)
|
||||
}
|
||||
|
||||
@ -473,8 +554,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
|
||||
override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
|
||||
mLifecycleRegistry.currentState = Lifecycle.State.STARTED
|
||||
|
||||
lastEditorInfo = info
|
||||
|
||||
super.onStartInputView(info, restarting)
|
||||
@ -561,36 +640,55 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
}
|
||||
|
||||
override fun onComputeInsets(outInsets: Insets?) {
|
||||
val composeView = uixManager.getComposeView()
|
||||
|
||||
// This method may be called before {@link #setInputView(View)}.
|
||||
if (legacyInputView == null || composeView == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val inputHeight: Int = composeView.height
|
||||
if (latinIMELegacy.isImeSuppressedByHardwareKeyboard && !legacyInputView!!.isShown) {
|
||||
// If there is a hardware keyboard and a visible software keyboard view has been hidden,
|
||||
// no visual element will be shown on the screen.
|
||||
latinIMELegacy.setInsets(outInsets!!.apply {
|
||||
contentTopInsets = inputHeight
|
||||
visibleTopInsets = inputHeight
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
val visibleTopY = inputHeight - touchableHeight
|
||||
|
||||
val touchLeft = 0
|
||||
val touchTop = if(isInputModal) { 0 } else { visibleTopY }
|
||||
val touchRight = composeView.width
|
||||
val touchBottom = inputHeight
|
||||
|
||||
val viewHeight = composeView!!.height
|
||||
val size = size.value ?: return
|
||||
latinIMELegacy.setInsets(outInsets!!.apply {
|
||||
touchableInsets = Insets.TOUCHABLE_INSETS_REGION;
|
||||
touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
|
||||
contentTopInsets = visibleTopY
|
||||
visibleTopInsets = visibleTopY
|
||||
when(size) {
|
||||
is FloatingKeyboardSize -> {
|
||||
val height = uixManager.touchableHeight
|
||||
|
||||
val left = size.bottomOrigin.first
|
||||
val bottomYFromBottom = size.bottomOrigin.second
|
||||
var bottom = viewHeight - bottomYFromBottom
|
||||
var top = bottom - height
|
||||
val right = left + size.width
|
||||
|
||||
if(top < 0) {
|
||||
bottom -= top
|
||||
top -= top
|
||||
}
|
||||
|
||||
touchableInsets = Insets.TOUCHABLE_INSETS_REGION
|
||||
touchableRegion.set(left, top, right, bottom)
|
||||
contentTopInsets = viewHeight
|
||||
visibleTopInsets = viewHeight
|
||||
}
|
||||
else -> {
|
||||
touchableInsets = Insets.TOUCHABLE_INSETS_CONTENT
|
||||
|
||||
val touchableHeight = uixManager.touchableHeight
|
||||
val topInset = if(touchableHeight < 1 || touchableHeight >= viewHeight - 1) {
|
||||
val actionBarHeight = sizingCalculator.calculateTotalActionBarHeightPx()
|
||||
|
||||
viewHeight - size.getHeight() - actionBarHeight
|
||||
} else {
|
||||
viewHeight - touchableHeight
|
||||
}
|
||||
|
||||
contentTopInsets = topInset
|
||||
visibleTopInsets = topInset
|
||||
}
|
||||
}
|
||||
|
||||
if(isInputModal) {
|
||||
touchableInsets = Insets.TOUCHABLE_INSETS_REGION
|
||||
touchableRegion.set(0, 0, composeView!!.width, composeView!!.height)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -737,14 +835,6 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
|
||||
return super.getCurrentInputConnection()
|
||||
}
|
||||
|
||||
override val lifecycle: Lifecycle
|
||||
get() = mLifecycleRegistry
|
||||
override val savedStateRegistry: SavedStateRegistry
|
||||
get() = mSavedStateRegistryController.savedStateRegistry
|
||||
override val viewModelStore: ViewModelStore
|
||||
get() = mViewModelStore
|
||||
|
||||
|
||||
private fun onDeviceUnlocked() {
|
||||
Log.i("LatinIME", "DEVICE has UNLOCKED!!! Reloading settings...")
|
||||
// Every place that called getDefaultSharedPreferences now needs to be refreshed or call it again
|
||||
|
@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import org.futo.inputmethod.latin.LatinIME
|
||||
import org.futo.inputmethod.latin.uix.theme.ThemeOption
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSizingCalculator
|
||||
import java.util.Locale
|
||||
|
||||
interface ActionInputTransaction {
|
||||
@ -68,6 +69,8 @@ interface KeyboardManagerForAction {
|
||||
|
||||
fun getLatinIMEForDebug(): LatinIME
|
||||
fun isDeviceLocked(): Boolean
|
||||
|
||||
fun getSizingCalculator(): KeyboardSizingCalculator
|
||||
}
|
||||
|
||||
interface ActionWindow {
|
||||
|
@ -13,7 +13,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Dp
|
||||
@ -30,6 +29,7 @@ import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardLayoutSetV2
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardLayoutSetV2Params
|
||||
import org.futo.inputmethod.v2keyboard.LayoutManager
|
||||
import org.futo.inputmethod.v2keyboard.RegularKeyboardSize
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -76,23 +76,8 @@ fun KeyboardLayoutPreview(id: String, width: Dp = 172.dp, locale: Locale? = null
|
||||
}
|
||||
}
|
||||
|
||||
val configuration = LocalConfiguration.current
|
||||
val isLandscape = false//configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
|
||||
val widthPx: Int
|
||||
val heightPx: Int
|
||||
|
||||
when {
|
||||
isLandscape -> {
|
||||
widthPx = (500.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
heightPx = (180.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
widthPx = (320.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
heightPx = (200.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
}
|
||||
}
|
||||
val widthPx: Int = (320.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
val heightPx: Int = (200.0 * context.resources.displayMetrics.density).roundToInt()
|
||||
|
||||
val keyboard = remember { mutableStateOf<Keyboard?>(null) }
|
||||
|
||||
@ -107,16 +92,12 @@ fun KeyboardLayoutPreview(id: String, width: Dp = 172.dp, locale: Locale? = null
|
||||
val layoutSet = KeyboardLayoutSetV2(
|
||||
context,
|
||||
KeyboardLayoutSetV2Params(
|
||||
width = widthPx,
|
||||
height = heightPx,
|
||||
padding = Rect(),
|
||||
computedSize = RegularKeyboardSize(width = widthPx, height = heightPx, padding = Rect()),
|
||||
gap = 4.0f,
|
||||
keyboardLayoutSet = id,
|
||||
locale = loc ?: Locale.ENGLISH,
|
||||
editorInfo = editorInfo,
|
||||
numberRow = numberRow,
|
||||
useSplitLayout = isLandscape,
|
||||
splitLayoutWidth = widthPx * 2 / 3,
|
||||
bottomActionKey = null
|
||||
)
|
||||
)
|
||||
|
@ -23,22 +23,29 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.absoluteOffset
|
||||
import androidx.compose.foundation.layout.absolutePadding
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredWidth
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@ -46,17 +53,21 @@ import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
@ -96,6 +107,14 @@ import org.futo.inputmethod.updates.deferManualUpdate
|
||||
import org.futo.inputmethod.updates.isManualUpdateTimeExpired
|
||||
import org.futo.inputmethod.updates.openManualUpdateCheck
|
||||
import org.futo.inputmethod.updates.retrieveSavedLastUpdateCheckResult
|
||||
import org.futo.inputmethod.v2keyboard.FloatingKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardSizingCalculator
|
||||
import org.futo.inputmethod.v2keyboard.OneHandedDirection
|
||||
import org.futo.inputmethod.v2keyboard.OneHandedKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.RegularKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.SplitKeyboardSize
|
||||
import org.futo.inputmethod.v2keyboard.getPadding
|
||||
import org.futo.inputmethod.v2keyboard.getWidth
|
||||
import java.util.Locale
|
||||
|
||||
val LocalManager = staticCompositionLocalOf<KeyboardManagerForAction> {
|
||||
@ -279,7 +298,7 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
|
||||
override fun announce(s: String) {
|
||||
AccessibilityUtils.init(getContext())
|
||||
if(AccessibilityUtils.getInstance().isAccessibilityEnabled) {
|
||||
AccessibilityUtils.getInstance().announceForAccessibility(uixManager.getComposeView(), s)
|
||||
AccessibilityUtils.getInstance().announceForAccessibility(uixManager.composeView, s)
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +314,9 @@ class UixActionKeyboardManager(val uixManager: UixManager, val latinIME: LatinIM
|
||||
return getContext().isDeviceLocked
|
||||
}
|
||||
|
||||
override fun getSizingCalculator(): KeyboardSizingCalculator =
|
||||
latinIME.sizingCalculator
|
||||
|
||||
override fun getLatinIMEForDebug(): LatinIME = latinIME
|
||||
}
|
||||
|
||||
@ -305,11 +327,12 @@ data class ActiveDialogRequest(
|
||||
)
|
||||
|
||||
class UixManager(private val latinIME: LatinIME) {
|
||||
internal val composeView: ComposeView?
|
||||
get() = latinIME.composeView
|
||||
|
||||
private var shouldShowSuggestionStrip: Boolean = true
|
||||
private var suggestedWords: SuggestedWords? = null
|
||||
|
||||
private var composeView: ComposeView? = null
|
||||
|
||||
private var currWindowAction: Action? = null
|
||||
private var persistentStates: HashMap<Action, PersistentActionState?> = hashMapOf()
|
||||
|
||||
@ -327,6 +350,9 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
latinIME.deferSetSetting(ActionBarExpanded, isActionsExpanded.value)
|
||||
}
|
||||
|
||||
val actionsExpanded: Boolean
|
||||
get() = isActionsExpanded.value
|
||||
|
||||
private var isShowingActionEditor = mutableStateOf(false)
|
||||
fun showActionEditor() {
|
||||
isShowingActionEditor.value = true
|
||||
@ -337,6 +363,12 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
var isInputOverridden = mutableStateOf(false)
|
||||
|
||||
var currWindowActionWindow: ActionWindow? = null
|
||||
val isActionWindowDocked: Boolean
|
||||
get() = currWindowActionWindow != null
|
||||
|
||||
private var measuredTouchableHeight = 0
|
||||
val touchableHeight: Int
|
||||
get() = measuredTouchableHeight
|
||||
|
||||
val isMainKeyboardHidden get() = mainKeyboardHidden
|
||||
|
||||
@ -626,6 +658,129 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SizePositionerSurface(content: @Composable BoxScope.(actionBarGap: Dp) -> Unit) {
|
||||
val size = latinIME.size.value
|
||||
when(size) {
|
||||
is FloatingKeyboardSize -> {
|
||||
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(configuration.screenWidthDp.dp.toPx() - size.width),
|
||||
newOffset.y.coerceAtMost(latinIME.getViewHeight().toFloat() - measuredTouchableHeight)
|
||||
)
|
||||
|
||||
offset.value = newOffset
|
||||
}, onDragEnd = {
|
||||
latinIME.sizingCalculator.editSavedSettings { settings ->
|
||||
settings.copy(
|
||||
floatingBottomCenterOriginDp = 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 RegularKeyboardSize,
|
||||
is SplitKeyboardSize -> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fun setContent() {
|
||||
composeView?.setContent {
|
||||
UixThemeWrapper(latinIME.colorScheme) {
|
||||
@ -639,29 +794,22 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
isShowingActionEditor.value = false
|
||||
}
|
||||
|
||||
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!!
|
||||
)
|
||||
SizePositionerSurface { gap ->
|
||||
Column {
|
||||
when {
|
||||
currWindowActionWindow != null -> ActionViewWithHeader(
|
||||
currWindowActionWindow!!
|
||||
)
|
||||
|
||||
else -> MainKeyboardViewWithActionBar()
|
||||
}
|
||||
|
||||
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
|
||||
}
|
||||
|
||||
ForgetWordDialog()
|
||||
else -> MainKeyboardViewWithActionBar()
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(gap))
|
||||
|
||||
latinIME.LegacyKeyboardView(hidden = isMainKeyboardHidden)
|
||||
}
|
||||
|
||||
ForgetWordDialog()
|
||||
}
|
||||
|
||||
ActionEditorHost()
|
||||
@ -734,28 +882,6 @@ class UixManager(private val latinIME: LatinIME) {
|
||||
}
|
||||
}
|
||||
|
||||
fun createComposeView(): View {
|
||||
if(composeView != null) {
|
||||
composeView = null
|
||||
//throw IllegalStateException("Attempted to create compose view, when one is already created!")
|
||||
}
|
||||
|
||||
composeView = ComposeView(latinIME).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
setParentCompositionContext(null)
|
||||
|
||||
latinIME.setOwners()
|
||||
}
|
||||
|
||||
setContent()
|
||||
|
||||
return composeView!!
|
||||
}
|
||||
|
||||
fun getComposeView(): View? {
|
||||
return composeView
|
||||
}
|
||||
|
||||
fun onColorSchemeChanged() {
|
||||
setContent()
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
package org.futo.inputmethod.latin.uix.actions
|
||||
|
||||
import org.futo.inputmethod.latin.R
|
||||
import org.futo.inputmethod.latin.uix.Action
|
||||
import org.futo.inputmethod.v2keyboard.KeyboardMode
|
||||
import org.futo.inputmethod.v2keyboard.OneHandedDirection
|
||||
|
||||
val LeftHandedKeyboardAction = Action(
|
||||
icon = R.drawable.arrow_left,
|
||||
name = R.string.left_handed_keyboard_action_title,
|
||||
simplePressImpl = { manager, _ ->
|
||||
manager.getSizingCalculator().editSavedSettings {
|
||||
if(it.currentMode == KeyboardMode.OneHanded
|
||||
&& it.oneHandedDirection == OneHandedDirection.Left) {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Regular
|
||||
)
|
||||
} else {
|
||||
it.copy(
|
||||
oneHandedDirection = OneHandedDirection.Left,
|
||||
currentMode = KeyboardMode.OneHanded
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
||||
|
||||
val RightHandedKeyboardAction = Action(
|
||||
icon = R.drawable.arrow_right,
|
||||
name = R.string.right_handed_keyboard_action_title,
|
||||
simplePressImpl = { manager, _ ->
|
||||
manager.getSizingCalculator().editSavedSettings {
|
||||
if(it.currentMode == KeyboardMode.OneHanded
|
||||
&& it.oneHandedDirection == OneHandedDirection.Right) {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Regular
|
||||
)
|
||||
} else {
|
||||
it.copy(
|
||||
oneHandedDirection = OneHandedDirection.Right,
|
||||
currentMode = KeyboardMode.OneHanded
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
||||
|
||||
val SplitKeyboardAction = Action(
|
||||
icon = R.drawable.arrow_down,
|
||||
name = R.string.split_keyboard_action_title,
|
||||
simplePressImpl = { manager, _ ->
|
||||
manager.getSizingCalculator().editSavedSettings {
|
||||
if(it.currentMode == KeyboardMode.Split) {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Regular
|
||||
)
|
||||
} else {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Split
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
||||
|
||||
val FloatingKeyboardAction = Action(
|
||||
icon = R.drawable.arrow_up,
|
||||
name = R.string.floating_keyboard_action_title,
|
||||
simplePressImpl = { manager, _ ->
|
||||
manager.getSizingCalculator().editSavedSettings {
|
||||
if(it.currentMode == KeyboardMode.Floating) {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Regular
|
||||
)
|
||||
} else {
|
||||
it.copy(
|
||||
currentMode = KeyboardMode.Floating
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
windowImpl = null,
|
||||
)
|
@ -31,7 +31,11 @@ val AllActionsMap = mapOf(
|
||||
"copy" to CopyAction,
|
||||
"select_all" to SelectAllAction,
|
||||
"more" to MoreActionsAction,
|
||||
"bugs" to BugViewerAction
|
||||
"bugs" to BugViewerAction,
|
||||
"onehanded_left" to LeftHandedKeyboardAction,
|
||||
"onehanded_right" to RightHandedKeyboardAction,
|
||||
"split_keyboard" to SplitKeyboardAction,
|
||||
"floating_keyboard" to FloatingKeyboardAction
|
||||
)
|
||||
|
||||
val ActionToId = AllActionsMap.entries.associate { it.value to it.key }
|
||||
|
@ -76,16 +76,12 @@ fun getPrimaryLayoutOverride(editorInfo: EditorInfo?): String? {
|
||||
}
|
||||
|
||||
data class KeyboardLayoutSetV2Params(
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val padding: Rect,
|
||||
val computedSize: ComputedKeyboardSize,
|
||||
val keyboardLayoutSet: String,
|
||||
val locale: Locale,
|
||||
val editorInfo: EditorInfo?,
|
||||
val numberRow: Boolean,
|
||||
val gap: Float = 4.0f,
|
||||
val useSplitLayout: Boolean,
|
||||
val splitLayoutWidth: Int,
|
||||
val bottomActionKey: Int?,
|
||||
val longPressKeySettings: LongPressKeySettings? = null
|
||||
)
|
||||
@ -184,14 +180,15 @@ class KeyboardLayoutSetV2 internal constructor(
|
||||
NumberRowMode.AlwaysDisabled -> false
|
||||
}
|
||||
|
||||
private val widthMinusPadding = params.width - params.padding.left - params.padding.right
|
||||
private val heightMinusPadding = params.height - params.padding.top - params.padding.bottom
|
||||
private val height = params.computedSize.getHeight()
|
||||
|
||||
private val padding = params.computedSize.getPadding()
|
||||
|
||||
private val widthMinusPadding = params.computedSize.getTotalKeyboardWidth()
|
||||
private val heightMinusPadding = height - padding.top - padding.bottom
|
||||
|
||||
private val singularRowHeight: Double
|
||||
get() = heightMinusPadding?.let { it / 4.0 } ?: run {
|
||||
(ResourceUtils.getDefaultKeyboardHeight(context.resources) / 4.0) *
|
||||
keyboardHeightMultiplier
|
||||
}
|
||||
get() = heightMinusPadding / 4.0
|
||||
|
||||
fun getKeyboard(element: KeyboardLayoutElement): Keyboard {
|
||||
|
||||
@ -221,10 +218,8 @@ class KeyboardLayoutSetV2 internal constructor(
|
||||
}
|
||||
|
||||
val layoutParams = LayoutParams(
|
||||
size = params.computedSize,
|
||||
gap = params.gap.dp,
|
||||
useSplitLayout = params.useSplitLayout,
|
||||
splitLayoutWidth = params.splitLayoutWidth,
|
||||
padding = params.padding,
|
||||
standardRowHeight = singularRowHeight,
|
||||
element = element
|
||||
)
|
||||
|
@ -2,12 +2,27 @@ package org.futo.inputmethod.v2keyboard
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.floatPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.window.layout.FoldingFeature
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.element
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.encoding.CompositeDecoder
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.encoding.decodeStructure
|
||||
import kotlinx.serialization.encoding.encodeStructure
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.futo.inputmethod.latin.FoldStateProvider
|
||||
import org.futo.inputmethod.latin.LatinIME
|
||||
import org.futo.inputmethod.latin.uix.SettingsKey
|
||||
import org.futo.inputmethod.latin.uix.UixManager
|
||||
import org.futo.inputmethod.latin.uix.getSettingBlocking
|
||||
import org.futo.inputmethod.latin.uix.setSettingBlocking
|
||||
import org.futo.inputmethod.latin.utils.ResourceUtils
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@ -17,13 +32,139 @@ interface KeyboardSizeStateProvider {
|
||||
|
||||
sealed class ComputedKeyboardSize()
|
||||
|
||||
class RegularKeyboardSize(val height: Int, val padding: Rect) : ComputedKeyboardSize()
|
||||
class RegularKeyboardSize(val height: Int, val width: Int, val padding: Rect) : ComputedKeyboardSize()
|
||||
|
||||
class SplitKeyboardSize(val height: Int, val padding: Rect, val splitLayoutWidth: Int) : ComputedKeyboardSize()
|
||||
class SplitKeyboardSize(val height: Int, val width: Int, val padding: Rect, val splitLayoutWidth: Int) : ComputedKeyboardSize()
|
||||
|
||||
//class OneHandedKeyboardSize(val height: Int, val offset: Int, val sideInset: Int, val isLeft: Boolean, val width: Int): ComputedKeyboardSize()
|
||||
//class FloatingKeyboardSize(val x: Int, val y: Int, val width: Int, val height: Int): ComputedKeyboardSize()
|
||||
enum class OneHandedDirection {
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
class OneHandedKeyboardSize(val height: Int, val width: Int, val padding: Rect, val layoutWidth: Int, val direction: OneHandedDirection): ComputedKeyboardSize()
|
||||
|
||||
class FloatingKeyboardSize(
|
||||
val bottomOrigin: Pair<Int, Int>,
|
||||
val width: Int,
|
||||
val height: Int,
|
||||
val decorationPadding: Rect
|
||||
): ComputedKeyboardSize()
|
||||
|
||||
fun ComputedKeyboardSize.getHeight(): Int = when(this) {
|
||||
is FloatingKeyboardSize -> height
|
||||
is OneHandedKeyboardSize -> height
|
||||
is RegularKeyboardSize -> height
|
||||
is SplitKeyboardSize -> height
|
||||
}
|
||||
|
||||
fun ComputedKeyboardSize.getWidth(): Int = when(this) {
|
||||
is FloatingKeyboardSize -> width
|
||||
is OneHandedKeyboardSize -> width
|
||||
is RegularKeyboardSize -> width
|
||||
is SplitKeyboardSize -> width
|
||||
}
|
||||
|
||||
fun ComputedKeyboardSize.getPadding(): Rect = when(this) {
|
||||
is FloatingKeyboardSize -> decorationPadding
|
||||
is OneHandedKeyboardSize -> padding
|
||||
is RegularKeyboardSize -> padding
|
||||
is SplitKeyboardSize -> padding
|
||||
}
|
||||
|
||||
fun ComputedKeyboardSize.getTotalKeyboardWidth(): Int = when(this) {
|
||||
is FloatingKeyboardSize -> width - decorationPadding.left - decorationPadding.right
|
||||
is OneHandedKeyboardSize -> layoutWidth
|
||||
is RegularKeyboardSize -> width - padding.left - padding.right
|
||||
is SplitKeyboardSize -> width - padding.left - padding.right
|
||||
}
|
||||
|
||||
enum class KeyboardMode {
|
||||
Regular,
|
||||
Split,
|
||||
OneHanded,
|
||||
Floating
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Serializer(forClass = Rect::class)
|
||||
object RectSerializer : KSerializer<Rect> {
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Rect") {
|
||||
element<Int>("left")
|
||||
element<Int>("top")
|
||||
element<Int>("right")
|
||||
element<Int>("bottom")
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: Rect) {
|
||||
encoder.encodeStructure(descriptor) {
|
||||
encodeIntElement(descriptor, 0, value.left)
|
||||
encodeIntElement(descriptor, 1, value.top)
|
||||
encodeIntElement(descriptor, 2, value.right)
|
||||
encodeIntElement(descriptor, 3, value.bottom)
|
||||
}
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): Rect {
|
||||
return decoder.decodeStructure(descriptor) {
|
||||
var left = 0
|
||||
var top = 0
|
||||
var right = 0
|
||||
var bottom = 0
|
||||
|
||||
while (true) {
|
||||
when (val index = decodeElementIndex(descriptor)) {
|
||||
0 -> left = decodeIntElement(descriptor, 0)
|
||||
1 -> top = decodeIntElement(descriptor, 1)
|
||||
2 -> right = decodeIntElement(descriptor, 2)
|
||||
3 -> bottom = decodeIntElement(descriptor, 3)
|
||||
CompositeDecoder.DECODE_DONE -> break
|
||||
else -> error("Unexpected index: $index")
|
||||
}
|
||||
}
|
||||
|
||||
Rect(left, top, right, bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Serializable
|
||||
data class SavedKeyboardSizingSettings(
|
||||
val currentMode: KeyboardMode,
|
||||
val heightMultiplier: Float,
|
||||
val paddingDp: @Serializable(RectSerializer::class) Rect,
|
||||
|
||||
// Split
|
||||
val splitWidthFraction: Float,
|
||||
|
||||
// One handed, values with respect to left handed mode
|
||||
// left = padding
|
||||
// right = width + padding
|
||||
// bottom = padding for bottom
|
||||
val oneHandedRectDp: @Serializable(RectSerializer::class) Rect,
|
||||
val oneHandedDirection: OneHandedDirection,
|
||||
|
||||
// Floating
|
||||
val floatingBottomCenterOriginDp: Pair<Float, Float>, // relative to bottom left of screen, .second is Y up
|
||||
val floatingWidthDp: Float,
|
||||
val floatingHeightDp: Float
|
||||
) {
|
||||
fun toJsonString(): String =
|
||||
Json.encodeToString(this)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromJsonString(s: String): SavedKeyboardSizingSettings? =
|
||||
try {
|
||||
Json.decodeFromString(s)
|
||||
} catch (e: Exception) {
|
||||
//e.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class KeyboardSizeSettingKind {
|
||||
Portrait,
|
||||
@ -31,117 +172,231 @@ enum class KeyboardSizeSettingKind {
|
||||
FoldableInnerDisplay
|
||||
}
|
||||
|
||||
val SplitKeyboardSettings = mapOf(
|
||||
KeyboardSizeSettingKind.Portrait to SettingsKey(
|
||||
booleanPreferencesKey("split_keyboard_portrait"), false),
|
||||
KeyboardSizeSettingKind.Landscape to SettingsKey(
|
||||
booleanPreferencesKey("split_keyboard_landscape"), true),
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay to SettingsKey(
|
||||
booleanPreferencesKey("split_keyboard_fold"), true),
|
||||
val DefaultKeyboardSettings = mapOf(
|
||||
KeyboardSizeSettingKind.Portrait to SavedKeyboardSizingSettings(
|
||||
currentMode = KeyboardMode.Regular,
|
||||
heightMultiplier = 1.0f,
|
||||
paddingDp = Rect(2, 4, 2, 10),
|
||||
splitWidthFraction = 4.0f / 5.0f,
|
||||
oneHandedDirection = OneHandedDirection.Right,
|
||||
oneHandedRectDp = Rect(4, 4, 364, 30),
|
||||
floatingBottomCenterOriginDp = Pair(0.0f, 0.0f),
|
||||
floatingHeightDp = 240.0f,
|
||||
floatingWidthDp = 360.0f
|
||||
),
|
||||
|
||||
KeyboardSizeSettingKind.Landscape to SavedKeyboardSizingSettings(
|
||||
currentMode = KeyboardMode.Split,
|
||||
heightMultiplier = 0.9f,
|
||||
paddingDp = Rect(8, 2, 8, 2),
|
||||
splitWidthFraction = 3.0f / 5.0f,
|
||||
oneHandedDirection = OneHandedDirection.Right,
|
||||
oneHandedRectDp = Rect(4, 4, 364, 30),
|
||||
floatingBottomCenterOriginDp = Pair(0.0f, 0.0f),
|
||||
floatingHeightDp = 240.0f,
|
||||
floatingWidthDp = 360.0f
|
||||
),
|
||||
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay to SavedKeyboardSizingSettings(
|
||||
currentMode = KeyboardMode.Split,
|
||||
heightMultiplier = 0.67f,
|
||||
paddingDp = Rect(44, 4, 44, 8),
|
||||
splitWidthFraction = 3.0f / 5.0f,
|
||||
oneHandedDirection = OneHandedDirection.Right,
|
||||
oneHandedRectDp = Rect(4, 4, 364, 30),
|
||||
floatingBottomCenterOriginDp = Pair(0.0f, 0.0f),
|
||||
floatingHeightDp = 240.0f,
|
||||
floatingWidthDp = 360.0f
|
||||
),
|
||||
)
|
||||
|
||||
val KeyboardHeightSettings = mapOf(
|
||||
val KeyboardSettings = mapOf(
|
||||
KeyboardSizeSettingKind.Portrait to SettingsKey(
|
||||
floatPreferencesKey("keyboardHeightMultiplier"), 1.0f),
|
||||
stringPreferencesKey("keyboard_settings_portrait"), ""),
|
||||
KeyboardSizeSettingKind.Landscape to SettingsKey(
|
||||
floatPreferencesKey("keyboard_height_landscape"), 0.9f),
|
||||
stringPreferencesKey("keyboard_settings_landscape"), ""),
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay to SettingsKey(
|
||||
floatPreferencesKey("keyboard_height_fold"), 0.67f),
|
||||
stringPreferencesKey("keyboard_settings_fold"), ""),
|
||||
)
|
||||
|
||||
val KeyboardOffsetSettings = mapOf(
|
||||
KeyboardSizeSettingKind.Portrait to SettingsKey(
|
||||
floatPreferencesKey("keyboard_offset_portrait"), 8.0f),
|
||||
KeyboardSizeSettingKind.Landscape to SettingsKey(
|
||||
floatPreferencesKey("keyboard_offset_landscape"), 0.0f),
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay to SettingsKey(
|
||||
floatPreferencesKey("keyboard_offset_fold"), 8.0f),
|
||||
)
|
||||
class KeyboardSizingCalculator(val context: Context, val uixManager: UixManager) {
|
||||
val sizeStateProvider = context as KeyboardSizeStateProvider
|
||||
val foldStateProvider = context as FoldStateProvider
|
||||
|
||||
val KeyboardSideInsetSettings = mapOf(
|
||||
KeyboardSizeSettingKind.Portrait to SettingsKey(
|
||||
floatPreferencesKey("keyboard_inset_portrait"), 2.0f),
|
||||
KeyboardSizeSettingKind.Landscape to SettingsKey(
|
||||
floatPreferencesKey("keyboard_inset_landscape"), 8.0f),
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay to SettingsKey(
|
||||
floatPreferencesKey("keyboard_inset_fold"), 44.0f),
|
||||
)
|
||||
private fun dp(v: Number): Int =
|
||||
(v.toFloat() * context.resources.displayMetrics.density).toInt()
|
||||
|
||||
private fun dp(v: Rect): Rect =
|
||||
Rect(dp(v.left), dp(v.top), dp(v.right), dp(v.bottom))
|
||||
|
||||
private fun limitFloating(rectPx: Rect): Rect {
|
||||
val width = rectPx.width()
|
||||
val height = rectPx.height()
|
||||
|
||||
val minWidth = dp(160)
|
||||
val minHeight = dp(160)
|
||||
|
||||
if(width < minWidth) {
|
||||
val delta = minWidth - width
|
||||
rectPx.left -= delta / 2
|
||||
rectPx.right += delta / 2
|
||||
}
|
||||
|
||||
if(height < minHeight) {
|
||||
val delta = minHeight - height
|
||||
rectPx.top -= delta
|
||||
rectPx.bottom += delta
|
||||
}
|
||||
|
||||
val maxWidth = context.resources.displayMetrics.widthPixels * 2 / 3
|
||||
val maxHeight = context.resources.displayMetrics.heightPixels * 2 / 3
|
||||
|
||||
if(width > maxWidth) {
|
||||
val delta = width - maxWidth
|
||||
rectPx.left += delta / 2
|
||||
rectPx.right -= delta / 2
|
||||
}
|
||||
|
||||
if(height > maxHeight) {
|
||||
val delta = height - maxHeight
|
||||
rectPx.top += delta / 2
|
||||
rectPx.bottom -= delta / 2
|
||||
}
|
||||
|
||||
|
||||
class KeyboardSizingCalculator(val context: Context) {
|
||||
private val sizeStateProvider = context as KeyboardSizeStateProvider
|
||||
private val foldStateProvider = context as FoldStateProvider
|
||||
val originX = rectPx.left
|
||||
val originY = rectPx.top
|
||||
|
||||
private fun isSplitKeyboard(mode: KeyboardSizeSettingKind): Boolean =
|
||||
context.getSettingBlocking(SplitKeyboardSettings[mode]!!)
|
||||
if(originX < 0){
|
||||
rectPx.left -= originX
|
||||
rectPx.right -= originX
|
||||
}
|
||||
|
||||
private fun heightMultiplier(mode: KeyboardSizeSettingKind): Float =
|
||||
context.getSettingBlocking(KeyboardHeightSettings[mode]!!)
|
||||
if(originY < 0) {
|
||||
rectPx.top -= originY
|
||||
rectPx.bottom -= originY
|
||||
}
|
||||
|
||||
private fun bottomOffsetPx(mode: KeyboardSizeSettingKind): Int =
|
||||
(context.getSettingBlocking(KeyboardOffsetSettings[mode]!!) * context.resources.displayMetrics.density).toInt()
|
||||
if(rectPx.right > context.resources.displayMetrics.widthPixels) {
|
||||
val delta = rectPx.right - context.resources.displayMetrics.widthPixels
|
||||
rectPx.right -= delta
|
||||
rectPx.left -= delta
|
||||
}
|
||||
if(rectPx.bottom < 0) {
|
||||
val delta = rectPx.bottom
|
||||
rectPx.top -= delta
|
||||
rectPx.bottom -= delta
|
||||
}
|
||||
|
||||
private fun sideInsetPx(mode: KeyboardSizeSettingKind): Int =
|
||||
(context.getSettingBlocking(KeyboardSideInsetSettings[mode]!!) * context.resources.displayMetrics.density).toInt()
|
||||
return rectPx
|
||||
}
|
||||
|
||||
private fun topPaddingPx(mode: KeyboardSizeSettingKind): Int =
|
||||
(when(mode) {
|
||||
KeyboardSizeSettingKind.Portrait -> 4.0f
|
||||
KeyboardSizeSettingKind.Landscape -> 0.0f
|
||||
KeyboardSizeSettingKind.FoldableInnerDisplay -> 8.0f
|
||||
} * context.resources.displayMetrics.density).toInt()
|
||||
fun getSavedSettings(): SavedKeyboardSizingSettings =
|
||||
SavedKeyboardSizingSettings.fromJsonString(context.getSettingBlocking(
|
||||
KeyboardSettings[sizeStateProvider.currentSizeState]!!
|
||||
)) ?: DefaultKeyboardSettings[sizeStateProvider.currentSizeState]!!
|
||||
|
||||
fun editSavedSettings(transform: (SavedKeyboardSizingSettings) -> SavedKeyboardSizingSettings) {
|
||||
val sizeState = sizeStateProvider.currentSizeState
|
||||
|
||||
val savedSettings = SavedKeyboardSizingSettings.fromJsonString(context.getSettingBlocking(
|
||||
KeyboardSettings[sizeState]!!
|
||||
)) ?: DefaultKeyboardSettings[sizeState]!!
|
||||
|
||||
val transformed = transform(savedSettings)
|
||||
|
||||
if(transformed != savedSettings) {
|
||||
context.setSettingBlocking(KeyboardSettings[sizeState]!!.key, transformed.toJsonString())
|
||||
}
|
||||
}
|
||||
|
||||
fun calculate(layoutName: String, isNumberRowActive: Boolean): ComputedKeyboardSize {
|
||||
val savedSettings = getSavedSettings()
|
||||
|
||||
val layout = LayoutManager.getLayout(context, layoutName)
|
||||
val effectiveRowCount = layout.effectiveRows.size
|
||||
|
||||
val configuration = context.resources.configuration
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
println("Display metrics ${displayMetrics.widthPixels / displayMetrics.density}")
|
||||
|
||||
val mode = sizeStateProvider.currentSizeState
|
||||
|
||||
val isSplit = isSplitKeyboard(mode)
|
||||
val heightMultiplier = heightMultiplier(mode)
|
||||
val bottomOffset = bottomOffsetPx(mode)
|
||||
val sideInset = sideInsetPx(mode)
|
||||
val topPadding = topPaddingPx(mode)
|
||||
|
||||
val singularRowHeight = (ResourceUtils.getDefaultKeyboardHeight(context.resources) / 4.0) * heightMultiplier
|
||||
val singularRowHeight = (ResourceUtils.getDefaultKeyboardHeight(context.resources) / 4.0) *
|
||||
savedSettings.heightMultiplier
|
||||
|
||||
val numRows = 4.0 +
|
||||
((effectiveRowCount - 5) / 2.0).coerceAtLeast(0.0) +
|
||||
if(isNumberRowActive) { 0.5 } else { 0.0 }
|
||||
|
||||
println("Num rows; $numRows, $effectiveRowCount ($layoutName) ($layout)")
|
||||
|
||||
val recommendedHeight = numRows * singularRowHeight
|
||||
|
||||
|
||||
val foldState = foldStateProvider.foldState.feature
|
||||
|
||||
val window = (context as LatinIME).window.window
|
||||
val width = ResourceUtils.getDefaultKeyboardWidth(window, context.resources)
|
||||
|
||||
return when {
|
||||
// Special case: 50% screen height no matter the row count or settings
|
||||
foldState != null && foldState.state == FoldingFeature.State.HALF_OPENED && foldState.orientation == FoldingFeature.Orientation.HORIZONTAL ->
|
||||
SplitKeyboardSize(
|
||||
displayMetrics.heightPixels / 2 - (displayMetrics.density * 80.0f).toInt(),
|
||||
Rect(
|
||||
height = displayMetrics.heightPixels / 2 - (displayMetrics.density * 80.0f).toInt(),
|
||||
width = width,
|
||||
padding = Rect(
|
||||
(displayMetrics.density * 44.0f).roundToInt(),
|
||||
(displayMetrics.density * 20.0f).roundToInt(),
|
||||
(displayMetrics.density * 50.0f).roundToInt(),
|
||||
(displayMetrics.density * 44.0f).roundToInt(),
|
||||
(displayMetrics.density * 12.0f).roundToInt(),
|
||||
),
|
||||
displayMetrics.widthPixels * 3 / 5
|
||||
splitLayoutWidth = displayMetrics.widthPixels * 3 / 5
|
||||
)
|
||||
|
||||
isSplit -> SplitKeyboardSize(
|
||||
recommendedHeight.roundToInt(),
|
||||
Rect(sideInset, topPadding, sideInset, bottomOffset),
|
||||
displayMetrics.widthPixels * 3 / 5)
|
||||
savedSettings.currentMode == KeyboardMode.Split ->
|
||||
SplitKeyboardSize(
|
||||
height = recommendedHeight.roundToInt(),
|
||||
width = width,
|
||||
padding = dp(savedSettings.paddingDp),
|
||||
splitLayoutWidth = (displayMetrics.widthPixels * savedSettings.splitWidthFraction).toInt()
|
||||
)
|
||||
|
||||
else -> RegularKeyboardSize(
|
||||
recommendedHeight.roundToInt(),
|
||||
Rect(sideInset, topPadding, sideInset, bottomOffset),
|
||||
)
|
||||
savedSettings.currentMode == KeyboardMode.OneHanded ->
|
||||
OneHandedKeyboardSize(
|
||||
height = recommendedHeight.roundToInt(),
|
||||
width = width,
|
||||
padding = dp(savedSettings.oneHandedRectDp).let { rect ->
|
||||
when(savedSettings.oneHandedDirection) {
|
||||
OneHandedDirection.Left -> Rect(rect.left, rect.top, rect.left, rect.bottom)
|
||||
OneHandedDirection.Right -> Rect(rect.left, rect.top, rect.left, rect.bottom)
|
||||
}
|
||||
},
|
||||
layoutWidth = dp(savedSettings.oneHandedRectDp.width()).coerceAtMost(displayMetrics.widthPixels * 9 / 10),
|
||||
direction = savedSettings.oneHandedDirection
|
||||
)
|
||||
|
||||
savedSettings.currentMode == KeyboardMode.Floating -> {
|
||||
val singularRowHeightFloat = dp(savedSettings.floatingHeightDp) / 4.0f
|
||||
val recommendedHeightFloat = singularRowHeightFloat * numRows
|
||||
FloatingKeyboardSize(
|
||||
bottomOrigin = Pair(
|
||||
dp(savedSettings.floatingBottomCenterOriginDp.first),
|
||||
dp(savedSettings.floatingBottomCenterOriginDp.second)
|
||||
),
|
||||
width = dp(savedSettings.floatingWidthDp),
|
||||
height = recommendedHeightFloat.toInt(),
|
||||
decorationPadding = dp(
|
||||
Rect(
|
||||
8,
|
||||
8,
|
||||
8,
|
||||
8
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else ->
|
||||
RegularKeyboardSize(
|
||||
height = recommendedHeight.roundToInt(),
|
||||
width = width,
|
||||
padding = dp(savedSettings.paddingDp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,4 +410,14 @@ class KeyboardSizingCalculator(val context: Context) {
|
||||
|
||||
return (minDp / 100.0f).coerceIn(3.0f, 6.0f)
|
||||
}
|
||||
|
||||
fun calculateSuggestionBarHeightDp(): Float {
|
||||
return 40.0f
|
||||
}
|
||||
|
||||
fun calculateTotalActionBarHeightPx(): Int =
|
||||
when {
|
||||
uixManager.actionsExpanded -> dp(2 * calculateSuggestionBarHeightDp())
|
||||
else -> dp(calculateSuggestionBarHeightDp())
|
||||
}
|
||||
}
|
@ -81,10 +81,8 @@ data class LayoutRow(
|
||||
)
|
||||
|
||||
data class LayoutParams(
|
||||
val size: ComputedKeyboardSize,
|
||||
val gap: Dp,
|
||||
val useSplitLayout: Boolean,
|
||||
val splitLayoutWidth: Int,
|
||||
val padding: Rect,
|
||||
val standardRowHeight: Double,
|
||||
val element: KeyboardLayoutElement,
|
||||
)
|
||||
@ -131,8 +129,6 @@ data class LayoutEngine(
|
||||
}
|
||||
|
||||
private fun computeRowHeight(): Double {
|
||||
//val normalKeyboardHeight = ((rowHeight.value + verticalGap.value) * density) * 3
|
||||
|
||||
val normalKeyboardHeight = totalRowHeight
|
||||
|
||||
// divide by total row height
|
||||
@ -140,19 +136,29 @@ data class LayoutEngine(
|
||||
BottomRowHeightMode.Fixed -> ((normalKeyboardHeight - layoutParams.standardRowHeight) / rows.filter { !it.isBottomRow }.sumOf { it.rowHeight })
|
||||
BottomRowHeightMode.Flexible -> (normalKeyboardHeight) / rows.sumOf { it.rowHeight }
|
||||
}
|
||||
//return ((normalKeyboardHeight - bottomRowHeightPx) / rows.filter { !it.isBottomRow }.sumOf { it.rowHeight })
|
||||
//return (normalKeyboardHeight) / rows.sumOf { it.rowHeight }
|
||||
}
|
||||
|
||||
private val isSplitLayout = layoutParams.useSplitLayout
|
||||
private val isSplitLayout = layoutParams.size is SplitKeyboardSize
|
||||
private val isOneHandedLayout = layoutParams.size is OneHandedKeyboardSize
|
||||
|
||||
private val layoutWidth = if(isSplitLayout) {
|
||||
layoutParams.splitLayoutWidth
|
||||
(layoutParams.size as SplitKeyboardSize).splitLayoutWidth
|
||||
} else if(isOneHandedLayout) {
|
||||
(layoutParams.size as OneHandedKeyboardSize).layoutWidth
|
||||
} else {
|
||||
params.mId.mWidth
|
||||
}
|
||||
|
||||
private val unsplitLayoutWidth = params.mId.mWidth
|
||||
private val unsplitLayoutWidth = if(isSplitLayout) {
|
||||
params.mId.mWidth
|
||||
} else {
|
||||
layoutWidth
|
||||
}
|
||||
|
||||
// TODO: Remove
|
||||
private val padding = Rect(0, 0, 0, 0)
|
||||
private val xOffset = 0
|
||||
|
||||
private val minimumBottomFunctionalKeyWidth = (layoutWidth * keyboard.minimumBottomRowFunctionalKeyWidth)
|
||||
|
||||
private val regularKeyWidth = computeRegularKeyWidth()
|
||||
@ -551,10 +557,10 @@ data class LayoutEngine(
|
||||
}
|
||||
|
||||
private fun addRowAlignLeft(row: List<LayoutEntry>, y: Int, height: Int)
|
||||
= addRow(row, 0.0f + layoutParams.padding.left, y, height)
|
||||
= addRow(row, 0.0f + padding.left + xOffset, y, height)
|
||||
|
||||
private fun addRowAlignRight(row: List<LayoutEntry>, y: Int, height: Int) {
|
||||
val startingOffset = params.mId.mWidth - row.sumOf { it.widthPx.toDouble() }.toFloat() + layoutParams.padding.left
|
||||
val startingOffset = params.mId.mWidth - row.sumOf { it.widthPx.toDouble() }.toFloat() + padding.left
|
||||
addRow(row, startingOffset, y, height)
|
||||
}
|
||||
|
||||
@ -570,7 +576,7 @@ data class LayoutEngine(
|
||||
}
|
||||
|
||||
private fun addKeys(rows: List<LayoutRow>): Int {
|
||||
var currentY = 0.0f + layoutParams.padding.top
|
||||
var currentY = 0.0f + padding.top
|
||||
rows.forEach { row ->
|
||||
addRow(row, currentY.toInt())
|
||||
currentY += row.height
|
||||
@ -588,14 +594,14 @@ data class LayoutEngine(
|
||||
|
||||
val rows = computeRows(this.rows)
|
||||
|
||||
val totalKeyboardHeight = addKeys(rows).let { totalRowHeight.roundToInt() } + layoutParams.padding.top + layoutParams.padding.bottom
|
||||
val totalKeyboardHeight = addKeys(rows).let { totalRowHeight.roundToInt() } + padding.top + padding.bottom
|
||||
|
||||
params.mOccupiedHeight = totalKeyboardHeight - verticalGapPx.roundToInt()
|
||||
params.mOccupiedWidth = params.mId.mWidth + layoutParams.padding.left + layoutParams.padding.right
|
||||
params.mTopPadding = 0//layoutParams.padding.top
|
||||
params.mBottomPadding = 0//layoutParams.padding.bottom
|
||||
params.mLeftPadding = 0//layoutParams.padding.left
|
||||
params.mRightPadding = 0//layoutParams.padding.right
|
||||
params.mOccupiedWidth = params.mId.mWidth + padding.left + padding.right
|
||||
params.mTopPadding = 0
|
||||
params.mBottomPadding = 0
|
||||
params.mLeftPadding = 0
|
||||
params.mRightPadding = 0
|
||||
|
||||
params.mBaseWidth = params.mOccupiedWidth
|
||||
params.mDefaultKeyWidth = regularKeyWidth.roundToInt()
|
||||
|
@ -33,7 +33,7 @@ object LayoutManager {
|
||||
|
||||
private fun getAllLayoutPaths(assetManager: AssetManager): List<String> {
|
||||
return listFilesRecursively(assetManager, "layouts").filter {
|
||||
(it.endsWith(".yml") || it.endsWith(".yaml")) && it != "mapping.yaml"
|
||||
(it.endsWith(".yml") || it.endsWith(".yaml")) && it != "layouts/mapping.yaml"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user