Compare commits

..

30 Commits

Author SHA1 Message Date
Patrick Goldinger
37bb4cea43 Release v0.3.13-beta04 2021-06-08 00:05:36 +02:00
Patrick Goldinger
79d608feea Update translations from Crowdin 2021-06-07 23:53:37 +02:00
Patrick Goldinger
54573de3e3 Merge pull request #1006 from Luensche/move_clipboard_item_to_begin
Move new clipboard items with the same content to the beginning
2021-06-07 23:51:35 +02:00
Björn Engel
2fba2d3b4a Do not compare images 2021-06-07 15:49:05 +02:00
Björn Engel
fd0cbbdcb1 Move new clipboard items with the same content to the beginning, closes #991 2021-06-07 14:08:39 +02:00
Patrick Goldinger
b6e3deedf4 Add default system subtype for proper display in system settings 2021-06-04 19:39:02 +02:00
Patrick Goldinger
4c74bf1b4a Fix glide typing not working for caps/caps-lock 2021-06-04 19:19:53 +02:00
Patrick Goldinger
2a4e3c8c58 Merge pull request #982 from dessalines/halmak
Add the Halmak keyboard layout
2021-06-04 18:56:48 +02:00
Patrick Goldinger
e34e5b4260 Merge pull request #992 from florisboard/rework-textkeyboard-rendering
Rework TextKeyboard rendering
2021-06-04 18:53:42 +02:00
Patrick Goldinger
ae2df7dfe4 Fix Smartbar incorrectly not updating selection-specific keys 2021-06-04 18:49:48 +02:00
Patrick Goldinger
1b3d0a5cf2 Fix touch logic incorrect pointer and capacity issues 2021-06-04 18:31:05 +02:00
Patrick Goldinger
4c94329071 Fix glide typing not correctly initialized at startup 2021-06-04 17:13:16 +02:00
Patrick Goldinger
6ffcf2f865 Fix keyboard preview in Settings 2021-06-04 05:43:42 +02:00
Patrick Goldinger
e2c9a66880 Fix further state bugs 2021-06-04 05:12:38 +02:00
Patrick Goldinger
e9bc25ebc7 Improve extended popup rendering performance 2021-06-04 03:53:03 +02:00
Patrick Goldinger
6379e63669 Rework TextKeyboard rendering 2021-06-04 03:31:46 +02:00
Patrick Goldinger
70a0763e7f Merge pull request #981 from florisboard/fix-keyboard-state-bug
Fix keyboard state bug for the active mode
2021-06-04 03:29:47 +02:00
Dessalines
863080e6ce Remove slash from bottom row. 2021-06-03 14:46:55 -04:00
Patrick Goldinger
3ef454b8bd Fix Smartbar not showing sometimes (#987) 2021-06-03 17:43:23 +02:00
Patrick Goldinger
2bbdfc71d0 Rework UI initialization and reduce duplicate state changes 2021-06-03 15:42:28 +02:00
Patrick Goldinger
d1c783dde1 Fix keyboard state bug for the active mode 2021-06-02 17:51:18 +02:00
Dessalines
644da67601 Add the Halmak keyboard layout 2021-06-01 21:39:26 -04:00
Patrick Goldinger
b8d99efd29 Merge pull request #977 from GoRaN909/patch-5
Update kurdish.json
2021-06-01 01:15:58 +02:00
GoRaN
4067d92a44 Update kurdish.json
Added stretched button (Kashida) to support all Kurdish layouts.
2021-06-01 01:06:00 +03:00
Patrick Goldinger
13a17f3a6b Merge pull request #974 from GoRaN909/patch-2
Update ckb.json
2021-05-31 23:50:01 +02:00
Patrick Goldinger
57c679e500 Merge pull request #975 from GoRaN909/patch-3
Update kurdish_standard.json
2021-05-31 23:41:42 +02:00
Patrick Goldinger
f70f45dab6 Merge pull request #973 from GoRaN909/patch-1
Update kurdish.json
2021-05-31 23:37:41 +02:00
GoRaN
8d8f723d66 Update kurdish_standard.json
popup characters added
2021-06-01 00:29:23 +03:00
GoRaN
7c3c6a7ad7 Update ckb.json
Added popup characters for letter (ح)
2021-06-01 00:24:18 +03:00
GoRaN
d7a1c9377a Update kurdish.json
Some changes of words position and corrections codes
2021-06-01 00:19:19 +03:00
44 changed files with 1112 additions and 635 deletions

View File

@@ -45,7 +45,11 @@ _A. IzzySoft's repo for F-Droid_:
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" height="64" alt="IzzySoft repo badge">](https://apt.izzysoft.de/fdroid/index/apk/dev.patrickgold.florisboard.beta)
_B. Use the APK provided in the release section of this repo_
_B. Google Play_:
Follow the same steps as for the stable track, the app can then be accessed [here](https://play.google.com/store/apps/details?id=dev.patrickgold.florisboard.beta).
_C. Use the APK provided in the release section of this repo_
### Giving feedback
If you want to give feedback to FlorisBoard, there are several ways to

View File

@@ -24,7 +24,7 @@ android {
applicationId = "dev.patrickgold.florisboard"
minSdkVersion(23)
targetSdkVersion(30)
versionCode(46)
versionCode(47)
versionName("0.3.13")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -73,7 +73,7 @@ android {
create("beta") // Needed because by default the "beta" BuildType does not exist
named("beta").configure {
applicationIdSuffix = ".beta"
versionNameSuffix = "-beta03"
versionNameSuffix = "-beta04"
proguardFiles.add(getDefaultProguardFile("proguard-android-optimize.txt"))
resValue("mipmap", "floris_app_icon", "@mipmap/ic_app_icon_beta")

View File

@@ -4,28 +4,22 @@
"authors": [ "GoRaN" ],
"mapping": {
"all": {
"": {
"relevant": [
{ "code": 1577, "label": "ة" },
{ "code": 1729, "label": "ـہ" }
]
},
"ر": {
"relevant": [
{ "code": 1685, "label": "ڕ" },
{ "code": 1682, "label": "ڒ" }
]
},
"ی": {
"relevant": [
{ "code": 1746, "label": "ے" },
{ "code": 1610, "label": "ي" },
{ "code": 1744, "label": "ې" },
{ "code": 1741, "label": "ۍ" },
{ "code": 1742, "label": "ێ" },
{ "code": 1744, "label": "ې" },
{ "code": 1610, "label": "ي" },
{ "code": 1597, "label": "ؽ" }
]
},
@@ -34,10 +28,15 @@
"ﺋ": {
"relevant": [
{ "code": 65163, "label": "ﺋ" },
{ "code": 1569, "label": "ء" },
{ "code": 65139, "label": "ﹳ" }
]
},
"ح": {
"relevant": [
{ "code": 65010, "label": "ﷲ" },
{ "code": 65019, "label": "ﷻ" }
]
},
"ع": {
"relevant": [
@@ -56,12 +55,9 @@
]
},
"ف": {
"relevant": [
{ "code": 1701, "label": "ڥ" },
{ "code": 1700, "label": "ڤ" },
{ "code": 1698, "label": "ڢ" },
{ "code": 1697, "label": "ڡ" }
]
@@ -70,7 +66,6 @@
"د": {
"relevant": [
{ "code": 1676, "label": "ڌ" },
{ "code": 1584, "label": "ذ" },
{ "code": 64390, "label": "ﮆ" },
{ "code": 1774, "label": "ۮ" }
]
@@ -93,9 +88,7 @@
},
"ب": {
"relevant": [
{ "code": 65010, "label": "" },
{ "code": 65021, "label": "﷽" },
{ "code": 65019, "label": "ﷻ" }
{ "code": 65021, "label": "" }
]
},
"م": {
@@ -108,7 +101,6 @@
"relevant": [
{ "code": 1718, "label": "ڶ" },
{ "code": 1719, "label": "ڷ" },
{ "code": 1717, "label": "ڵ" },
{ "code": 1720, "label": "ڸ" }
]
},

View File

@@ -0,0 +1,77 @@
{
"type": "characters",
"name": "halmak",
"label": "Halmak",
"authors": [ "dessalines" ],
"direction": "ltr",
"arrangement": [
[
{ "$": "auto_text_key", "code": 119, "label": "w" },
{ "$": "auto_text_key", "code": 108, "label": "l" },
{ "$": "auto_text_key", "code": 114, "label": "r" },
{ "$": "auto_text_key", "code": 98, "label": "b" },
{ "$": "auto_text_key", "code": 122, "label": "z" },
{ "$": "case_selector",
"lower": { "code": 59, "label": ";", "popup": {
"relevant": [
{ "code": 58, "label": ":" }
]
} },
"upper": { "code": 58, "label": ":", "popup": {
"relevant": [
{ "code": 59, "label": ";" }
]
} }
},
{ "$": "auto_text_key", "code": 113, "label": "q" },
{ "$": "auto_text_key", "code": 117, "label": "u" },
{ "$": "auto_text_key", "code": 100, "label": "d" },
{ "$": "auto_text_key", "code": 106, "label": "j" }
],
[
{ "$": "auto_text_key", "code": 115, "label": "s" },
{ "$": "auto_text_key", "code": 104, "label": "h" },
{ "$": "auto_text_key", "code": 110, "label": "n" },
{ "$": "auto_text_key", "code": 116, "label": "t" },
{ "$": "case_selector",
"lower": { "code": 44, "label": ",", "popup": {
"relevant": [
{ "code": 40, "label": "(" }
]
} },
"upper": { "code": 40, "label": "(", "popup": {
"relevant": [
{ "code": 44, "label": "," }
]
} }
},
{ "$": "case_selector",
"lower": { "code": 46, "label": ".", "popup": {
"relevant": [
{ "code": 41, "label": ")" }
]
} },
"upper": { "code": 41, "label": ")", "popup": {
"relevant": [
{ "code": 46, "label": "." }
]
} }
},
{ "$": "auto_text_key", "code": 97, "label": "a" },
{ "$": "auto_text_key", "code": 101, "label": "e" },
{ "$": "auto_text_key", "code": 111, "label": "o" },
{ "$": "auto_text_key", "code": 105, "label": "i" }
],
[
{ "$": "auto_text_key", "code": 102, "label": "f" },
{ "$": "auto_text_key", "code": 109, "label": "m" },
{ "$": "auto_text_key", "code": 118, "label": "v" },
{ "$": "auto_text_key", "code": 99, "label": "c" },
{ "$": "auto_text_key", "code": 103, "label": "g" },
{ "$": "auto_text_key", "code": 112, "label": "p" },
{ "$": "auto_text_key", "code": 120, "label": "x" },
{ "$": "auto_text_key", "code": 107, "label": "k" },
{ "$": "auto_text_key", "code": 121, "label": "y" }
]
]
}

View File

@@ -1,7 +1,7 @@
{
"type": "characters",
"name": "kurdish",
"label": "کوردی",
"label": "کوردی (قوەرتی نوێ)",
"authors": [ "GoRaN" ],
"direction": "rtl",
"modifier": "kurdish",
@@ -13,34 +13,46 @@
{ "code": 1608, "label": "و", "popup": {
"main": { "code": -255, "label": "وو" }
} },
{ "code": 1749, "label": "" },
{ "code": 1585, "label": "ر" },
{ "code": 1749, "label": "", "popup": {
"main": { "code": 1577, "label": "ة" }
} },
{ "code": 1585, "label": "ر", "popup": {
"main": { "code": 1685, "label": "ڕ" }
} },
{ "code": 1578, "label": "ت", "popup": {
"main": { "code": 1591, "label": "ط" }
} },
{ "code": 1740, "label": "ی" },
{ "code": 1574, "label": "ﺋ"},
{ "code": 1740, "label": "ی", "popup": {
"main": { "code": 1742, "label": "ێ" }
} },
{ "code": 1574, "label": "ﺋ", "popup": {
"main": { "code": 1569, "label": "ء" }
} },
{ "code": 1593, "label": "ع", "popup": {
"main": { "code": 1594, "label": "غ" }
} },
{ "code": 1734, "label": "ۆ" },
{ "code": 1662, "label": "پ", "popup": {
"main": { "code": 1579, "label": "ث" }
} }
],
[
{ "code": 1575, "label": "ا" },
{"code": 1575, "label": "ا"},
{ "code": 1587, "label": "س" },
{ "code": 1588, "label": "ش" },
{ "code": 1583, "label": "د" },
{ "code": 1601, "label": "ف" },
{ "code": 1583, "label": "د", "popup": {
"main": {"code": 1584, "label": "ذ" }
} },
{ "code": 1601, "label": "ف" , "popup": {
"main": {"code": 1700, "label": "ڤ" }
} },
{ "code": 1607, "label": "ھ" },
{ "code": 1688, "label": "ژ" },
{ "code": 1604, "label": "ل" },
{ "code": 1688, "label": "ژ", "popup": {
"main": { "code": 1600, "label": "" }
} },
{ "code": 1604, "label": "ل", "popup": {
"main": { "code": 1717, "label": "ڵ" }
} },
{ "code": 1705, "label": "ک" },
{ "code": 1711, "label": "گ" }
],

View File

@@ -1,7 +1,7 @@
{
"type": "characters",
"name": "kurdish_standard",
"label": "کوردی - ستاندارد",
"label": "کوردی (ق‌ڤ‌ف‌غ)",
"authors": [ "GoRaN" ],
"direction": "rtl",
"modifier": "kurdish",
@@ -10,16 +10,14 @@
{ "code": 1602, "label": "ق", "popup": {
"main": { "code": 1647, "label": "ٯ" }
} },
{ "code": 1700, "label": "ڤ", "popup": {
"main": { "code": 1701, "label": "ڥ" }
} },
{ "code": 1601, "label": "ف", "popup": {
"main": { "code": 1698, "label": "ڢ" }
} },
{ "code": 1700, "label": "ڤ" },
{ "code": 1601, "label": "ف" },
{ "code": 1594, "label": "غ" },
{ "code": 1593, "label": "ع"},
{ "code": 1607, "label": "ھ" },
{ "code": 1749, "label": "" },
{ "code": 1749, "label": "", "popup": {
"main": { "code": 1577, "label": "ة" }
} },
{ "code": 1578, "label": "ت", "popup": {
"main": { "code": 1591, "label": "ط" }
@@ -46,7 +44,9 @@
} },
{ "code": 1585, "label": "ر" },
{ "code": 1685, "label": "ڕ" },
{ "code": 1583, "label": "د" },
{ "code": 1583, "label": "د", "popup": {
"main": {"code": 1584, "label": "ذ" }
} },
{ "code": -255, "label": "وو" },
{ "code": 1608, "label": "و" },
{ "code": 1734, "label": "ۆ" },
@@ -55,8 +55,10 @@
],
[
{ "code": 1600, "label": "kashida", "variation": "normal" },
{ "code": 1574, "label": "ﺋ"},
{ "code": 1574, "label": "ﺋ", "popup": {
"main": { "code": 1569, "label": "ء" }
} },
{ "code": 1662, "label": "پ", "popup": {
"main": { "code": 1579, "label": "ث" }

View File

@@ -6,14 +6,17 @@
"direction": "rtl",
"arrangement": [
[
{ "code": 1600, "label": "kashida", "popup":
{ "main": { "code": 8204, "label": "half_space" }
} },
{ "code": 0, "type": "placeholder" },
{ "code": -5, "label": "delete", "type": "enter_editing" }
],
[
{ "code": -202, "label": "view_symbols", "type": "system_gui" },
{ "$": "variation_selector",
"default": { "code": 1567, "label": "؟", "groupId": 1 },
"password": { "code": 1548, "label": "،", "groupId": 1 },
"default": { "code": 1548, "label": "،", "groupId": 1 },
"password": { "code": 35, "label": "#", "groupId": 1 },
"email": { "code": 64, "label": "@", "groupId": 1 },
"uri": { "code": 47, "label": "/", "groupId": 1 }
},

View File

@@ -25,12 +25,10 @@ import dev.patrickgold.florisboard.ime.core.SubtypeManager
import dev.patrickgold.florisboard.ime.dictionary.DictionaryManager
import dev.patrickgold.florisboard.ime.extension.AssetManager
import dev.patrickgold.florisboard.ime.theme.ThemeManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import timber.log.Timber
@Suppress("unused")
class FlorisApplication : Application(), CoroutineScope by MainScope() {
class FlorisApplication : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {

View File

@@ -64,7 +64,7 @@ class ClipboardHistoryView : LinearLayout, FlorisBoard.EventListener,
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val height = florisboard?.inputView?.desiredMediaKeyboardViewHeight ?: 0.0f
val height = florisboard?.uiBinding?.inputView?.desiredMediaKeyboardViewHeight ?: 0.0f
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height.roundToInt(), MeasureSpec.EXACTLY))
}

View File

@@ -3,15 +3,14 @@ package dev.patrickgold.florisboard.ime.clip
import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.databinding.FlorisboardBinding
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.KeyCode
import dev.patrickgold.florisboard.ime.text.keyboard.BasicTextKeyData
import kotlinx.coroutines.*
@@ -43,27 +42,23 @@ class ClipboardInputManager private constructor() : CoroutineScope by MainScope(
florisboard.addEventListener(this)
}
/**
* Called when a new input view has been registered. Used to initialize all media-relevant
* views and layouts.
*/
@SuppressLint("ClickableViewAccessibility")
override fun onRegisterInputView(inputView: InputView) {
inputView.findViewById<ImageButton>(R.id.back_to_keyboard_button)
override fun onInitializeInputUi(uiBinding: FlorisboardBinding) {
uiBinding.clipboard.backToKeyboardButton
.setOnTouchListener { view, event -> onButtonPressEvent(view, event) }
uiBinding.clipboard.clearClipboardHistory
.setOnTouchListener { view, event -> onButtonPressEvent(view, event) }
inputView.findViewById<ImageButton>(R.id.clear_clipboard_history)
.setOnTouchListener { view, event -> onButtonPressEvent(view, event) }
recyclerView = uiBinding.clipboard.clipboardHistoryItems.also {
if (BuildConfig.DEBUG && adapter == null) {
error("initClipboard() not called")
}
recyclerView = inputView.findViewById(R.id.clipboard_history_items)
if (BuildConfig.DEBUG && adapter == null) {
error("initClipboard() not called")
it.adapter = adapter
val manager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
it.layoutManager = manager
}
recyclerView!!.adapter = adapter
val manager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
recyclerView!!.layoutManager = manager
}
/**
@@ -78,7 +73,7 @@ class ClipboardInputManager private constructor() : CoroutineScope by MainScope(
* Returns a reference to the [ClipboardHistoryView]
*/
fun getClipboardHistoryView(): ClipboardHistoryView {
return FlorisBoard.getInstance().inputView?.mainViewFlipper?.getChildAt(2) as ClipboardHistoryView
return florisboard.uiBinding?.mainViewFlipper?.getChildAt(2) as ClipboardHistoryView
}
/**

View File

@@ -108,21 +108,44 @@ class FlorisClipboardManager private constructor() : ClipboardManager.OnPrimaryC
val clipboardPrefs = prefs.clipboard
if (clipboardPrefs.enableHistory) {
if (clipboardPrefs.limitHistorySize) {
var numRemoved = 0
while (history.size >= clipboardPrefs.maxHistorySize) {
numRemoved += 1
history.removeLast().data.close()
}
ClipboardInputManager.getInstance().notifyItemRangeRemoved(history.size, numRemoved)
}
val clipboardInputManager = ClipboardInputManager.getInstance()
val timed = TimedClipData(newData, System.currentTimeMillis())
history.addFirst(timed)
ClipboardInputManager.getInstance().notifyItemInserted(pins.size)
val historyElement = history.firstOrNull { it.data.type == ItemType.TEXT && it.data.text == newData.text }
if (historyElement != null) {
moveToTheBeginning(historyElement, newData, clipboardInputManager)
} else {
if (clipboardPrefs.limitHistorySize) {
var numRemoved = 0
while (history.size >= clipboardPrefs.maxHistorySize) {
numRemoved += 1
history.removeLast().data.close()
}
clipboardInputManager.notifyItemRangeRemoved(history.size, numRemoved)
}
createAndAddNewTimedClipData(newData)
clipboardInputManager.notifyItemInserted(pins.size)
}
}
}
/**
* Moves a ClipboardItem to the beginning of the history by removing the old one and creating a new one
*/
private fun moveToTheBeginning(
historyElement: TimedClipData,
newData: ClipboardItem,
clipboardInputManager: ClipboardInputManager
) {
val elementsPosition = history.indexOf(historyElement)
history.remove(historyElement)
createAndAddNewTimedClipData(newData)
clipboardInputManager.notifyItemMoved(elementsPosition, 0)
clipboardInputManager.notifyItemChanged(0)
}
/**
* Used so that [onPrimaryClipChanged] knows whether it was called by [changeCurrent] (and hence shouldn't update
* history)
@@ -341,8 +364,7 @@ class FlorisClipboardManager private constructor() : ClipboardManager.OnPrimaryC
ClipboardInputManager.getInstance().notifyItemRangeRemoved(history.size, numRemoved)
}
val timed = TimedClipData(item, System.currentTimeMillis())
history.addFirst(timed)
createAndAddNewTimedClipData(item)
clipInputManager.notifyItemMoved(adapterPos, pins.size)
clipInputManager.notifyItemChanged(pins.size)
@@ -352,6 +374,14 @@ class FlorisClipboardManager private constructor() : ClipboardManager.OnPrimaryC
}
}
/**
* Creates a new TimedClipData and adds it to the history
*/
private fun createAndAddNewTimedClipData(newData: ClipboardItem) {
val timed = TimedClipData(newData, System.currentTimeMillis())
history.addFirst(timed)
}
fun removeClip(pos: Int) {
when {
pos < pins.size -> {

View File

@@ -62,16 +62,6 @@ class EditorInstance private constructor(
}
val inputConnection: InputConnection?
get() = ims?.currentInputConnection
var isComposingEnabled: Boolean = false
set(v) {
field = v
cachedInput.reevaluate()
if (v && !activeState.isRawInputEditor) {
markComposingRegion(cachedInput.currentWord)
} else {
markComposingRegion(null)
}
}
var shouldReevaluateComposingSuggestions: Boolean = false
var selection: Selection = Selection(this)
private set
@@ -137,7 +127,7 @@ class EditorInstance private constructor(
}
if (selection.isCursorMode) {
cachedInput.update()
if (isComposingEnabled) {
if (activeState.isComposingEnabled) {
if (candidatesStart >= 0 && candidatesEnd >= 0) {
shouldReevaluateComposingSuggestions = true
}
@@ -154,6 +144,15 @@ class EditorInstance private constructor(
}
}
fun composingEnabledChanged() {
cachedInput.reevaluate()
if (activeState.isComposingEnabled && activeState.isRichInputEditor) {
markComposingRegion(cachedInput.currentWord)
} else {
markComposingRegion(null)
}
}
/**
* Completes the given [text] in the current composing region. Does nothing if the current
* composing region is of zero length or null.
@@ -212,7 +211,7 @@ class EditorInstance private constructor(
*/
fun commitText(text: String): Boolean {
val ic = inputConnection ?: return false
return if (activeState.isRawInputEditor || selection.isSelectionMode || !isComposingEnabled) {
return if (activeState.isRawInputEditor || selection.isSelectionMode || !activeState.isComposingEnabled) {
doCommitText(text).first
} else {
ic.beginBatchEdit()

View File

@@ -68,13 +68,13 @@ import dev.patrickgold.florisboard.ime.text.composing.Composer
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
import dev.patrickgold.florisboard.ime.text.key.CurrencySet
import dev.patrickgold.florisboard.ime.text.key.KeyCode
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
import dev.patrickgold.florisboard.util.AppVersionUtils
import dev.patrickgold.florisboard.common.ViewUtils
import dev.patrickgold.florisboard.databinding.FlorisboardBinding
import dev.patrickgold.florisboard.ime.keyboard.KeyboardState
import dev.patrickgold.florisboard.ime.keyboard.updateKeyboardState
import dev.patrickgold.florisboard.util.debugSummarize
@@ -128,10 +128,9 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
private val prefs: Preferences get() = Preferences.default()
val activeState: KeyboardState = KeyboardState.new()
private var extractEditLayout: WeakReference<ViewGroup?> = WeakReference(null)
var inputView: InputView? = null
var uiBinding: FlorisboardBinding? = null
private set
private var inputWindowView: InputWindowView? = null
private var extractEditLayout: WeakReference<ViewGroup?> = WeakReference(null)
var popupLayerView: PopupLayerView? = null
private set
private var eventListeners: CopyOnWriteArrayList<EventListener> = CopyOnWriteArrayList()
@@ -160,7 +159,6 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
lateinit var activeSubtype: Subtype
private var currentThemeIsNight: Boolean = false
private var currentThemeResId: Int = 0
private var isNumberRowVisible: Boolean = false
private var isWindowShown: Boolean = false
private var responseState = ResponseState.RESET
@@ -235,7 +233,6 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
currentThemeIsNight = themeManager.activeTheme.isNightTheme
currentThemeResId = getDayNightBaseThemeId(currentThemeIsNight)
isNumberRowVisible = prefs.keyboard.numberRow
setTheme(currentThemeResId)
themeManager.registerOnThemeUpdatedListener(this)
@@ -267,13 +264,28 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
updateThemeContext(currentThemeResId)
popupLayerView = PopupLayerView(themeContext)
window?.window?.findViewById<View>(android.R.id.content)?.let { content ->
if (content is ViewGroup) {
content.addView(popupLayerView)
}
}
inputWindowView = LayoutInflater.from(themeContext).inflate(R.layout.florisboard, null) as? InputWindowView
inputWindowView?.isHapticFeedbackEnabled = true
uiBinding = FlorisboardBinding.inflate(LayoutInflater.from(themeContext))
eventListeners.toList().forEach { it?.onCreateInputView() }
eventListeners.toList().forEach { it?.onInitializeInputUi(uiBinding!!) }
return inputWindowView
return uiBinding!!.inputWindowView
}
fun initWindow() {
flogInfo(LogTopic.IMS_EVENTS)
updateSoftInputWindowLayoutParameters()
updateOneHandedPanelVisibility()
themeManager.requestThemeUpdate(this)
dispatchCurrentStateToInputUi()
}
/**
@@ -319,8 +331,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
imeManager = null
vibrator = null
popupLayerView = null
inputView = null
inputWindowView = null
uiBinding = null
florisboardInstance = null
eventListeners.toList().forEach { it?.onDestroy() }
@@ -355,24 +366,6 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
}
}
fun registerInputView(inputView: InputView) {
flogInfo(LogTopic.IMS_EVENTS)
window?.window?.findViewById<View>(android.R.id.content)?.let { content ->
if (content is ViewGroup) {
popupLayerView?.let { content.addView(it) }
}
}
this.inputView = inputView
updateSoftInputWindowLayoutParameters()
updateOneHandedPanelVisibility()
themeManager.notifyCallbackReceivers()
setActiveInput(R.id.text_input)
dispatchCurrentStateToInputUi()
eventListeners.toList().forEach { it?.onRegisterInputView(inputView) }
}
override fun onStartInput(attribute: EditorInfo?, restarting: Boolean) {
flogInfo(LogTopic.IMS_EVENTS)
@@ -390,8 +383,10 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
flogInfo(LogTopic.IMS_EVENTS) { info?.debugSummarize() ?: "" }
super.onStartInputView(info, restarting)
prefs.sync()
if (info != null) {
activeState.update(info)
activeState.isSelectionMode = (info.initialSelEnd - info.initialSelStart) != 0
}
activeEditorInstance = EditorInstance.from(info, this, activeState)
themeManager.updateRemoteColorValues(activeEditorInstance.packageName)
@@ -433,12 +428,12 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
val stylesBundle = themeManager.createInlineSuggestionUiStyleBundle(themeContext)
InlinePresentationSpec.Builder(
Size(
inputView?.desiredInlineSuggestionsMinWidth ?: 0,
inputView?.desiredInlineSuggestionsMinHeight ?: 0
uiBinding?.inputView?.desiredInlineSuggestionsMinWidth ?: 0,
uiBinding?.inputView?.desiredInlineSuggestionsMinHeight ?: 0
),
Size(
inputView?.desiredInlineSuggestionsMaxWidth ?: 0,
inputView?.desiredInlineSuggestionsMaxHeight ?: 0
uiBinding?.inputView?.desiredInlineSuggestionsMaxWidth ?: 0,
uiBinding?.inputView?.desiredInlineSuggestionsMaxHeight ?: 0
)
).let { spec ->
spec.setStyle(stylesBundle)
@@ -490,7 +485,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
}
fun dispatchCurrentStateToInputUi() {
inputView?.updateKeyboardState(activeState)
uiBinding?.inputView?.updateKeyboardState(activeState)
}
override fun onWindowShown() {
@@ -504,23 +499,23 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
isWindowShown = true
prefs.sync()
val newIsNumberRowVisible = prefs.keyboard.numberRow
if (isNumberRowVisible != newIsNumberRowVisible) {
textInputManager.keyboards.clear(KeyboardMode.CHARACTERS)
isNumberRowVisible = newIsNumberRowVisible
val newActiveSubtype = subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT
if (newActiveSubtype != activeSubtype) {
activeSubtype = newActiveSubtype
onSubtypeChanged(activeSubtype, true)
} else {
onSubtypeChanged(activeSubtype, false)
}
themeManager.update()
activeSubtype = subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT
onSubtypeChanged(activeSubtype)
setActiveInput(R.id.text_input)
updateOneHandedPanelVisibility()
themeManager.update()
if (prefs.devtools.enabled && prefs.devtools.showHeapMemoryStats) {
devtoolsOverlaySyncJob?.cancel()
devtoolsOverlaySyncJob = uiScope.launch(Dispatchers.Default) {
while (true) {
if (!isActive) break
withContext(Dispatchers.Main) { inputView?.invalidate() }
withContext(Dispatchers.Main) { uiBinding?.inputView?.invalidate() }
delay(1000)
}
}
@@ -612,7 +607,6 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
candidatesStart, candidatesEnd
)
eventListeners.toList().forEach { it?.onUpdateSelection() }
dispatchCurrentStateToInputUi()
} else {
flogInfo(LogTopic.IMS_EVENTS) { "onUpdateSelection($oldSelStart, $oldSelEnd, $newSelStart, $newSelEnd, $candidatesStart, $candidatesEnd): caught due to internal batch level of $internalBatchNestingLevel!" }
if (internalSelectionCache.selectionCatchCount++ == 0) {
@@ -624,6 +618,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
internalSelectionCache.candidatesStart = candidatesStart
internalSelectionCache.candidatesEnd = candidatesEnd
}
dispatchCurrentStateToInputUi()
}
override fun onThemeUpdated(theme: Theme) {
@@ -664,8 +659,8 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
w.decorView.systemUiVisibility = flags
// Update InputView theme
inputView?.setBackgroundColor(theme.getAttr(Theme.Attr.KEYBOARD_BACKGROUND).toSolidColor().color)
inputView?.invalidate()
uiBinding?.inputView?.setBackgroundColor(theme.getAttr(Theme.Attr.KEYBOARD_BACKGROUND).toSolidColor().color)
uiBinding?.inputView?.invalidate()
// Update ExtractTextView theme and attributes
extractEditLayout.get()?.let { eel ->
@@ -699,8 +694,8 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
override fun onComputeInsets(outInsets: Insets?) {
super.onComputeInsets(outInsets)
val inputView = this.inputView ?: return
val inputWindowView = this.inputWindowView ?: return
val inputView = uiBinding?.inputView ?: return
val inputWindowView = uiBinding?.inputWindowView ?: return
// TODO: Check also if the keyboard is currently suppressed by a hardware keyboard
if (!isInputViewShown) {
@@ -724,7 +719,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
private fun updateSoftInputWindowLayoutParameters() {
val w = window?.window ?: return
ViewUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
val inputWindowView = this.inputWindowView
val inputWindowView = uiBinding?.inputWindowView
if (inputWindowView != null) {
val layoutHeight = if (isFullscreenMode) {
WindowManager.LayoutParams.WRAP_CONTENT
@@ -752,9 +747,9 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
val hapticsPerformed = if (vibrationDuration < 0 && vibrationStrength < 0) {
if (isMovingGestureEffect && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
inputWindowView?.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE)
uiBinding?.inputWindowView?.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE)
} else {
inputWindowView?.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
uiBinding?.inputWindowView?.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
}
} else {
false
@@ -884,35 +879,35 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
fun switchToPrevSubtype() {
flogInfo(LogTopic.IMS_EVENTS)
activeSubtype = subtypeManager.switchToPrevSubtype() ?: Subtype.DEFAULT
onSubtypeChanged(activeSubtype)
onSubtypeChanged(activeSubtype, true)
}
fun switchToNextSubtype() {
flogInfo(LogTopic.IMS_EVENTS)
activeSubtype = subtypeManager.switchToNextSubtype() ?: Subtype.DEFAULT
onSubtypeChanged(activeSubtype)
onSubtypeChanged(activeSubtype, true)
}
private fun onSubtypeChanged(newSubtype: Subtype) {
private fun onSubtypeChanged(newSubtype: Subtype, doRefreshLayouts: Boolean) {
flogInfo(LogTopic.SUBTYPE_MANAGER) { "New subtype: $newSubtype" }
textInputManager.onSubtypeChanged(newSubtype)
mediaInputManager.onSubtypeChanged(newSubtype)
clipInputManager.onSubtypeChanged(newSubtype)
textInputManager.onSubtypeChanged(newSubtype, doRefreshLayouts)
mediaInputManager.onSubtypeChanged(newSubtype, doRefreshLayouts)
clipInputManager.onSubtypeChanged(newSubtype, doRefreshLayouts)
}
fun setActiveInput(type: Int, forceSwitchToCharacters: Boolean = false) {
when (type) {
R.id.text_input -> {
inputView?.mainViewFlipper?.displayedChild = 0
uiBinding?.mainViewFlipper?.displayedChild = 0
if (forceSwitchToCharacters) {
textInputManager.inputEventDispatcher.send(InputKeyEvent.downUp(TextKeyData.VIEW_CHARACTERS))
}
}
R.id.media_input -> {
inputView?.mainViewFlipper?.displayedChild = 1
uiBinding?.mainViewFlipper?.displayedChild = 1
}
R.id.clip_input -> {
inputView?.mainViewFlipper?.displayedChild = 2
uiBinding?.mainViewFlipper?.displayedChild = 2
}
}
textInputManager.isGlidePostEffect = false
@@ -928,27 +923,27 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
fun updateOneHandedPanelVisibility() {
if (resources.configuration.orientation != Configuration.ORIENTATION_PORTRAIT) {
inputView?.oneHandedCtrlPanelStart?.visibility = View.GONE
inputView?.oneHandedCtrlPanelEnd?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelStart?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelEnd?.visibility = View.GONE
} else {
when (prefs.keyboard.oneHandedMode) {
OneHandedMode.OFF -> {
inputView?.oneHandedCtrlPanelStart?.visibility = View.GONE
inputView?.oneHandedCtrlPanelEnd?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelStart?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelEnd?.visibility = View.GONE
}
OneHandedMode.START -> {
inputView?.oneHandedCtrlPanelStart?.visibility = View.GONE
inputView?.oneHandedCtrlPanelEnd?.visibility = View.VISIBLE
uiBinding?.oneHandedCtrlPanelStart?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelEnd?.visibility = View.VISIBLE
}
OneHandedMode.END -> {
inputView?.oneHandedCtrlPanelStart?.visibility = View.VISIBLE
inputView?.oneHandedCtrlPanelEnd?.visibility = View.GONE
uiBinding?.oneHandedCtrlPanelStart?.visibility = View.VISIBLE
uiBinding?.oneHandedCtrlPanelEnd?.visibility = View.GONE
}
}
}
// Delay execution so this function can return, then refresh the whole layout
uiScope.launch {
refreshLayoutOf(inputView)
refreshLayoutOf(uiBinding?.inputView)
}
}
@@ -981,8 +976,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
interface EventListener {
fun onCreate() {}
fun onCreateInputView() {}
fun onRegisterInputView(inputView: InputView) {}
fun onInitializeInputUi(uiBinding: FlorisboardBinding) {}
fun onDestroy() {}
fun onStartInputView(instance: EditorInstance, restarting: Boolean) {}
@@ -995,7 +989,7 @@ open class FlorisBoard : InputMethodService(), LifecycleOwner, FlorisClipboardMa
fun onApplyThemeAttributes() {}
fun onPrimaryClipChanged() {}
fun onSubtypeChanged(newSubtype: Subtype) {}
fun onSubtypeChanged(newSubtype: Subtype, doRefreshLayouts: Boolean) {}
}
private enum class ResponseState {

View File

@@ -57,7 +57,7 @@ class InputEventDispatcher private constructor(
/**
* The default input event channel capacity to be used in [new].
*/
private const val DEFAULT_CHANNEL_CAPACITY: Int = 32
private const val DEFAULT_CHANNEL_CAPACITY: Int = 64
/**
* Creates a new [InputEventDispatcher] instance from given arguments and returns it.

View File

@@ -26,19 +26,16 @@ import android.os.Build
import android.text.TextPaint
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.ViewFlipper
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.ime.onehanded.OneHandedMode
import dev.patrickgold.florisboard.ime.text.key.KeyVariation
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
import dev.patrickgold.florisboard.common.ViewUtils
import timber.log.Timber
import kotlin.math.roundToInt
/**
* Root view of the keyboard. Notifies [FlorisBoard] when it has been attached to a window.
* Root view of the keyboard.
*/
class InputView : LinearLayout {
private val florisboard get() = FlorisBoard.getInstance()
@@ -66,13 +63,6 @@ class InputView : LinearLayout {
var desiredInlineSuggestionsMaxHeight: Int = 0
private set
var mainViewFlipper: ViewFlipper? = null
private set
var oneHandedCtrlPanelStart: ViewGroup? = null
private set
var oneHandedCtrlPanelEnd: ViewGroup? = null
private set
private val overlayTextPaint: TextPaint = TextPaint().apply {
color = Color.GREEN
textAlign = Paint.Align.RIGHT
@@ -88,18 +78,6 @@ class InputView : LinearLayout {
defStyleAttr
)
override fun onAttachedToWindow() {
Timber.i("onAttachedToWindow()")
super.onAttachedToWindow()
mainViewFlipper = findViewById(R.id.main_view_flipper)
oneHandedCtrlPanelStart = findViewById(R.id.one_handed_ctrl_panel_start)
oneHandedCtrlPanelEnd = findViewById(R.id.one_handed_ctrl_panel_end)
florisboard.registerInputView(this)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
heightFactor = when (resources.configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> 1.0f

View File

@@ -21,10 +21,17 @@ import android.util.AttributeSet
import android.widget.FrameLayout
/**
* Root view of the keyboard.
* Root window view of the keyboard.
*/
class InputWindowView : FrameLayout {
private val florisboard get() = FlorisBoard.getInstanceOrNull()
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)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
florisboard?.initWindow()
}
}

View File

@@ -44,6 +44,7 @@ import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
* | | 1 | | Is private mode
* | 1 | | | Is Smartbar quick actions visible
* | 1 | | | Is Smartbar showing inline suggestions
* | 1 | | | Is composing enabled
*
* <Byte 7> | <Byte 6> | <Byte 5> | <Byte 4> | Description
* ---------|----------|----------|----------|---------------------------------
@@ -77,10 +78,10 @@ import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
*/
class KeyboardState private constructor(var value: ULong, var maskOfInterest: ULong) {
companion object {
const val M_KEY_VARIATION: ULong = 0x0Fu
const val O_KEY_VARIATION: Int = 0
const val M_KEYBOARD_MODE: ULong = 0x0Fu
const val O_KEYBOARD_MODE: Int = 4
const val O_KEYBOARD_MODE: Int = 0
const val M_KEY_VARIATION: ULong = 0x0Fu
const val O_KEY_VARIATION: Int = 4
const val F_CAPS: ULong = 0x00000100u
const val F_CAPS_LOCK: ULong = 0x00000200u
@@ -88,6 +89,7 @@ class KeyboardState private constructor(var value: ULong, var maskOfInterest: UL
const val F_IS_PRIVATE_MODE: ULong = 0x00008000u
const val F_IS_QUICK_ACTIONS_VISIBLE: ULong = 0x00010000u
const val F_IS_SHOWING_INLINE_SUGGESTIONS: ULong = 0x00020000u
const val F_IS_COMPOSING_ENABLED: ULong = 0x00040000u
const val STATE_ALL_ZERO: ULong = 0uL
@@ -152,11 +154,12 @@ class KeyboardState private constructor(var value: ULong, var maskOfInterest: UL
value = (value and (m shl o).inv()) or ((v.toULong() and m) shl o)
}
override operator fun equals(other: Any?): Boolean {
if (other is KeyboardState) {
return (other.value and maskOfInterest) == (value and maskOfInterest)
}
return false
fun isEqualTo(other: KeyboardState): Boolean {
return (other.value and maskOfInterest) == (value and maskOfInterest)
}
fun isDifferentTo(other: KeyboardState): Boolean {
return !isEqualTo(other)
}
override fun hashCode(): Int {
@@ -165,13 +168,27 @@ class KeyboardState private constructor(var value: ULong, var maskOfInterest: UL
return result
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as KeyboardState
if (value != other.value) return false
if (maskOfInterest != other.maskOfInterest) return false
if (imeOptions != other.imeOptions) return false
if (inputAttributes != other.inputAttributes) return false
return true
}
var keyVariation: KeyVariation
get() = KeyVariation.fromInt(getRegion(M_KEY_VARIATION, O_KEY_VARIATION))
set(v) { setRegion(M_KEY_VARIATION, O_KEY_VARIATION, v.toInt()) }
var keyboardMode: KeyboardMode
get() = KeyboardMode.fromInt(getRegion(M_KEYBOARD_MODE, O_KEYBOARD_MODE))
set(v) { setRegion(M_KEY_VARIATION, O_KEY_VARIATION, v.toInt()) }
set(v) { setRegion(M_KEYBOARD_MODE, O_KEYBOARD_MODE, v.toInt()) }
var caps: Boolean
get() = getFlag(F_CAPS)
@@ -207,6 +224,10 @@ class KeyboardState private constructor(var value: ULong, var maskOfInterest: UL
get() = getFlag(F_IS_SHOWING_INLINE_SUGGESTIONS)
set(v) { setFlag(F_IS_SHOWING_INLINE_SUGGESTIONS, v) }
var isComposingEnabled: Boolean
get() = getFlag(F_IS_COMPOSING_ENABLED)
set(v) { setFlag(F_IS_COMPOSING_ENABLED, v) }
interface OnUpdateStateListener {
/**
* Adds the ability for Views to intercept a update keyboard state dispatch.

View File

@@ -20,7 +20,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import dev.patrickgold.florisboard.ime.core.FlorisBoard
import dev.patrickgold.florisboard.ime.core.Preferences
import dev.patrickgold.florisboard.ime.theme.ThemeManager
@@ -29,7 +29,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.sendBlocking
@Suppress("MemberVisibilityCanBePrivate")
abstract class KeyboardView : View, KeyboardState.OnUpdateStateListener, ThemeManager.OnThemeUpdatedListener {
abstract class KeyboardView : ViewGroup, KeyboardState.OnUpdateStateListener, ThemeManager.OnThemeUpdatedListener {
protected val florisboard get() = FlorisBoard.getInstanceOrNull()
protected val prefs get() = Preferences.default()
protected val themeManager get() = ThemeManager.defaultOrNull()
@@ -37,7 +37,7 @@ abstract class KeyboardView : View, KeyboardState.OnUpdateStateListener, ThemeMa
var isMeasured: Boolean = false
private set
protected var isTouchable: Boolean = true
protected val touchEventChannel: Channel<MotionEvent> = Channel(16)
protected val touchEventChannel: Channel<MotionEvent> = Channel(64)
protected val mainScope: CoroutineScope = CoroutineScope(Dispatchers.Main.immediate + SupervisorJob())
constructor(context: Context) : this(context, null)
@@ -64,6 +64,10 @@ abstract class KeyboardView : View, KeyboardState.OnUpdateStateListener, ThemeMa
themeManager?.unregisterOnThemeUpdatedListener(this)
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
return true
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
event ?: return false

View File

@@ -22,17 +22,18 @@ import android.view.View
import android.widget.*
import com.google.android.material.tabs.TabLayout
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.databinding.FlorisboardBinding
import dev.patrickgold.florisboard.debug.LogTopic
import dev.patrickgold.florisboard.debug.flogInfo
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.keyboard.TextKeyData
import kotlinx.coroutines.*
import timber.log.Timber
import java.util.*
/**
@@ -57,8 +58,6 @@ class MediaInputManager private constructor() : CoroutineScope by MainScope(),
private var tabLayout: TabLayout? = null
private val tabViews = EnumMap<Tab, LinearLayout>(Tab::class.java)
private var mediaViewGroup: LinearLayout? = null
companion object {
private var instance: MediaInputManager? = null
@@ -75,27 +74,20 @@ class MediaInputManager private constructor() : CoroutineScope by MainScope(),
florisboard.addEventListener(this)
}
/**
* Called when a new input view has been registered. Used to initialize all media-relevant
* views and layouts.
* TODO: evaluate if the view initializing process can be optimized.
*/
@SuppressLint("ClickableViewAccessibility")
override fun onRegisterInputView(inputView: InputView) {
Timber.i("onRegisterInputView(inputView)")
override fun onInitializeInputUi(uiBinding: FlorisboardBinding) {
flogInfo(LogTopic.IMS_EVENTS)
launch(Dispatchers.Default) {
mediaViewGroup = inputView.findViewById(R.id.media_input)
mediaViewFlipper = inputView.findViewById(R.id.media_input_view_flipper)
mediaViewFlipper = uiBinding.media.mediaInputViewFlipper
// Init bottom buttons
inputView.findViewById<Button>(R.id.media_input_switch_to_text_input_button)
.setOnTouchListener { view, event -> onBottomButtonEvent(view, event) }
inputView.findViewById<ImageButton>(R.id.media_input_backspace_button)
.setOnTouchListener { view, event -> onBottomButtonEvent(view, event) }
// Init bottom buttons
uiBinding.media.mediaInputSwitchToTextInputButton
.setOnTouchListener { view, event -> onBottomButtonEvent(view, event) }
uiBinding.media.mediaInputBackspaceButton
.setOnTouchListener { view, event -> onBottomButtonEvent(view, event) }
tabLayout = inputView.findViewById(R.id.media_input_tabs)
tabLayout?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
tabLayout = uiBinding.media.mediaInputTabs.also {
it.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
when (tab.position) {
0 -> setActiveTab(Tab.EMOJI)
@@ -107,15 +99,15 @@ class MediaInputManager private constructor() : CoroutineScope by MainScope(),
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
})
}
withContext(Dispatchers.Main) {
for (tab in Tab.values()) {
val tabView = createTabViewFor(tab)
tabViews[tab] = tabView
mediaViewFlipper?.addView(tabView)
}
tabLayout?.selectTab(tabLayout?.getTabAt(0))
launch(Dispatchers.Main) {
for (tab in Tab.values()) {
val tabView = createTabViewFor(tab)
tabViews[tab] = tabView
mediaViewFlipper?.addView(tabView)
}
tabLayout?.selectTab(tabLayout?.getTabAt(0))
}
}
@@ -123,7 +115,7 @@ class MediaInputManager private constructor() : CoroutineScope by MainScope(),
* Clean-up of resources and stopping all coroutines.
*/
override fun onDestroy() {
Timber.i("onDestroy()")
flogInfo(LogTopic.IMS_EVENTS)
cancel()
instance = null

View File

@@ -72,7 +72,7 @@ class MediaInputView : LinearLayout, FlorisBoard.EventListener,
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val height = florisboard?.inputView?.desiredMediaKeyboardViewHeight ?: 0.0f
val height = florisboard?.uiBinding?.inputView?.desiredMediaKeyboardViewHeight ?: 0.0f
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height.roundToInt(), MeasureSpec.EXACTLY))
}
}

View File

@@ -45,6 +45,7 @@ class PopupLayerView : FrameLayout {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
)
setWillNotDraw(true)
}
var clipboardPopupManager: ClipboardPopupManager? = null

View File

@@ -146,8 +146,22 @@ class PopupManager<V : View>(
}
fun isSuitableForPopups(key: Key): Boolean {
return isSuitableForBasicPopup(key) || isSuitableForExtendedPopup(key)
}
private fun isSuitableForBasicPopup(key: Key): Boolean {
return if (key is TextKey) {
key.computedData.code > KeyCode.SPACE && key.computedData.code != KeyCode.MULTIPLE_CODE_POINTS
val c = key.computedData.code
c > KeyCode.SPACE && c != KeyCode.MULTIPLE_CODE_POINTS
} else {
true
}
}
private fun isSuitableForExtendedPopup(key: Key): Boolean {
return if (key is TextKey) {
val c = key.computedData.code
c > KeyCode.SPACE && c != KeyCode.MULTIPLE_CODE_POINTS || exceptionsForKeyCodes.contains(c)
} else {
true
}
@@ -194,7 +208,7 @@ class PopupManager<V : View>(
* @param keyHintConfiguration The key hint configuration to use.
*/
fun show(key: Key, keyHintConfiguration: KeyHintConfiguration) {
if (!isSuitableForPopups(key)) return
if (!isSuitableForBasicPopup(key)) return
calc(key)
@@ -242,10 +256,7 @@ class PopupManager<V : View>(
* @param keyHintConfiguration The key hint configuration to use.
*/
fun extend(key: Key, keyHintConfiguration: KeyHintConfiguration) {
if (key is TextKey && !isSuitableForPopups(key)
&& !exceptionsForKeyCodes.contains(key.computedData.code)) {
return
}
if (!isSuitableForExtendedPopup(key)) return
if (!isShowingPopup) {
calc(key)
@@ -424,7 +435,7 @@ class PopupManager<V : View>(
return false
}
popupViewExt.properties.activeElementIndex = when {
val newActiveElementIndex = when {
anchorLeft -> when {
// check if out of boundary on x-axis
x < keyPopupDiffX - (anchorOffset + 1) * keyPopupWidth ||
@@ -469,7 +480,10 @@ class PopupManager<V : View>(
}
else -> -1
}
popupViewExt.invalidate()
if (newActiveElementIndex != popupViewExt.properties.activeElementIndex) {
popupViewExt.properties.activeElementIndex = newActiveElementIndex
popupViewExt.invalidate()
}
return true
}

View File

@@ -16,14 +16,12 @@
package dev.patrickgold.florisboard.ime.text
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.view.KeyEvent
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.text.isDigitsOnly
import dev.patrickgold.florisboard.BuildConfig
import dev.patrickgold.florisboard.R
import dev.patrickgold.florisboard.databinding.FlorisboardBinding
import dev.patrickgold.florisboard.debug.*
import dev.patrickgold.florisboard.ime.clip.provider.ClipboardItem
import dev.patrickgold.florisboard.ime.core.*
@@ -43,7 +41,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 kotlin.math.roundToLong
/**
* TextInputManager is responsible for managing everything which is related to text input. All of
@@ -72,7 +69,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
private var textInputKeyboardView: TextKeyboardView? = null
lateinit var textKeyboardIconSet: TextKeyboardIconSet
private set
private var textViewGroup: LinearLayout? = null
private val dictionaryManager: DictionaryManager get() = DictionaryManager.default()
val inputEventDispatcher: InputEventDispatcher = InputEventDispatcher.new(
repeatableKeyCodes = intArrayOf(
@@ -89,6 +85,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
val activeState: KeyboardState get() = florisboard.activeState
private var newCapsState: Boolean = false
private var isNumberRowVisible: Boolean = false
// Composing text related properties
var isManualSelectionMode: Boolean = false
@@ -213,6 +210,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
layoutManager = LayoutManager()
textKeyboardIconSet = TextKeyboardIconSet.new(florisboard)
inputEventDispatcher.keyEventReceiver = this
isNumberRowVisible = prefs.keyboard.numberRow
var subtypes = florisboard.subtypeManager.subtypes
if (subtypes.isEmpty()) {
subtypes = listOf(Subtype.DEFAULT)
@@ -224,64 +222,21 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
}
override fun onCreateInputView() {
flogInfo(LogTopic.IMS_EVENTS)
}
/**
* Sets up the newly registered input view.
*/
override fun onRegisterInputView(inputView: InputView) {
override fun onInitializeInputUi(uiBinding: FlorisboardBinding) {
flogInfo(LogTopic.IMS_EVENTS)
textViewGroup = inputView.findViewById(R.id.text_input)
textInputKeyboardView = inputView.findViewById(R.id.text_input_keyboard_view)
textInputKeyboardView?.setIconSet(textKeyboardIconSet)
textInputKeyboardView?.setComputingEvaluator(evaluator)
textInputKeyboardView?.sync()
launch(Dispatchers.Main) {
val animator1 = textViewGroup?.let {
ObjectAnimator.ofFloat(it, "alpha", 0.9f, 1.0f).apply {
duration = 125
repeatCount = 0
start()
}
}
val animator2 = textViewGroup?.let {
ObjectAnimator.ofFloat(it, "alpha", 1.0f, 0.4f).apply {
startDelay = 125
duration = 500
repeatCount = ValueAnimator.INFINITE
repeatMode = ValueAnimator.REVERSE
start()
}
}
setActiveKeyboardMode(getActiveKeyboardMode())
animator1?.cancel()
animator2?.cancel()
val animator3 = textViewGroup?.let {
ObjectAnimator.ofFloat(it, "alpha", it.alpha, 1.0f).apply {
duration = (((1.0f - it.alpha) / 0.6f) * 125f).roundToLong()
repeatCount = 0
start()
}
}
delay(animator3?.duration ?: 1)
animator3?.end()
textInputKeyboardView = uiBinding.text.mainKeyboardView.also {
it.setIconSet(textKeyboardIconSet)
it.setComputingEvaluator(evaluator)
it.sync()
}
}
fun registerSmartbarView(view: SmartbarView) {
smartbarView = view
smartbarView?.setEventListener(this)
smartbarView?.sync()
}
fun unregisterSmartbarView(view: SmartbarView) {
if (smartbarView == view) {
smartbarView = null
smartbarView = uiBinding.text.smartbar.root.also {
it.setEventListener(this)
it.sync()
}
setActiveKeyboardMode(getActiveKeyboardMode(), updateState = false)
}
/**
@@ -290,18 +245,25 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
override fun onDestroy() {
flogInfo(LogTopic.IMS_EVENTS)
smartbarView?.setEventListener(null)
smartbarView = null
textInputKeyboardView?.setComputingEvaluator(null)
textInputKeyboardView = null
keyboards.clear()
inputEventDispatcher.keyEventReceiver = null
inputEventDispatcher.close()
dictionaryManager.unloadUserDictionariesIfNecessary()
cancel()
layoutManager.onDestroy()
instance = null
}
/**
* Evaluates the [KeyboardState.keyboardMode], [KeyboardState.keyVariation] and [EditorInstance.isComposingEnabled]
* Evaluates the [KeyboardState.keyboardMode], [KeyboardState.keyVariation] and [KeyboardState.isComposingEnabled]
* property values when starting to interact with a input editor. Also resets the composing
* texts and sets the initial caps mode accordingly.
*/
@@ -340,25 +302,29 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
KeyboardMode.CHARACTERS
}
}
instance.apply {
isComposingEnabled = when (keyboardMode) {
KeyboardMode.NUMERIC,
KeyboardMode.PHONE,
KeyboardMode.PHONE2 -> false
else -> activeState.keyVariation != KeyVariation.PASSWORD &&
prefs.suggestion.enabled// &&
//!instance.inputAttributes.flagTextAutoComplete &&
//!instance.inputAttributes.flagTextNoSuggestions
}
activeState.isPrivateMode = prefs.advanced.forcePrivateMode ||
activeState.imeOptions.flagNoPersonalizedLearning
activeState.isComposingEnabled = when (keyboardMode) {
KeyboardMode.NUMERIC,
KeyboardMode.PHONE,
KeyboardMode.PHONE2 -> false
else -> activeState.keyVariation != KeyVariation.PASSWORD &&
prefs.suggestion.enabled// &&
//!instance.inputAttributes.flagTextAutoComplete &&
//!instance.inputAttributes.flagTextNoSuggestions
}
val newIsNumberRowVisible = prefs.keyboard.numberRow
if (isNumberRowVisible != newIsNumberRowVisible) {
keyboards.clear(KeyboardMode.CHARACTERS)
isNumberRowVisible = newIsNumberRowVisible
}
setActiveKeyboardMode(keyboardMode, updateState = false)
instance.composingEnabledChanged()
activeState.isPrivateMode = prefs.advanced.forcePrivateMode ||
activeState.imeOptions.flagNoPersonalizedLearning
if (!prefs.correction.rememberCapsLockState) {
activeState.capsLock = false
}
isGlidePostEffect = false
updateCapsState()
setActiveKeyboardMode(keyboardMode, updateState = false)
smartbarView?.setCandidateSuggestionWords(System.nanoTime(), null)
}
@@ -382,7 +348,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
/**
* Sets the active keyboard mode and updates the [KeyboardState.isQuickActionsVisible] state.
*/
private fun setActiveKeyboardMode(mode: KeyboardMode, updateState: Boolean = true) = launch {
private fun setActiveKeyboardMode(mode: KeyboardMode, updateState: Boolean = true) {
activeState.keyboardMode = mode
isManualSelectionMode = false
isManualSelectionModeStart = false
@@ -406,15 +372,17 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
}
}
override fun onSubtypeChanged(newSubtype: Subtype) {
override fun onSubtypeChanged(newSubtype: Subtype, doRefreshLayouts: Boolean) {
launch {
if (activeEditorInstance.isComposingEnabled) {
if (activeState.isComposingEnabled) {
dictionaryManager.prepareDictionaries(newSubtype)
}
if (prefs.glide.enabled) {
GlideTypingManager.getInstance().setWordData(newSubtype)
}
setActiveKeyboard(getActiveKeyboardMode(), newSubtype)
if (doRefreshLayouts) {
setActiveKeyboard(getActiveKeyboardMode(), newSubtype)
}
}
isGlidePostEffect = false
}
@@ -428,7 +396,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(), In
updateCapsState()
}
flogInfo(LogTopic.IMS_EVENTS) { "current word: ${activeEditorInstance.cachedInput.currentWord.text}" }
if (activeEditorInstance.isComposingEnabled && !inputEventDispatcher.isPressed(KeyCode.DELETE) && !isGlidePostEffect) {
if (activeState.isComposingEnabled && !inputEventDispatcher.isPressed(KeyCode.DELETE) && !isGlidePostEffect) {
if (activeEditorInstance.shouldReevaluateComposingSuggestions) {
activeEditorInstance.shouldReevaluateComposingSuggestions = false
launch(Dispatchers.Default) {

View File

@@ -98,11 +98,11 @@ class EditingKeyboardView : ConstraintLayout, FlorisBoard.EventListener,
}
MeasureSpec.AT_MOST -> {
// Can't be bigger than...
(florisboard?.inputView?.desiredTextKeyboardViewHeight ?: 0.0f).coerceAtMost(heightSize)
(florisboard?.uiBinding?.inputView?.desiredTextKeyboardViewHeight ?: 0.0f).coerceAtMost(heightSize)
}
else -> {
// Be whatever you want
florisboard?.inputView?.desiredTextKeyboardViewHeight ?: 0.0f
florisboard?.uiBinding?.inputView?.desiredTextKeyboardViewHeight ?: 0.0f
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.text.keyboard
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.graphics.drawable.PaintDrawable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import dev.patrickgold.florisboard.common.ViewUtils
class TextKeyView : View {
private val parentKeyboardView get() = parent as? TextKeyboardView
var key: TextKey? = null
val bgDrawable = PaintDrawable().also {
it.setCornerRadius(ViewUtils.dp2px(6.0f))
}
val labelPaint: Paint = Paint().also {
it.isAntiAlias = true
it.isFakeBoldText = false
it.textAlign = Paint.Align.CENTER
it.typeface = Typeface.DEFAULT
}
val hintedLabelPaint: Paint = Paint().also {
it.isAntiAlias = true
it.isFakeBoldText = false
it.textAlign = Paint.Align.CENTER
it.typeface = Typeface.MONOSPACE
}
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) {
background = bgDrawable
setWillNotDraw(false)
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
return false
}
override fun onHoverEvent(event: MotionEvent?): Boolean {
return false
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
return // This view does not measure itself
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val key = key ?: return
canvas ?: return
canvas.save()
canvas.translate(-x, -y)
parentKeyboardView?.onDrawComputedKey(canvas, key, this)
canvas.restore()
}
}

View File

@@ -33,6 +33,9 @@ class TextKeyboard(
val rowCount: Int
get() = arrangement.size
val keyCount: Int
get() = arrangement.sumOf { it.size }
companion object {
fun layoutDrawableBounds(key: TextKey, factor: Double) {
layoutForegroundBounds(key, key.visibleDrawableBounds, 0.21 * (1.0 / factor), isLabel = false)

View File

@@ -55,9 +55,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
private var computedKeyboard: TextKeyboard? = null
private var iconSet: TextKeyboardIconSet? = null
// IS ONLY USED IF KEYBOARD IS IN PREVIEW MODE
private var cachedTheme: Theme? = null
private var cachedState: KeyboardState = KeyboardState.new(maskOfInterest = KeyboardState.INTEREST_TEXT)
private var externalComputingEvaluator: TextComputingEvaluator? = null
@@ -109,8 +107,8 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
}
internal var isSmartbarKeyboardView: Boolean = false
private var isPreviewMode: Boolean = false
private var isLoadingPlaceholderKeyboard: Boolean = false
internal var isPreviewMode: Boolean = false
internal var isLoadingPlaceholderKeyboard: Boolean = false
private var keyHintConfiguration: KeyHintConfiguration = KeyHintConfiguration.HINTS_DISABLED
private val pointerMap: PointerMap<TouchPointer> = PointerMap { TouchPointer() }
@@ -129,21 +127,12 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
private var fadingGlideRadius: Float = 0.0f
val desiredKey: TextKey = TextKey(data = TextKeyData.UNSPECIFIED)
private val desiredKeyView: TextKeyView = TextKeyView(context).also {
it.key = desiredKey
}
private var keyMarginH: Int = 0
private var keyMarginV: Int = 0
private var keyBackgroundPaint = Paint().also {
it.isAntiAlias = true
it.style = Paint.Style.FILL
}
private var keyShadowBackgroundPaint = Paint().also {
it.isAntiAlias = true
it.style = Paint.Style.STROKE
it.strokeCap = Paint.Cap.ROUND
it.strokeWidth = 6.0f
}
private val keyBackgroundCornerSize: Float = ViewUtils.dp2px(6.0f)
private var backgroundDrawable: PaintDrawable = PaintDrawable()
private val baselineTextSize = resources.getDimension(R.dimen.key_textSize)
var fontSizeMultiplier: Double = 1.0
@@ -151,21 +140,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
private val glideTrailPaint: Paint = Paint()
private var labelPaintTextSize: Float = resources.getDimension(R.dimen.key_textSize)
private var labelPaintSpaceTextSize: Float = resources.getDimension(R.dimen.key_textSize)
private val labelPaint: Paint = Paint().also {
it.isAntiAlias = true
it.isFakeBoldText = false
it.textAlign = Paint.Align.CENTER
it.textSize = labelPaintTextSize
it.typeface = Typeface.DEFAULT
}
private var hintedLabelPaintTextSize: Float = resources.getDimension(R.dimen.key_textHintSize)
private val hintedLabelPaint: Paint = Paint().also {
it.isAntiAlias = true
it.isFakeBoldText = false
it.textAlign = Paint.Align.CENTER
it.textSize = hintedLabelPaintTextSize
it.typeface = Typeface.MONOSPACE
}
private val tempRect: Rect = Rect()
constructor(context: Context) : this(context, null)
@@ -186,6 +161,10 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
popupManager = PopupManager(this, popupLayerView)
swipeGestureDetector.isEnabled = !isSmartbarKeyboardView
if (isPreviewMode) {
background = backgroundDrawable
}
setWillNotDraw(false)
}
@@ -195,6 +174,17 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
fun setComputedKeyboard(keyboard: TextKeyboard) {
flogInfo(LogTopic.TEXT_KEYBOARD_VIEW) { keyboard.mode.toString() }
val renderViewDiff = keyboard.keyCount - childCount
if (renderViewDiff > 0) {
// We have more keys than render views, add abs(diff) views
for (n in 0 until abs(renderViewDiff)) {
addView(TextKeyView(context))
}
} else if (renderViewDiff < 0) {
// We have more render views than keys, remove abs(diff) views
val n = abs(renderViewDiff)
removeViews(childCount - n, n)
}
computedKeyboard = keyboard
initGlideClassifier(keyboard)
if (isMeasured) {
@@ -212,7 +202,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
override fun onUpdateKeyboardState(newState: KeyboardState) {
flogInfo(LogTopic.TEXT_KEYBOARD_VIEW) { computedKeyboard?.mode?.toString() ?: "" }
if (isMeasured) {
if (newState != cachedState) {
if (cachedState.isDifferentTo(newState)) {
// Something within the defined interest has changed
cachedState.reset(newState)
computeKeyboard()
@@ -333,7 +323,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
pointer.longPressJob = null
pointer.hasTriggeredGestureMove = true
pointer.activeKey?.let { activeKey ->
activeKey.setPressed(false) { invalidate() }
activeKey.setPressed(false) { invalidate(activeKey) }
florisboard!!.textInputManager.inputEventDispatcher.let { dispatcher ->
if (dispatcher.isPressed(activeKey.computedData.code)) {
dispatcher.send(InputKeyEvent.cancel(activeKey.computedData))
@@ -351,6 +341,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
val pointerId = event.getPointerId(pointerIndex)
val pointer = pointerMap.findById(pointerId)
if (pointer != null) {
pointer.index = pointerIndex
if (swipeGestureDetector.onTouchUp(event, pointer) || pointer.hasTriggeredGestureMove || pointer.shouldBlockNextUp) {
if (pointer.hasTriggeredGestureMove && pointer.initialKey?.computedData?.code == KeyCode.DELETE) {
florisboard!!.textInputManager.isGlidePostEffect = false
@@ -420,7 +411,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
}
florisboard!!.keyPressVibrate()
florisboard!!.keyPressSound(key.computedData)
key.setPressed(true) { invalidate() }
key.setPressed(true) { invalidate(key) }
if (pointer.initialKey == null) {
pointer.initialKey = key
}
@@ -502,7 +493,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
val initialKey = pointer.initialKey
val activeKey = pointer.activeKey
if (initialKey != null && activeKey != null) {
activeKey.setPressed(false) { invalidate() }
activeKey.setPressed(false) { invalidate(activeKey) }
florisboard!!.textInputManager.inputEventDispatcher.let { dispatcher ->
if (popupManager.isSuitableForPopups(activeKey)) {
val retData = popupManager.getActiveKeyData(activeKey, keyHintConfiguration)
@@ -545,7 +536,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
val activeKey = pointer.activeKey
if (activeKey != null) {
activeKey.setPressed(false) { invalidate() }
activeKey.setPressed(false) { invalidate(activeKey) }
florisboard.textInputManager.inputEventDispatcher.let { dispatcher ->
dispatcher.send(InputKeyEvent.cancel(activeKey.computedData))
}
@@ -734,7 +725,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
val desiredHeight = if (isSmartbarKeyboardView || isPreviewMode) {
MeasureSpec.getSize(heightMeasureSpec).toFloat()
} else {
(florisboard?.inputView?.desiredTextKeyboardViewHeight ?: MeasureSpec.getSize(heightMeasureSpec).toFloat())
(florisboard?.uiBinding?.inputView?.desiredTextKeyboardViewHeight ?: MeasureSpec.getSize(heightMeasureSpec).toFloat())
} * if (isPreviewMode) {
0.90f
} else {
@@ -749,7 +740,6 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
flogInfo(LogTopic.TEXT_KEYBOARD_VIEW) { computedKeyboard?.mode?.toString() ?: "" }
super.onLayout(changed, left, top, right, bottom)
computeDesiredDimensions()
computeKeyboard()
}
@@ -767,7 +757,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
isSmartbarKeyboardView -> {
measuredHeight
}
florisboard?.inputView?.shouldGiveAdditionalSpace == true -> {
florisboard?.uiBinding?.inputView?.shouldGiveAdditionalSpace == true -> {
(measuredHeight / (keyboard.rowCount + 0.5f).coerceAtMost(5.0f)).toInt()
}
else -> {
@@ -793,23 +783,23 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
TextKeyboard.layoutLabelBounds(desiredKey)
setTextSizeFor(
labelPaint,
desiredKeyView.labelPaint,
desiredKey.visibleLabelBounds.width().toFloat(),
desiredKey.visibleLabelBounds.height().toFloat(),
"X",
fontSizeMultiplier
)
labelPaintTextSize = labelPaint.textSize
labelPaintSpaceTextSize = labelPaint.textSize.coerceAtMost(resources.getDimension(R.dimen.key_space_textSize))
labelPaintTextSize = desiredKeyView.labelPaint.textSize
labelPaintSpaceTextSize = desiredKeyView.labelPaint.textSize.coerceAtMost(resources.getDimension(R.dimen.key_space_textSize))
setTextSizeFor(
hintedLabelPaint,
desiredKeyView.hintedLabelPaint,
desiredKey.visibleBounds.width() * 1.0f / 5.0f,
desiredKey.visibleBounds.height() * 1.0f / 5.0f,
"X",
fontSizeMultiplier
)
hintedLabelPaintTextSize = hintedLabelPaint.textSize
hintedLabelPaintTextSize = desiredKeyView.hintedLabelPaint.textSize
}
private fun computeKeyboard() {
@@ -820,6 +810,117 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
computeLabelsAndDrawables(key, keyHintConfiguration)
}
keyboard.layout(this)
val theme = cachedTheme ?: themeManager?.activeTheme ?: Theme.BASE_THEME
val isBorderless = !theme.getAttr(Theme.Attr.KEY_SHOW_BORDER).toOnOff().state
keyboard.keys().withIndex().forEach { (n, key) ->
getChildAt(n)?.let { rv ->
if (rv is TextKeyView) {
rv.key = key
layoutRenderView(rv, key, isBorderless)
prepareKey(key, theme, rv)
rv.invalidate()
}
}
}
}
private fun layoutRenderView(rv: TextKeyView, key: TextKey, isBorderless: Boolean) {
rv.layout(
key.visibleBounds.left,
if (isBorderless) {
(key.visibleBounds.top + key.visibleBounds.height() * 0.12).toInt()
} else {
key.visibleBounds.top
},
key.visibleBounds.right,
if (isBorderless) {
(key.visibleBounds.bottom - key.visibleBounds.height() * 0.12).toInt()
} else {
key.visibleBounds.bottom
}
)
}
private fun prepareKey(key: TextKey, theme: Theme, renderView: TextKeyView) {
val keyBackground: ThemeValue
val keyForeground: ThemeValue
val shouldShowBorder: Boolean
val themeLabel = key.computedData.asString(isForDisplay = false)
when {
isLoadingPlaceholderKeyboard -> {
shouldShowBorder = theme.getAttr(Theme.Attr.KEY_SHOW_BORDER, themeLabel).toOnOff().state
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND_PRESSED, themeLabel)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND_PRESSED, themeLabel)
} else {
keyBackground = if (shouldShowBorder) {
theme.getAttr(Theme.Attr.KEY_BACKGROUND, themeLabel)
} else {
theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_BACKGROUND, themeLabel)
}
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND, themeLabel)
}
}
isSmartbarKeyboardView -> {
shouldShowBorder = false
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_BACKGROUND)
keyForeground = theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND)
} else {
keyBackground = theme.getAttr(Theme.Attr.SMARTBAR_BACKGROUND)
keyForeground = if (!key.isEnabled) {
theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND_ALT)
} else {
theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND)
}
}
}
else -> {
val capsSpecific = when {
cachedState.capsLock -> {
"capslock"
}
cachedState.caps -> {
"caps"
}
else -> {
null
}
}
shouldShowBorder = theme.getAttr(Theme.Attr.KEY_SHOW_BORDER, themeLabel, capsSpecific).toOnOff().state
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND_PRESSED, themeLabel, capsSpecific)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND_PRESSED, themeLabel, capsSpecific)
} else {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND, themeLabel, capsSpecific)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND, themeLabel, capsSpecific)
}
}
}
renderView.let { rv ->
rv.elevation = if (shouldShowBorder) 4.0f else 0.0f
rv.bgDrawable.paint.color = keyBackground.toSolidColor().color
rv.labelPaint.let {
it.color = keyForeground.toSolidColor().color
if (computedKeyboard?.mode == KeyboardMode.CHARACTERS && key.computedData.code == KeyCode.SPACE) {
it.alpha = 120
}
it.textSize = when (key.computedData.code) {
KeyCode.SPACE -> labelPaintSpaceTextSize
KeyCode.VIEW_CHARACTERS,
KeyCode.VIEW_SYMBOLS,
KeyCode.VIEW_SYMBOLS2 -> labelPaintTextSize * 0.80f
KeyCode.VIEW_NUMERIC,
KeyCode.VIEW_NUMERIC_ADVANCED -> labelPaintTextSize * 0.55f
else -> labelPaintTextSize
}
}
rv.hintedLabelPaint.let {
it.color = keyForeground.toSolidColor().color
it.alpha = 170
it.textSize = hintedLabelPaintTextSize
}
}
}
/**
@@ -882,160 +983,34 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
} else {
glideTrailPaint.color = theme.getAttr(Theme.Attr.GLIDE_TRAIL_COLOR).toSolidColor().color
}
keyShadowBackgroundPaint.color = Color.argb(32, 0, 0, 0)
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (!isVisible) return
if (canvas == null) {
flogWarning(LogTopic.TEXT_KEYBOARD_VIEW) { "${computedKeyboard?.mode} Cannot draw: 'canvas' is null!" }
return
} else {
flogInfo(LogTopic.TEXT_KEYBOARD_VIEW) { computedKeyboard?.mode.toString() }
}
if (isPreviewMode) {
backgroundDrawable.let {
it.setBounds(0, 0, measuredWidth, measuredHeight)
it.draw(canvas)
val isBorderless = !theme.getAttr(Theme.Attr.KEY_SHOW_BORDER).toOnOff().state
for (n in 0 until childCount) {
val rv = getChildAt(n) as? TextKeyView
if (rv?.key != null) {
layoutRenderView(rv, rv.key!!, isBorderless)
prepareKey(rv.key!!, cachedTheme ?: themeManager?.activeTheme ?: Theme.BASE_THEME, rv)
rv.invalidate()
}
}
onDrawComputedKeyboard(canvas)
}
private fun onDrawComputedKeyboard(canvas: Canvas) {
flogInfo(LogTopic.TEXT_KEYBOARD_VIEW) { computedKeyboard?.mode.toString() }
val keyboard = computedKeyboard ?: return
// SUPER JANK nyi message implementation for the editing layout
if (keyboard.mode == KeyboardMode.EDITING) {
val msg = "The Editing layout is currently not available, see #216."
val msg2 = "Will be re-implemented in a later stage."
labelPaint.apply {
textSize = 30.0f
private fun invalidate(key: TextKey) {
for (n in 0 until childCount) {
val rv = getChildAt(n) as? TextKeyView
if (rv != null && rv.key == key) {
prepareKey(key, cachedTheme ?: themeManager?.activeTheme ?: Theme.BASE_THEME, rv)
rv.invalidate()
break
}
canvas.drawText(msg, measuredWidth / 2.0f, 100.0f, labelPaint)
canvas.drawText(msg2, measuredWidth / 2.0f, 200.0f, labelPaint)
return
}
val theme = cachedTheme ?: themeManager?.activeTheme ?: Theme.BASE_THEME
val isBorderless = !theme.getAttr(Theme.Attr.KEY_SHOW_BORDER).toOnOff().state &&
Color.alpha(theme.getAttr(Theme.Attr.KEY_BACKGROUND).toSolidColor().color) <= 0x0F
for (key in keyboard.keys()) {
onDrawComputedKey(canvas, key, theme, isBorderless)
}
}
private fun onDrawComputedKey(canvas: Canvas, key: TextKey, theme: Theme, isBorderless: Boolean) {
fun onDrawComputedKey(canvas: Canvas, key: TextKey, renderView: TextKeyView) {
if (!key.isVisible) return
val keyBackground: ThemeValue
val keyForeground: ThemeValue
val shouldShowBorder: Boolean
val themeLabel = key.computedData.asString(isForDisplay = false)
when {
isLoadingPlaceholderKeyboard -> {
shouldShowBorder = theme.getAttr(Theme.Attr.KEY_SHOW_BORDER, themeLabel).toOnOff().state
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND_PRESSED, themeLabel)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND_PRESSED, themeLabel)
} else {
keyBackground = if (shouldShowBorder) {
theme.getAttr(Theme.Attr.KEY_BACKGROUND, themeLabel)
} else {
theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_BACKGROUND, themeLabel)
}
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND, themeLabel)
}
}
isSmartbarKeyboardView -> {
shouldShowBorder = false
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.SMARTBAR_BUTTON_BACKGROUND)
keyForeground = theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND)
} else {
keyBackground = theme.getAttr(Theme.Attr.SMARTBAR_BACKGROUND)
keyForeground = if (!key.isEnabled) {
theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND_ALT)
} else {
theme.getAttr(Theme.Attr.SMARTBAR_FOREGROUND)
}
}
}
else -> {
val capsSpecific = when {
cachedState.capsLock -> {
"capslock"
}
cachedState.caps -> {
"caps"
}
else -> {
null
}
}
shouldShowBorder = theme.getAttr(Theme.Attr.KEY_SHOW_BORDER, themeLabel, capsSpecific).toOnOff().state
if (key.isPressed && key.isEnabled) {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND_PRESSED, themeLabel, capsSpecific)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND_PRESSED, themeLabel, capsSpecific)
} else {
keyBackground = theme.getAttr(Theme.Attr.KEY_BACKGROUND, themeLabel, capsSpecific)
keyForeground = theme.getAttr(Theme.Attr.KEY_FOREGROUND, themeLabel, capsSpecific)
}
}
}
val bgBoundsLeft = key.visibleBounds.left.toFloat()
val bgBoundsTop = (if (isBorderless) {
(key.visibleBounds.top + key.visibleBounds.height() * 0.12).toInt()
} else {
key.visibleBounds.top
}).toFloat()
val bgBoundsRight = key.visibleBounds.right.toFloat()
val bgBoundsBottom = (if (isBorderless) {
(key.visibleBounds.bottom - key.visibleBounds.height() * 0.12).toInt()
} else {
key.visibleBounds.bottom
}).toFloat()
if (shouldShowBorder) {
keyShadowBackgroundPaint.let {
canvas.drawRoundRect(
bgBoundsLeft, bgBoundsTop, bgBoundsRight, bgBoundsBottom,
keyBackgroundCornerSize,
keyBackgroundCornerSize,
it
)
}
}
keyBackgroundPaint.let {
it.color = keyBackground.toSolidColor().color
canvas.drawRoundRect(
bgBoundsLeft, bgBoundsTop, bgBoundsRight, bgBoundsBottom,
keyBackgroundCornerSize,
keyBackgroundCornerSize,
it
)
}
val label = key.label
if (label != null) {
labelPaint.let {
it.color = keyForeground.toSolidColor().color
if (computedKeyboard?.mode == KeyboardMode.CHARACTERS && key.computedData.code == KeyCode.SPACE) {
it.alpha = 120
}
it.textSize = when (key.computedData.code) {
KeyCode.SPACE -> labelPaintSpaceTextSize
KeyCode.VIEW_CHARACTERS,
KeyCode.VIEW_SYMBOLS,
KeyCode.VIEW_SYMBOLS2 -> labelPaintTextSize * 0.80f
KeyCode.VIEW_NUMERIC,
KeyCode.VIEW_NUMERIC_ADVANCED -> labelPaintTextSize * 0.55f
else -> labelPaintTextSize
}
renderView.labelPaint.let {
val centerX = key.visibleLabelBounds.exactCenterX()
val centerY = key.visibleLabelBounds.exactCenterY() + (it.textSize - it.descent()) / 2
if (label.contains("\n")) {
@@ -1052,10 +1027,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
val hintedLabel = key.hintedLabel
if (hintedLabel != null) {
hintedLabelPaint.let {
it.color = keyForeground.toSolidColor().color
it.alpha = 170
it.textSize = hintedLabelPaintTextSize
renderView.hintedLabelPaint.let {
val centerX = key.visibleBounds.left + key.visibleBounds.width() * 5.0f / 6.0f
val centerY = key.visibleBounds.top + key.visibleBounds.height() * 1.0f / 6.0f + (it.textSize - it.descent()) / 2
canvas.drawText(hintedLabel, centerX, centerY, it)
@@ -1066,7 +1038,7 @@ class TextKeyboardView : KeyboardView, SwipeGesture.Listener, GlideTypingGesture
if (foregroundDrawableId != null) {
iconSet?.withDrawable(foregroundDrawableId) {
bounds = key.visibleDrawableBounds
setTint(keyForeground.toSolidColor().color)
setTint(renderView.labelPaint.color)
draw(canvas)
}
}

View File

@@ -132,7 +132,7 @@ class CandidateView : View, ThemeManager.OnThemeUpdatedListener {
recomputeCandidates()
}
fun setEventListener(listener: SmartbarView.EventListener) {
fun setEventListener(listener: SmartbarView.EventListener?) {
eventListener = WeakReference(listener)
}

View File

@@ -85,6 +85,11 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onFinishInflate() {
super.onFinishInflate()
binding = SmartbarBinding.bind(this)
}
/**
* Called by Android when this view has been attached to a window. At this point we can be
* certain that all children have been instantiated and that we can begin working with them.
@@ -96,8 +101,6 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
super.onAttachedToWindow()
binding = SmartbarBinding.bind(this)
for (view in binding.actionStartArea.children) {
indexedActionStartArea.add(view.id)
}
@@ -156,21 +159,12 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
eventListener.get()?.onSmartbarQuickActionPressed(it.id)
}
configureFeatureVisibility(
actionStartAreaVisible = false,
actionStartAreaId = null,
mainAreaId = null,
actionEndAreaVisible = false,
actionEndAreaId = null
)
configureFeatureVisibility()
themeManager.registerOnThemeUpdatedListener(this)
florisboard?.textInputManager?.registerSmartbarView(this)
}
override fun onDetachedFromWindow() {
florisboard?.textInputManager?.unregisterSmartbarView(this)
themeManager.unregisterOnThemeUpdatedListener(this)
super.onDetachedFromWindow()
}
@@ -220,6 +214,12 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
binding.actionEndArea.displayedChild =
indexedActionEndArea.indexOf(actionEndAreaId).coerceAtLeast(0)
}
cachedActionStartAreaVisible = actionStartAreaVisible
cachedActionStartAreaId = actionStartAreaId
cachedMainAreaId = mainAreaId
cachedActionEndAreaVisible = actionEndAreaVisible
cachedActionEndAreaId = actionEndAreaId
}
override fun onInterceptUpdateKeyboardState(newState: KeyboardState): Boolean {
@@ -228,14 +228,12 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
override fun onUpdateKeyboardState(newState: KeyboardState) {
flogInfo(LogTopic.SMARTBAR)
if (newState != cachedState) {
if (cachedState.isDifferentTo(newState)) {
cachedState.reset(newState)
if (this::binding.isInitialized) {
updateUi()
when (cachedMainAreaId) {
R.id.clipboard_cursor_row -> binding.clipboardCursorRow.updateKeyboardState(newState)
R.id.number_row -> binding.numberRow.updateKeyboardState(newState)
}
updateUi()
when (cachedMainAreaId) {
R.id.clipboard_cursor_row -> binding.clipboardCursorRow.updateKeyboardState(newState)
R.id.number_row -> binding.numberRow.updateKeyboardState(newState)
}
}
}
@@ -265,15 +263,13 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
cachedState.keyVariation == KeyVariation.PASSWORD -> {
if (!prefs.keyboard.numberRow) R.id.number_row else null
}
else -> when (florisboard.textInputManager.getActiveKeyboardMode()) {
else -> when (cachedState.keyboardMode) {
KeyboardMode.EDITING -> null
KeyboardMode.NUMERIC,
KeyboardMode.PHONE,
KeyboardMode.PHONE2 -> R.id.clipboard_cursor_row
else -> when {
florisboard.activeEditorInstance.isComposingEnabled &&
florisboard.activeEditorInstance.selection.isCursorMode
-> R.id.candidates
cachedState.isComposingEnabled && cachedState.isCursorMode -> R.id.candidates
else -> R.id.clipboard_cursor_row
}
}
@@ -362,7 +358,7 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
binding.inlineSuggestionsStrip.removeAllViews()
val florisboard = florisboard ?: return
if (suggestionViews.isEmpty()) {
florisboard.activeState.isQuickActionsVisible = false
florisboard.activeState.isShowingInlineSuggestions = false
return
} else {
for (suggestionView in suggestionViews) {
@@ -371,7 +367,7 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
}
binding.inlineSuggestionsStrip.addView(suggestionView)
}
florisboard.activeState.isQuickActionsVisible = true
florisboard.activeState.isShowingInlineSuggestions = true
}
updateKeyboardState(florisboard.activeState)
}
@@ -386,11 +382,11 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
}
MeasureSpec.AT_MOST -> {
// Can't be bigger than...
(florisboard?.inputView?.desiredSmartbarHeight ?: resources.getDimension(R.dimen.smartbar_baseHeight)).coerceAtMost(heightSize)
(florisboard?.uiBinding?.inputView?.desiredSmartbarHeight ?: resources.getDimension(R.dimen.smartbar_baseHeight)).coerceAtMost(heightSize)
}
else -> {
// Be whatever you want
florisboard?.inputView?.desiredSmartbarHeight ?: resources.getDimension(R.dimen.smartbar_baseHeight)
florisboard?.uiBinding?.inputView?.desiredSmartbarHeight ?: resources.getDimension(R.dimen.smartbar_baseHeight)
}
}
@@ -402,7 +398,7 @@ class SmartbarView : ConstraintLayout, KeyboardState.OnUpdateStateListener, Them
invalidate()
}
fun setEventListener(listener: EventListener) {
fun setEventListener(listener: EventListener?) {
eventListener = WeakReference(listener)
binding.candidates.setEventListener(listener)
}

View File

@@ -91,6 +91,8 @@ class ThemeEditorActivity : AppCompatActivity() {
binding.themeNameEditBtn.setOnClickListener { showMetaEditDialog() }
binding.keyboardPreview.sync()
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)

View File

@@ -164,6 +164,7 @@ class ThemeManagerActivity : FlorisActivity<ThemeManagerActivityBinding>() {
textKeyboardIconSet = TextKeyboardIconSet.new(this)
binding.keyboardPreview.setIconSet(textKeyboardIconSet)
binding.keyboardPreview.setComputingEvaluator(textComputingEvaluator)
binding.keyboardPreview.sync()
buildUi()
}
@@ -182,11 +183,18 @@ class ThemeManagerActivity : FlorisActivity<ThemeManagerActivityBinding>() {
}
}
override fun finish() {
override fun onPause() {
super.onPause()
// Normally the selection should already be applied to the prefs, but just to make sure we
// apply it here again.
setThemeRefInPrefs(selectedRef)
}
override fun finish() {
super.finish()
// Normally the selection should already be applied to the prefs, but just to make sure we
// apply it here again.
setThemeRefInPrefs(selectedRef)
}
private fun evaluateSelectedRef(ignorePrefs: Boolean = false): AssetRef? {

View File

@@ -2,16 +2,17 @@
<dev.patrickgold.florisboard.ime.core.InputWindowView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/florisboard"
android:id="@+id/input_window_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="bottom"
android:orientation="vertical"
android:layoutDirection="ltr">
android:layoutDirection="ltr"
android:hapticFeedbackEnabled="true">
<dev.patrickgold.florisboard.ime.core.InputView
android:id="@+id/inner_input_view_container"
android:id="@+id/input_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
@@ -53,11 +54,11 @@
android:layout_weight="1"
android:measureAllChildren="false">
<include layout="@layout/text_input_layout"/>
<include android:id="@+id/text" layout="@layout/text_input_layout"/>
<include layout="@layout/media_input_layout"/>
<include android:id="@+id/media" layout="@layout/media_input_layout"/>
<include layout="@layout/clipboard_layout"/>
<include android:id="@+id/clipboard" layout="@layout/clipboard_layout"/>
</dev.patrickgold.florisboard.common.FlorisViewFlipper>

View File

@@ -2,7 +2,6 @@
<dev.patrickgold.florisboard.ime.text.smartbar.SmartbarView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/smartbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"

View File

@@ -4,29 +4,12 @@
android:id="@+id/text_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:alpha="0.9">
android:orientation="vertical">
<include layout="@layout/smartbar"/>
<include android:id="@+id/smartbar" layout="@layout/smartbar"/>
<!-- KeyboardViews will be inserted in ViewFlipper below dynamically -->
<!--<dev.patrickgold.florisboard.app.FlorisViewFlipper
android:id="@+id/text_input_view_flipper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:measureAllChildren="true">
<dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
android:id="@+id/keyboard_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isLoadingPlaceholderKeyboard="true"/>
<include layout="@layout/editing_layout"/>
</dev.patrickgold.florisboard.app.FlorisViewFlipper>-->
<dev.patrickgold.florisboard.ime.text.keyboard.TextKeyboardView
android:id="@+id/text_input_keyboard_view"
android:id="@+id/main_keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

View File

@@ -38,7 +38,7 @@
<string name="smartbar__quick_action__redo" comment="Content-description for the redo quick action in Smartbar">زر الإعادة لعكس آخر إلغاء</string>
<string name="smartbar__quick_action__private_mode" comment="Content-description for the private mode button in Smartbar">إذا كان مرئيًا، يشير إلى أن الوضع الخاص نشط. عند النقر فوقه، يظهر معلومات حول الوضع الخاص.</string>
<!-- Settings UI strings -->
<string name="settings__title" comment="Title of Settings">الاعدادات</string>
<string name="settings__title" comment="Title of Settings">الإعدادات</string>
<string name="settings__menu" comment="Hint of top-right three-dot icon in Settings">المزيد من الخيارات</string>
<string name="settings__menu_help" comment="Three-dot menu entry for Help and Feedback web link">المساعدة والملاحظات</string>
<string name="settings__help" comment="General label for help buttons in Settings">مساعدة</string>

View File

@@ -202,6 +202,20 @@
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">So en prémer la tecla</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Volum del so en prémer la tecla</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">Vibrar al prémer la tecla</string>
<string name="pref__keyboard__vibration_duration__label" comment="Preference title">Durada de la vibració en prémer la tecla</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Força de vibració en prémer la tecla</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Visibilitat de la finestra emergent</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Mostra una finestra emergent quan premeu una tecla</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Retard de la premuda de tecla llarga</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">La barra espaiadora canvia a la disposició de caràcters</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">En prémer la barra d\'espai, es torna automàticament als caràcters quan estan en símbols o numèrics</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Habilita la barra intel·ligent</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Es mostrarà a la part superior del teclat</string>
<string name="pref__suggestion__title" comment="Preference group title">Suggeriments</string>
<string name="pref__dictionary__title" comment="Preference group title">Diccionari</string>
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">Habilita el diccionari d\'usuari del sistema</string>
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">Suggereix paraules emmagatzemades al diccionari d\'usuari del sistema</string>
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">Gestiona el diccionari d\'usuari del sistema</string>
<string name="pref__correction__title" comment="Preference group title">Correccions</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Majúscules automàtiques</string>
<!-- About UI strings -->

View File

@@ -40,7 +40,7 @@
<!-- Settings UI strings -->
<string name="settings__title" comment="Title of Settings">Nastavení</string>
<string name="settings__menu" comment="Hint of top-right three-dot icon in Settings">Více možností</string>
<string name="settings__menu_help" comment="Three-dot menu entry for Help and Feedback web link">Pomoc &amp; odezva</string>
<string name="settings__menu_help" comment="Three-dot menu entry for Help and Feedback web link">Nápověda &amp; zpětná vazba</string>
<string name="settings__help" comment="General label for help buttons in Settings">Nápověda</string>
<string name="settings__navigation__home" comment="Long-press hint of bottom nav item Home in Settings">Domov</string>
<string name="settings__navigation__keyboard" comment="Long-press hint of bottom nav item Keyboard in Settings">Klávesnice</string>
@@ -73,7 +73,7 @@
<string name="settings__localization__subtype_phone2_layout" comment="Label for layout dropdown in subtype dialog">Sekundární telefonní rozložení</string>
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">Tento podtyp již existuje!</string>
<string name="settings__theme__title" comment="Title of the Theme fragment">Motiv klávesnice</string>
<string name="settings__theme__undefined" comment="General string for an undefined preference value">Definován</string>
<string name="settings__theme__undefined" comment="General string for an undefined preference value">Nedefinováno</string>
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Režim motivu</string>
<string name="pref__theme__mode__always_day" comment="Preference value for theme mode">Vždy denní</string>
<string name="pref__theme__mode__always_night" comment="Preference value for theme mode">Vždy noční</string>
@@ -108,14 +108,14 @@
<string name="settings__theme_editor__value_type_reference" comment="Theme value type">Odkaz</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Skupina</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atribut</string>
<string name="settings__theme_editor__value_type_solid_color" comment="Theme value type">Jednolitá barva</string>
<string name="settings__theme_editor__value_type_solid_color" comment="Theme value type">Plná barva</string>
<string name="settings__theme_editor__value_type_lin_grad" comment="Theme value type">Lineární přechod</string>
<string name="settings__theme_editor__value_type_rad_grad" comment="Theme value type">Radiální přechod</string>
<string name="settings__theme_editor__value_type_on_off" comment="Theme value type">Přepínač</string>
<string name="settings__theme_editor__value_type_on_off_state" comment="Theme value type sub-field">Stav</string>
<string name="settings__theme_editor__value_type_other" comment="Theme value type">Ostatní</string>
<string name="settings__theme_editor__value_type_other_text" comment="Theme value type sub-field">Text</string>
<string name="settings__theme_editor__value_preview_content_description" comment="Theme value preview content description">Náhled této hodnoty tématu</string>
<string name="settings__theme_editor__value_preview_content_description" comment="Theme value preview content description">Náhled této hodnoty motivu</string>
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Zadejte prosím název motivu.</string>
<string name="settings__theme_editor__error_group_name" comment="Error text for an invalid group name">Prosím, zadejte název skupiny který používá pouze písmena (a-z a/nebo A-Z), dvojtečku (:) pro podskupiny a navíc číslice (0-9), vlnovku (~) a podtržítko (_) pro název klíče.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">Zadejte název skupiny.</string>
@@ -171,13 +171,13 @@
<string name="pref__keyboard__utility_key_action__dynamic_switch_language_emojis" comment="Preference value">Dynamicky: Přepnout na emoji / Přepnout jazyk</string>
<string name="pref__keyboard__merge_hint_popups_enabled__label">Ukazovat vyskakovací symboly</string>
<string name="pref__keyboard_merge_hint_popups_enabled__summary">Přidat vyskakovací symboly do základního rozpoložení</string>
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplikátor velikosti písma (portrét)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplikátor velikosti písma (Krajina)</string>
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">Multiplikátor velikosti písma (na výšku)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">Multiplikátor velikosti písma (na šířku)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Rozložení</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Režim s jednou rukou</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Z</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Režim pravé ruky</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Režim levé ruky</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Režim jedné ruky</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Vypnuto</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Režim pro praváky</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Režim pro leváky</string>
<string name="pref__keyboard__one_handed_mode_scale_factor__label" comment="Preference title">Šířka klávesnice v režimu jedné ruky</string>
<string name="pref__keyboard__landscape_input_ui_mode__label" comment="Preference value">Vstupní okno v celoobrazovkovém režimu na šířku</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Nikdy nezobrazovat</string>
@@ -192,7 +192,7 @@
<string name="pref__keyboard__height_factor__tall" comment="Preference value">Vysoká</string>
<string name="pref__keyboard__height_factor__extra_tall" comment="Preference value">Extra vysoká</string>
<string name="pref__keyboard__height_factor__custom" comment="Preference value">Vlastní</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Vlastní hodnota výšky klávesnice</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">Hodnota vlastní výšky klávesnice</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">Spodní odsazení (na výšku)</string>
<string name="pref__keyboard__bottom_offset_landscape__label" comment="Preference title">Spodní odsazení (na šířku)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">Mezery mezi klávesami (na výšku)</string>
@@ -201,25 +201,25 @@
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">Zvuk při stisku klávesy</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">Hlasitost zvuku při stisku klávesy</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">Vibrace při stisku klávesy</string>
<string name="pref__keyboard__vibration_duration__label" comment="Preference title">Trvání vibrací při stisknutí tlačítka</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Síla vibrací na stisknutí tlačítka</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Vyskakovací Viditelnost</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Zobrazit vyskakovací okno, když stisknete klávesu</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Dlouhé zpoždění stisknutí tlačítka</string>
<string name="pref__keyboard__vibration_duration__label" comment="Preference title">Trvání vibrací při stisku klávesy</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">Síla vibrací při stisku klávesy</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">Viditelnost vyskakovacího okna</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">Zobrazit vyskakovací okno při stisku klávesy</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">Délka dlouhého stisku</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">Mezerník přepne znovu do písmenného rozložení</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">Stisknutím mezerníku se automaticky vrátíte z nabídky čísel/symbolů ke klasické klávesnici</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Psaní zkušenosti</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Zážitek z psaní</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">Povolit chytrou lištu</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Zobrazí se na vrchu klávesnice</string>
<string name="pref__suggestion__title" comment="Preference group title">Návrh</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Zobrazí se v horní části klávesnice</string>
<string name="pref__suggestion__title" comment="Preference group title">Návrhy</string>
<string name="pref__dictionary__title" comment="Preference group title">Slovník</string>
<string name="pref__correction__title" comment="Preference group title">Oprava</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Automatická kapitalizace</string>
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Vydělávejte slova na základě aktuálního vstupního kontextu</string>
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">Pamatovat caps lock stav</string>
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Caps lock zůstane při přesunu do jiného textového pole</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">Doba dvojitého prostoru</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Poklepáním dvakrát na mezerník vloží období následuje prostor</string>
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">Kapitalizovat slova na základě aktuálního vstupního kontextu</string>
<string name="pref__correction__remember_caps_lock_state__label" comment="Preference title">Pamatovat stav caps locku</string>
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Caps lock zůstane aktivní při přesunu do jiného textového pole</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">Tečka dovjitou mezerou</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Dvojité poklepání na mezerník vloží tečku a mezeru</string>
<string name="settings__udm__word_summary_freq" comment="Summary label for a word entry. The decimal placeholder inserts the frequency for the word it summarizes.">Frekvence: %d</string>
<string name="settings__udm__word_summary_freq_shortcut" comment="Summary label for a word entry. The first placeholder inserts the frequency for the word it summarizes, the second placeholder the shortcut defined.">Frekvence: %d | Zkratka: %s</string>
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">Pro všechny jazyky</string>
@@ -229,10 +229,10 @@
<string name="settings__udm__dialog__word_error_empty" comment="Error label for the word in the user dictionary add/edit dialog">Zadejte prosím slovo!</string>
<string name="settings__udm__dialog__word_error_invalid" comment="Error label for the word in the user dictionary add/edit dialog">Toto slovo obsahuje neplatné znaky.</string>
<string name="settings__udm__dialog__freq_label" comment="Label for the frequency in the user dictionary add/edit dialog. The two decimal placeholders are the minimum and maximum frequency, both inclusive.">Frekvence (mezi %d a %d)</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gesta &amp; Glide psan</string>
<string name="pref__glide__title" comment="Preference group title">Glide psan</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Gesta &amp; Psaní tahem</string>
<string name="pref__glide__title" comment="Preference group title">Psaní tahem</string>
<string name="pref__glide__enabled__label" comment="Preference title">Povolit psaní tahem</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Zadejte slovo posunutím prstu jeho písmeny</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Zadejte slovo posouváním přes jeho písmena</string>
<string name="pref__glide__show_trail__label" comment="Preference title">Zobrazit stopu tahu</string>
<string name="pref__glide__show_trail__summary" comment="Preference summary">Zmizí po každém slově</string>
<string name="pref__gestures__general_title" comment="Preference group title">Obecná gesta</string>
@@ -254,50 +254,56 @@
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Přesunout kurzor na konec řádku</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Přesunout kurzor na začátek stránky</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Přesunout kurzor na konec stránky</string>
<string name="pref__gestures__swipe_action__switch_to_clipboard_context" comment="Preference value for swipe action">Otevřít správce schránky / historie</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Posun</string>
<string name="pref__gestures__swipe_action__switch_to_clipboard_context" comment="Preference value for swipe action">Otevřít správce schránky / historii</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Přepnout shift</string>
<string name="pref__gestures__swipe_action__redo" comment="Preference value for swipe action">Vpřed</string>
<string name="pref__gestures__swipe_action__undo" comment="Preference value for swipe action">Zpět</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">Zobrazit výběr metody zadávání</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Přepnout na předchozí klávesnici</string>
<string name="pref__gestures__swipe_action__switch_to_prev_subtype" comment="Preference value for swipe action">Přepněte na předchozí podtyp</string>
<string name="pref__gestures__swipe_action__switch_to_next_subtype" comment="Preference value for swipe action">Přepněte na další podtyp</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Přejeďte nahoru</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Přejet</string>
<string name="pref__gestures__swipe_left__label" comment="Preference title">Přejeďte doleva</string>
<string name="pref__gestures__swipe_action__switch_to_prev_subtype" comment="Preference value for swipe action">Přepnout na předchozí podtyp</string>
<string name="pref__gestures__swipe_action__switch_to_next_subtype" comment="Preference value for swipe action">Přepnout na další podtyp</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Přeje nahoru</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Přejetí dolů</string>
<string name="pref__gestures__swipe_left__label" comment="Preference title">Přeje doleva</string>
<string name="pref__gestures__swipe_right__label" comment="Preference title">Přejeďte prstem doprava</string>
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Přejetí nahoru přes mezerník</string>
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Mezerník přejeďte doleva</string>
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Mezerník přejeďte doprava</string>
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Přejetí vlevo přes mezerník</string>
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Přejetí vpravo přes mezerník</string>
<string name="pref__gestures__space_bar_long_press__label" comment="Preference title">Dlouhý stisk mezerníku</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Odstranit klíč přejeďte doleva</string>
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Práh rychlosti přejetí prstem</string>
<string name="pref__gestures__swipe_velocity_threshold__very_slow" comment="Preference value for swipe velocity threshold">Velmi pomalé</string>
<string name="pref__gestures__delete_key_swipe_left__label" comment="Preference title">Přeje doleva na klávese mazání</string>
<string name="pref__gestures__swipe_velocity_threshold__label" comment="Preference title">Práh rychlosti přejetí</string>
<string name="pref__gestures__swipe_velocity_threshold__very_slow" comment="Preference value for swipe velocity threshold">Velmi pomalý</string>
<string name="pref__gestures__swipe_velocity_threshold__slow" comment="Preference value for swipe velocity threshold">Pomalý</string>
<string name="pref__gestures__swipe_velocity_threshold__normal" comment="Preference value for swipe velocity threshold">Normální</string>
<string name="pref__gestures__swipe_velocity_threshold__fast" comment="Preference value for swipe velocity threshold">Rychlý</string>
<string name="pref__gestures__swipe_velocity_threshold__very_fast" comment="Preference value for swipe velocity threshold">Velmi rychle</string>
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Práh vzdálenosti přejetím prstem</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Velmi krátká</string>
<string name="pref__gestures__swipe_velocity_threshold__very_fast" comment="Preference value for swipe velocity threshold">Velmi rychlý</string>
<string name="pref__gestures__swipe_distance_threshold__label" comment="Preference title">Práh vzdálenosti přejetí</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Velmi krátký</string>
<string name="pref__gestures__swipe_distance_threshold__short" comment="Preference value for swipe distance threshold">Krátký</string>
<string name="pref__gestures__swipe_distance_threshold__normal" comment="Preference value for swipe distance threshold">Normální</string>
<string name="pref__gestures__swipe_distance_threshold__long" comment="Preference value for swipe distance threshold">Dlouhý</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Dlouhý</string>
<string name="settings__advanced__title" comment="Title of Advanced settings activity">Upřesnit</string>
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Téma nastavení</string>
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Světlo</string>
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Tma</string>
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Zobrazit ikonu aplikace v launcher</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Velmi dlouhý</string>
<string name="settings__advanced__title" comment="Title of Advanced settings activity">Pokročilé</string>
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Motiv nastavení</string>
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Světlý</string>
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Tma</string>
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Zobrazit ikonu aplikace na domovské obrazovce</string>
<string name="pref__advanced__force_private_mode__label" comment="Label of Force private mode preference in Advanced">Vynutit soukromý režim</string>
<string name="pref__advanced__force_private_mode__summary" comment="Summary of Force private mode preference in Advanced">Dočasně vypne všechny funkce, které pracují se vstupními daty</string>
<!-- About UI strings -->
<string name="about__title" comment="Title of About activity">O</string>
<string name="about__title" comment="Title of About activity">O aplikaci</string>
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Ikona aplikace FlorisBoard</string>
<string name="about__view_licenses" comment="Label of View licenses button in About">Open source licence</string>
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">Soukromí</string>
<string name="about__view_source_code" comment="Label of View source code button in About">Kód</string>
<string name="about__view_source_code" comment="Label of View source code button in About">Zdrojový kód</string>
<string name="about__license__title" comment="Title of Open-source licenses dialog">Open-source licence</string>
<!-- Assets strings -->
<plurals name="assets__file__authors">
<item quantity="one">Autor</item>
<item quantity="few">Autoři</item>
<item quantity="many">Autorů</item>
<item quantity="other">Autorů</item>
</plurals>
<string name="assets__file__name">Název</string>
<string name="assets__file__source">Zdroj</string>
<string name="assets__action__add">Přidat</string>
@@ -318,32 +324,32 @@
<string name="assets__error__invalid">Neplatné</string>
<string name="assets__error__snackbar_message">Něco se pokazilo</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Nastavení</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Náhled</string>
<string name="setup__title" comment="Title of Setup">Prvotní nastavení</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Předchozí</string>
<string name="setup__cancel_button" comment="Label of Cancel button in Setup">Zrušit</string>
<string name="setup__next_button" comment="Label of Next button in Setup (try to find a short translation due to limited space in UI)">Další</string>
<string name="setup__finish_button" comment="Label of Finish button in Setup">Dokončit</string>
<string name="setup__ok_button" comment="Label of OK button in Setup">OK</string>
<string name="setup__welcome__title" comment="Title of Welcome fragment in Setup">Vítejte!</string>
<string name="setup__welcome__intro" comment="Paragraph in Welcome fragment in Setup">Díky za vyzkoušení FlorisBoard! Než jej začnete používat, musíme udělat obvyklé věci a povolit je v nastavení systému, nastavit preferovaný jazyk/rozvržení atd.... ale bez obav - průvodce nastavením vás provede tímto!</string>
<string name="setup__welcome__intro" comment="Paragraph in Welcome fragment in Setup">Díky za vyzkoušení aplikace FlorisBoard! Než ji začnete používat, musíme ji povolit v nastavení systému, zvolit preferovaný jazyk/rozvržení atd ale bez obav - průvodce nastavením vás tímto provede!</string>
<string name="setup__welcome__privacy" comment="Paragraph in Welcome fragment in Setup">FlorisBoard plně respektuje vaše soukromí a neshromažďuje žádná uživatelská data. Pro více informací viz zde:</string>
<string name="setup__welcome__trust" comment="Paragraph in Welcome fragment in Setup">Zdrojový kód pro FlorisBoard je veřejně přístupný pro každého, takže můžete snadno zkontrolovat, co FlorisBoard dělá na pozadí. Podívejte se na odkaz úložiště níže.</string>
<string name="setup__welcome__contribute" comment="Paragraph in Welcome fragment in Setup">Jedna poslední věc, než začnete nastavení - pokud narazíte na nějaké chyby/pády/problémy s FlorisBoard, nebo máte požadavek na funkci - přes hlavu na GitHub úložiště google níže a soubor problém. To pomáhá při zlepšování zkušeností pro všechny uživatele!</string>
<string name="setup__welcome__outro" comment="Paragraph in Welcome fragment in Setup">Chcete-li spustit nastavení, klikněte na <i>další</i>.</string>
<string name="setup__welcome__trust" comment="Paragraph in Welcome fragment in Setup">Zdrojový kód aplikace FlorisBoard je veřejně přístupný pro každého, takže můžete snadno zkontrolovat, co FlorisBoard dělá na pozadí. Podívejte se na odkaz repozitáře níže.</string>
<string name="setup__welcome__contribute" comment="Paragraph in Welcome fragment in Setup">Poslední věc, než začnete s nastavovám - pokud narazíte na nějaké chyby/pády/problémy s FlorisBoard, nebo máte požadavek na funkci - navštivte repozitář na GitHubu odkazovaný níže a vytvořte issue. To pomáhá se zlepšováním zážitku pro všechny uživatele!</string>
<string name="setup__welcome__outro" comment="Paragraph in Welcome fragment in Setup">Chcete-li spustit prvotní nastavení, klikněte na <i>další</i>.</string>
<string name="setup__enable_ime__title" comment="Title of Enable IME fragment in Setup">Povolit FlorisBoard</string>
<string name="setup__enable_ime__text_before_enabled" comment="Description of state in Enable IME fragment before user enabled">Android vyžaduje, abyste před použitím mohli každou vlastní klávesnici ručně povolit. Kliknutím na tlačítko níže přejděte do nabídky <i> Jazyk &amp; Zadejte </i> nastavení a nezapomeňte zkontrolovat<i> FlorisBoard </i>“.</string>
<string name="setup__enable_ime__text_before_enabled" comment="Description of state in Enable IME fragment before user enabled">Android vyžaduje ruční povolení vlastní klávesnice před jejím použitím. Kliknutím na tlačítko níže přejděte do nabídky nastavení<i> Jazyk &amp; Zadávání</i> a povolte<i> FlorisBoard </i>“.</string>
<string name="setup__enable_ime__text_after_enabled" comment="Description of state in Enable IME fragment after user enabled">FlorisBoard byl úspěšně povolen. Chcete-li pokračovat, klikněte na <i>další</i>!</string>
<string name="setup__enable_ime__text_button_language_and_input" comment="Label of language and input button in Enable IME fragment">Otevřený Jazyk &amp; Nastavení vstupu</string>
<string name="setup__make_default__title" comment="Title of Make IME default fragment in Setup">Aby FlorisBoard výchozí</string>
<string name="setup__make_default__text_before_switch" comment="Description of state in Make IME default fragment before user switched">FlorisBoard je nyní povolen ve vašem systému. Chcete-li ji aktivně používat, přepněte na FlorisBoard výběrem v dialogu pro výběr vstupu!</string>
<string name="setup__make_default__text_after_switch" comment="Description of state in Make IME default fragment after user switched">Úspěšně přepnul výchozí klávesnici na FlorisBoard!</string>
<string name="setup__enable_ime__text_button_language_and_input" comment="Label of language and input button in Enable IME fragment">Otevřít nastavení Jazyk &amp; Zadávání</string>
<string name="setup__make_default__title" comment="Title of Make IME default fragment in Setup">Nastavit FlorisBoard jako výchozí</string>
<string name="setup__make_default__text_before_switch" comment="Description of state in Make IME default fragment before user switched">FlorisBoard je nyní povolen. Chcete-li ji aktivně používat, přepněte na FlorisBoard zvolením v dialogu pro výběr vstupu!</string>
<string name="setup__make_default__text_after_switch" comment="Description of state in Make IME default fragment after user switched">Úspěšné zvolení FlorisBoard jako výchozí klávesnice!</string>
<string name="setup__make_default__text_switch_button" comment="Label of switch button in Make IME default fragment">Přepnout klávesnici</string>
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">Nastavení dokončeno!</string>
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">Prvorní nastavení dokončeno!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">Zpráva o chybě florisboardu</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Uzavřít</string>
<string name="crash_notification_channel__title" comment="Title of crash notification channel">FlorisBoard chybové hlášení</string>
<string name="crash_once_notification__title" comment="Title of the notification for a single crash">FlorisBoard přestal fungovat…</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Zavřít</string>
<string name="crash_notification_channel__title" comment="Title of crash notification channel">FlorisBoard chybová hlášení</string>
<string name="crash_once_notification__title" comment="Title of the notification for a single crash">FlorisBoard přestal pracovat…</string>
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Klepnutím zobrazíte podrobnosti o chybě</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">Zdá se, že FlorisBoard přestal opakovaně pracovat…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">Vrácení zpět na předchozí klávesnici pro zastavení nekonečného crash loopu. Klepnutím zobrazíte podrobnosti o chybě</string>

View File

@@ -86,7 +86,10 @@
<string name="settings__theme__attr_textColor" comment="Theme attribute label">Tekstfarve</string>
<string name="settings__keyboard__title" comment="Title of Keyboard preferences fragment">Tastatur præferencer</string>
<string name="pref__keyboard__hint_mode__disabled" comment="Preference value">Deaktiveret</string>
<string name="pref__keyboard__utility_key_action__switch_language" comment="Preference value">Skift sprog</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">Vis aldrig</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">Vis altid</string>
<string name="pref__keyboard__landscape_input_ui_mode__dynamically_show" comment="Preference value">Vis dynamisk</string>
<string name="pref__keyboard__height_factor__extra_short" comment="Preference value">Ekstra kort</string>
<string name="pref__keyboard__height_factor__short" comment="Preference value">Kort</string>
<string name="pref__keyboard__height_factor__normal" comment="Preference value">Normal</string>
@@ -118,6 +121,8 @@
<string name="settings__udm__word_summary_freq" comment="Summary label for a word entry. The decimal placeholder inserts the frequency for the word it summarizes.">Frekvens: %d</string>
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">For alle sprog</string>
<string name="settings__udm__dialog__word_label" comment="Label for the word in the user dictionary add/edit dialog">Ord</string>
<string name="settings__udm__dialog__word_error_empty" comment="Error label for the word in the user dictionary add/edit dialog">Indtast venligst et ord!</string>
<string name="settings__udm__dialog__shortcut_label" comment="Label for the shortcut in the user dictionary add/edit dialog">Genvej (valgfri)</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">Bevægelser &amp; Strygeskrivning</string>
<string name="pref__glide__title" comment="Preference group title">Strygeskrivning</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Skriv ord ved at stryge fingeren igennem bogstaver</string>
@@ -133,16 +138,25 @@
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Flyt musen højre</string>
<string name="pref__gestures__swipe_action__undo" comment="Preference value for swipe action">Fortryd</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Skift til forrige tastatur</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Stryg opad</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Stryg nedad</string>
<string name="pref__gestures__swipe_left__label" comment="Preference title">Stryg til venstre</string>
<string name="pref__gestures__swipe_right__label" comment="Preference title">Swipe til højre</string>
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Space bar knalde op</string>
<string name="pref__gestures__swipe_velocity_threshold__slow" comment="Preference value for swipe velocity threshold">Langsom</string>
<string name="pref__gestures__swipe_velocity_threshold__normal" comment="Preference value for swipe velocity threshold">Normal</string>
<string name="pref__gestures__swipe_velocity_threshold__fast" comment="Preference value for swipe velocity threshold">Hurtig</string>
<string name="pref__gestures__swipe_velocity_threshold__very_fast" comment="Preference value for swipe velocity threshold">Meget hurtig</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Meget kort</string>
<string name="pref__gestures__swipe_distance_threshold__short" comment="Preference value for swipe distance threshold">Kort</string>
<string name="pref__gestures__swipe_distance_threshold__normal" comment="Preference value for swipe distance threshold">Normal</string>
<string name="pref__gestures__swipe_distance_threshold__long" comment="Preference value for swipe distance threshold">Lang</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Meget lang</string>
<string name="settings__advanced__title" comment="Title of Advanced settings activity">Avanceret</string>
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Lys</string>
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Mørk</string>
<!-- About UI strings -->
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">Privatlivspolitik</string>
<!-- Assets strings -->
<string name="assets__file__name">Navn</string>
<string name="assets__action__add">Tilføj</string>

View File

@@ -65,6 +65,7 @@
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">Διάταξη χαρακτήρων</string>
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">Πρωτεύουσα διάταξη συμβόλων</string>
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">Δευτερεύουσα διάταξη συμβόλων</string>
<string name="settings__localization__subtype_composer" comment="Label for composer dropdown in subtype dialog.">Συνθέτης</string>
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Σύνολο συναλλαγμάτων</string>
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">Αριθμητική διάταξη</string>
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">(Προχωρημένη) αριθμητική διάταξη</string>

View File

@@ -1,18 +1,241 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">FlorisBoard</string>
<!-- One-handed strings -->
<string name="one_handed__close_btn_content_description" comment="Content description for the one-handed close button">Tutup mode satu-tangan.</string>
<string name="one_handed__move_start_btn_content_description" comment="Content description for the one-handed move to left button">Pindahkan papan ketik ke kiri.</string>
<string name="one_handed__move_end_btn_content_description" comment="Content description for the one-handed move to right button">Pindahkan papan ketik ke kanan.</string>
<!-- Private mode info dialog strings -->
<string name="private_mode_dialog__title" comment="Title of the private mode dialog">Mode pribadi</string>
<!--
<string name="private_mode_dialog__text" comment="Text of the private mode dialog">The icon you just clicked at indicates that FlorisBoard works in the private mode. This means that all features which require to process and temporarily save your input stop working. This applies at minimum to the following features (if they\'ve been turned on previously):\n\n - Next word algorithm adjustments\n\n - Clipboard paste suggestions\n\n - Clipboard history\n\nFlorisBoard enters this mode either if an app requests it or if it was specifically enabled in the advanced settings.</string>
-->
<!-- Media strings -->
<string name="media__tab__emojis" comment="Tab description for emojis in the media UI">Emoji</string>
<string name="media__tab__kaomoji" comment="Tab description for kaomoji in the media UI">Kaomoji</string>
<!-- Emoji strings -->
<string name="emoji__category__people_body" comment="Emoji category name">Orang &amp; Badan</string>
<string name="emoji__category__animals_nature" comment="Emoji category name">Hewan &amp; Alam</string>
<string name="emoji__category__food_drink" comment="Emoji category name">Makanan &amp; Minuman</string>
<string name="emoji__category__travel_places" comment="Emoji category name">Perjalanan &amp; Tempat</string>
<string name="emoji__category__activities" comment="Emoji category name">Aktivitas</string>
<string name="emoji__category__objects" comment="Emoji category name">Obyek</string>
<string name="emoji__category__symbols" comment="Emoji category name">Simbol</string>
<string name="emoji__category__flags" comment="Emoji category name">Bendera</string>
<!-- Smartbar strings -->
<string name="smartbar__quick_action__open_settings" comment="Content-description for the settings quick action in Smartbar">Buka pengaturan.</string>
<string name="smartbar__quick_action__private_mode" comment="Content-description for the private mode button in Smartbar">Jika terlihat, menandakan bahwa mode pribadi aktif. Jika diklik, menampilkan informasi tentang mode pribadi.</string>
<!-- Settings UI strings -->
<string name="settings__title" comment="Title of Settings">Pengaturan</string>
<string name="settings__menu" comment="Hint of top-right three-dot icon in Settings">Opsi lainnya</string>
<string name="settings__menu_help" comment="Three-dot menu entry for Help and Feedback web link">Dukungan &amp; masukan</string>
<string name="settings__help" comment="General label for help buttons in Settings">Bantuan</string>
<string name="settings__navigation__home" comment="Long-press hint of bottom nav item Home in Settings">Beranda</string>
<string name="settings__navigation__keyboard" comment="Long-press hint of bottom nav item Keyboard in Settings">Papan Ketik</string>
<string name="settings__navigation__typing" comment="Long-press hint of bottom nav item Typing in Settings">Mengetik</string>
<string name="settings__navigation__theme" comment="Long-press hint of bottom nav item Theme in Settings">Tema</string>
<string name="settings__navigation__gestures" comment="Long-press hint of bottom nav item Gestures in Settings">Gestur</string>
<string name="settings__default" comment="General string which is used when a preference has the default value set">Default</string>
<string name="settings__system_default" comment="General string which is used when a preference has the system default value set">Default sistem</string>
<string name="settings__home__title" comment="Title of the Home fragment">Selamat datang di %s</string>
<string name="settings__home__contribute" comment="Contributing message shown in Home fragment">Terima kasih telah mencoba FlorisBoard! Proyek ini masih dalam versi alpha dan karena itu banyak fitur belum ada. Jika Anda menemukan sebuah bug atau ingin memberikan saran, harap periksa repositori di GitHub dan membuat sebuah masalah (issue). Ini membantu membuat FlorisBoard lebih baik. Terima kasih!</string>
<string name="settings__localization__title" comment="Title of languages and layout box in the Typing fragment">Bahasa &amp; Tata letak papan ketik</string>
<string name="settings__localization__subtype_add" comment="Subtype dialog add button">Tambahkan</string>
<string name="settings__localization__subtype_apply" comment="Subtype dialog apply button">Terapkan</string>
<string name="settings__localization__subtype_cancel" comment="Subtype dialog cancel button">Batal</string>
<string name="settings__localization__subtype_delete" comment="Subtype dialog delete button">Hapus</string>
<string name="settings__localization__subtype_characters_layout" comment="Label for layout dropdown in subtype dialog">Tata letak karakter</string>
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">Set mata uang</string>
<string name="settings__theme__title" comment="Title of the Theme fragment">Tema papan ketik</string>
<string name="settings__theme__undefined" comment="General string for an undefined preference value">Tidak ditetapkan</string>
<string name="pref__theme__mode__label" comment="Label of the theme mode preference">Mode tema</string>
<string name="pref__theme__mode__always_day" comment="Preference value for theme mode">Selalu siang</string>
<string name="pref__theme__mode__always_night" comment="Preference value for theme mode">Selalu malam</string>
<string name="pref__theme__mode__follow_system" comment="Preference value for theme mode">Ikuti sistem</string>
<string name="pref__theme__mode__follow_time" comment="Preference value for theme mode">Ikuti waktu</string>
<string name="pref__theme__sunrise_time__label" comment="Label of the sunrise time preference">Waktu matahari terbit</string>
<string name="pref__theme__sunset_time__label" comment="Label of the sunset time preference">Waktu matahari terbenam</string>
<string name="pref__theme__day" comment="Label of the day group (day means light theme)">Tema siang</string>
<string name="pref__theme__night" comment="Label of the night group (night means dark theme)">Tema malam</string>
<string name="pref__theme__any_theme__label" comment="Label of the theme selector preference">Tema yang dipilih</string>
<string name="pref__theme__source_assets" comment="Label for the theme source field">Aset Aplikasi FlorisBoard</string>
<string name="pref__theme__source_internal" comment="Label for the theme source field">Penyimpanan Internal</string>
<string name="settings__theme_manager__create_empty" comment="Label of the Create empty FAB action">Buat tema kosong</string>
<string name="settings__theme_manager__create_from_selected" comment="Label of the Create from selected FAB action">Buat dari tema yang dipilih</string>
<string name="settings__theme_manager__theme_custom_title" comment="Title template for a custom theme">Kustom (berdasarkan %s)</string>
<string name="settings__theme_manager__theme_new_title" comment="Title template for a new theme">Tema baru</string>
<string name="settings__theme_manager__theme_import_success" comment="Message for theme import success">Tema berhasil diimpor!</string>
<string name="settings__theme_manager__theme_export_success" comment="Message for theme export success">Tema berhasil diekspor!</string>
<string name="settings__theme_editor__title" comment="Title of the edit theme activity">Sunting tema</string>
<string name="settings__theme_editor__name_label" comment="Label of name input">Nama</string>
<string name="settings__theme_editor__type_label" comment="Label of type input">Jenis</string>
<string name="settings__theme_editor__add_group_dialog_title" comment="Title of the add group dialog in the theme editor">Tambahkan kelompok</string>
<string name="settings__theme_editor__edit_group_dialog_title" comment="Title of the edit group dialog in the theme editor">Sunting kelompok</string>
<string name="settings__theme_editor__add_attr_dialog_title" comment="Title of the add attribute dialog in the theme editor">Tambahkan atribut</string>
<string name="settings__theme_editor__edit_attr_dialog_title" comment="Title of the edit attribute dialog in the theme editor">Sunting atribut</string>
<string name="settings__theme_editor__edit_theme_name_dialog_title" comment="Title of the edit theme name dialog in the theme editor">Sunting nama tema</string>
<string name="settings__theme_editor__value_type_reference_group" comment="Theme value type sub-field">Kelompok</string>
<string name="settings__theme_editor__value_type_reference_attr" comment="Theme value type sub-field">Atribut</string>
<string name="settings__theme_editor__value_type_other" comment="Theme value type">Lainnya</string>
<string name="settings__theme_editor__value_type_other_text" comment="Theme value type sub-field">Teka</string>
<string name="settings__theme_editor__error_theme_label_empty" comment="Error text for an empty theme label">Harap masukkan nama tema.</string>
<string name="settings__theme_editor__error_group_name_empty" comment="Error text for an empty group name">Harap masukkan nama kelompok.</string>
<string name="settings__theme_editor__error_attr_name" comment="Error text for an invalid attribute name">Harap masukkan nama atribut yang hanya mengandung huruf a-z dan/atau A-Z.</string>
<string name="settings__theme_editor__error_attr_name_empty" comment="Error text for an empty attribute name">Harap masukkan nama atribut.</string>
<string name="settings__theme__group_keyboard" comment="Theme group label">Papan ketik</string>
<string name="settings__theme__group_oneHanded" comment="Theme group label">Satu-tangan</string>
<string name="settings__theme__group_privateMode" comment="Theme group label">Mode pribadi</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">Warna latar belakang</string>
<string name="settings__theme__attr_backgroundActive" comment="Theme attribute label">Warna latar belakang (aktif)</string>
<string name="settings__theme__attr_colorPrimary" comment="Theme attribute label">Warna utama</string>
<string name="settings__theme__attr_colorPrimaryDark" comment="Theme attribute label">Warna utama (gelap)</string>
<string name="settings__theme__attr_navBarColor" comment="Theme attribute label">Warna bilah navigasi</string>
<string name="settings__theme__attr_textColor" comment="Theme attribute label">Warna teks</string>
<string name="settings__keyboard__title" comment="Title of Keyboard preferences fragment">Preferensi Papan Ketik</string>
<string name="pref__keyboard__number_row__label" comment="Preference title">Baris angka</string>
<string name="pref__keyboard__hint_mode__disabled" comment="Preference value">Nonaktif</string>
<string name="pref__keyboard__utility_key_action__switch_to_emojis" comment="Preference value">Beralih ke emoji</string>
<string name="pref__keyboard__utility_key_action__switch_language" comment="Preference value">Beralih bahasa</string>
<string name="pref__keyboard__utility_key_action__switch_keyboard_app" comment="Preference value">Beralih aplikasi papan ketik</string>
<string name="pref__keyboard__utility_key_action__dynamic_switch_language_emojis" comment="Preference value">Dinamis: Beralih ke emoji / Beralih bahasa</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">Tata letak</string>
<string name="pref__keyboard__one_handed_mode__label" comment="Preference title">Mode satu-tangan</string>
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">Mati</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">Mode tangan kanan</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">Mode tangan kiri</string>
<string name="pref__keyboard__height_factor__label" comment="Preference title">Tinggi papan ketik</string>
<string name="pref__keyboard__height_factor__extra_short" comment="Preference value">Ekstra-rendah</string>
<string name="pref__keyboard__height_factor__short" comment="Preference value">Rendah</string>
<string name="pref__keyboard__height_factor__normal" comment="Preference value">Normal</string>
<string name="pref__keyboard__height_factor__tall" comment="Preference value">Tinggi</string>
<string name="pref__keyboard__height_factor__extra_tall" comment="Preference value">Ekstra-tinggi</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">Pengalaman mengetik</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">Akan tampil di atas papan ketik</string>
<string name="pref__suggestion__title" comment="Preference group title">Saran</string>
<string name="pref__dictionary__title" comment="Preference group title">Kamus</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">Kapitalisasi otomatis</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">Mengetuk batang spasi dua kali memasukkan titik yang diikuti oleh sebuah spasi</string>
<string name="settings__udm__word_summary_freq" comment="Summary label for a word entry. The decimal placeholder inserts the frequency for the word it summarizes.">Frekuensi: %d</string>
<string name="settings__udm__all_languages" comment="Label of the For all languages entry in the language list">Untuk semua bahasa</string>
<string name="settings__udm__dictionary_import_success" comment="Message for dictionary import success">Kamus pengguna berhasil diimpor!</string>
<string name="settings__udm__dictionary_export_success" comment="Message for dictionary export success">Kamus pengguna berhasil diekspor!</string>
<string name="settings__udm__dialog__word_label" comment="Label for the word in the user dictionary add/edit dialog">Kata</string>
<string name="settings__udm__dialog__word_error_empty" comment="Error label for the word in the user dictionary add/edit dialog">Harap masukkan sebuah kata!</string>
<string name="settings__udm__dialog__word_error_invalid" comment="Error label for the word in the user dictionary add/edit dialog">Kata ini mengandung karakter yang tidak valid.</string>
<string name="settings__udm__dialog__freq_label" comment="Label for the frequency in the user dictionary add/edit dialog. The two decimal placeholders are the minimum and maximum frequency, both inclusive.">Frekuensi (diantara %d dan %d)</string>
<string name="settings__udm__dialog__locale_label" comment="Label for the language code in the user dictionary add/edit dialog">Kode bahasa (opsional)</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">Ketik sebuah kata dengan menggeser jari Anda melewati huruf-huruf nya</string>
<string name="pref__glide__show_trail__summary" comment="Preference summary">Akan menghilang setelah setiap kata</string>
<string name="pref__gestures__general_title" comment="Preference group title">Gestur umum</string>
<string name="pref__gestures__space_bar_title" comment="Preference group title">Gestur batang spasi</string>
<string name="pref__gestures__swipe_action__no_action" comment="Preference value for swipe action">Tidak ada tindakan</string>
<string name="pref__gestures__swipe_action__delete_word" comment="Preference value for swipe action">Hapus kata saat ini</string>
<string name="pref__gestures__swipe_action__hide_keyboard" comment="Preference value for swipe action">Sembunyikan papan ketik</string>
<string name="pref__gestures__swipe_action__insert_space" comment="Preference value for swipe action">Masukkan spasi</string>
<string name="pref__gestures__swipe_action__move_cursor_up" comment="Preference value for swipe action">Pindahkan kursor ke atas</string>
<string name="pref__gestures__swipe_action__move_cursor_down" comment="Preference value for swipe action">Pindahkan kursor ke bawah</string>
<string name="pref__gestures__swipe_action__move_cursor_left" comment="Preference value for swipe action">Pindahkan kursor ke kiri</string>
<string name="pref__gestures__swipe_action__move_cursor_right" comment="Preference value for swipe action">Pindahkan kursor ke kanan</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">Pindahkan kursor ke awal baris</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">Pindahkan kursor ke akhir baris</string>
<string name="pref__gestures__swipe_action__move_cursor_start_of_page" comment="Preference value for swipe action">Pindahkan kursor ke awal halaman</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_page" comment="Preference value for swipe action">Pindahkan kursor ke akhir halaman</string>
<string name="pref__gestures__swipe_action__switch_to_clipboard_context" comment="Preference value for swipe action">Buka pengelola/riwayat papan klip</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">Beralih ke papan ketik sebelumnya</string>
<string name="pref__gestures__swipe_up__label" comment="Preference title">Geser ke atas</string>
<string name="pref__gestures__swipe_down__label" comment="Preference title">Geser ke bawah</string>
<string name="pref__gestures__swipe_left__label" comment="Preference title">Geser ke kiri</string>
<string name="pref__gestures__swipe_right__label" comment="Preference title">Geser ke kanan</string>
<string name="pref__gestures__space_bar_swipe_up__label" comment="Preference title">Geser batang spasi ke atas</string>
<string name="pref__gestures__space_bar_swipe_left__label" comment="Preference title">Geser batang spasi ke kiri</string>
<string name="pref__gestures__space_bar_swipe_right__label" comment="Preference title">Geser batang spasi ke kanan</string>
<string name="pref__gestures__swipe_velocity_threshold__very_slow" comment="Preference value for swipe velocity threshold">Sangat lambat</string>
<string name="pref__gestures__swipe_velocity_threshold__slow" comment="Preference value for swipe velocity threshold">Lambat</string>
<string name="pref__gestures__swipe_velocity_threshold__normal" comment="Preference value for swipe velocity threshold">Normal</string>
<string name="pref__gestures__swipe_velocity_threshold__fast" comment="Preference value for swipe velocity threshold">Cepat</string>
<string name="pref__gestures__swipe_velocity_threshold__very_fast" comment="Preference value for swipe velocity threshold">Sangat cepat</string>
<string name="pref__gestures__swipe_distance_threshold__very_short" comment="Preference value for swipe distance threshold">Sangat singkat</string>
<string name="pref__gestures__swipe_distance_threshold__short" comment="Preference value for swipe distance threshold">Singkat</string>
<string name="pref__gestures__swipe_distance_threshold__normal" comment="Preference value for swipe distance threshold">Normal</string>
<string name="pref__gestures__swipe_distance_threshold__long" comment="Preference value for swipe distance threshold">Panjang</string>
<string name="pref__gestures__swipe_distance_threshold__very_long" comment="Preference value for swipe distance threshold">Sangat panjang</string>
<string name="pref__advanced__settings_theme__label" comment="Label of Settings theme preference in Advanced">Tema pengaturan</string>
<string name="pref__advanced__settings_theme__light" comment="Possible value of Settings theme preference in Advanced">Cerah</string>
<string name="pref__advanced__settings_theme__dark" comment="Possible value of Settings theme preference in Advanced">Gelap</string>
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">Tampilkan ikon aplikasi pada peluncur</string>
<string name="pref__advanced__force_private_mode__label" comment="Label of Force private mode preference in Advanced">Paksa mode pribadi</string>
<string name="pref__devtools__enabled__label" comment="Label of Enable developer tools in Advanced">Aktifkan alat pengembang</string>
<!-- About UI strings -->
<string name="about__title" comment="Title of About activity">Tentang</string>
<string name="about__app_icon_content_description" comment="Content description of app icon in About">Ikon aplikasi FlorisBoard</string>
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">Kebijakan privasi</string>
<string name="about__view_source_code" comment="Label of View source code button in About">Kode sumber</string>
<string name="about__version_copied__title" comment="Title of the toast for copying the version string">Versi disalin ke papan klip</string>
<!-- Assets strings -->
<plurals name="assets__file__authors">
<item quantity="other">Penulis</item>
</plurals>
<string name="assets__file__name">Nama</string>
<string name="assets__file__source">Sumber</string>
<string name="assets__action__add">Tambahkan</string>
<string name="assets__action__apply">Terapkan</string>
<string name="assets__action__cancel">Batal</string>
<string name="assets__action__cancel_confirm_title">Konfirmasi pembatalan</string>
<string name="assets__action__cancel_confirm_message">Apakah Anda yakin ingin membuang perubahan yang belum disimpan? Tindakan ini tidak dapat dibatalkan setelah dieksekusi.</string>
<string name="assets__action__delete">Hapus</string>
<string name="assets__action__delete_confirm_title">Konfirmasi penghapusan</string>
<string name="assets__action__delete_confirm_message">Apakah Anda yakin ingin menghapus \"%s\"? Tindakan ini tidak dapat dibatalkan setelah dieksekusi.</string>
<string name="assets__action__edit">Sunting</string>
<string name="assets__action__export">Ekspor</string>
<string name="assets__action__import">Impor</string>
<string name="assets__action__no">Tidak</string>
<string name="assets__action__save">Simpan</string>
<string name="assets__action__yes">Ya</string>
<string name="assets__error__details">Keterangan</string>
<string name="assets__error__invalid">Tidak valid</string>
<string name="assets__error__snackbar_message">Terjadi kesalahan</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">Persiapan</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">Seb</string>
<string name="setup__cancel_button" comment="Label of Cancel button in Setup">Batal</string>
<string name="setup__next_button" comment="Label of Next button in Setup (try to find a short translation due to limited space in UI)">Lanjut</string>
<string name="setup__finish_button" comment="Label of Finish button in Setup">Selesai</string>
<string name="setup__ok_button" comment="Label of OK button in Setup">Oke</string>
<string name="setup__welcome__title" comment="Title of Welcome fragment in Setup">Selamat datang!</string>
<string name="setup__welcome__privacy" comment="Paragraph in Welcome fragment in Setup">FlorisBoard sepenuhnya menghormati privasi Anda dan tidak mengumpulkan data pengguna apapun. Untuk informasi lebih lanjut lihat di sini:</string>
<string name="setup__welcome__trust" comment="Paragraph in Welcome fragment in Setup">Kode sumber FlorisBoard dapat diakses oleh siapapun, sehingga Anda dapat memeriksa apa yang FlorisBoard lakukan di belakang. Cek tautan repositori nya berikut ini.</string>
<string name="setup__welcome__outro" comment="Paragraph in Welcome fragment in Setup">Untuk memulai persiapan, klik <i>LANJUT</i>.</string>
<string name="setup__enable_ime__title" comment="Title of Enable IME fragment in Setup">Aktifkan FlorisBoard</string>
<string name="setup__enable_ime__text_after_enabled" comment="Description of state in Enable IME fragment after user enabled">FlorisBoard berhasil diaktifkan. Untuk melanjutkan klik <i>LANJUT</i>!</string>
<string name="setup__enable_ime__text_button_language_and_input" comment="Label of language and input button in Enable IME fragment">Buka pengaturan Bahasa &amp; Masukan</string>
<string name="setup__make_default__text_after_switch" comment="Description of state in Make IME default fragment after user switched">Berhasil mengalihkan papan ketik default menjadi FlorisBoard!</string>
<string name="setup__make_default__text_switch_button" comment="Label of switch button in Make IME default fragment">Beralih papan ketik</string>
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">Persiapan selesai!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">Laporan kesalahan FlorisBoard</string>
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">Salin ke papan klip sistem</string>
<string name="crash_dialog__copy_to_clipboard_success" comment="Label of Copy to clipboard success message in crash dialog">Disalin ke papan klip sistem</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">Tutup</string>
<string name="crash_once_notification__title" comment="Title of the notification for a single crash">FlorisBoard berhenti bekerja…</string>
<string name="crash_once_notification__body" comment="Body of the notification for a single crash">Ketuk untuk melihat keterangan kesalahan</string>
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">FlorisBoard kelihatannya berhenti bekerja berulang kali…</string>
<!-- clipboard strings -->
<string name="clip__context_header">Riwayat papan klip</string>
<string name="clip__clear_history">Hapus riwayat</string>
<string name="clip__delete_item">Hapus</string>
<string name="clip__paste_item">Tempel</string>
<string name="clip__cant_paste">Aplikasi ini tidak mengizinkan untuk menempel konten ini.</string>
<string name="pref__clipboard__clipboard_category__label">Papan klip</string>
<string name="pref__clipboard__use_internal_clipboard___label">Gunakan papan klip internal</string>
<string name="pref__clipboard__sync_from_system_clipboard__label">Sinkronkan dari papan klip sistem</string>
<string name="pref__clipboard__keyboard_sync_from_system_clipboard__summary">Pembaruan papan klip sistem juga memperbarui papan klip Floris</string>
<string name="pref__clipboard__sync_to_system_clipboard__label">Sinkronkan ke papan klip sistem</string>
<string name="pref__clipboard__sync_to_system_clipboard__summary">Pembaruan papan klip Floris juga memperbarui papan klip sistem</string>
<string name="pref__clipboard__enable_clipboard_history__label">Aktifkan riwayat papan klip</string>
<string name="pref__clipboard__clean_up_old_clipboard_items__label">Bersihkan item-item lama</string>
<string name="pref__clipboard__clean_up_old_after__label">Bersihkan item lama setelah</string>
<string name="pref__unit_minutes">" menit"</string>
<string name="pref__clipboard__limit_history_size__label">Batasi ukuran riwayat</string>
<string name="pref__unit_items">" item"</string>
<!-- glide strings -->
</resources>

View File

@@ -61,6 +61,13 @@
<string name="settings__localization__subtype_delete" comment="Subtype dialog delete button">מחק</string>
<string name="settings__localization__subtype_edit_title" comment="Title of subtype dialog when editing an existing subtype">ערוך תת-סוג</string>
<string name="settings__localization__subtype_locale" comment="Label for locale dropdown in subtype dialog">שפה</string>
<string name="settings__localization__subtype_symbols_layout" comment="Label for layout dropdown in subtype dialog">סמלים פריסה ראשית</string>
<string name="settings__localization__subtype_symbols2_layout" comment="Label for layout dropdown in subtype dialog">סמלים פריסה משנית</string>
<string name="settings__localization__subtype_composer" comment="Label for composer dropdown in subtype dialog.">מחבר</string>
<string name="settings__localization__subtype_currency_set" comment="Label for currency set dropdown in subtype dialog. 'set' is used as a noun here and can be compared to a group of elements (in this case currency symbols).">הגדרות מטבע</string>
<string name="settings__localization__subtype_numeric_layout" comment="Label for layout dropdown in subtype dialog">פריסה מספרית</string>
<string name="settings__localization__subtype_numeric_advanced_layout" comment="Label for layout dropdown in subtype dialog">פריסה מספרית (מתקדם)</string>
<string name="settings__localization__subtype_numeric_row_layout" comment="Label for layout dropdown in subtype dialog">פריסת שורת מספרים</string>
<string name="settings__localization__subtype_error_already_exists" comment="Error message shown in subtype dialog when a subtype to add already exists">תת הסוג הזה כבר קיים!</string>
<string name="settings__theme__title" comment="Title of the Theme fragment">ערכת נושא של המקלדת</string>
<string name="settings__theme__undefined" comment="General string for an undefined preference value">לא מוגדר</string>
@@ -120,6 +127,8 @@
<string name="settings__theme__group_privateMode" comment="Theme group label">מצב פרטיות</string>
<string name="settings__theme__group_smartbar" comment="Theme group label">שורה חכמה</string>
<string name="settings__theme__group_smartbarButton" comment="Theme group label">כפתור שורה חכמה</string>
<string name="settings__theme__group_extractEditLayout" comment="Theme group label">פריסת מסך מלא לרוחב</string>
<string name="settings__theme__group_extractActionButton" comment="Theme group label">כפתור פעולה מסך מלא לרוחב</string>
<string name="settings__theme__group_custom" comment="Theme group label (%s is custom group name)">קבוצה מותאמת אישית (%s)</string>
<string name="settings__theme__attr_background" comment="Theme attribute label">צבע רקע</string>
<string name="settings__theme__attr_backgroundActive" comment="Theme attribute label">צבע רקע (מופעל)</string>
@@ -153,6 +162,7 @@
<string name="pref__keyboard__utility_key_action__switch_language" comment="Preference value">החלף שפה</string>
<string name="pref__keyboard__utility_key_action__switch_keyboard_app" comment="Preference value">החלף אפליקציית מקלדת</string>
<string name="pref__keyboard__utility_key_action__dynamic_switch_language_emojis" comment="Preference value">דינמי: עבור לאימוג\'ים / החלף שפה</string>
<string name="pref__keyboard__merge_hint_popups_enabled__label">הראה גם חלונות קופצים של סמל</string>
<string name="pref__keyboard__font_size_multiplier_portrait__label" comment="Preference title">מכפלת גודל גופן (אנכי)</string>
<string name="pref__keyboard__font_size_multiplier_landscape__label" comment="Preference title">מכפלת גודל גופן (אופקי)</string>
<string name="pref__keyboard__group_layout__label" comment="Preference group title">אופן תצוגה</string>
@@ -160,6 +170,9 @@
<string name="pref__keyboard__one_handed_mode__off" comment="Preference value">כבה</string>
<string name="pref__keyboard__one_handed_mode__right" comment="Preference value">מצב ליד ימין</string>
<string name="pref__keyboard__one_handed_mode__left" comment="Preference value">מצב לשמאליים</string>
<string name="pref__keyboard__landscape_input_ui_mode__never_show" comment="Preference value">לעולם אל תציג</string>
<string name="pref__keyboard__landscape_input_ui_mode__always_show" comment="Preference value">הצג תמיד</string>
<string name="pref__keyboard__landscape_input_ui_mode__dynamically_show" comment="Preference value">להציג באופן דינמי</string>
<string name="pref__keyboard__height_factor__label" comment="Preference title">גובה המקלדת</string>
<string name="pref__keyboard__height_factor__extra_short" comment="Preference value">קצר במיוחד</string>
<string name="pref__keyboard__height_factor__short" comment="Preference value">קצר</string>
@@ -170,18 +183,31 @@
<string name="pref__keyboard__height_factor__extra_tall" comment="Preference value">גבוה במיוחד</string>
<string name="pref__keyboard__height_factor__custom" comment="Preference value">מותאם אישית</string>
<string name="pref__keyboard__height_factor_custom__label" comment="Preference title">גובה מקלדת מותאם אישית</string>
<string name="pref__keyboard__bottom_offset_portrait__label" comment="Preference title">קיזוז תחתון (דיוקן)</string>
<string name="pref__keyboard__key_spacing_vertical__label" comment="Preference title">ריווח מקשים (אנכי)</string>
<string name="pref__keyboard__key_spacing_horizontal__label" comment="Preference title">ריווח מקשים (אופקי)</string>
<string name="pref__keyboard__group_keypress__label" comment="Preference group title">לחיצת מקש</string>
<string name="pref__keyboard__sound_enabled__label" comment="Preference title">שמע בעת לחיצה על מקש</string>
<string name="pref__keyboard__sound_volume__label" comment="Preference title">השמע צליל בעת לחיצה על מקש</string>
<string name="pref__keyboard__vibration_enabled__label" comment="Preference title">הפעל רטט בעת לחיצה על מקש</string>
<string name="pref__keyboard__vibration_duration__label" comment="Preference title">משך הרטט בלחיצת מקש</string>
<string name="pref__keyboard__vibration_strength__label" comment="Preference title">עוצמת רטט בעת לחיצה על מקש</string>
<string name="pref__keyboard__popup_visible__label" comment="Preference title">תצוגת חלונית</string>
<string name="pref__keyboard__popup_visible__summary" comment="Preference summary">הצד חלונית בעת לחיצה על מקש</string>
<string name="pref__keyboard__long_press_delay__label" comment="Preference title">השהיית לחיצה מקש ארוכה</string>
<string name="pref__keyboard__space_bar_switches_to_characters__label" comment="Preference title">סרגל רווח עובר חזרה לפריסת התווים</string>
<string name="pref__keyboard__space_bar_switches_to_characters__summary" comment="Preference summary">לחיצה על סרגל הרווח מחזירה אוטומטית לתווים כאשר היא נמצאת בסמלים או במספרים</string>
<string name="settings__typing__title" comment="Title of Typing experience fragment">חווית הקלדה</string>
<string name="pref__smartbar__enabled__label" comment="Preference title">הפעל שורה חכמה</string>
<string name="pref__smartbar__enabled__summary" comment="Preference summary">יהיה ממוקם מעל המקלדת</string>
<string name="pref__suggestion__title" comment="Preference group title">הצעות</string>
<string name="pref__dictionary__title" comment="Preference group title">מילון</string>
<string name="pref__dictionary__enable_system_user_dictionary__label" comment="Preference title">אפשר מילון משתמשי מערכת</string>
<string name="pref__dictionary__enable_system_user_dictionary__summary" comment="Preference summary">הצע מילים המאוחסנות במילון משתמשי המערכת</string>
<string name="pref__dictionary__manage_system_user_dictionary__label" comment="Preference title">נהל את מילון משתמשי המערכת</string>
<string name="pref__dictionary__manage_system_user_dictionary__summary" comment="Preference summary">הוסף, הצג והסר ערכים עבור מילון המשתמשים במערכת</string>
<string name="pref__dictionary__enable_internal_user_dictionary__label" comment="Preference title">אפשר מילון משתמשים פנימי</string>
<string name="pref__dictionary__enable_internal_user_dictionary__summary" comment="Preference summary">הצע מילים המאוחסנות במילון המשתמש הפנימי</string>
<string name="pref__correction__title" comment="Preference group title">תיקונים</string>
<string name="pref__correction__auto_capitalization__label" comment="Preference title">שימוש אוטומטי באותיות גדולות</string>
<string name="pref__correction__auto_capitalization__summary" comment="Preference summary">הפוך אותיות לגדולות בהתחשב בהקשר של הקלט הנכוחי</string>
@@ -189,6 +215,12 @@
<string name="pref__correction__remember_caps_lock_state__summary" comment="Preference summary">Caps lock ישאר פעיל גם כאשר תעבור לשדה טקסט אחר</string>
<string name="pref__correction__double_space_period__label" comment="Preference title">רווח-כפול סוף משפט</string>
<string name="pref__correction__double_space_period__summary" comment="Preference summary">לחיצה על מקש הרווח פעמים תכניס נקודה ואחריה רווח</string>
<string name="settings__udm__title_floris" comment="Title of the User Dictionary Manager activity for internal">מילון משתמשים פנימי</string>
<string name="settings__udm__title_system" comment="Title of the User Dictionary Manager activity for system">מילון משתמשי מערכת</string>
<string name="settings__udm__dictionary_import_success" comment="Message for dictionary import success">מילון המשתמש יובא בהצלחה!</string>
<string name="settings__udm__dictionary_export_success" comment="Message for dictionary export success">מילון משתמשים מיוצא בהצלחה!</string>
<string name="settings__udm__dialog__title_add" comment="Label for the title (when in adding mode) in the user dictionary add/edit dialog">הוסף ערך מילים</string>
<string name="settings__udm__dialog__title_edit" comment="Label for the title (when in editing mode) in the user dictionary add/edit dialog">ערוך הזנת מילים</string>
<string name="settings__gestures__title" comment="Title of Gestures fragment">מחוות &amp; הקלדה גולשת</string>
<string name="pref__glide__title" comment="Preference group title">הקלדה גולשת</string>
<string name="pref__glide__enabled__summary" comment="Preference summary">הקלד מילה באמצעות החלקה של האצבע בין האותיות</string>
@@ -209,6 +241,8 @@
<string name="pref__gestures__swipe_action__move_cursor_start_of_line" comment="Preference value for swipe action">הזז את הסמן לתחילת השורה</string>
<string name="pref__gestures__swipe_action__move_cursor_end_of_line" comment="Preference value for swipe action">העבר את הסמן לסוף השורה</string>
<string name="pref__gestures__swipe_action__shift" comment="Preference value for swipe action">Shift</string>
<string name="pref__gestures__swipe_action__redo" comment="Preference value for swipe action">בצע שוב</string>
<string name="pref__gestures__swipe_action__undo" comment="Preference value for swipe action">ביטול</string>
<string name="pref__gestures__swipe_action__show_input_method_picker" comment="Preference value for swipe action">הצג בורר שיטות קלט</string>
<string name="pref__gestures__swipe_action__switch_to_prev_keyboard" comment="Preference value for swipe action">החלפה למקלדת הקודמת</string>
<string name="pref__gestures__swipe_action__switch_to_prev_subtype" comment="Preference value for swipe action">החלף לתת-סוג הקודם</string>
@@ -241,6 +275,9 @@
<string name="pref__advanced__show_app_icon__label" comment="Label of Show app icon preference in Advanced">הצד את סמל האפליקציה בLauncher</string>
<string name="pref__advanced__force_private_mode__label" comment="Label of Force private mode preference in Advanced">כפה מצב פרטיות</string>
<string name="pref__advanced__force_private_mode__summary" comment="Summary of Force private mode preference in Advanced">יבטל כל תכולה אשר חייבת להשתמש בצורה זמנית בקלט שלך</string>
<string name="pref__devtools__enabled__label" comment="Label of Enable developer tools in Advanced">אפשר כלי מפתח</string>
<string name="pref__devtools__enabled__summary" comment="Summary of Enable developer tools in Advanced">כלים שתוכננו במיוחד לצורך איתור באגים ופתרון בעיות</string>
<string name="pref__devtools__show_heap_memory_stats__label" comment="Label of Show heap memory stats in Advanced">הראה נתונים סטטיסטיים של זיכרון ערימה</string>
<!-- About UI strings -->
<string name="about__title" comment="Title of About activity">אודות</string>
<string name="about__app_icon_content_description" comment="Content description of app icon in About">סמל האפליקציה של FlorisBoard</string>
@@ -248,6 +285,7 @@
<string name="about__view_privacy_policy" comment="Label of View privacy policy button in About">מדיניות פרטיות</string>
<string name="about__view_source_code" comment="Label of View source code button in About">קוד מקור</string>
<string name="about__license__title" comment="Title of Open-source licenses dialog">רישיונות קוד פתוח</string>
<string name="about__version_copied__title" comment="Title of the toast for copying the version string">הגרסה הועתקה ללוח</string>
<!-- Assets strings -->
<plurals name="assets__file__authors">
<item quantity="one">יוצר</item>
@@ -258,6 +296,7 @@
<string name="assets__file__name">שם</string>
<string name="assets__file__source">מקור</string>
<string name="assets__action__add">הוסף</string>
<string name="assets__action__apply">החל</string>
<string name="assets__action__cancel">ביטול</string>
<string name="assets__action__cancel_confirm_title">אשר ביטול</string>
<string name="assets__action__cancel_confirm_message">האם אתה בטוח שברצונך לבטל שינויים שלא נשמרו? לא ניתן לבטל פעולה זו לאחר ביצועה.</string>
@@ -270,7 +309,9 @@
<string name="assets__action__no">לא</string>
<string name="assets__action__save">שמור</string>
<string name="assets__action__yes">כן</string>
<string name="assets__error__details">פרטים</string>
<string name="assets__error__invalid">לא תקין</string>
<string name="assets__error__snackbar_message">משהו השתבש</string>
<!-- Setup UI strings -->
<string name="setup__title" comment="Title of Setup">הגדרות</string>
<string name="setup__prev_button" comment="Label of Previous button in Setup (try to find a short translation due to limited space in UI)">הקודם</string>
@@ -295,6 +336,8 @@
<string name="setup__finish__title" comment="Title of Setup finished fragment in Setup">ההתקנה הושלמה!</string>
<!-- Crash Dialog strings -->
<string name="crash_dialog__title" comment="Title of crash dialog">FlorisBoard דוח שגיאה</string>
<string name="crash_dialog__description" comment="Description of crash dialog">מצטער על אי הנוחות, אך FlorisBoard קרס בגלל שגיאה לא צפויה.</string>
<string name="crash_dialog__copy_to_clipboard" comment="Label of Copy to clipboard button in crash dialog">העתק ללוח המערכת</string>
<string name="crash_dialog__close" comment="Label of Close button in crash dialog">סגור</string>
<string name="crash_notification_channel__title" comment="Title of crash notification channel">FlorisBoard דוח שגיאה</string>
<string name="crash_once_notification__title" comment="Title of the notification for a single crash">FlorisBoard הפסיק לעבוד…</string>
@@ -302,5 +345,20 @@
<string name="crash_multiple_notification__title" comment="Title of the notification for consecutive crashes">נראה שFlorisBoard מפסיק לעבוד שוב שוב…</string>
<string name="crash_multiple_notification__body" comment="Body of the notification for consecutive crashes">המקדלת הקומדת הוחזרה כדי למנוע לולאת קריסה אינסופית. לחץ כדי לראות את פרטי השגיאה</string>
<!-- clipboard strings -->
<string name="clip__clear_history">נקה היסטוריה</string>
<string name="clip__unpin_item">ביטול הצמדה של פריט</string>
<string name="clip__delete_item">מחק</string>
<string name="clip__paste_item">הדבק</string>
<string name="clip__back_to_text_input">חזרה להזנת טקסט</string>
<string name="clip__cant_paste">אפליקציה זו אינה מאפשרת הדבקת תוכן זה.</string>
<string name="pref__clipboard__enable_clipboard_history__label">אפשר היסטוריה של הלוח</string>
<string name="pref__clipboard__enable_clipboard_history__summary">שמור פריטי לוח</string>
<string name="pref__clipboard__clean_up_old_clipboard_items__label">נקה פריטים ישנים</string>
<string name="pref__clipboard__clean_up_old_after__label">נקה פריטים ישנים אחרי</string>
<string name="pref__unit_minutes">" דקות"</string>
<string name="pref__clipboard__limit_history_size__label">הגבל את גודל ההיסטוריה</string>
<string name="pref__clipboard__max_history_size__label">גודל היסטוריה מקסימלי</string>
<string name="pref__unit_items">" פריטים"</string>
<!-- glide strings -->
<string name="pref__glide_preview_refresh_delay">תצוגה מקדימה של עיכוב רענון</string>
</resources>

View File

@@ -2,4 +2,15 @@
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="dev.patrickgold.florisboard.settings.SettingsMainActivity"
android:supportsInlineSuggestions="true"
android:supportsSwitchingToNextInputMethod="true"/>
android:supportsSwitchingToNextInputMethod="true">
<!-- Add default system subtype so we can properly set the icon and label -->
<subtype
android:label="@string/floris_app_name"
android:icon="@mipmap/floris_app_icon"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable"
android:isAsciiCapable="true"
android:overridesImplicitlyEnabledSubtype="true"/>
</input-method>

View File

@@ -1,4 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsActivity="dev.patrickgold.florisboard.settings.SettingsMainActivity"
android:supportsSwitchingToNextInputMethod="true"/>
android:supportsSwitchingToNextInputMethod="true">
<!-- Add default system subtype so we can properly set the icon and label -->
<subtype
android:label="@string/floris_app_name"
android:icon="@mipmap/floris_app_icon"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="AsciiCapable"
android:isAsciiCapable="true"
android:overridesImplicitlyEnabledSubtype="true"/>
</input-method>

View File

@@ -0,0 +1,6 @@
- Added Halmak keyboard layout (#982, thanks @dessalines)
- Keyboard rendering and performance (#992)
- Duplicates in the clipboard view are now discarded (#991, thanks @Luensche)
- Smartbar not showing sometimes (#987)
Detailed changelog: https://github.com/florisboard/florisboard/releases/tag/v0.3.13-beta04