0
0
mirror of https://github.com/florisboard/florisboard.git synced 2024-09-20 03:52:18 +02:00

Move abstract definitions to own namespace and document them

This commit is contained in:
Patrick Goldinger 2021-04-30 18:36:34 +02:00
parent 3de07c30c6
commit fd00c2fa4c
31 changed files with 555 additions and 236 deletions

View File

@ -12,8 +12,8 @@ import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
import dev.patrickgold.florisboard.ime.core.InputView
import dev.patrickgold.florisboard.ime.text.key.AutoTextKeyData
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.keyboard.BasicTextKeyData
import kotlinx.coroutines.*
import kotlin.math.pow
@ -135,8 +135,8 @@ class ClipboardInputManager private constructor() : CoroutineScope by MainScope(
event ?: return false
val data = when (view.id) {
R.id.back_to_keyboard_button -> AutoTextKeyData(code = KeyCode.SWITCH_TO_TEXT_CONTEXT)
R.id.clear_clipboard_history -> AutoTextKeyData(code = KeyCode.CLEAR_CLIPBOARD_HISTORY)
R.id.back_to_keyboard_button -> BasicTextKeyData(code = KeyCode.SWITCH_TO_TEXT_CONTEXT)
R.id.clear_clipboard_history -> BasicTextKeyData(code = KeyCode.CLEAR_CLIPBOARD_HISTORY)
else -> null
} ?: return false

View File

@ -43,6 +43,7 @@ import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.debug.*
import dev.patrickgold.florisboard.ime.clip.ClipboardInputManager
import dev.patrickgold.florisboard.ime.clip.FlorisClipboardManager
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.landscapeinput.LandscapeInputUiMode
import dev.patrickgold.florisboard.ime.media.MediaInputManager
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
@ -51,6 +52,7 @@ import dev.patrickgold.florisboard.ime.text.TextInputManager
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.setup.SetupActivity

View File

@ -19,7 +19,7 @@ package dev.patrickgold.florisboard.ime.core
import android.os.SystemClock
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.TextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import timber.log.Timber

View File

@ -18,7 +18,14 @@ package dev.patrickgold.florisboard.ime.extension
import android.content.Context
import android.net.Uri
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.keyboard.CaseSelector
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.keyboard.VariationSelector
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.AutoTextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.BasicTextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.MultiTextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.keyboard
import android.graphics.Rect
/**
* Abstract class describing the smallest computed unit in a computed keyboard. Each key represents exactly one key
* displayed in the UI. It allows to save the absolute location within the parent keyboard, save touch and visual
* bounds, managing the state (enabled, pressed, visibility) as well as layout sizing factors. Each key in this IME
* inherits from this base key class. This allows for a inter-operable usage of a key without knowing the exact
* subclass upfront.
*
* @property data The base key data this key represents.This can be anything - from a basic text key to an emoji key
* to a complex selector.
*/
abstract class Key(open val data: KeyData) {
/**
* Specifies whether this key is enabled or not.
*/
open var isEnabled: Boolean = true
/**
* Specifies whether this key is actively pressed or not. Is used by the parent keyboard view to draw the key
* differently to indicate this state.
*/
open var isPressed: Boolean = false
/**
* Specifies whether this key is visible or not. Is used by the parent keyboard view to omit this key in the
* layout and drawing process. A `false`-value is equivalent to `VISIBILITY_GONE` on Android's View class.
*/
open var isVisible: Boolean = true
/**
* The touch bounds of this key. All bounds defined here are absolute coordinates within the parent keyboard.
*/
open val touchBounds: Rect = Rect()
/**
* The visible bounds of this key. All bounds defined here are absolute coordinates within the parent keyboard.
*/
open val visibleBounds: Rect = Rect()
/**
* The visible drawable bounds of this key. All bounds defined here are absolute coordinates within the parent
* keyboard.
*/
open val visibleDrawableBounds: Rect = Rect()
/**
* The visible label bounds of this key. All bounds defined here are absolute coordinates within the parent
* keyboard.
*/
open val visibleLabelBounds: Rect = Rect()
/**
* Specifies how much this key is willing to shrink if too many keys are in a keyboard row. A value of 0.0
* indicates that the key does not want to shrink in such scenario. This value should not be set manually, only
* by the key's compute method and is used in the layout process to determine the real key width.
*/
open var flayShrink: Double = 0.0
/**
* Specifies how much this key is willing to grow if too few keys are in a keyboard row. A value of 0.0
* indicates that the key does not want to grow in such scenario. This value should not be set manually, only
* by the key's compute method and is used in the layout process to determine the real key width.
*/
open var flayGrow: Double = 0.0
/**
* Specifies the relative proportional width this key aims to get in respective to the keyboard view's desired key
* width. A value of 1.0 indicates that the key wants to be exactly as wide as the desired key width, a value of
* 0.0 is basically equivalent to setting [isVisible] to false. This value should not be set manually, only
* by the key's compute method and is used in the layout process to determine the real key width.
*/
open var flayWidthFactor: Double = 0.0
/**
* The computed UI label of this key. This value is used by the keyboard view to temporarily save the label string
* for UI rendering and should not be set manually.
*/
open var label: String? = null
/**
* The computed UI hint label of this key. This value is used by the keyboard view to temporarily save the hint
* label string for UI rendering and should not be set manually.
*/
open var hintedLabel: String? = null
/**
* The computed UI drawable ID of this key. This value is used by the keyboard view to temporarily save the
* drawable ID for UI rendering and should not be set manually.
*/
open var foregroundDrawableId: Int? = null
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.keyboard
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.ime.text.keyboard.TextComputingEvaluator
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Basic interface for a key data object. Base for all key data objects across the IME, such as text, emojis and
* selectors. The implementation is as abstract as possible, as different features require different implementations.
*/
interface KeyData {
/**
* Computes a [TextKeyData] object for this key data. Returns null if no computation is possible or if the key is
* not relevant based on the result of [evaluator].
*
* @param evaluator The evaluator used to retrieve different states from the parent controller.
*
* @return A [TextKeyData] object or null if no computation is possible.
*/
fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData?
/**
* Returns the data described by this key as a string.
*
* @param isForDisplay Specifies if the returned string is intended to be displayed in a UI label (=true) or if
* it should be computed to be sent to an input connection (=false).
*
* @return The computed string for the key data object. Note: some objects may return an empty string here, meaning
* it is always required to check for the string's length before attempting to directly retrieve the first char.
*/
fun asString(isForDisplay: Boolean): String
}
/**
* Allows to select a [KeyData] based on the current caps state. Note that this type of selector only really makes
* sense in a text context, though technically speaking it can be used anywhere, so this implementation allows for
* any [KeyData] to be used here. The JSON class identifier for this selector is `case_selector`.
*
* Example usage in a layout JSON file:
* ```
* { "$": "case_selector",
* "lower": { "code": 59, "label": ";" },
* "upper": { "code": 58, "label": ":" }
* }
* ```
*
* @property lower The property to use if the current caps state is lowercase.
* @property upper The property to use if the current caps state is uppercase.
*/
@Serializable
@SerialName("case_selector")
class CaseSelector(
val lower: KeyData,
val upper: KeyData,
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return (if (evaluator.evaluateCaps()) { upper } else { lower }).computeTextKeyData(evaluator)
}
override fun asString(isForDisplay: Boolean): String {
return ""
}
}
/**
* Allows to select a [KeyData] based on the current key variation. Note that this type of selector only really makes
* sense in a text context, though technically speaking it can be used anywhere, so this implementation allows for
* any [KeyData] to be used here. The JSON class identifier for this selector is `variation_selector`.
*
* Example usage in a layout JSON file:
* ```
* { "$": "variation_selector",
* "default": { "code": 44, "label": "," },
* "email": { "code": 64, "label": "@" },
* "uri": { "code": 47, "label": "/" }
* }
* ```
*
* @property default The default [KeyData] which should be used in case no key variation is known or for the current
* key variation no override key is defined.
* @property email The key data to use if [KeyVariation.EMAIL_ADDRESS] is the active key variation. If this value is
* null, [default] will be used instead.
* @property uri The key data to use if [KeyVariation.URI] is the active key variation. If this value is null,
* [default] will be used instead.
* @property normal The key data to use if [KeyVariation.NORMAL] is the active key variation. If this value is null,
* [default] will be used instead.
* @property password The key data to use if [KeyVariation.PASSWORD] is the active key variation. If this value is
* null, [default] will be used instead.
*/
@Serializable
@SerialName("variation_selector")
data class VariationSelector(
val default: KeyData,
val email: KeyData? = null,
val uri: KeyData? = null,
val normal: KeyData? = null,
val password: KeyData? = null,
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return when (evaluator.getKeyVariation()) {
KeyVariation.ALL -> default
KeyVariation.EMAIL_ADDRESS -> email ?: default
KeyVariation.NORMAL -> normal ?: default
KeyVariation.PASSWORD -> password ?: default
KeyVariation.URI -> uri ?: default
}.computeTextKeyData(evaluator)
}
override fun asString(isForDisplay: Boolean): String {
return ""
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.keyboard
/**
* Abstract class describing a computed keyboard. The exact implementation is dependent on the subclass and the
* structure can vary quite much between different subclasses.
*/
abstract class Keyboard {
/**
* Returns the key for given [pointerX] and [pointerY] coords or null if no key touch hit box is defined at the
* given coords.
*
* @param pointerX The x-coordinate of the input event, absolute within the parent keyboard view.
* @param pointerY The y-coordinate of the input event, absolute within the parent keyboard view.
*
* @return The key for given coords or null if no key touch hit box is defined for this position.
*/
abstract fun getKeyForPos(pointerX: Int, pointerY: Int): Key?
/**
* Returns an iterator which allows to loop through all keys within the layout, independent of the actual
* structure and layout.
*/
abstract fun keys(): Iterator<Key>
/**
* Layouts the keys according the the dimensions and parameters provided by given [keyboardView]. This method's
* exact behavior is highly dependent aon the actual subclass.
*
* @param keyboardView The parent keyboard view which is used to gather the absolute dimensions and other
* subclass specific parameters.
*/
abstract fun layout(keyboardView: KeyboardView)
}

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.keyboard
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.sendBlocking
@Suppress("MemberVisibilityCanBePrivate")
abstract class KeyboardView : View, ThemeManager.OnThemeUpdatedListener {
protected val florisboard: FlorisBoard?
get() = FlorisBoard.getInstanceOrNull()
protected val prefs: PrefHelper
get() = PrefHelper.getDefaultInstance(context)
protected val themeManager: ThemeManager?
get() = ThemeManager.defaultOrNull()
protected var isTouchable: Boolean = true
protected val touchEventChannel: Channel<MotionEvent> = Channel(16)
protected val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())
constructor(context: Context) : this(context, null)
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
init {
mainScope.launch {
for (event in touchEventChannel) {
if (!isActive) break
onTouchEventInternal(event)
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
themeManager?.registerOnThemeUpdatedListener(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
themeManager?.unregisterOnThemeUpdatedListener(this)
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
event ?: return false
if (!isTouchable) return false
when (event.actionMasked) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN,
MotionEvent.ACTION_MOVE,
MotionEvent.ACTION_POINTER_UP,
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
touchEventChannel.sendBlocking(event)
return true
}
}
return false
}
protected abstract fun onTouchEventInternal(event: MotionEvent)
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
onLayoutInternal()
}
protected abstract fun onLayoutInternal()
}

View File

@ -26,11 +26,11 @@ import dev.patrickgold.florisboard.ime.core.EditorInstance
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
import dev.patrickgold.florisboard.ime.core.InputView
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKeyData
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKeyboardView
import dev.patrickgold.florisboard.ime.media.emoticon.EmoticonKeyData
import dev.patrickgold.florisboard.ime.media.emoticon.EmoticonKeyboardView
import dev.patrickgold.florisboard.ime.text.key.EmojiKeyData
import dev.patrickgold.florisboard.ime.text.key.TextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.coroutines.*
import timber.log.Timber
import java.util.*

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.media.emoji
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.popup.PopupSet
class EmojiKey(override val data: KeyData) : Key(data) {
var computedData: EmojiKeyData = EmojiKeyData(listOf())
private set
var computedPopups: PopupSet<EmojiKeyData> = PopupSet()
private set
fun dummyCompute() {
computedData = data as? EmojiKeyData ?: computedData
computedPopups = PopupSet(relevant = (data as? EmojiKeyData)?.popup ?: listOf())
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2021 Patrick Goldinger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.media.emoji
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextComputingEvaluator
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Data class for a single emoji (with possible emoji variants in [popup]). The JSON class identifier for this selector
* is `emoji_key`.
*
* @property codePoints The code points of the emoji.
* @property asString The name of the emoji.
* @property popup List of possible variants of the emoji.
*/
@Serializable
@SerialName("emoji_key")
class EmojiKeyData(
val codePoints: List<Int>,
val label: String = "",
val popup: MutableList<EmojiKeyData> = mutableListOf()
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return null
}
override fun asString(isForDisplay: Boolean): String {
return StringBuilder().run {
for (codePoint in codePoints) {
append(Character.toChars(codePoint))
}
toString()
}
}
override fun toString(): String {
return "${EmojiKeyData::class.simpleName}"// { code=$code label=\"$label\" }"
}
}

View File

@ -25,14 +25,10 @@ import android.view.Gravity
import android.view.MotionEvent
import android.widget.ScrollView
import androidx.core.content.ContextCompat
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.ime.text.key.EmojiKeyData
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.keyboard.EmojiKey
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import kotlinx.coroutines.CoroutineScope

View File

@ -32,7 +32,6 @@ import com.google.android.material.tabs.TabLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.popup.PopupManager
import dev.patrickgold.florisboard.ime.text.keyboard.EmojiKey
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import kotlinx.coroutines.*

View File

@ -20,7 +20,6 @@ import android.content.Context
import android.graphics.Paint
import android.graphics.Typeface
import androidx.core.graphics.PaintCompat
import dev.patrickgold.florisboard.ime.text.key.EmojiKeyData
import timber.log.Timber
import java.io.BufferedReader
import java.io.IOException

View File

@ -27,7 +27,7 @@ import android.widget.LinearLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.media.MediaInputManager
import dev.patrickgold.florisboard.ime.text.key.AutoTextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.util.getColorFromAttr
/**
@ -68,7 +68,7 @@ class EmoticonKeyView : androidx.appcompat.widget.AppCompatTextView {
MotionEvent.ACTION_DOWN -> {
setBackgroundColor(getColorFromAttr(context, R.attr.semiTransparentColor))
florisboard.keyPressVibrate()
florisboard.keyPressSound(AutoTextKeyData())
florisboard.keyPressSound(TextKeyData.UNSPECIFIED)
}
MotionEvent.ACTION_UP -> {
setBackgroundColor(Color.TRANSPARENT)

View File

@ -27,7 +27,7 @@ import android.view.Gravity
import android.view.View
import android.widget.FrameLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.util.ViewLayoutUtils

View File

@ -18,7 +18,7 @@ package dev.patrickgold.florisboard.ime.popup
import dev.patrickgold.florisboard.ime.extension.Asset
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.ime.text.key.TextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.serialization.Serializable
/**

View File

@ -22,12 +22,12 @@ import android.view.MotionEvent
import android.view.View
import androidx.core.content.ContextCompat.getDrawable
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKey
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKeyData
import dev.patrickgold.florisboard.ime.media.emoji.EmojiKeyboardView
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.text.keyboard.EmojiKey
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import dev.patrickgold.florisboard.ime.text.keyboard.TextKey
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboardView
import dev.patrickgold.florisboard.ime.text.keyboard.*
/**
* Manages the creation and dismissal of key popups as well as the checks if the pointer moved

View File

@ -16,7 +16,7 @@
package dev.patrickgold.florisboard.ime.popup
import dev.patrickgold.florisboard.ime.text.key.KeyData
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.text.key.KeyHintMode
import dev.patrickgold.florisboard.ime.text.keyboard.TextComputingEvaluator
import kotlinx.serialization.Serializable

View File

@ -27,7 +27,7 @@ import android.view.View
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.util.ViewLayoutUtils

View File

@ -42,7 +42,6 @@ import dev.patrickgold.florisboard.ime.text.layout.LayoutManager
import dev.patrickgold.florisboard.ime.text.smartbar.SmartbarView
import kotlinx.coroutines.*
import org.json.JSONArray
import java.util.*
import kotlin.math.roundToLong
/**

View File

@ -33,7 +33,7 @@ import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.InputKeyEvent
import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.TextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.ime.theme.ThemeValue

View File

@ -1,7 +1,7 @@
package dev.patrickgold.florisboard.ime.text.gestures
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.Key
/**
* Inherit this to be able to handle gesture typing. Takes in raw pointer data, and

View File

@ -6,8 +6,8 @@ import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.extension.AssetManager
import dev.patrickgold.florisboard.ime.extension.AssetRef
import dev.patrickgold.florisboard.ime.extension.AssetSource
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.text.TextInputManager
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import kotlinx.coroutines.*
import org.json.JSONObject

View File

@ -3,7 +3,7 @@ package dev.patrickgold.florisboard.ime.text.gestures
import android.util.SparseArray
import androidx.collection.LruCache
import dev.patrickgold.florisboard.ime.core.Subtype
import dev.patrickgold.florisboard.ime.text.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.Key
import java.text.Normalizer
import java.util.*
import kotlin.collections.HashMap

View File

@ -16,6 +16,8 @@
package dev.patrickgold.florisboard.ime.text.key
import dev.patrickgold.florisboard.ime.text.keyboard.BasicTextKeyData
import dev.patrickgold.florisboard.ime.text.keyboard.TextKeyData
import kotlinx.serialization.Serializable
import kotlin.math.abs

View File

@ -16,30 +16,12 @@
package dev.patrickgold.florisboard.ime.text.keyboard
import android.graphics.Rect
import dev.patrickgold.florisboard.ime.keyboard.Key
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.popup.MutablePopupSet
import dev.patrickgold.florisboard.ime.popup.PopupSet
import dev.patrickgold.florisboard.ime.text.key.*
abstract class Key(open val data: KeyData) {
open var isEnabled: Boolean = true
open var isPressed: Boolean = false
open var isVisible: Boolean = true
open val touchBounds: Rect = Rect()
open val visibleBounds: Rect = Rect()
open val visibleDrawableBounds: Rect = Rect()
open val visibleLabelBounds: Rect = Rect()
open var flayShrink: Double = 0.0
open var flayGrow: Double = 0.0
open var flayWidthFactor: Double = 0.0
open var label: String? = null
open var hintedLabel: String? = null
open var foregroundDrawableId: Int? = null
}
class TextKey(override val data: KeyData) : Key(data) {
var computedData: TextKeyData = TextKeyData.UNSPECIFIED
private set
@ -169,15 +151,3 @@ class TextKey(override val data: KeyData) : Key(data) {
}
}
}
class EmojiKey(override val data: KeyData) : Key(data) {
var computedData: EmojiKeyData = EmojiKeyData(listOf())
private set
var computedPopups: PopupSet<EmojiKeyData> = PopupSet()
private set
fun dummyCompute() {
computedData = data as? EmojiKeyData ?: computedData
computedPopups = PopupSet(relevant = (data as? EmojiKeyData)?.popup ?: listOf())
}
}

View File

@ -14,19 +14,15 @@
* limitations under the License.
*/
package dev.patrickgold.florisboard.ime.text.key
package dev.patrickgold.florisboard.ime.text.keyboard
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.popup.PopupSet
import dev.patrickgold.florisboard.ime.text.keyboard.TextComputingEvaluator
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.KeyType
import kotlinx.serialization.*
import java.util.*
interface KeyData {
fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData?
fun asString(isForDisplay: Boolean): String
}
interface TextKeyData : KeyData {
val type: KeyType
val code: Int
@ -387,73 +383,3 @@ class MultiTextKeyData(
return "${AutoTextKeyData::class.simpleName} { type=$type code=$code label=\"$label\" groupId=$groupId }"
}
}
/**
* Data class for a single emoji (with possible emoji variants in [popup]).
*
* @property codePoints The code points of the emoji.
* @property asString The name of the emoji.
* @property popup List of possible variants of the emoji.
*/
@Serializable
@SerialName("emoji_key")
class EmojiKeyData(
val codePoints: List<Int>,
val label: String = "",
val popup: MutableList<EmojiKeyData> = mutableListOf()
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return null
}
override fun asString(isForDisplay: Boolean): String {
var ret = ""
for (codePoint in codePoints) {
ret += String(Character.toChars(codePoint))
}
return ret
}
override fun toString(): String {
return "EmojiKeyData"// { code=$code label=\"$label\" }"
}
}
@Serializable
@SerialName("case_selector")
class CaseSelector(
val lower: KeyData,
val upper: KeyData
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return (if (evaluator.evaluateCaps()) { upper } else { lower }).computeTextKeyData(evaluator)
}
override fun asString(isForDisplay: Boolean): String {
return ""
}
}
@Serializable
@SerialName("variation_selector")
data class VariationSelector(
val default: KeyData,
val email: KeyData? = null,
val normal: KeyData? = null,
val password: KeyData? = null,
val uri: KeyData? = null,
) : KeyData {
override fun computeTextKeyData(evaluator: TextComputingEvaluator): TextKeyData? {
return when (evaluator.getKeyVariation()) {
KeyVariation.ALL -> default
KeyVariation.EMAIL_ADDRESS -> email ?: default
KeyVariation.NORMAL -> normal ?: default
KeyVariation.PASSWORD -> password ?: default
KeyVariation.URI -> uri ?: default
}.computeTextKeyData(evaluator)
}
override fun asString(isForDisplay: Boolean): String {
return ""
}
}

View File

@ -17,17 +17,13 @@
package dev.patrickgold.florisboard.ime.text.keyboard
import android.graphics.Rect
import dev.patrickgold.florisboard.ime.keyboard.Keyboard
import dev.patrickgold.florisboard.ime.keyboard.KeyboardView
import dev.patrickgold.florisboard.ime.popup.PopupMapping
import dev.patrickgold.florisboard.ime.text.key.KeyCode
import kotlin.math.abs
import kotlin.math.roundToInt
abstract class Keyboard {
abstract fun getKeyForPos(pointerX: Int, pointerY: Int): Key?
abstract fun keys(): Iterator<Key>
}
class TextKeyboard(
val arrangement: Array<Array<TextKey>>,
val mode: KeyboardMode,
@ -84,8 +80,8 @@ class TextKeyboard(
return null
}
fun layout(keyboardView: TextKeyboardView) {
if (arrangement.isEmpty()) return
override fun layout(keyboardView: KeyboardView) {
if (arrangement.isEmpty() || keyboardView !is TextKeyboardView) return
val desiredTouchBounds = keyboardView.desiredKey.touchBounds
val desiredVisibleBounds = keyboardView.desiredKey.visibleBounds

View File

@ -16,44 +16,29 @@
package dev.patrickgold.florisboard.ime.text.keyboard
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.graphics.drawable.PaintDrawable
import android.os.Handler
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.debug.*
import dev.patrickgold.florisboard.ime.core.*
import dev.patrickgold.florisboard.ime.keyboard.KeyboardView
import dev.patrickgold.florisboard.ime.popup.PopupManager
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.gestures.SwipeGesture
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.theme.Theme
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import dev.patrickgold.florisboard.ime.theme.ThemeValue
import dev.patrickgold.florisboard.util.ViewLayoutUtils
import dev.patrickgold.florisboard.util.cancelAll
import dev.patrickgold.florisboard.util.postDelayed
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.sendBlocking
import kotlin.math.abs
import kotlin.math.roundToInt
class TextKeyboardView : View, ThemeManager.OnThemeUpdatedListener, SwipeGesture.Listener {
private val florisboard: FlorisBoard?
get() = FlorisBoard.getInstanceOrNull()
private val prefs: PrefHelper
get() = PrefHelper.getDefaultInstance(context)
private val themeManager: ThemeManager?
get() = ThemeManager.defaultOrNull()
private val channel: Channel<MotionEvent> = Channel(16)
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())
class TextKeyboardView : KeyboardView, SwipeGesture.Listener {
private var computedKeyboard: TextKeyboard? = null
private var iconSet: TextKeyboardIconSet? = null
@ -158,6 +143,7 @@ class TextKeyboardView : View, ThemeManager.OnThemeUpdatedListener, SwipeGesture
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
context.obtainStyledAttributes(attrs, R.styleable.TextKeyboardView).apply {
isPreviewMode = getBoolean(R.styleable.TextKeyboardView_isPreviewKeyboard, false)
isTouchable = !isPreviewMode
isSmartbarKeyboardView = getBoolean(R.styleable.TextKeyboardView_isSmartbarKeyboard, false)
isLoadingPlaceholderKeyboard = getBoolean(R.styleable.TextKeyboardView_isLoadingPlaceholderKeyboard, false)
recycle()
@ -170,13 +156,6 @@ class TextKeyboardView : View, ThemeManager.OnThemeUpdatedListener, SwipeGesture
popupManager = PopupManager(this, popupLayerView)
setWillNotDraw(false)
scope.launch {
for (event in channel) {
if (!isActive) break
onTouchEventInternal(event)
}
}
}
fun setComputingEvaluator(evaluator: TextComputingEvaluator?) {
@ -201,37 +180,12 @@ class TextKeyboardView : View, ThemeManager.OnThemeUpdatedListener, SwipeGesture
invalidate()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
themeManager?.registerOnThemeUpdatedListener(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
themeManager?.unregisterOnThemeUpdatedListener(this)
cachedTheme = null
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
event ?: return false
if (isPreviewMode) return false
when (event.actionMasked) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN,
MotionEvent.ACTION_MOVE,
MotionEvent.ACTION_POINTER_UP,
MotionEvent.ACTION_UP,
MotionEvent.ACTION_CANCEL -> {
channel.sendBlocking(event)
return true
}
}
return false
}
private fun onTouchEventInternal(event: MotionEvent) {
override fun onTouchEventInternal(event: MotionEvent) {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN,
MotionEvent.ACTION_POINTER_DOWN -> {
@ -613,12 +567,7 @@ class TextKeyboardView : View, ThemeManager.OnThemeUpdatedListener, SwipeGesture
)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
onLayoutInternal()
}
private fun onLayoutInternal() {
override fun onLayoutInternal() {
val keyboard = computedKeyboard
if (keyboard == null) {
flogWarning(LogTopic.TEXT_KEYBOARD_VIEW) { "Computed keyboard is null!" }

View File

@ -17,7 +17,9 @@
package dev.patrickgold.florisboard.ime.text.layout
import dev.patrickgold.florisboard.ime.extension.Asset
import dev.patrickgold.florisboard.ime.keyboard.KeyData
import dev.patrickgold.florisboard.ime.text.key.*
import dev.patrickgold.florisboard.ime.text.keyboard.BasicTextKeyData
import kotlinx.serialization.Serializable
@Serializable
@ -39,46 +41,46 @@ data class Layout(
direction = "ltr",
arrangement = listOf(
listOf(
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0)
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0)
),
listOf(
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0)
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0)
),
listOf(
AutoTextKeyData(code = KeyCode.SHIFT, type = KeyType.MODIFIER, label = "shift"),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = KeyCode.DELETE, type = KeyType.ENTER_EDITING, label = "delete")
BasicTextKeyData(code = KeyCode.SHIFT, type = KeyType.MODIFIER, label = "shift"),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = KeyCode.DELETE, type = KeyType.ENTER_EDITING, label = "delete")
),
listOf(
AutoTextKeyData(code = KeyCode.VIEW_SYMBOLS, type = KeyType.SYSTEM_GUI, label = "view_symbols"),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = KeyCode.SPACE, label = "space"),
AutoTextKeyData(code = 0),
AutoTextKeyData(code = KeyCode.ENTER, type = KeyType.ENTER_EDITING, label = "enter")
BasicTextKeyData(code = KeyCode.VIEW_SYMBOLS, type = KeyType.SYSTEM_GUI, label = "view_symbols"),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = KeyCode.SPACE, label = "space"),
BasicTextKeyData(code = 0),
BasicTextKeyData(code = KeyCode.ENTER, type = KeyType.ENTER_EDITING, label = "enter")
)
)
)