Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15caf66370 | ||
|
|
ae0a8e551b | ||
|
|
cb4bedfc2c | ||
|
|
7d63a6885c | ||
|
|
841d797b7c | ||
|
|
0c9ba5326a | ||
|
|
7c5a7dc148 | ||
|
|
37fc714729 | ||
|
|
ec7d65ebc0 | ||
|
|
5670af16d6 | ||
|
|
6b39a846e6 | ||
|
|
a25501d63c | ||
|
|
e9a5f2161c | ||
|
|
6f12f22937 | ||
|
|
25054ef679 | ||
|
|
3af17f99fe | ||
|
|
06664ff521 | ||
|
|
fde0749a3b | ||
|
|
c061e15263 | ||
|
|
7256c597c2 | ||
|
|
2f9d32027b | ||
|
|
538912edc2 | ||
|
|
ee5ff81ee8 | ||
|
|
d873dc54c5 | ||
|
|
1e967463de | ||
|
|
5c084a10dc | ||
|
|
f158a9deb3 | ||
|
|
66d328293c | ||
|
|
e33b652bb3 | ||
|
|
65d8c02b95 | ||
|
|
bd090132eb |
68
README.md
68
README.md
@@ -3,8 +3,16 @@
|
||||
An open-source keyboard for Android. Currently in alpha stage.
|
||||
|
||||
#### Public Alpha Test Programme
|
||||
Wanna try it out on your device? You can join the public alpha test
|
||||
programme on Google Play. To become a tester, follow these steps:
|
||||
Wanna try it out on your device? Use one of the following options:
|
||||
|
||||
_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)
|
||||
|
||||
_B. Google Play Public Alpha Test_:
|
||||
|
||||
You can join the public alpha test programme on Google Play. To become a
|
||||
tester, follow these steps:
|
||||
1. Join the
|
||||
[FlorisBoard Public Alpha Test](https://groups.google.com/g/florisboard-public-alpha-test)
|
||||
Google Group to be able to access the testing programme.
|
||||
@@ -18,6 +26,8 @@ programme on Google Play. To become a tester, follow these steps:
|
||||
4. Finished! You will receive future versions of FlorisBoard via Google
|
||||
Play.
|
||||
|
||||
_C. Use the APK provided in the release section of this repo_
|
||||
|
||||
##### Giving feedback
|
||||
If you want to give feedback to FlorisBoard, there are 2 ways to do so,
|
||||
as listed below:
|
||||
@@ -29,54 +39,55 @@ as listed below:
|
||||
Thank you for contributing to FlorisBoard!
|
||||
|
||||
##### Note on F-Droid release
|
||||
FlorisBoard is currently only available through Google Play, but it is
|
||||
planned to also release it via F-Droid later on. There is no exact
|
||||
timeline for this, but I aim for the 0.2.0 or 0.3.0 release.
|
||||
FlorisBoard is currently available through Google Play and IzzySoft's
|
||||
repo for F-Droid, but is currently in the inclusion process for the main
|
||||
F-Droid repo. Planned proper F-Droid release is version 0.3.0.
|
||||
|
||||
---
|
||||
|
||||

|
||||
<img src="https://patrickgold.dev/media/previews/florisboard.png"
|
||||
height="256" alt="Preview Image">
|
||||
|
||||
## Feature roadmap
|
||||
|
||||
### Basics
|
||||
* [x] Implementation of the keyboard core (InputMethodService)
|
||||
* [x] Own implementation of deprecated KeyboardView (base only)
|
||||
* [x] Custom implementation of deprecated KeyboardView (base only)
|
||||
* [x] Caps + Caps Lock
|
||||
* [x] Key popups
|
||||
* [x] Extended key popups (e.g. a -> á, à, ä, ...) (needs tweaks for
|
||||
emojis)
|
||||
* [x] Extended key popups (e.g. a -> á, à, ä, ...)
|
||||
* [x] Key press sound/vibration
|
||||
* [x] Portrait orientation support
|
||||
* [x] Landscape orientation support (needs tweaks)
|
||||
* [ ] Tablet screen support
|
||||
* [ ] Tablet screen support (0.4.0)
|
||||
|
||||
### Layouts
|
||||
* [x] Latin character layouts (QWERTY, QWERTZ, AZERTY, Swiss, Spanish,
|
||||
Norwegian, Swedish/Finnish, Icelandic, Danish)
|
||||
Norwegian, Swedish/Finnish, Icelandic, Danish); more coming in
|
||||
future versions
|
||||
* [x] Non-latin character layouts (Persian)
|
||||
* [x] Adapt to situation in app (password, url, text, etc. )
|
||||
* [x] Special character layout(s)
|
||||
* [x] Numeric layout
|
||||
* [x] Numeric layout (advanced)
|
||||
* [x] Phone number layout
|
||||
* [x] Emoji layout (popups buggy atm)
|
||||
* [x] Emoji layout (tweaks: 0.3.0)
|
||||
* [x] Emoticon layout
|
||||
* [ ] Kaomoji layout
|
||||
* [ ] Kaomoji layout (0.3.0)
|
||||
|
||||
### Preferences
|
||||
* [x] Setup wizard
|
||||
* [x] Preferences screen
|
||||
* [x] Customize look and behaviour of keyboard (currently only
|
||||
light/dark theme)
|
||||
* [ ] Theme customization
|
||||
* [ ] Theme import/export (?)
|
||||
* [x] Customize look and behaviour of keyboard
|
||||
* [x] Theme presets (currently only day/night theme)
|
||||
* [x] Theme customization
|
||||
* [ ] Theme import/export (0.4.0 or 0.5.0)
|
||||
* [x] Subtype selection (language/layout)
|
||||
* [x] Keyboard behaviour preferences
|
||||
* [ ] Text suggestion / Auto correct preferences
|
||||
* [ ] Gesture preferences
|
||||
* [ ] Text suggestion / Auto correct preferences (0.4.0 or 0.5.0)
|
||||
* [x] Gesture preferences (0.3.0)
|
||||
|
||||
### Composing suggestions
|
||||
### Composing suggestions (0.4.0 or 0.5.0)
|
||||
* [ ] Auto suggest words from precompiled dictionary
|
||||
* [ ] Auto suggest words from user dictionary
|
||||
* [ ] Auto suggest contacts
|
||||
@@ -85,25 +96,32 @@ timeline for this, but I aim for the 0.2.0 or 0.3.0 release.
|
||||
### Other useful features
|
||||
* [x] One-handed mode
|
||||
* [x] Clipboard/cursor tools
|
||||
* [ ] Floating keyboard
|
||||
* [ ] Gesture support
|
||||
* [ ] Glide typing (?)
|
||||
* [ ] Floating keyboard (0.4.0)
|
||||
* [x] Gesture support (0.3.0)
|
||||
* [ ] Glide typing (0.3.0)
|
||||
* [x] Full integration in IME service list of Android (xml/method)
|
||||
(integration is internal-only, because Android's default subtype
|
||||
implementation not really allows for dynamic language/layout
|
||||
pairs, only compile-time defined ones)
|
||||
* [ ] Description and settings reference in System Language & Input
|
||||
* [ ] (dev only) Generate well-structured documentation of code
|
||||
* [ ] ...
|
||||
|
||||
Note: (?) = not sure if it will be implemented
|
||||
Note:
|
||||
|
||||
## Used libraries and icons
|
||||
(?) = not sure if it will be implemented
|
||||
|
||||
(0.x.0) = planned version when feature will be implemented.
|
||||
|
||||
## Used libraries, components and icons
|
||||
* [Google Flexbox Layout for Android](https://github.com/google/flexbox-layout)
|
||||
by [google](https://github.com/google)
|
||||
* [Google Material icons](https://github.com/google/material-design-icons) by
|
||||
[google](https://github.com/google)
|
||||
* [Moshi JSON library](https://github.com/square/moshi) by
|
||||
[square](https://github.com/square)
|
||||
* [ColorPicker preference](https://github.com/jaredrummler/ColorPicker) by
|
||||
[Jared Rummler](https://github.com/jaredrummler)
|
||||
|
||||
## License
|
||||
```
|
||||
|
||||
@@ -10,8 +10,8 @@ android {
|
||||
applicationId "dev.patrickgold.florisboard"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 11
|
||||
versionName "0.1.2"
|
||||
versionCode 13
|
||||
versionName "0.2.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -31,10 +31,11 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.core:core-ktx:1.3.1'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'androidx.test:core:1.2.0'
|
||||
testImplementation 'org.mockito:mockito-core:1.10.19'
|
||||
@@ -43,7 +44,8 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'com.google.android:flexbox:2.0.1'
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.9.2"
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.2.0'
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7"
|
||||
implementation 'com.jaredrummler:colorpicker:1.1.0'
|
||||
}
|
||||
|
||||
@@ -74,6 +74,14 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/SettingsTheme"/>
|
||||
|
||||
<!-- Advanced Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.settings.AdvancedActivity"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/settings__advanced__title"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:theme="@style/SettingsTheme"/>
|
||||
|
||||
<!-- Setup Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.setup.SetupActivity"
|
||||
|
||||
60
app/src/main/assets/ime/theme/floris_day.json
Normal file
60
app/src/main/assets/ime/theme/floris_day.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "floris_day",
|
||||
"displayName": "Floris Day",
|
||||
"author": "patrickgold",
|
||||
"isNightTheme": false,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/bgColor",
|
||||
"navigationBarLight": "true",
|
||||
"semiTransparentColor": "#20000000",
|
||||
"textColor": "#000000"
|
||||
},
|
||||
"keyboard": {
|
||||
"bgColor": "#E0E0E0"
|
||||
},
|
||||
"key": {
|
||||
"bgColor": "#FFFFFF",
|
||||
"bgColorPressed": "#F5F5F5",
|
||||
"fgColor": "@window/textColor"
|
||||
},
|
||||
"keyEnter": {
|
||||
"bgColor": "@window/colorPrimary",
|
||||
"bgColorPressed": "@window/colorPrimaryDark",
|
||||
"fgColor": "#FFFFFF"
|
||||
},
|
||||
"keyPopup": {
|
||||
"bgColor": "#EEEEEE",
|
||||
"bgColorActive": "#BDBDBD",
|
||||
"fgColor": "@window/textColor"
|
||||
},
|
||||
"keyShift": {
|
||||
"bgColor": "@key/bgColor",
|
||||
"bgColorPressed": "@key/bgColorPressed",
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorCapsLock": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorAlt": "#757575"
|
||||
},
|
||||
"oneHanded": {
|
||||
"bgColor": "#E8F5E9"
|
||||
},
|
||||
"oneHandedButton": {
|
||||
"fgColor": "#424242"
|
||||
},
|
||||
"smartbar": {
|
||||
"bgColor": "transparent",
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorAlt": "#8A8A8A"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"bgColor": "@key/bgColor",
|
||||
"fgColor": "@key/fgColor"
|
||||
}
|
||||
}
|
||||
}
|
||||
60
app/src/main/assets/ime/theme/floris_night.json
Normal file
60
app/src/main/assets/ime/theme/floris_night.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "floris_night",
|
||||
"displayName": "Floris Night",
|
||||
"author": "patrickgold",
|
||||
"isNightTheme": true,
|
||||
"attributes": {
|
||||
"window": {
|
||||
"colorPrimary": "#4CAF50",
|
||||
"colorPrimaryDark": "#388E3C",
|
||||
"colorAccent": "#FF9800",
|
||||
"navigationBarColor": "@keyboard/bgColor",
|
||||
"navigationBarLight": "false",
|
||||
"semiTransparentColor": "#20FFFFFF",
|
||||
"textColor": "#FFFFFF"
|
||||
},
|
||||
"keyboard": {
|
||||
"bgColor": "#212121"
|
||||
},
|
||||
"key": {
|
||||
"bgColor": "#424242",
|
||||
"bgColorPressed": "#616161",
|
||||
"fgColor": "@window/textColor"
|
||||
},
|
||||
"keyEnter": {
|
||||
"bgColor": "@window/colorPrimary",
|
||||
"bgColorPressed": "@window/colorPrimaryDark",
|
||||
"fgColor": "#FFFFFF"
|
||||
},
|
||||
"keyPopup": {
|
||||
"bgColor": "#757575",
|
||||
"bgColorActive": "#BDBDBD",
|
||||
"fgColor": "@window/textColor"
|
||||
},
|
||||
"keyShift": {
|
||||
"bgColor": "@key/bgColor",
|
||||
"bgColorPressed": "@key/bgColorPressed",
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorCapsLock": "@window/colorAccent"
|
||||
},
|
||||
"media": {
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorAlt": "#BDBDBD"
|
||||
},
|
||||
"oneHanded": {
|
||||
"bgColor": "#1B5E20"
|
||||
},
|
||||
"oneHandedButton": {
|
||||
"fgColor": "#EEEEEE"
|
||||
},
|
||||
"smartbar": {
|
||||
"bgColor": "transparent",
|
||||
"fgColor": "@window/textColor",
|
||||
"fgColorAlt": "#73FFFFFF"
|
||||
},
|
||||
"smartbarButton": {
|
||||
"bgColor": "@key/bgColor",
|
||||
"fgColor": "@key/fgColor"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,24 @@ 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.
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>ColorPicker preference</h3>
|
||||
<span>Copyright 2016 Jared Rummler / Copyright 2015 Daniel Nilsson</span>
|
||||
<pre>
|
||||
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.
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Configuration
|
||||
import android.inputmethodservice.InputMethodService
|
||||
import android.media.AudioManager
|
||||
@@ -33,12 +34,12 @@ import android.view.inputmethod.CursorAnchorInfo
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputConnection
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import com.squareup.moshi.Json
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.media.MediaInputManager
|
||||
import dev.patrickgold.florisboard.ime.text.TextInputManager
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.settings.SettingsMainActivity
|
||||
@@ -59,8 +60,10 @@ class FlorisBoard : InputMethodService() {
|
||||
private set
|
||||
|
||||
val context: Context
|
||||
get() = inputView?.context ?: this
|
||||
private var inputView: InputView? = null
|
||||
get() = inputWindowView?.context ?: this
|
||||
var inputView: InputView? = null
|
||||
private set
|
||||
private var inputWindowView: InputWindowView? = null
|
||||
private var eventListeners: MutableList<EventListener> = mutableListOf()
|
||||
|
||||
private var audioManager: AudioManager? = null
|
||||
@@ -70,6 +73,7 @@ class FlorisBoard : InputMethodService() {
|
||||
|
||||
lateinit var subtypeManager: SubtypeManager
|
||||
lateinit var activeSubtype: Subtype
|
||||
private var currentThemeIsNight: Boolean = false
|
||||
private var currentThemeResId: Int = 0
|
||||
|
||||
val textInputManager: TextInputManager
|
||||
@@ -112,6 +116,13 @@ class FlorisBoard : InputMethodService() {
|
||||
fun getInstanceOrNull(): FlorisBoard? {
|
||||
return florisboardInstance
|
||||
}
|
||||
|
||||
fun getDayNightBaseThemeId(isNightTheme: Boolean): Int {
|
||||
return when (isNightTheme) {
|
||||
true -> R.style.KeyboardThemeBase_Night
|
||||
else -> R.style.KeyboardThemeBase_Day
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
@@ -138,19 +149,21 @@ class FlorisBoard : InputMethodService() {
|
||||
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
vibrator = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
prefs = PrefHelper(this)
|
||||
prefs = PrefHelper.getDefaultInstance(this)
|
||||
prefs.initDefaultPreferences()
|
||||
prefs.sync()
|
||||
subtypeManager = SubtypeManager(this, prefs)
|
||||
activeSubtype = subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT
|
||||
|
||||
currentThemeResId = prefs.theme.getSelectedThemeResId()
|
||||
currentThemeIsNight = prefs.internal.themeCurrentIsNight
|
||||
currentThemeResId = getDayNightBaseThemeId(currentThemeIsNight)
|
||||
setTheme(currentThemeResId)
|
||||
updateTheme()
|
||||
|
||||
AppVersionUtils.updateVersionOnInstallAndLastUse(this, prefs)
|
||||
|
||||
super.onCreate()
|
||||
eventListeners.forEach { it.onCreate() }
|
||||
eventListeners.toList().forEach { it.onCreate() }
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
@@ -159,11 +172,11 @@ class FlorisBoard : InputMethodService() {
|
||||
|
||||
baseContext.setTheme(currentThemeResId)
|
||||
|
||||
inputView = layoutInflater.inflate(R.layout.florisboard, null) as InputView
|
||||
inputWindowView = layoutInflater.inflate(R.layout.florisboard, null) as InputWindowView
|
||||
|
||||
eventListeners.forEach { it.onCreateInputView() }
|
||||
eventListeners.toList().forEach { it.onCreateInputView() }
|
||||
|
||||
return inputView
|
||||
return inputWindowView
|
||||
}
|
||||
|
||||
fun registerInputView(inputView: InputView) {
|
||||
@@ -171,10 +184,11 @@ class FlorisBoard : InputMethodService() {
|
||||
|
||||
this.inputView = inputView
|
||||
initializeOneHandedEnvironment()
|
||||
updateTheme()
|
||||
updateSoftInputWindowLayoutParameters()
|
||||
updateOneHandedPanelVisibility()
|
||||
|
||||
eventListeners.forEach { it.onRegisterInputView(inputView) }
|
||||
eventListeners.toList().forEach { it.onRegisterInputView(inputView) }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
@@ -183,43 +197,44 @@ class FlorisBoard : InputMethodService() {
|
||||
osHandler.removeCallbacksAndMessages(null)
|
||||
florisboardInstance = null
|
||||
|
||||
eventListeners.toList().forEach { it.onDestroy() }
|
||||
eventListeners.clear()
|
||||
super.onDestroy()
|
||||
eventListeners.forEach { it.onDestroy() }
|
||||
}
|
||||
|
||||
override fun onStartInputView(info: EditorInfo?, restarting: Boolean) {
|
||||
currentInputConnection?.requestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR)
|
||||
|
||||
super.onStartInputView(info, restarting)
|
||||
eventListeners.forEach { it.onStartInputView(info, restarting) }
|
||||
eventListeners.toList().forEach { it.onStartInputView(info, restarting) }
|
||||
}
|
||||
|
||||
override fun onFinishInputView(finishingInput: Boolean) {
|
||||
currentInputConnection?.requestCursorUpdates(0)
|
||||
|
||||
super.onFinishInputView(finishingInput)
|
||||
eventListeners.forEach { it.onFinishInputView(finishingInput) }
|
||||
eventListeners.toList().forEach { it.onFinishInputView(finishingInput) }
|
||||
}
|
||||
|
||||
override fun onWindowShown() {
|
||||
if (BuildConfig.DEBUG) Log.i(this::class.simpleName, "onWindowShown()")
|
||||
|
||||
prefs.sync()
|
||||
updateThemeIfNecessary()
|
||||
updateTheme()
|
||||
updateOneHandedPanelVisibility()
|
||||
activeSubtype = subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT
|
||||
onSubtypeChanged(activeSubtype)
|
||||
setActiveInput(R.id.text_input)
|
||||
|
||||
super.onWindowShown()
|
||||
eventListeners.forEach { it.onWindowShown() }
|
||||
eventListeners.toList().forEach { it.onWindowShown() }
|
||||
}
|
||||
|
||||
override fun onWindowHidden() {
|
||||
if (BuildConfig.DEBUG) Log.i(this::class.simpleName, "onWindowHidden()")
|
||||
|
||||
super.onWindowHidden()
|
||||
eventListeners.forEach { it.onWindowHidden() }
|
||||
eventListeners.toList().forEach { it.onWindowHidden() }
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
@@ -232,7 +247,7 @@ class FlorisBoard : InputMethodService() {
|
||||
|
||||
override fun onUpdateCursorAnchorInfo(cursorAnchorInfo: CursorAnchorInfo?) {
|
||||
super.onUpdateCursorAnchorInfo(cursorAnchorInfo)
|
||||
eventListeners.forEach { it.onUpdateCursorAnchorInfo(cursorAnchorInfo) }
|
||||
eventListeners.toList().forEach { it.onUpdateCursorAnchorInfo(cursorAnchorInfo) }
|
||||
}
|
||||
|
||||
override fun onUpdateSelection(
|
||||
@@ -251,7 +266,7 @@ class FlorisBoard : InputMethodService() {
|
||||
candidatesStart,
|
||||
candidatesEnd
|
||||
)
|
||||
eventListeners.forEach {
|
||||
eventListeners.toList().forEach {
|
||||
it.onUpdateSelection(
|
||||
oldSelStart,
|
||||
oldSelEnd,
|
||||
@@ -264,40 +279,52 @@ class FlorisBoard : InputMethodService() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the preferences if the selected theme res id has changed and updates the theme only
|
||||
* then by rebuilding the UI and setting the navigation bar theme manually.
|
||||
* Reapplies the supplies colors and settings from prefs to navigation bar.
|
||||
*/
|
||||
private fun updateThemeIfNecessary() {
|
||||
val newThemeResId = prefs.theme.getSelectedThemeResId()
|
||||
if (newThemeResId != currentThemeResId) {
|
||||
currentThemeResId = newThemeResId
|
||||
private fun updateTheme() {
|
||||
val newThemeIsNightMode = prefs.internal.themeCurrentIsNight
|
||||
if (currentThemeIsNight != newThemeIsNightMode) {
|
||||
currentThemeResId = getDayNightBaseThemeId(newThemeIsNightMode)
|
||||
currentThemeIsNight = newThemeIsNightMode
|
||||
setInputView(onCreateInputView())
|
||||
val w = window?.window ?: return
|
||||
w.navigationBarColor = getColorFromAttr(baseContext, android.R.attr.navigationBarColor)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
var flags = w.decorView.systemUiVisibility
|
||||
flags = if (getBooleanFromAttr(baseContext, android.R.attr.windowLightNavigationBar)) {
|
||||
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||
} else {
|
||||
flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
|
||||
}
|
||||
w.decorView.systemUiVisibility = flags
|
||||
}
|
||||
return
|
||||
}
|
||||
val w = window?.window ?: return
|
||||
inputView?.setBackgroundColor(prefs.theme.keyboardBgColor)
|
||||
w.navigationBarColor = prefs.theme.navBarColor
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
var flags = w.decorView.systemUiVisibility
|
||||
flags = if (prefs.theme.navBarIsLight) {
|
||||
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
||||
} else {
|
||||
flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
|
||||
}
|
||||
w.decorView.systemUiVisibility = flags
|
||||
}
|
||||
inputView?.oneHandedCtrlPanelStart?.setBackgroundColor(prefs.theme.oneHandedBgColor)
|
||||
inputView?.oneHandedCtrlPanelEnd?.setBackgroundColor(prefs.theme.oneHandedBgColor)
|
||||
inputView?.findViewById<ImageButton>(R.id.one_handed_ctrl_move_start)
|
||||
?.imageTintList = ColorStateList.valueOf(prefs.theme.oneHandedButtonFgColor)
|
||||
inputView?.findViewById<ImageButton>(R.id.one_handed_ctrl_move_end)
|
||||
?.imageTintList = ColorStateList.valueOf(prefs.theme.oneHandedButtonFgColor)
|
||||
inputView?.findViewById<ImageButton>(R.id.one_handed_ctrl_close_start)
|
||||
?.imageTintList = ColorStateList.valueOf(prefs.theme.oneHandedButtonFgColor)
|
||||
inputView?.findViewById<ImageButton>(R.id.one_handed_ctrl_close_end)
|
||||
?.imageTintList = ColorStateList.valueOf(prefs.theme.oneHandedButtonFgColor)
|
||||
eventListeners.toList().forEach { it.onApplyThemeAttributes() }
|
||||
}
|
||||
|
||||
override fun onComputeInsets(outInsets: Insets?) {
|
||||
super.onComputeInsets(outInsets)
|
||||
val inputView = this.inputView ?: return
|
||||
val inputWindowView = this.inputWindowView ?: return
|
||||
// TODO: Check also if the keyboard is currently suppressed by a hardware keyboard
|
||||
if (!isInputViewShown) {
|
||||
outInsets?.contentTopInsets = inputView.height
|
||||
outInsets?.visibleTopInsets = inputView.height
|
||||
outInsets?.contentTopInsets = inputWindowView.height
|
||||
outInsets?.visibleTopInsets = inputWindowView.height
|
||||
return
|
||||
}
|
||||
val innerInputViewContainer =
|
||||
inputView.findViewById<LinearLayout>(R.id.inner_input_view_container) ?: return
|
||||
val visibleTopY = inputView.height - innerInputViewContainer.measuredHeight
|
||||
val visibleTopY = inputWindowView.height - inputView.measuredHeight
|
||||
outInsets?.contentTopInsets = visibleTopY
|
||||
outInsets?.visibleTopInsets = visibleTopY
|
||||
}
|
||||
@@ -313,8 +340,8 @@ class FlorisBoard : InputMethodService() {
|
||||
private fun updateSoftInputWindowLayoutParameters() {
|
||||
val w = window?.window ?: return
|
||||
ViewLayoutUtils.updateLayoutHeightOf(w, WindowManager.LayoutParams.MATCH_PARENT)
|
||||
val inputView = this.inputView
|
||||
if (inputView != null) {
|
||||
val inputWindowView = this.inputWindowView
|
||||
if (inputWindowView != null) {
|
||||
val layoutHeight = if (isFullscreenMode) {
|
||||
WindowManager.LayoutParams.WRAP_CONTENT
|
||||
} else {
|
||||
@@ -323,7 +350,7 @@ class FlorisBoard : InputMethodService() {
|
||||
val inputArea = w.findViewById<View>(android.R.id.inputArea)
|
||||
ViewLayoutUtils.updateLayoutHeightOf(inputArea, layoutHeight)
|
||||
ViewLayoutUtils.updateLayoutGravityOf(inputArea, Gravity.BOTTOM)
|
||||
ViewLayoutUtils.updateLayoutHeightOf(inputView, layoutHeight)
|
||||
ViewLayoutUtils.updateLayoutHeightOf(inputWindowView, layoutHeight)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,9 +358,9 @@ class FlorisBoard : InputMethodService() {
|
||||
* Makes a key press vibration if the user has this feature enabled in the preferences.
|
||||
*/
|
||||
fun keyPressVibrate() {
|
||||
if (prefs.looknfeel.vibrationEnabled) {
|
||||
var vibrationStrength = prefs.looknfeel.vibrationStrength
|
||||
if (vibrationStrength == -1 && prefs.looknfeel.vibrationEnabledSystem) {
|
||||
if (prefs.keyboard.vibrationEnabled) {
|
||||
var vibrationStrength = prefs.keyboard.vibrationStrength
|
||||
if (vibrationStrength == -1 && prefs.keyboard.vibrationEnabledSystem) {
|
||||
vibrationStrength = 36
|
||||
}
|
||||
if (vibrationStrength > 0) {
|
||||
@@ -355,15 +382,15 @@ class FlorisBoard : InputMethodService() {
|
||||
* Makes a key press sound if the user has this feature enabled in the preferences.
|
||||
*/
|
||||
fun keyPressSound(keyData: KeyData? = null) {
|
||||
if (prefs.looknfeel.soundEnabled) {
|
||||
val soundVolume = prefs.looknfeel.soundVolume
|
||||
if (prefs.keyboard.soundEnabled) {
|
||||
val soundVolume = prefs.keyboard.soundVolume
|
||||
val effect = when (keyData?.code) {
|
||||
KeyCode.SPACE -> AudioManager.FX_KEYPRESS_SPACEBAR
|
||||
KeyCode.DELETE -> AudioManager.FX_KEYPRESS_DELETE
|
||||
KeyCode.ENTER -> AudioManager.FX_KEYPRESS_RETURN
|
||||
else -> AudioManager.FX_KEYPRESS_STANDARD
|
||||
}
|
||||
if (soundVolume == -1 && prefs.looknfeel.soundEnabledSystem) {
|
||||
if (soundVolume == -1 && prefs.keyboard.soundEnabledSystem) {
|
||||
audioManager!!.playSoundEffect(effect)
|
||||
} else if (soundVolume > 0) {
|
||||
audioManager!!.playSoundEffect(effect, soundVolume / 100f)
|
||||
@@ -371,6 +398,19 @@ class FlorisBoard : InputMethodService() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given [SwipeAction]. Ignores any [SwipeAction] but the ones relevant for this
|
||||
* class.
|
||||
*/
|
||||
fun executeSwipeAction(swipeAction: SwipeAction) {
|
||||
when (swipeAction) {
|
||||
SwipeAction.HIDE_KEYBOARD -> requestHideSelf(0)
|
||||
SwipeAction.SWITCH_TO_PREV_SUBTYPE -> switchToPrevSubtype()
|
||||
SwipeAction.SWITCH_TO_NEXT_SUBTYPE -> switchToNextSubtype()
|
||||
else -> textInputManager.executeSwipeAction(swipeAction)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the IME and launches [SettingsMainActivity].
|
||||
*/
|
||||
@@ -390,6 +430,11 @@ class FlorisBoard : InputMethodService() {
|
||||
return subtypeManager.subtypes.size > 1
|
||||
}
|
||||
|
||||
fun switchToPrevSubtype() {
|
||||
activeSubtype = subtypeManager.switchToPrevSubtype() ?: Subtype.DEFAULT
|
||||
onSubtypeChanged(activeSubtype)
|
||||
}
|
||||
|
||||
fun switchToNextSubtype() {
|
||||
activeSubtype = subtypeManager.switchToNextSubtype() ?: Subtype.DEFAULT
|
||||
onSubtypeChanged(activeSubtype)
|
||||
@@ -427,26 +472,26 @@ class FlorisBoard : InputMethodService() {
|
||||
private fun onOneHandedPanelButtonClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.one_handed_ctrl_move_start -> {
|
||||
prefs.looknfeel.oneHandedMode = "start"
|
||||
prefs.keyboard.oneHandedMode = "start"
|
||||
}
|
||||
R.id.one_handed_ctrl_move_end -> {
|
||||
prefs.looknfeel.oneHandedMode = "end"
|
||||
prefs.keyboard.oneHandedMode = "end"
|
||||
}
|
||||
R.id.one_handed_ctrl_close_start,
|
||||
R.id.one_handed_ctrl_close_end -> {
|
||||
prefs.looknfeel.oneHandedMode = "off"
|
||||
prefs.keyboard.oneHandedMode = "off"
|
||||
}
|
||||
}
|
||||
updateOneHandedPanelVisibility()
|
||||
}
|
||||
|
||||
fun toggleOneHandedMode() {
|
||||
when (prefs.looknfeel.oneHandedMode) {
|
||||
when (prefs.keyboard.oneHandedMode) {
|
||||
"off" -> {
|
||||
prefs.looknfeel.oneHandedMode = "end"
|
||||
prefs.keyboard.oneHandedMode = "end"
|
||||
}
|
||||
else -> {
|
||||
prefs.looknfeel.oneHandedMode = "off"
|
||||
prefs.keyboard.oneHandedMode = "off"
|
||||
}
|
||||
}
|
||||
updateOneHandedPanelVisibility()
|
||||
@@ -457,7 +502,7 @@ class FlorisBoard : InputMethodService() {
|
||||
inputView?.oneHandedCtrlPanelStart?.visibility = View.GONE
|
||||
inputView?.oneHandedCtrlPanelEnd?.visibility = View.GONE
|
||||
} else {
|
||||
when (prefs.looknfeel.oneHandedMode) {
|
||||
when (prefs.keyboard.oneHandedMode) {
|
||||
"off" -> {
|
||||
inputView?.oneHandedCtrlPanelStart?.visibility = View.GONE
|
||||
inputView?.oneHandedCtrlPanelEnd?.visibility = View.GONE
|
||||
@@ -521,6 +566,7 @@ class FlorisBoard : InputMethodService() {
|
||||
candidatesEnd: Int
|
||||
) {}
|
||||
|
||||
fun onApplyThemeAttributes() {}
|
||||
fun onSubtypeChanged(newSubtype: Subtype) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.core
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ViewFlipper
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
/**
|
||||
* Custom ViewFlipper class used to prevent an unnecessary exception to be thrown when it is
|
||||
* detached from a window.
|
||||
*
|
||||
* Based on the solution of this SO answer: https://stackoverflow.com/a/8208874/6801193
|
||||
*/
|
||||
class FlorisViewFlipper : ViewFlipper {
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
try {
|
||||
super.onDetachedFromWindow()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
stopFlipping()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,20 +17,30 @@
|
||||
package dev.patrickgold.florisboard.ime.core
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ViewFlipper
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Root view of the keyboard. Notifies [FlorisBoard] when it has been attached to a window.
|
||||
*/
|
||||
class InputView : FrameLayout {
|
||||
|
||||
class InputView : LinearLayout {
|
||||
private var florisboard: FlorisBoard = FlorisBoard.getInstance()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
var desiredInputViewHeight: Int = resources.getDimension(R.dimen.inputView_baseHeight).roundToInt()
|
||||
private set
|
||||
var desiredSmartbarHeight: Int = resources.getDimension(R.dimen.smartbar_baseHeight).roundToInt()
|
||||
private set
|
||||
var desiredTextKeyboardViewHeight: Int = resources.getDimension(R.dimen.textKeyboardView_baseHeight).roundToInt()
|
||||
private set
|
||||
var desiredMediaKeyboardViewHeight: Int = resources.getDimension(R.dimen.mediaKeyboardView_baseHeight).roundToInt()
|
||||
private set
|
||||
|
||||
var mainViewFlipper: ViewFlipper? = null
|
||||
private set
|
||||
@@ -54,4 +64,31 @@ class InputView : FrameLayout {
|
||||
|
||||
florisboard.registerInputView(this)
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val heightFactor = when (resources.configuration.orientation) {
|
||||
Configuration.ORIENTATION_LANDSCAPE -> 0.85f
|
||||
else -> if (prefs.keyboard.oneHandedMode != "off") {
|
||||
0.9f
|
||||
} else {
|
||||
1.0f
|
||||
}
|
||||
} * when (prefs.keyboard.heightFactor) {
|
||||
"extra_short" -> 0.85f
|
||||
"short" -> 0.90f
|
||||
"mid_short" -> 0.95f
|
||||
"normal" -> 1.00f
|
||||
"mid_tall" -> 1.05f
|
||||
"tall" -> 1.10f
|
||||
"extra_tall" -> 1.15f
|
||||
else -> 1.00f
|
||||
}
|
||||
val height = (resources.getDimension(R.dimen.inputView_baseHeight) * heightFactor).roundToInt()
|
||||
desiredInputViewHeight = height
|
||||
desiredSmartbarHeight = (0.16129 * height).roundToInt()
|
||||
desiredTextKeyboardViewHeight = height - desiredSmartbarHeight
|
||||
desiredMediaKeyboardViewHeight = height
|
||||
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.core
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ViewFlipper
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
/**
|
||||
* Root view of the keyboard.
|
||||
*/
|
||||
class InputWindowView : FrameLayout {
|
||||
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)
|
||||
}
|
||||
@@ -21,6 +21,9 @@ import android.content.SharedPreferences
|
||||
import android.provider.Settings
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.DistanceThreshold
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.VelocityThreshold
|
||||
import dev.patrickgold.florisboard.util.VersionName
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
@@ -37,11 +40,12 @@ class PrefHelper(
|
||||
|
||||
val advanced = Advanced(this)
|
||||
val correction = Correction(this)
|
||||
val gestures = Gestures(this)
|
||||
val glide = Glide(this)
|
||||
val internal = Internal(this)
|
||||
val keyboard = Keyboard(this)
|
||||
val looknfeel = Looknfeel(this)
|
||||
val localization = Localization(this)
|
||||
val suggestion = Suggestion(this)
|
||||
val popup = PopUp(this)
|
||||
val theme = Theme(this)
|
||||
|
||||
/**
|
||||
@@ -111,15 +115,28 @@ class PrefHelper(
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var defaultInstance: PrefHelper? = null
|
||||
|
||||
@Synchronized
|
||||
fun getDefaultInstance(context: Context): PrefHelper {
|
||||
if (defaultInstance == null) {
|
||||
defaultInstance = PrefHelper(context)
|
||||
}
|
||||
return defaultInstance!!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells the [PreferenceManager] to set the defined preferences to their default values, if
|
||||
* they have not been initialized yet.
|
||||
*/
|
||||
fun initDefaultPreferences() {
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_advanced, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_gestures, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_keyboard, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_looknfeel, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_theme, true)
|
||||
PreferenceManager.setDefaultValues(context, R.xml.prefs_typing, true)
|
||||
//setPref(Keyboard.SUBTYPES, "")
|
||||
//setPref(Internal.IS_IME_SET_UP, false)
|
||||
}
|
||||
@@ -129,10 +146,10 @@ class PrefHelper(
|
||||
*/
|
||||
fun sync() {
|
||||
val contentResolver = context.contentResolver
|
||||
looknfeel.soundEnabledSystem = Settings.System.getInt(
|
||||
keyboard.soundEnabledSystem = Settings.System.getInt(
|
||||
contentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 0
|
||||
) != 0
|
||||
looknfeel.vibrationEnabledSystem = Settings.System.getInt(
|
||||
keyboard.vibrationEnabledSystem = Settings.System.getInt(
|
||||
contentResolver, Settings.System.HAPTIC_FEEDBACK_ENABLED, 0
|
||||
) != 0
|
||||
|
||||
@@ -172,28 +189,103 @@ class PrefHelper(
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for internal preferences.
|
||||
* Wrapper class for gestures preferences.
|
||||
*/
|
||||
class Gestures(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val SWIPE_UP = "gestures__swipe_up"
|
||||
const val SWIPE_DOWN = "gestures__swipe_down"
|
||||
const val SWIPE_LEFT = "gestures__swipe_left"
|
||||
const val SWIPE_RIGHT = "gestures__swipe_right"
|
||||
const val SPACE_BAR_SWIPE_LEFT = "gestures__space_bar_swipe_left"
|
||||
const val SPACE_BAR_SWIPE_RIGHT = "gestures__space_bar_swipe_right"
|
||||
const val DELETE_KEY_SWIPE_LEFT = "gestures__delete_key_swipe_left"
|
||||
const val SWIPE_VELOCITY_THRESHOLD = "gestures__swipe_velocity_threshold"
|
||||
const val SWIPE_DISTANCE_THRESHOLD = "gestures__swipe_distance_threshold"
|
||||
}
|
||||
|
||||
var swipeUp: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SWIPE_UP, "no_action"))
|
||||
set(v) = prefHelper.setPref(SWIPE_UP, v)
|
||||
var swipeDown: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SWIPE_DOWN, "no_action"))
|
||||
set(v) = prefHelper.setPref(SWIPE_DOWN, v)
|
||||
var swipeLeft: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SWIPE_LEFT, "no_action"))
|
||||
set(v) = prefHelper.setPref(SWIPE_LEFT, v)
|
||||
var swipeRight: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SWIPE_RIGHT, "no_action"))
|
||||
set(v) = prefHelper.setPref(SWIPE_RIGHT, v)
|
||||
var spaceBarSwipeLeft: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SPACE_BAR_SWIPE_LEFT, "no_action"))
|
||||
set(v) = prefHelper.setPref(SPACE_BAR_SWIPE_LEFT, v)
|
||||
var spaceBarSwipeRight: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(SPACE_BAR_SWIPE_RIGHT, "no_action"))
|
||||
set(v) = prefHelper.setPref(SPACE_BAR_SWIPE_RIGHT, v)
|
||||
var deleteKeySwipeLeft: SwipeAction
|
||||
get() = SwipeAction.fromString(prefHelper.getPref(DELETE_KEY_SWIPE_LEFT, "no_action"))
|
||||
set(v) = prefHelper.setPref(DELETE_KEY_SWIPE_LEFT, v)
|
||||
var swipeVelocityThreshold: VelocityThreshold
|
||||
get() = VelocityThreshold.fromString(prefHelper.getPref(SWIPE_VELOCITY_THRESHOLD, "normal"))
|
||||
set(v) = prefHelper.setPref(SWIPE_VELOCITY_THRESHOLD, v)
|
||||
var swipeDistanceThreshold: DistanceThreshold
|
||||
get() = DistanceThreshold.fromString(prefHelper.getPref(SWIPE_DISTANCE_THRESHOLD, "normal"))
|
||||
set(v) = prefHelper.setPref(SWIPE_DISTANCE_THRESHOLD, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for glide preferences.
|
||||
*/
|
||||
class Glide(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val ENABLED = "glide__enabled"
|
||||
const val SHOW_TRAIL = "glide__show_trail"
|
||||
}
|
||||
|
||||
var enabled: Boolean
|
||||
get() = prefHelper.getPref(ENABLED, false)
|
||||
set(v) = prefHelper.setPref(ENABLED, v)
|
||||
var showTrail: Boolean
|
||||
get() = prefHelper.getPref(SHOW_TRAIL, false)
|
||||
set(v) = prefHelper.setPref(SHOW_TRAIL, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for internal preferences. A preference qualifies as an internal pref if the
|
||||
* user has no ability to control this preference's value directly (via a UI pref view).
|
||||
*/
|
||||
class Internal(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val IS_IME_SET_UP = "internal__is_ime_set_up"
|
||||
const val VERSION_ON_INSTALL = "internal__version_on_install"
|
||||
const val VERSION_LAST_USE = "internal__version_last_use"
|
||||
const val VERSION_LAST_CHANGELOG = "internal__version_last_changelog"
|
||||
const val IS_IME_SET_UP = "internal__is_ime_set_up"
|
||||
const val THEME_CURRENT_BASED_ON = "internal__theme_current_based_on"
|
||||
const val THEME_CURRENT_IS_MODIFIED = "internal__theme_current_is_modified"
|
||||
const val THEME_CURRENT_IS_NIGHT = "internal__theme_current_is_night"
|
||||
const val VERSION_ON_INSTALL = "internal__version_on_install"
|
||||
const val VERSION_LAST_USE = "internal__version_last_use"
|
||||
const val VERSION_LAST_CHANGELOG = "internal__version_last_changelog"
|
||||
}
|
||||
|
||||
var isImeSetUp: Boolean
|
||||
get() = prefHelper.getPref(IS_IME_SET_UP, false)
|
||||
set(value) = prefHelper.setPref(IS_IME_SET_UP, value)
|
||||
get() = prefHelper.getPref(IS_IME_SET_UP, false)
|
||||
set(v) = prefHelper.setPref(IS_IME_SET_UP, v)
|
||||
var themeCurrentBasedOn: String
|
||||
get() = prefHelper.getPref(THEME_CURRENT_BASED_ON, "undefined")
|
||||
set(v) = prefHelper.setPref(THEME_CURRENT_BASED_ON, v)
|
||||
var themeCurrentIsModified: Boolean
|
||||
get() = prefHelper.getPref(THEME_CURRENT_IS_MODIFIED, false)
|
||||
set(v) = prefHelper.setPref(THEME_CURRENT_IS_MODIFIED, v)
|
||||
var themeCurrentIsNight: Boolean
|
||||
get() = prefHelper.getPref(THEME_CURRENT_IS_NIGHT, false)
|
||||
set(v) = prefHelper.setPref(THEME_CURRENT_IS_NIGHT, v)
|
||||
var versionOnInstall: String
|
||||
get() = prefHelper.getPref(VERSION_ON_INSTALL, VersionName.DEFAULT_RAW)
|
||||
set(value) = prefHelper.setPref(VERSION_ON_INSTALL, value)
|
||||
get() = prefHelper.getPref(VERSION_ON_INSTALL, VersionName.DEFAULT_RAW)
|
||||
set(v) = prefHelper.setPref(VERSION_ON_INSTALL, v)
|
||||
var versionLastUse: String
|
||||
get() = prefHelper.getPref(VERSION_LAST_USE, VersionName.DEFAULT_RAW)
|
||||
set(value) = prefHelper.setPref(VERSION_LAST_USE, value)
|
||||
get() = prefHelper.getPref(VERSION_LAST_USE, VersionName.DEFAULT_RAW)
|
||||
set(v) = prefHelper.setPref(VERSION_LAST_USE, v)
|
||||
var versionLastChangelog: String
|
||||
get() = prefHelper.getPref(VERSION_LAST_CHANGELOG, VersionName.DEFAULT_RAW)
|
||||
set(value) = prefHelper.setPref(VERSION_LAST_CHANGELOG, value)
|
||||
get() = prefHelper.getPref(VERSION_LAST_CHANGELOG, VersionName.DEFAULT_RAW)
|
||||
set(v) = prefHelper.setPref(VERSION_LAST_CHANGELOG, v)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,30 +293,14 @@ class PrefHelper(
|
||||
*/
|
||||
class Keyboard(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val ACTIVE_SUBTYPE_ID = "keyboard__active_subtype_id"
|
||||
const val SUBTYPES = "keyboard__subtypes"
|
||||
}
|
||||
|
||||
var activeSubtypeId: Int
|
||||
get() = prefHelper.getPref(ACTIVE_SUBTYPE_ID, -1)
|
||||
set(v) = prefHelper.setPref(ACTIVE_SUBTYPE_ID, v)
|
||||
var subtypes: String
|
||||
get() = prefHelper.getPref(SUBTYPES, "")
|
||||
set(v) = prefHelper.setPref(SUBTYPES, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for looknfeel preferences.
|
||||
*/
|
||||
class Looknfeel(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val HEIGHT_FACTOR = "looknfeel__height_factor"
|
||||
const val LONG_PRESS_DELAY = "looknfeel__long_press_delay"
|
||||
const val ONE_HANDED_MODE = "looknfeel__one_handed_mode"
|
||||
const val SOUND_ENABLED = "looknfeel__sound_enabled"
|
||||
const val SOUND_VOLUME = "looknfeel__sound_volume"
|
||||
const val VIBRATION_ENABLED = "looknfeel__vibration_enabled"
|
||||
const val VIBRATION_STRENGTH = "looknfeel__vibration_strength"
|
||||
const val HEIGHT_FACTOR = "keyboard__height_factor"
|
||||
const val LONG_PRESS_DELAY = "keyboard__long_press_delay"
|
||||
const val ONE_HANDED_MODE = "keyboard__one_handed_mode"
|
||||
const val POPUP_ENABLED = "keyboard__popup_enabled"
|
||||
const val SOUND_ENABLED = "keyboard__sound_enabled"
|
||||
const val SOUND_VOLUME = "keyboard__sound_volume"
|
||||
const val VIBRATION_ENABLED = "keyboard__vibration_enabled"
|
||||
const val VIBRATION_STRENGTH = "keyboard__vibration_strength"
|
||||
}
|
||||
|
||||
var heightFactor: String = ""
|
||||
@@ -236,6 +312,9 @@ class PrefHelper(
|
||||
var oneHandedMode: String
|
||||
get() = prefHelper.getPref(ONE_HANDED_MODE, "off")
|
||||
set(value) = prefHelper.setPref(ONE_HANDED_MODE, value)
|
||||
var popupEnabled: Boolean = false
|
||||
get() = prefHelper.getPref(POPUP_ENABLED, true)
|
||||
private set
|
||||
var soundEnabled: Boolean = false
|
||||
get() = prefHelper.getPref(SOUND_ENABLED, true)
|
||||
private set
|
||||
@@ -252,6 +331,23 @@ class PrefHelper(
|
||||
private set
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for localization preferences.
|
||||
*/
|
||||
class Localization(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val ACTIVE_SUBTYPE_ID = "localization__active_subtype_id"
|
||||
const val SUBTYPES = "localization__subtypes"
|
||||
}
|
||||
|
||||
var activeSubtypeId: Int
|
||||
get() = prefHelper.getPref(ACTIVE_SUBTYPE_ID, Subtype.DEFAULT.id)
|
||||
set(v) = prefHelper.setPref(ACTIVE_SUBTYPE_ID, v)
|
||||
var subtypes: String
|
||||
get() = prefHelper.getPref(SUBTYPES, "")
|
||||
set(v) = prefHelper.setPref(SUBTYPES, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for suggestion preferences.
|
||||
*/
|
||||
@@ -273,36 +369,124 @@ class PrefHelper(
|
||||
private set
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for popup preferences.
|
||||
*/
|
||||
class PopUp(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val ENABLED = "popup__enabled"
|
||||
}
|
||||
|
||||
var enabled: Boolean = false
|
||||
get() = prefHelper.getPref(ENABLED, true)
|
||||
private set
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for theme preferences.
|
||||
*/
|
||||
class Theme(private val prefHelper: PrefHelper) {
|
||||
companion object {
|
||||
const val NAME = "theme__name"
|
||||
const val COLOR_PRIMARY = "theme__colorPrimary"
|
||||
const val COLOR_PRIMARY_DARK = "theme__colorPrimaryDark"
|
||||
const val COLOR_ACCENT = "theme__colorAccent"
|
||||
const val NAV_BAR_COLOR = "theme__navBarColor"
|
||||
const val NAV_BAR_IS_LIGHT = "theme__navBarIsLight"
|
||||
const val KEYBOARD_BG_COLOR = "theme__keyboard_bgColor"
|
||||
const val KEY_BG_COLOR = "theme__key_bgColor"
|
||||
const val KEY_BG_COLOR_PRESSED = "theme__key_bgColorPressed"
|
||||
const val KEY_FG_COLOR = "theme__key_fgColor"
|
||||
const val KEY_ENTER_BG_COLOR = "theme__keyEnter_bgColor"
|
||||
const val KEY_ENTER_BG_COLOR_PRESSED = "theme__keyEnter_bgColorPressed"
|
||||
const val KEY_ENTER_FG_COLOR = "theme__keyEnter_fgColor"
|
||||
const val KEY_SHIFT_BG_COLOR = "theme__keyShift_bgColor"
|
||||
const val KEY_SHIFT_BG_COLOR_PRESSED = "theme__keyShift_bgColorPressed"
|
||||
const val KEY_SHIFT_FG_COLOR = "theme__keyShift_fgColor"
|
||||
const val KEY_SHIFT_FG_COLOR_CAPSLOCK = "theme__keyShift_fgColorCapsLock"
|
||||
const val KEY_POPUP_BG_COLOR = "theme__keyPopup_bgColor"
|
||||
const val KEY_POPUP_BG_COLOR_ACTIVE = "theme__keyPopup_bgColorActive"
|
||||
const val KEY_POPUP_FG_COLOR = "theme__keyPopup_fgColor"
|
||||
const val MEDIA_FG_COLOR = "theme__media_fgColor"
|
||||
const val MEDIA_FG_COLOR_ALT = "theme__media_fgColorAlt"
|
||||
const val ONE_HANDED_BG_COLOR = "theme__oneHanded_bgColor"
|
||||
const val ONE_HANDED_BUTTON_FG_COLOR = "theme__oneHandedButton_fgColor"
|
||||
const val SMARTBAR_BG_COLOR = "theme__smartbar_bgColor"
|
||||
const val SMARTBAR_FG_COLOR = "theme__smartbar_fgColor"
|
||||
const val SMARTBAR_FG_COLOR_ALT = "theme__smartbar_fgColorAlt"
|
||||
const val SMARTBAR_BUTTON_BG_COLOR = "theme__smartbarButton_bgColor"
|
||||
const val SMARTBAR_BUTTON_FG_COLOR = "theme__smartbarButton_fgColor"
|
||||
}
|
||||
|
||||
var name: String = ""
|
||||
get() = prefHelper.getPref(NAME, "floris_light")
|
||||
private set
|
||||
fun getSelectedThemeResId(): Int {
|
||||
return when (name) {
|
||||
"floris_light" -> R.style.KeyboardTheme_FlorisLight
|
||||
"floris_dark" -> R.style.KeyboardTheme_FlorisDark
|
||||
else -> R.style.KeyboardTheme_FlorisLight
|
||||
}
|
||||
}
|
||||
var colorPrimary: Int
|
||||
get() = prefHelper.getPref(COLOR_PRIMARY, 0)
|
||||
set(v) = prefHelper.setPref(COLOR_PRIMARY, v)
|
||||
var colorPrimaryDark: Int
|
||||
get() = prefHelper.getPref(COLOR_PRIMARY_DARK, 0)
|
||||
set(v) = prefHelper.setPref(COLOR_PRIMARY_DARK, v)
|
||||
var colorAccent: Int
|
||||
get() = prefHelper.getPref(COLOR_ACCENT, 0)
|
||||
set(v) = prefHelper.setPref(COLOR_ACCENT, v)
|
||||
var navBarColor: Int
|
||||
get() = prefHelper.getPref(NAV_BAR_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(NAV_BAR_COLOR, v)
|
||||
var navBarIsLight: Boolean
|
||||
get() = prefHelper.getPref(NAV_BAR_IS_LIGHT, false)
|
||||
set(v) = prefHelper.setPref(NAV_BAR_IS_LIGHT, v)
|
||||
var keyboardBgColor: Int
|
||||
get() = prefHelper.getPref(KEYBOARD_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEYBOARD_BG_COLOR, v)
|
||||
var keyBgColor: Int
|
||||
get() = prefHelper.getPref(KEY_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_BG_COLOR, v)
|
||||
var keyBgColorPressed: Int
|
||||
get() = prefHelper.getPref(KEY_BG_COLOR_PRESSED, 0)
|
||||
set(v) = prefHelper.setPref(KEY_BG_COLOR_PRESSED, v)
|
||||
var keyFgColor: Int
|
||||
get() = prefHelper.getPref(KEY_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_FG_COLOR, v)
|
||||
var keyEnterBgColor: Int
|
||||
get() = prefHelper.getPref(KEY_ENTER_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_ENTER_BG_COLOR, v)
|
||||
var keyEnterBgColorPressed: Int
|
||||
get() = prefHelper.getPref(KEY_ENTER_BG_COLOR_PRESSED, 0)
|
||||
set(v) = prefHelper.setPref(KEY_ENTER_BG_COLOR_PRESSED, v)
|
||||
var keyEnterFgColor: Int
|
||||
get() = prefHelper.getPref(KEY_ENTER_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_ENTER_FG_COLOR, v)
|
||||
var keyShiftBgColor: Int
|
||||
get() = prefHelper.getPref(KEY_SHIFT_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_SHIFT_BG_COLOR, v)
|
||||
var keyShiftBgColorPressed: Int
|
||||
get() = prefHelper.getPref(KEY_SHIFT_BG_COLOR_PRESSED, 0)
|
||||
set(v) = prefHelper.setPref(KEY_SHIFT_BG_COLOR_PRESSED, v)
|
||||
var keyShiftFgColor: Int
|
||||
get() = prefHelper.getPref(KEY_SHIFT_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_SHIFT_FG_COLOR, v)
|
||||
var keyShiftFgColorCapsLock: Int
|
||||
get() = prefHelper.getPref(KEY_SHIFT_FG_COLOR_CAPSLOCK, 0)
|
||||
set(v) = prefHelper.setPref(KEY_SHIFT_FG_COLOR_CAPSLOCK, v)
|
||||
var keyPopupBgColor: Int
|
||||
get() = prefHelper.getPref(KEY_POPUP_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_POPUP_BG_COLOR, v)
|
||||
var keyPopupBgColorActive: Int
|
||||
get() = prefHelper.getPref(KEY_POPUP_BG_COLOR_ACTIVE, 0)
|
||||
set(v) = prefHelper.setPref(KEY_POPUP_BG_COLOR_ACTIVE, v)
|
||||
var keyPopupFgColor: Int
|
||||
get() = prefHelper.getPref(KEY_POPUP_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(KEY_POPUP_FG_COLOR, v)
|
||||
var mediaFgColor: Int
|
||||
get() = prefHelper.getPref(MEDIA_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(MEDIA_FG_COLOR, v)
|
||||
var mediaFgColorAlt: Int
|
||||
get() = prefHelper.getPref(MEDIA_FG_COLOR_ALT, 0)
|
||||
set(v) = prefHelper.setPref(MEDIA_FG_COLOR_ALT, v)
|
||||
var oneHandedBgColor: Int
|
||||
get() = prefHelper.getPref(ONE_HANDED_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(ONE_HANDED_BG_COLOR, v)
|
||||
var oneHandedButtonFgColor: Int
|
||||
get() = prefHelper.getPref(ONE_HANDED_BUTTON_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(ONE_HANDED_BUTTON_FG_COLOR, v)
|
||||
var smartbarBgColor: Int
|
||||
get() = prefHelper.getPref(SMARTBAR_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(SMARTBAR_BG_COLOR, v)
|
||||
var smartbarFgColor: Int
|
||||
get() = prefHelper.getPref(SMARTBAR_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(SMARTBAR_FG_COLOR, v)
|
||||
var smartbarFgColorAlt: Int
|
||||
get() = prefHelper.getPref(SMARTBAR_FG_COLOR_ALT, 0)
|
||||
set(v) = prefHelper.setPref(SMARTBAR_FG_COLOR_ALT, v)
|
||||
var smartbarButtonBgColor: Int
|
||||
get() = prefHelper.getPref(SMARTBAR_BUTTON_BG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(SMARTBAR_BUTTON_BG_COLOR, v)
|
||||
var smartbarButtonFgColor: Int
|
||||
get() = prefHelper.getPref(SMARTBAR_BUTTON_FG_COLOR, 0)
|
||||
set(v) = prefHelper.setPref(SMARTBAR_BUTTON_FG_COLOR, v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class SubtypeManager(
|
||||
var imeConfig: FlorisBoard.ImeConfig = FlorisBoard.ImeConfig(context.packageName)
|
||||
var subtypes: List<Subtype>
|
||||
get() {
|
||||
val listRaw = prefs.keyboard.subtypes
|
||||
val listRaw = prefs.localization.subtypes
|
||||
return if (listRaw.isBlank()) {
|
||||
listOf()
|
||||
} else {
|
||||
@@ -58,7 +58,7 @@ class SubtypeManager(
|
||||
}
|
||||
}
|
||||
set(v) {
|
||||
prefs.keyboard.subtypes = v.joinToString(SUBTYPE_LIST_STR_DELIMITER)
|
||||
prefs.localization.subtypes = v.joinToString(SUBTYPE_LIST_STR_DELIMITER)
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -134,16 +134,16 @@ class SubtypeManager(
|
||||
*/
|
||||
fun getActiveSubtype(): Subtype? {
|
||||
for (subtype in subtypes) {
|
||||
if (subtype.id == prefs.keyboard.activeSubtypeId) {
|
||||
if (subtype.id == prefs.localization.activeSubtypeId) {
|
||||
return subtype
|
||||
}
|
||||
}
|
||||
val subtypeList = subtypes
|
||||
return if (subtypeList.isNotEmpty()) {
|
||||
prefs.keyboard.activeSubtypeId = subtypeList[0].id
|
||||
prefs.localization.activeSubtypeId = subtypeList[0].id
|
||||
subtypeList[0]
|
||||
} else {
|
||||
prefs.keyboard.activeSubtypeId = -1
|
||||
prefs.localization.activeSubtypeId = Subtype.DEFAULT.id
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -212,11 +212,39 @@ class SubtypeManager(
|
||||
}
|
||||
}
|
||||
subtypes = subtypeList
|
||||
if (subtypeToRemove.id == prefs.keyboard.activeSubtypeId) {
|
||||
if (subtypeToRemove.id == prefs.localization.activeSubtypeId) {
|
||||
getActiveSubtype()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the previous subtype in the subtype list if possible.
|
||||
*
|
||||
* @returns The new active subtype or null if the determination process failed.
|
||||
*/
|
||||
fun switchToPrevSubtype(): Subtype? {
|
||||
val subtypeList = subtypes
|
||||
val activeSubtype = getActiveSubtype() ?: return null
|
||||
var triggerNextSubtype = false
|
||||
var newActiveSubtype: Subtype? = null
|
||||
for (subtype in subtypeList.reversed()) {
|
||||
if (triggerNextSubtype) {
|
||||
triggerNextSubtype = false
|
||||
newActiveSubtype = subtype
|
||||
} else if (subtype == activeSubtype) {
|
||||
triggerNextSubtype = true
|
||||
}
|
||||
}
|
||||
if (triggerNextSubtype) {
|
||||
newActiveSubtype = subtypeList.last()
|
||||
}
|
||||
prefs.localization.activeSubtypeId = when (newActiveSubtype) {
|
||||
null -> Subtype.DEFAULT.id
|
||||
else -> newActiveSubtype.id
|
||||
}
|
||||
return newActiveSubtype
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to the next subtype in the subtype list if possible.
|
||||
*
|
||||
@@ -236,10 +264,10 @@ class SubtypeManager(
|
||||
}
|
||||
}
|
||||
if (triggerNextSubtype) {
|
||||
newActiveSubtype = subtypeList[0]
|
||||
newActiveSubtype = subtypeList.first()
|
||||
}
|
||||
prefs.keyboard.activeSubtypeId = when (newActiveSubtype) {
|
||||
null -> -1
|
||||
prefs.localization.activeSubtypeId = when (newActiveSubtype) {
|
||||
null -> Subtype.DEFAULT.id
|
||||
else -> newActiveSubtype.id
|
||||
}
|
||||
return newActiveSubtype
|
||||
|
||||
@@ -129,7 +129,6 @@ class MediaInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
if (BuildConfig.DEBUG) Log.i(this::class.simpleName, "onDestroy()")
|
||||
|
||||
cancel()
|
||||
florisboard.removeEventListener(this)
|
||||
instance = null
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.media
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import android.widget.Button
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
|
||||
class MediaInputView : LinearLayout, FlorisBoard.EventListener {
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
var tabLayout: TabLayout? = null
|
||||
private set
|
||||
var switchToTextInputButton: Button? = null
|
||||
private set
|
||||
var backspaceButton: ImageButton? = null
|
||||
private set
|
||||
|
||||
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) {
|
||||
florisboard?.addEventListener(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
tabLayout = findViewById(R.id.media_input_tabs)
|
||||
switchToTextInputButton = findViewById(R.id.media_input_switch_to_text_input_button)
|
||||
backspaceButton = findViewById(R.id.media_input_backspace_button)
|
||||
onApplyThemeAttributes()
|
||||
}
|
||||
|
||||
override fun onApplyThemeAttributes() {
|
||||
tabLayout?.setTabTextColors(prefs.theme.mediaFgColor, prefs.theme.mediaFgColor)
|
||||
tabLayout?.tabIconTint = ColorStateList.valueOf(prefs.theme.mediaFgColor)
|
||||
tabLayout?.setSelectedTabIndicatorColor(prefs.theme.colorPrimary)
|
||||
switchToTextInputButton?.setTextColor(prefs.theme.mediaFgColor)
|
||||
backspaceButton?.imageTintList = ColorStateList.valueOf(prefs.theme.mediaFgColor)
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val height = florisboard?.inputView?.desiredInputViewHeight ?: 0
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
|
||||
}
|
||||
}
|
||||
@@ -18,17 +18,20 @@ package dev.patrickgold.florisboard.ime.media.emoji
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Handler
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.view.MotionEvent
|
||||
import android.widget.HorizontalScrollView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
|
||||
/**
|
||||
* View class for managing the rendering and the events of a single emoji keyboard key.
|
||||
@@ -40,10 +43,12 @@ import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
class EmojiKeyView(
|
||||
private val florisboard: FlorisBoard,
|
||||
private val emojiKeyboardView: EmojiKeyboardView,
|
||||
val data: EmojiKeyData
|
||||
) : androidx.appcompat.widget.AppCompatTextView(florisboard.context) {
|
||||
) : androidx.appcompat.widget.AppCompatTextView(emojiKeyboardView.context),
|
||||
FlorisBoard.EventListener {
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
private var isCancelled: Boolean = false
|
||||
private var osHandler: Handler? = null
|
||||
@@ -55,14 +60,16 @@ class EmojiKeyView(
|
||||
setPadding(0, 0, 0, 0)
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, resources.getDimension(R.dimen.emoji_key_textSize))
|
||||
|
||||
triangleDrawable = resources.getDrawable(
|
||||
R.drawable.triangle_bottom_right, context.theme
|
||||
)
|
||||
triangleDrawable?.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(
|
||||
getColorFromAttr(context, R.attr.emoji_key_fgColor), BlendModeCompat.SRC_ATOP
|
||||
)
|
||||
triangleDrawable = ContextCompat.getDrawable(context, R.drawable.triangle_bottom_right)
|
||||
|
||||
text = data.getCodePointsAsString()
|
||||
|
||||
florisboard?.addEventListener(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
onApplyThemeAttributes()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +86,7 @@ class EmojiKeyView(
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
isCancelled = false
|
||||
val delayMillis = florisboard.prefs.looknfeel.longPressDelay
|
||||
val delayMillis = prefs.keyboard.longPressDelay
|
||||
if (osHandler == null) {
|
||||
osHandler = Handler()
|
||||
}
|
||||
@@ -89,8 +96,8 @@ class EmojiKeyView(
|
||||
emojiKeyboardView.isScrollBlocked = true
|
||||
emojiKeyboardView.popupManager.show(this)
|
||||
emojiKeyboardView.popupManager.extend(this)
|
||||
florisboard.keyPressVibrate()
|
||||
florisboard.keyPressSound()
|
||||
florisboard?.keyPressVibrate()
|
||||
florisboard?.keyPressSound()
|
||||
}, delayMillis.toLong())
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
@@ -117,10 +124,10 @@ class EmojiKeyView(
|
||||
if (event.actionMasked != MotionEvent.ACTION_CANCEL &&
|
||||
retData != null && !isCancelled) {
|
||||
if (!emojiKeyboardView.isScrollBlocked) {
|
||||
florisboard.keyPressVibrate()
|
||||
florisboard.keyPressSound()
|
||||
florisboard?.keyPressVibrate()
|
||||
florisboard?.keyPressSound()
|
||||
}
|
||||
florisboard.mediaInputManager.sendEmojiKeyPress(retData)
|
||||
florisboard?.mediaInputManager?.sendEmojiKeyPress(retData)
|
||||
performClick()
|
||||
}
|
||||
if (event.actionMasked == MotionEvent.ACTION_CANCEL) {
|
||||
@@ -131,18 +138,29 @@ class EmojiKeyView(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
triangleDrawable?.setBounds(
|
||||
(measuredWidth * 0.75f).toInt(),
|
||||
(measuredHeight * 0.75f).toInt(),
|
||||
(measuredWidth * 0.85f).toInt(),
|
||||
(measuredHeight * 0.85f).toInt()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onApplyThemeAttributes() {
|
||||
triangleDrawable?.colorFilter =
|
||||
BlendModeColorFilterCompat.createBlendModeColorFilterCompat(
|
||||
prefs.theme.mediaFgColorAlt, BlendModeCompat.SRC_ATOP
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
canvas ?: return
|
||||
|
||||
if (data.popup.isNotEmpty()) {
|
||||
triangleDrawable?.setBounds(
|
||||
(measuredWidth * 0.75f).toInt(),
|
||||
(measuredHeight * 0.75f).toInt(),
|
||||
(measuredWidth * 0.85f).toInt(),
|
||||
(measuredHeight * 0.85f).toInt()
|
||||
)
|
||||
triangleDrawable?.draw(canvas)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package dev.patrickgold.florisboard.ime.media.emoji
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
@@ -31,6 +32,7 @@ import com.google.android.flexbox.FlexboxLayout
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.popup.KeyPopupManager
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
@@ -42,15 +44,17 @@ import java.util.*
|
||||
*
|
||||
* @property florisboard Reference to instance of core class [FlorisBoard].
|
||||
*/
|
||||
class EmojiKeyboardView : LinearLayout {
|
||||
class EmojiKeyboardView : LinearLayout, FlorisBoard.EventListener {
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
private var activeCategory: EmojiCategory = EmojiCategory.SMILEYS_EMOTION
|
||||
private var emojiViewFlipper: ViewFlipper
|
||||
private val emojiKeyWidth = resources.getDimension(R.dimen.emoji_key_width).toInt()
|
||||
private val emojiKeyHeight = resources.getDimension(R.dimen.emoji_key_height).toInt()
|
||||
private val florisboard: FlorisBoard = FlorisBoard.getInstance()
|
||||
private var layouts: Deferred<EmojiLayoutDataMap>
|
||||
private val mainScope = MainScope()
|
||||
private val tabLayout: TabLayout
|
||||
private val uiLayouts = EnumMap<EmojiCategory, HorizontalScrollView>(EmojiCategory::class.java)
|
||||
|
||||
var isScrollBlocked: Boolean = false
|
||||
@@ -71,9 +75,9 @@ class EmojiKeyboardView : LinearLayout {
|
||||
emojiViewFlipper.measureAllChildren = false
|
||||
addView(emojiViewFlipper)
|
||||
|
||||
val tabs =
|
||||
tabLayout =
|
||||
ViewGroup.inflate(context, R.layout.media_input_emoji_tabs, null) as TabLayout
|
||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
setActiveCategory(when (tab?.position) {
|
||||
0 -> EmojiCategory.SMILEYS_EMOTION
|
||||
@@ -92,7 +96,8 @@ class EmojiKeyboardView : LinearLayout {
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {}
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {}
|
||||
})
|
||||
addView(tabs)
|
||||
addView(tabLayout)
|
||||
florisboard?.addEventListener(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
@@ -102,11 +107,7 @@ class EmojiKeyboardView : LinearLayout {
|
||||
buildLayout()
|
||||
setActiveCategory(EmojiCategory.SMILEYS_EMOTION)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
mainScope.cancel()
|
||||
onApplyThemeAttributes()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +145,7 @@ class EmojiKeyboardView : LinearLayout {
|
||||
flexboxLayout.flexWrap = FlexWrap.WRAP
|
||||
for (emojiKeyData in layouts.await()[category].orEmpty()) {
|
||||
val emojiKeyView =
|
||||
EmojiKeyView(florisboard, this@EmojiKeyboardView, emojiKeyData)
|
||||
EmojiKeyView(this@EmojiKeyboardView, emojiKeyData)
|
||||
emojiKeyView.layoutParams = FlexboxLayout.LayoutParams(
|
||||
emojiKeyWidth, emojiKeyHeight
|
||||
)
|
||||
@@ -192,4 +193,9 @@ class EmojiKeyboardView : LinearLayout {
|
||||
))
|
||||
isScrollBlocked = true
|
||||
}
|
||||
|
||||
override fun onApplyThemeAttributes() {
|
||||
tabLayout.tabIconTint = ColorStateList.valueOf(prefs.theme.mediaFgColor)
|
||||
tabLayout.setSelectedTabIndicatorColor(prefs.theme.colorAccent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ package dev.patrickgold.florisboard.ime.popup
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat.getDrawable
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.*
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
@@ -32,7 +34,7 @@ class KeyPopupExtendedSingleView(
|
||||
) : androidx.appcompat.widget.AppCompatTextView(
|
||||
context, null, 0
|
||||
) {
|
||||
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
var iconDrawable: Drawable? = null
|
||||
|
||||
init {
|
||||
@@ -40,15 +42,16 @@ class KeyPopupExtendedSingleView(
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
setBackgroundTintColor2(this, when {
|
||||
isActive -> prefs.theme.keyPopupBgColorActive
|
||||
else -> Color.TRANSPARENT
|
||||
})
|
||||
setTextColor(prefs.theme.keyPopupFgColor)
|
||||
|
||||
super.onDraw(canvas)
|
||||
|
||||
canvas ?: return
|
||||
|
||||
setBackgroundTintColor(this, when {
|
||||
isActive -> R.attr.key_popup_extended_bgColorActive
|
||||
else -> R.attr.key_popup_extended_bgColor
|
||||
})
|
||||
|
||||
val drawable = iconDrawable
|
||||
val drawablePadding = (0.2f * measuredHeight).toInt()
|
||||
if (drawable != null) {
|
||||
@@ -65,7 +68,7 @@ class KeyPopupExtendedSingleView(
|
||||
measuredWidth - marginH - drawablePadding,
|
||||
measuredHeight - marginV - drawablePadding)
|
||||
drawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(
|
||||
getColorFromAttr(context, R.attr.key_popup_fgColor),
|
||||
prefs.theme.keyPopupFgColor,
|
||||
BlendModeCompat.SRC_ATOP
|
||||
)
|
||||
drawable.draw(canvas)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.popup
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.util.AttributeSet
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.*
|
||||
|
||||
class KeyPopupExtendedView : FlexboxLayout {
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
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 onDraw(canvas: Canvas?) {
|
||||
setBackgroundTintColor2(this, prefs.theme.keyPopupBgColor)
|
||||
super.onDraw(canvas)
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyView
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
|
||||
import dev.patrickgold.florisboard.util.setTextTintColor
|
||||
|
||||
/**
|
||||
* Manages the creation and dismissal of key popups as well as the checks if the pointer moved
|
||||
@@ -107,10 +106,6 @@ class KeyPopupManager<T_KBD: View, T_KV: View>(private val keyboardView: T_KBD)
|
||||
lp.isWrapBefore = isWrapBefore
|
||||
textView.layoutParams = lp
|
||||
textView.gravity = Gravity.CENTER
|
||||
setTextTintColor(
|
||||
textView,
|
||||
R.attr.key_popup_fgColor
|
||||
)
|
||||
val textSize = keyboardView.resources.getDimension(R.dimen.key_popup_textSize)
|
||||
if (keyView is KeyView) {
|
||||
when (keyView.data.popup[k].code) {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.popup
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.*
|
||||
|
||||
class KeyPopupView : LinearLayout {
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
private lateinit var text: TextView
|
||||
private lateinit var threedots: ImageView
|
||||
|
||||
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()
|
||||
text = findViewById(R.id.key_popup_text)
|
||||
threedots = findViewById(R.id.key_popup_threedots)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
setBackgroundTintColor2(this, prefs.theme.keyPopupBgColor)
|
||||
text.setTextColor(prefs.theme.keyPopupFgColor)
|
||||
setImageTintColor2(threedots, prefs.theme.keyPopupFgColor)
|
||||
super.onDraw(canvas)
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.InputView
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.editing.EditingKeyboardView
|
||||
import dev.patrickgold.florisboard.ime.text.editing.EditingKeyboardView
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyType
|
||||
@@ -137,8 +138,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
|
||||
private suspend fun addKeyboardView(mode: KeyboardMode) {
|
||||
val keyboardView = KeyboardView(florisboard.context)
|
||||
keyboardView.florisboard = florisboard
|
||||
keyboardView.prefs = florisboard.prefs
|
||||
keyboardView.computedLayout = layoutManager.fetchComputedLayoutAsync(mode, florisboard.activeSubtype).await()
|
||||
keyboardViews[mode] = keyboardView
|
||||
withContext(Dispatchers.Main) {
|
||||
@@ -180,7 +179,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
osHandler.removeCallbacksAndMessages(null)
|
||||
layoutManager.onDestroy()
|
||||
smartbarManager.onDestroy()
|
||||
florisboard.removeEventListener(this)
|
||||
instance = null
|
||||
}
|
||||
|
||||
@@ -306,7 +304,8 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
val inputText =
|
||||
(ic?.getExtractedText(ExtractedTextRequest(), 0)?.text ?: "").toString()
|
||||
selectionEndMax = inputText.length
|
||||
if (isComposingEnabled) {
|
||||
// TODO: separate composing text from delete swipe word detection
|
||||
//if (isComposingEnabled) {
|
||||
if (!isTextSelected) {
|
||||
val newCursorPos = cursorAnchorInfo.selectionStart
|
||||
val prevComposingText = (cursorAnchorInfo.composingText ?: "").toString()
|
||||
@@ -328,7 +327,7 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
resetComposingText()
|
||||
}
|
||||
smartbarManager.generateCandidatesFromComposing(composingText)
|
||||
}
|
||||
//}
|
||||
if (!isNewSelectionInBoundsOfOld) {
|
||||
isManualSelectionMode = false
|
||||
isManualSelectionModeLeft = false
|
||||
@@ -434,6 +433,22 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a given [SwipeAction]. Ignores any [SwipeAction] but the ones relevant for this
|
||||
* class.
|
||||
*/
|
||||
fun executeSwipeAction(swipeAction: SwipeAction) {
|
||||
when (swipeAction) {
|
||||
SwipeAction.DELETE_WORD -> handleDeleteWord()
|
||||
SwipeAction.MOVE_CURSOR_DOWN -> handleArrow(KeyCode.ARROW_DOWN)
|
||||
SwipeAction.MOVE_CURSOR_UP -> handleArrow(KeyCode.ARROW_UP)
|
||||
SwipeAction.MOVE_CURSOR_LEFT -> handleArrow(KeyCode.ARROW_LEFT)
|
||||
SwipeAction.MOVE_CURSOR_RIGHT -> handleArrow(KeyCode.ARROW_RIGHT)
|
||||
SwipeAction.SHIFT -> handleShift()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a given [keyCode] as a [KeyEvent.ACTION_DOWN].
|
||||
*
|
||||
@@ -478,30 +493,48 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
|
||||
ic?.endBatchEdit()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a [KeyCode.DELETE_WORD] event.
|
||||
*/
|
||||
private fun handleDeleteWord() {
|
||||
val ic = florisboard.currentInputConnection
|
||||
ic?.beginBatchEdit()
|
||||
isManualSelectionMode = false
|
||||
isManualSelectionModeLeft = false
|
||||
isManualSelectionModeRight = false
|
||||
ic?.setComposingText("", 1)
|
||||
ic?.finishComposingText()
|
||||
if (ic?.getTextBeforeCursor(1, 0)?.length ?: 0 > 0) {
|
||||
ic?.deleteSurroundingText(1, 0)
|
||||
}
|
||||
composingText = null
|
||||
composingTextStart = null
|
||||
ic?.endBatchEdit()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a [KeyCode.ENTER] event.
|
||||
*/
|
||||
private fun handleEnter() {
|
||||
val ic = florisboard.currentInputConnection
|
||||
ic?.beginBatchEdit()
|
||||
resetComposingText()
|
||||
val action = florisboard.currentInputEditorInfo?.imeOptions ?: 0
|
||||
val actionMasked = action and EditorInfo.IME_MASK_ACTION
|
||||
if (action and EditorInfo.IME_FLAG_NO_ENTER_ACTION > 0) {
|
||||
sendSystemKeyEvent(ic, KeyEvent.KEYCODE_ENTER)
|
||||
} else {
|
||||
when (action and EditorInfo.IME_MASK_ACTION) {
|
||||
when (actionMasked) {
|
||||
EditorInfo.IME_ACTION_DONE,
|
||||
EditorInfo.IME_ACTION_GO,
|
||||
EditorInfo.IME_ACTION_NEXT,
|
||||
EditorInfo.IME_ACTION_PREVIOUS,
|
||||
EditorInfo.IME_ACTION_SEARCH,
|
||||
EditorInfo.IME_ACTION_SEND -> {
|
||||
ic?.performEditorAction(action)
|
||||
ic?.performEditorAction(actionMasked)
|
||||
}
|
||||
else -> sendSystemKeyEvent(ic, KeyEvent.KEYCODE_ENTER)
|
||||
}
|
||||
}
|
||||
ic?.endBatchEdit()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.editing
|
||||
package dev.patrickgold.florisboard.ime.text.editing
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
@@ -29,9 +29,9 @@ import android.widget.Button
|
||||
import androidx.appcompat.widget.AppCompatImageButton
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyData
|
||||
import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@@ -39,6 +39,7 @@ import java.util.*
|
||||
*/
|
||||
class EditingKeyView : AppCompatImageButton {
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
private val data: KeyData
|
||||
private var isKeyPressed: Boolean = false
|
||||
private var osTimer: Timer? = null
|
||||
@@ -133,20 +134,20 @@ class EditingKeyView : AppCompatImageButton {
|
||||
|
||||
canvas ?: return
|
||||
|
||||
imageTintList = ColorStateList.valueOf(getColorFromAttr(context, when {
|
||||
isEnabled -> R.attr.key_fgColor
|
||||
else -> android.R.attr.colorButtonNormal
|
||||
}))
|
||||
imageTintList = ColorStateList.valueOf(when {
|
||||
isEnabled -> prefs.theme.smartbarFgColor
|
||||
else -> prefs.theme.smartbarFgColorAlt
|
||||
})
|
||||
|
||||
// Draw label
|
||||
val label = label
|
||||
if (label != null) {
|
||||
labelPaint.color = if (isHighlighted && isEnabled) {
|
||||
getColorFromAttr(context, R.attr.colorPrimary)
|
||||
prefs.theme.colorPrimary
|
||||
} else if (!isEnabled) {
|
||||
getColorFromAttr(context, android.R.attr.colorButtonNormal)
|
||||
prefs.theme.smartbarFgColorAlt
|
||||
} else {
|
||||
getColorFromAttr(context, R.attr.key_fgColor)
|
||||
prefs.theme.smartbarFgColor
|
||||
}
|
||||
val isPortrait =
|
||||
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
@@ -14,21 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.editing
|
||||
package dev.patrickgold.florisboard.ime.text.editing
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.inputmethod.CursorAnchorInfo
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.setBackgroundTintColor2
|
||||
|
||||
/**
|
||||
* View class for updating the key views depending on the current selection and clipboard state.
|
||||
*/
|
||||
class EditingKeyboardView : ConstraintLayout, FlorisBoard.EventListener {
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
private var arrowUpKey: EditingKeyView? = null
|
||||
private var arrowDownKey: EditingKeyView? = null
|
||||
@@ -56,12 +60,6 @@ class EditingKeyboardView : ConstraintLayout, FlorisBoard.EventListener {
|
||||
pasteKey = findViewById(R.id.clipboard_paste)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
|
||||
florisboard?.removeEventListener(this)
|
||||
}
|
||||
|
||||
override fun onUpdateCursorAnchorInfo(cursorAnchorInfo: CursorAnchorInfo?) {
|
||||
val isSelectionActive = florisboard?.textInputManager?.isTextSelected ?: false
|
||||
val isSelectionMode = florisboard?.textInputManager?.isManualSelectionMode ?: false
|
||||
@@ -79,4 +77,30 @@ class EditingKeyboardView : ConstraintLayout, FlorisBoard.EventListener {
|
||||
copyKey?.isEnabled = isSelectionActive
|
||||
pasteKey?.isEnabled = florisboard?.clipboardManager?.hasPrimaryClip() ?: false
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
|
||||
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
|
||||
val height = when (heightMode) {
|
||||
MeasureSpec.EXACTLY -> {
|
||||
// Must be this size
|
||||
heightSize
|
||||
}
|
||||
MeasureSpec.AT_MOST -> {
|
||||
// Can't be bigger than...
|
||||
(florisboard?.inputView?.desiredTextKeyboardViewHeight ?: 0).coerceAtMost(heightSize)
|
||||
}
|
||||
else -> {
|
||||
// Be whatever you want
|
||||
florisboard?.inputView?.desiredTextKeyboardViewHeight ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
setBackgroundTintColor2(this, prefs.theme.smartbarBgColor)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.gestures
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Enum for declaring the distance thresholds for swipe gestures.
|
||||
*/
|
||||
enum class DistanceThreshold {
|
||||
VERY_SHORT,
|
||||
SHORT,
|
||||
NORMAL,
|
||||
LONG,
|
||||
VERY_LONG;
|
||||
|
||||
companion object {
|
||||
fun fromString(string: String): DistanceThreshold {
|
||||
return valueOf(string.toUpperCase(Locale.ROOT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString().toLowerCase(Locale.ROOT)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.gestures
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Enum for declaring the possible actions for swipe gestures.
|
||||
*/
|
||||
enum class SwipeAction {
|
||||
NO_ACTION,
|
||||
DELETE_WORD,
|
||||
HIDE_KEYBOARD,
|
||||
MOVE_CURSOR_UP,
|
||||
MOVE_CURSOR_DOWN,
|
||||
MOVE_CURSOR_LEFT,
|
||||
MOVE_CURSOR_RIGHT,
|
||||
SHIFT,
|
||||
SWITCH_TO_PREV_SUBTYPE,
|
||||
SWITCH_TO_NEXT_SUBTYPE;
|
||||
|
||||
companion object {
|
||||
fun fromString(string: String): SwipeAction {
|
||||
return valueOf(string.toUpperCase(Locale.ROOT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString().toLowerCase(Locale.ROOT)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.gestures
|
||||
|
||||
import android.content.Context
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.MotionEvent
|
||||
import dev.patrickgold.florisboard.R
|
||||
import java.lang.Exception
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper class which holds all enums, interfaces and classes for detecting a swipe gesture.
|
||||
*/
|
||||
abstract class SwipeGesture {
|
||||
/**
|
||||
* Class which detects swipes based on given [MotionEvent]s. Only supports single-finger swipes
|
||||
* and ignores additional pointers provided, if any.
|
||||
*
|
||||
* @property listener The listener to report detected swipes to.
|
||||
*/
|
||||
class Detector(private val context: Context, private val listener: Listener) {
|
||||
private val eventList: MutableList<MotionEvent> = mutableListOf()
|
||||
private var indexFirst: Int = 0
|
||||
private var indexLastMoveRecognized: Int = 0
|
||||
|
||||
var distanceThreshold: DistanceThreshold = DistanceThreshold.NORMAL
|
||||
var velocityThreshold: VelocityThreshold = VelocityThreshold.NORMAL
|
||||
|
||||
fun onTouchEvent(event: MotionEvent): Boolean {
|
||||
try {
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
clearEventList()
|
||||
eventList.add(MotionEvent.obtainNoHistory(event))
|
||||
}
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
eventList.add(MotionEvent.obtainNoHistory(event))
|
||||
val lastEvent = eventList[indexLastMoveRecognized]
|
||||
val diffX = event.x - lastEvent.x
|
||||
val diffY = event.y - lastEvent.y
|
||||
val distanceThresholdNV = numericValue(distanceThreshold) / 2.0f
|
||||
return if (abs(diffX) > distanceThresholdNV || abs(diffY) > distanceThresholdNV) {
|
||||
indexLastMoveRecognized = eventList.size - 1
|
||||
val direction = detectDirection(diffX.toDouble(), diffY.toDouble())
|
||||
listener.onSwipe(direction, Type.TOUCH_MOVE)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
val firstEvent = eventList[indexFirst]
|
||||
val diffX = event.x - firstEvent.x
|
||||
val diffY = event.y - firstEvent.y
|
||||
val distanceThresholdNV = numericValue(distanceThreshold)
|
||||
val velocityThresholdNV = numericValue(velocityThreshold)
|
||||
val velocity =
|
||||
((convertPixelsToDp(
|
||||
sqrt(diffX.pow(2) + diffY.pow(2)),
|
||||
context
|
||||
) / event.downTime) * 10.0f.pow(8)).toInt()
|
||||
clearEventList()
|
||||
return if ((abs(diffX) > distanceThresholdNV || abs(diffY) > distanceThresholdNV) && velocity >= velocityThresholdNV) {
|
||||
val direction = detectDirection(diffX.toDouble(), diffY.toDouble())
|
||||
listener.onSwipe(direction, Type.TOUCH_UP)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
clearEventList()
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
return false
|
||||
} catch(e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the angle based on the given x any y lengths. The returned angle is in degree
|
||||
* and goes clockwise, beginning with 0° at +x, 90° at +y, 180° at -y and 270° at -y.
|
||||
*
|
||||
* Coordinate system (based on the Android display coordinate system):
|
||||
* -y
|
||||
* -x 00 +x
|
||||
* +y
|
||||
*/
|
||||
private fun angle(diffX: Double, diffY: Double): Double {
|
||||
val tmpAngle = abs(360 * atan(diffY / diffX) / (2 * PI))
|
||||
return if (diffX < 0 && diffY >= 0) {
|
||||
180.0f - tmpAngle
|
||||
} else if (diffX < 0 && diffY < 0) {
|
||||
180.0f + tmpAngle
|
||||
} else if (diffX >= 0 && diffY < 0) {
|
||||
360.0f - tmpAngle
|
||||
} else {
|
||||
tmpAngle
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the direction of a finger swipe by two given events.
|
||||
*/
|
||||
private fun detectDirection(diffX: Double, diffY: Double): Direction {
|
||||
val diffAngle = angle(diffX, diffY) / 360
|
||||
return when {
|
||||
diffAngle >= (1/16.0f) && diffAngle < (3/16.0f) -> Direction.DOWN_RIGHT
|
||||
diffAngle >= (3/16.0f) && diffAngle < (5/16.0f) -> Direction.DOWN
|
||||
diffAngle >= (5/16.0f) && diffAngle < (7/16.0f) -> Direction.DOWN_LEFT
|
||||
diffAngle >= (7/16.0f) && diffAngle < (9/16.0f) -> Direction.LEFT
|
||||
diffAngle >= (9/16.0f) && diffAngle < (11/16.0f) -> Direction.UP_LEFT
|
||||
diffAngle >= (11/16.0f) && diffAngle < (13/16.0f) -> Direction.UP
|
||||
diffAngle >= (13/16.0f) && diffAngle < (15/16.0f) -> Direction.UP_RIGHT
|
||||
else -> Direction.RIGHT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up and clears the event list.
|
||||
*/
|
||||
private fun clearEventList() {
|
||||
for (event in eventList) {
|
||||
event.recycle()
|
||||
}
|
||||
eventList.clear()
|
||||
indexFirst = 0
|
||||
indexLastMoveRecognized = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a numeric value for a given [DistanceThreshold], based on the values defined in
|
||||
* the resources dimens.xml file.
|
||||
*/
|
||||
private fun numericValue(of: DistanceThreshold): Double {
|
||||
return when (of) {
|
||||
DistanceThreshold.VERY_SHORT -> context.resources.getDimension(R.dimen.gesture_distance_threshold_very_short)
|
||||
DistanceThreshold.SHORT -> context.resources.getDimension(R.dimen.gesture_distance_threshold_short)
|
||||
DistanceThreshold.NORMAL -> context.resources.getDimension(R.dimen.gesture_distance_threshold_normal)
|
||||
DistanceThreshold.LONG -> context.resources.getDimension(R.dimen.gesture_distance_threshold_long)
|
||||
DistanceThreshold.VERY_LONG -> context.resources.getDimension(R.dimen.gesture_distance_threshold_very_long)
|
||||
}.toDouble()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a numeric value for a given [VelocityThreshold], based on the values defined in
|
||||
* the resources dimens.xml file.
|
||||
*/
|
||||
private fun numericValue(of: VelocityThreshold): Double {
|
||||
return when (of) {
|
||||
VelocityThreshold.VERY_SLOW -> context.resources.getInteger(R.integer.gesture_velocity_threshold_very_slow)
|
||||
VelocityThreshold.SLOW -> context.resources.getInteger(R.integer.gesture_velocity_threshold_slow)
|
||||
VelocityThreshold.NORMAL -> context.resources.getInteger(R.integer.gesture_velocity_threshold_normal)
|
||||
VelocityThreshold.FAST -> context.resources.getInteger(R.integer.gesture_velocity_threshold_fast)
|
||||
VelocityThreshold.VERY_FAST -> context.resources.getInteger(R.integer.gesture_velocity_threshold_very_fast)
|
||||
}.toDouble()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method converts device specific pixels to density independent pixels.
|
||||
*
|
||||
* Source: https://stackoverflow.com/a/9563438/6801193 (by Muhammad Nabeel Arif)
|
||||
*
|
||||
* @param px A value in px (pixels) unit. Which we need to convert into db
|
||||
* @param context Context to get resources and device specific display metrics
|
||||
* @return A float value to represent dp equivalent to px value
|
||||
*/
|
||||
private fun convertPixelsToDp(px: Float, context: Context): Float {
|
||||
return px / (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun onSwipe(direction: Direction, type: Type): Boolean
|
||||
}
|
||||
|
||||
enum class Direction {
|
||||
UP_LEFT,
|
||||
UP,
|
||||
UP_RIGHT,
|
||||
RIGHT,
|
||||
DOWN_RIGHT,
|
||||
DOWN,
|
||||
DOWN_LEFT,
|
||||
LEFT,
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
TOUCH_UP,
|
||||
TOUCH_MOVE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.gestures
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Enum for declaring the velocity thresholds for swipe gestures.
|
||||
*/
|
||||
enum class VelocityThreshold {
|
||||
VERY_SLOW,
|
||||
SLOW,
|
||||
NORMAL,
|
||||
FAST,
|
||||
VERY_FAST;
|
||||
|
||||
companion object {
|
||||
fun fromString(string: String): VelocityThreshold {
|
||||
return valueOf(string.toUpperCase(Locale.ROOT))
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString().toLowerCase(Locale.ROOT)
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,11 @@ import androidx.core.view.children
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeGesture
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
|
||||
import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
import dev.patrickgold.florisboard.util.setBackgroundTintColor
|
||||
import dev.patrickgold.florisboard.util.setBackgroundTintColor2
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@@ -51,7 +52,7 @@ import java.util.*
|
||||
class KeyView(
|
||||
private val keyboardView: KeyboardView,
|
||||
val data: KeyData
|
||||
) : View(keyboardView.context) {
|
||||
) : View(keyboardView.context), SwipeGesture.Listener {
|
||||
|
||||
private var isKeyPressed: Boolean = false
|
||||
set(value) {
|
||||
@@ -60,6 +61,7 @@ class KeyView(
|
||||
}
|
||||
private var osHandler: Handler? = null
|
||||
private var osTimer: Timer? = null
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
private var shouldBlockNextKeyCode: Boolean = false
|
||||
|
||||
private var drawable: Drawable? = null
|
||||
@@ -77,6 +79,7 @@ class KeyView(
|
||||
}
|
||||
|
||||
var florisboard: FlorisBoard? = null
|
||||
private val swipeGestureDetector = SwipeGesture.Detector(context, this)
|
||||
var touchHitBox: Rect = Rect(-1, -1, -1, -1)
|
||||
|
||||
init {
|
||||
@@ -172,10 +175,19 @@ class KeyView(
|
||||
*/
|
||||
fun onFlorisTouchEvent(event: MotionEvent?): Boolean {
|
||||
event ?: return false
|
||||
if (swipeGestureDetector.onTouchEvent(event)) {
|
||||
isKeyPressed = false
|
||||
osHandler?.removeCallbacksAndMessages(null)
|
||||
osTimer?.cancel()
|
||||
osTimer = null
|
||||
keyboardView.popupManager.hide()
|
||||
return true
|
||||
}
|
||||
when (event.actionMasked) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
florisboard?.prefs?.popup?.let {
|
||||
if (it.enabled){
|
||||
shouldBlockNextKeyCode = false
|
||||
florisboard?.prefs?.keyboard?.let {
|
||||
if (it.popupEnabled){
|
||||
keyboardView.popupManager.show(this)
|
||||
}
|
||||
}
|
||||
@@ -194,7 +206,7 @@ class KeyView(
|
||||
}
|
||||
}, 500, 50)
|
||||
}
|
||||
val delayMillis = keyboardView.prefs.looknfeel.longPressDelay
|
||||
val delayMillis = prefs.keyboard.longPressDelay
|
||||
if (osHandler == null) {
|
||||
osHandler = Handler()
|
||||
}
|
||||
@@ -252,6 +264,34 @@ class KeyView(
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Swipe event handler. Listens to touch_move left/right swipes and triggers the swipe action
|
||||
* defined in the prefs.
|
||||
*/
|
||||
override fun onSwipe(direction: SwipeGesture.Direction, type: SwipeGesture.Type): Boolean {
|
||||
return when (data.code) {
|
||||
KeyCode.SPACE -> when (type) {
|
||||
SwipeGesture.Type.TOUCH_MOVE -> when (direction) {
|
||||
SwipeGesture.Direction.LEFT -> {
|
||||
florisboard?.executeSwipeAction(prefs.gestures.spaceBarSwipeLeft)
|
||||
osHandler?.removeCallbacksAndMessages(null)
|
||||
shouldBlockNextKeyCode = true
|
||||
true
|
||||
}
|
||||
SwipeGesture.Direction.RIGHT -> {
|
||||
florisboard?.executeSwipeAction(prefs.gestures.spaceBarSwipeRight)
|
||||
osHandler?.removeCallbacksAndMessages(null)
|
||||
shouldBlockNextKeyCode = true
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Solution base from this great StackOverflow answer which explained and helped a lot
|
||||
* for handling onMeasure():
|
||||
@@ -337,20 +377,31 @@ class KeyView(
|
||||
* Updates the background depending on [isKeyPressed] and [data].
|
||||
*/
|
||||
private fun updateKeyPressedBackground() {
|
||||
if (data.code == KeyCode.ENTER) {
|
||||
setBackgroundTintColor(
|
||||
this, when {
|
||||
isKeyPressed -> R.attr.colorPrimaryDark
|
||||
else -> R.attr.colorPrimary
|
||||
}
|
||||
)
|
||||
} else {
|
||||
setBackgroundTintColor(
|
||||
this, when {
|
||||
isKeyPressed -> R.attr.key_bgColorPressed
|
||||
else -> R.attr.key_bgColor
|
||||
}
|
||||
)
|
||||
when (data.code) {
|
||||
KeyCode.ENTER -> {
|
||||
setBackgroundTintColor2(
|
||||
this, when {
|
||||
isKeyPressed -> prefs.theme.keyEnterBgColorPressed
|
||||
else -> prefs.theme.keyEnterBgColor
|
||||
}
|
||||
)
|
||||
}
|
||||
KeyCode.SHIFT -> {
|
||||
setBackgroundTintColor2(
|
||||
this, when {
|
||||
isKeyPressed -> prefs.theme.keyShiftBgColorPressed
|
||||
else -> prefs.theme.keyShiftBgColor
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
setBackgroundTintColor2(
|
||||
this, when {
|
||||
isKeyPressed -> prefs.theme.keyBgColorPressed
|
||||
else -> prefs.theme.keyBgColor
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,7 +488,7 @@ class KeyView(
|
||||
when (data.code) {
|
||||
KeyCode.DELETE -> {
|
||||
drawable = getDrawable(context, R.drawable.ic_backspace)
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyFgColor
|
||||
}
|
||||
KeyCode.ENTER -> {
|
||||
val action = florisboard?.currentInputEditorInfo?.imeOptions ?: 0
|
||||
@@ -451,29 +502,29 @@ class KeyView(
|
||||
EditorInfo.IME_ACTION_SEND -> R.drawable.ic_send
|
||||
else -> R.drawable.ic_arrow_right_alt
|
||||
})
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_enter_fgColor)
|
||||
drawableColor = prefs.theme.keyEnterFgColor
|
||||
if (action and EditorInfo.IME_FLAG_NO_ENTER_ACTION > 0) {
|
||||
drawable = getDrawable(context, R.drawable.ic_keyboard_return)
|
||||
}
|
||||
}
|
||||
KeyCode.LANGUAGE_SWITCH -> {
|
||||
drawable = getDrawable(context, R.drawable.ic_language)
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyFgColor
|
||||
}
|
||||
KeyCode.PHONE_PAUSE -> label = resources.getString(R.string.key__phone_pause)
|
||||
KeyCode.PHONE_WAIT -> label = resources.getString(R.string.key__phone_wait)
|
||||
KeyCode.SHIFT -> {
|
||||
drawable = getDrawable(context, when {
|
||||
florisboard?.textInputManager?.caps ?: false && florisboard?.textInputManager?.capsLock ?: false -> {
|
||||
drawableColor = getColorFromAttr(context, R.attr.colorAccent)
|
||||
drawableColor = prefs.theme.keyShiftFgColorCapsLock
|
||||
R.drawable.ic_keyboard_capslock
|
||||
}
|
||||
florisboard?.textInputManager?.caps ?: false && !(florisboard?.textInputManager?.capsLock ?: false) -> {
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyShiftFgColor
|
||||
R.drawable.ic_keyboard_capslock
|
||||
}
|
||||
else -> {
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyShiftFgColor
|
||||
R.drawable.ic_keyboard_arrow_up
|
||||
}
|
||||
})
|
||||
@@ -485,7 +536,7 @@ class KeyView(
|
||||
KeyboardMode.PHONE,
|
||||
KeyboardMode.PHONE2 -> {
|
||||
drawable = getDrawable(context, R.drawable.ic_space_bar)
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyFgColor
|
||||
}
|
||||
KeyboardMode.CHARACTERS -> {
|
||||
label = florisboard?.activeSubtype?.locale?.displayName
|
||||
@@ -495,7 +546,7 @@ class KeyView(
|
||||
}
|
||||
KeyCode.SWITCH_TO_MEDIA_CONTEXT -> {
|
||||
drawable = getDrawable(context, R.drawable.ic_sentiment_satisfied)
|
||||
drawableColor = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
drawableColor = prefs.theme.keyFgColor
|
||||
}
|
||||
KeyCode.SWITCH_TO_TEXT_CONTEXT,
|
||||
KeyCode.VIEW_CHARACTERS -> {
|
||||
@@ -557,12 +608,12 @@ class KeyView(
|
||||
} else {
|
||||
labelPaint.textSize = resources.getDimension(R.dimen.key_textSize)
|
||||
}
|
||||
labelPaint.color = getColorFromAttr(context, R.attr.key_fgColor)
|
||||
labelPaint.color = prefs.theme.keyFgColor
|
||||
labelPaint.alpha = if (keyboardView.computedLayout?.mode == KeyboardMode.CHARACTERS &&
|
||||
data.code == KeyCode.SPACE) { 120 } else { 255 }
|
||||
val isPortrait =
|
||||
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
if (keyboardView.prefs.looknfeel.oneHandedMode != "off" && isPortrait) {
|
||||
if (prefs.keyboard.oneHandedMode != "off" && isPortrait) {
|
||||
labelPaint.textSize *= 0.9f
|
||||
}
|
||||
val centerX = measuredWidth / 2.0f
|
||||
|
||||
@@ -18,9 +18,6 @@ package dev.patrickgold.florisboard.ime.text.keyboard
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.ViewGroup
|
||||
@@ -32,25 +29,27 @@ import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.popup.KeyPopupManager
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeAction
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyView
|
||||
import dev.patrickgold.florisboard.ime.text.layout.ComputedLayoutData
|
||||
import dev.patrickgold.florisboard.util.getColorFromAttr
|
||||
import dev.patrickgold.florisboard.ime.text.gestures.SwipeGesture
|
||||
import dev.patrickgold.florisboard.ime.text.key.KeyCode
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Manages the layout of the keyboard, key measurement, key selection and all touch events.
|
||||
* Supports multi touch events.
|
||||
*
|
||||
* TODO: Implement swipe gesture support
|
||||
* Supports multi touch events. Note that the keyboard's background is transparent. The 'real'
|
||||
* background of this keyboard is the background of the underlying mainViewFlipper. This prevents
|
||||
* rendering issues when a keyboard is being loaded for the first time.
|
||||
*
|
||||
* @property florisboard Reference to instance of core class [FlorisBoard].
|
||||
*/
|
||||
class KeyboardView : LinearLayout {
|
||||
class KeyboardView : LinearLayout, FlorisBoard.EventListener, SwipeGesture.Listener {
|
||||
private var activeKeyView: KeyView? = null
|
||||
private var activePointerId: Int? = null
|
||||
private var activeX: Float = 0.0f
|
||||
private var activeY: Float = 0.0f
|
||||
|
||||
private var colorDrawable: ColorDrawable
|
||||
var computedLayout: ComputedLayoutData? = null
|
||||
set(v) {
|
||||
field = v
|
||||
@@ -58,21 +57,23 @@ class KeyboardView : LinearLayout {
|
||||
}
|
||||
var desiredKeyWidth: Int = resources.getDimension(R.dimen.key_width).toInt()
|
||||
var desiredKeyHeight: Int = resources.getDimension(R.dimen.key_height).toInt()
|
||||
var florisboard: FlorisBoard? = null
|
||||
var florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private var initialKeyCode: Int = 0
|
||||
var isPreviewMode: Boolean = false
|
||||
var popupManager = KeyPopupManager<KeyboardView, KeyView>(this)
|
||||
lateinit var prefs: PrefHelper
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
private val swipeGestureDetector = SwipeGesture.Detector(context, this)
|
||||
|
||||
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) {
|
||||
colorDrawable = ColorDrawable(getColorFromAttr(context, R.attr.keyboard_bgColor))
|
||||
background = colorDrawable
|
||||
orientation = VERTICAL
|
||||
layoutParams = layoutParams ?: FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
florisboard?.addEventListener(this)
|
||||
onWindowShown()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,6 +108,13 @@ class KeyboardView : LinearLayout {
|
||||
popupManager.dismissAllPopups()
|
||||
}
|
||||
|
||||
override fun onWindowShown() {
|
||||
swipeGestureDetector.apply {
|
||||
distanceThreshold = prefs.gestures.swipeDistanceThreshold
|
||||
velocityThreshold = prefs.gestures.swipeVelocityThreshold
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch all events which are designated for child views.
|
||||
*/
|
||||
@@ -124,6 +132,12 @@ class KeyboardView : LinearLayout {
|
||||
return false
|
||||
}
|
||||
val eventFloris = MotionEvent.obtainNoHistory(event)
|
||||
if (swipeGestureDetector.onTouchEvent(event)) {
|
||||
sendFlorisTouchEvent(eventFloris, MotionEvent.ACTION_CANCEL)
|
||||
activeKeyView = null
|
||||
activePointerId = null
|
||||
return true
|
||||
}
|
||||
val pointerIndex = event.actionIndex
|
||||
var pointerId = event.getPointerId(pointerIndex)
|
||||
when (event.actionMasked) {
|
||||
@@ -134,6 +148,7 @@ class KeyboardView : LinearLayout {
|
||||
activeX = event.getX(pointerIndex)
|
||||
activeY = event.getY(pointerIndex)
|
||||
searchForActiveKeyView()
|
||||
initialKeyCode = activeKeyView?.data?.code ?: 0
|
||||
sendFlorisTouchEvent(eventFloris, MotionEvent.ACTION_DOWN)
|
||||
} else if (activePointerId != pointerId) {
|
||||
// New pointer arrived. Send ACTION_UP to current active view and move on
|
||||
@@ -142,6 +157,7 @@ class KeyboardView : LinearLayout {
|
||||
activeX = event.getX(pointerIndex)
|
||||
activeY = event.getY(pointerIndex)
|
||||
searchForActiveKeyView()
|
||||
initialKeyCode = activeKeyView?.data?.code ?: 0
|
||||
sendFlorisTouchEvent(eventFloris, MotionEvent.ACTION_DOWN)
|
||||
}
|
||||
}
|
||||
@@ -199,6 +215,45 @@ class KeyboardView : LinearLayout {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Swipe event handler. Listens to touch_up swipes and executes the swipe action defined for it
|
||||
* in the prefs.
|
||||
*/
|
||||
override fun onSwipe(direction: SwipeGesture.Direction, type: SwipeGesture.Type): Boolean {
|
||||
return when {
|
||||
initialKeyCode == KeyCode.DELETE -> {
|
||||
if (type == SwipeGesture.Type.TOUCH_UP && direction == SwipeGesture.Direction.LEFT) {
|
||||
florisboard?.executeSwipeAction(prefs.gestures.deleteKeySwipeLeft)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
initialKeyCode > KeyCode.SPACE && !popupManager.isShowingExtendedPopup -> when {
|
||||
!prefs.glide.enabled -> when (type) {
|
||||
SwipeGesture.Type.TOUCH_UP -> {
|
||||
val swipeAction = when (direction) {
|
||||
SwipeGesture.Direction.UP -> prefs.gestures.swipeUp
|
||||
SwipeGesture.Direction.DOWN -> prefs.gestures.swipeDown
|
||||
SwipeGesture.Direction.LEFT -> prefs.gestures.swipeLeft
|
||||
SwipeGesture.Direction.RIGHT -> prefs.gestures.swipeRight
|
||||
else -> SwipeAction.NO_ACTION
|
||||
}
|
||||
if (swipeAction != SwipeAction.NO_ACTION) {
|
||||
florisboard?.executeSwipeAction(swipeAction)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for an active key view at [activeX]/[activeY].
|
||||
*/
|
||||
@@ -237,32 +292,21 @@ class KeyboardView : LinearLayout {
|
||||
val keyMarginH = resources.getDimension((R.dimen.key_marginH)).toInt()
|
||||
desiredKeyWidth = (widthSize / 10) - (2 * keyMarginH)
|
||||
|
||||
val factor = prefs.looknfeel.heightFactor
|
||||
val keyHeightFactor = when (resources.configuration.orientation) {
|
||||
Configuration.ORIENTATION_LANDSCAPE -> 0.85f
|
||||
else -> if (prefs.looknfeel.oneHandedMode == "start" ||
|
||||
prefs.looknfeel.oneHandedMode == "end") {
|
||||
0.9f
|
||||
} else {
|
||||
1.0f
|
||||
}
|
||||
} * when (factor) {
|
||||
"extra_short" -> 0.85f
|
||||
"short" -> 0.90f
|
||||
"mid_short" -> 0.95f
|
||||
"normal" -> 1.00f
|
||||
"mid_tall" -> 1.05f
|
||||
"tall" -> 1.10f
|
||||
"extra_tall" -> 1.15f
|
||||
else -> 1.00f
|
||||
} * when (isPreviewMode) {
|
||||
val keyMarginV = resources.getDimension((R.dimen.key_marginV)).toInt()
|
||||
val keyHeightFactor = when (isPreviewMode) {
|
||||
true -> 0.90f
|
||||
else -> 1.00f
|
||||
}
|
||||
desiredKeyHeight = (resources.getDimension(R.dimen.key_height) * keyHeightFactor).toInt()
|
||||
florisboard?.textInputManager?.smartbarManager?.smartbarView?.setHeightFactor(keyHeightFactor)
|
||||
val desiredHeight = keyHeightFactor * (florisboard?.inputView?.desiredTextKeyboardViewHeight ?: resources.getDimension(R.dimen.textKeyboardView_baseHeight).toInt())
|
||||
desiredKeyHeight = (desiredHeight / 4 - 2 * keyMarginV).roundToInt()
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(desiredHeight.roundToInt(), MeasureSpec.EXACTLY))
|
||||
}
|
||||
|
||||
override fun onApplyThemeAttributes() {
|
||||
if (isPreviewMode) {
|
||||
setBackgroundColor(prefs.theme.keyboardBgColor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -309,10 +353,4 @@ class KeyboardView : LinearLayout {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
colorDrawable.color = getColorFromAttr(context, R.attr.keyboard_bgColor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,17 @@
|
||||
package dev.patrickgold.florisboard.ime.text.smartbar
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.util.AttributeSet
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.setBackgroundTintColor2
|
||||
|
||||
/**
|
||||
* Basically the same as an ImageButton.
|
||||
* @see [onMeasure] why this view class exists.
|
||||
*/
|
||||
class SmartbarQuickActionButton : androidx.appcompat.widget.AppCompatImageButton {
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
constructor(context: Context) : this(context, null)
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
@@ -37,4 +41,10 @@ class SmartbarQuickActionButton : androidx.appcompat.widget.AppCompatImageButton
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
super.onMeasure(heightMeasureSpec, heightMeasureSpec)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
setBackgroundTintColor2(this, prefs.theme.smartbarButtonBgColor)
|
||||
setColorFilter(prefs.theme.smartbarButtonFgColor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package dev.patrickgold.florisboard.ime.text.smartbar
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.util.AttributeSet
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
@@ -25,8 +26,13 @@ import android.widget.Button
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.view.children
|
||||
import dev.patrickgold.florisboard.BuildConfig
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.setImageTintColor2
|
||||
import kotlinx.android.synthetic.main.florisboard.view.*
|
||||
|
||||
/**
|
||||
* View class which keeps the references to important children and informs [SmartbarManager] that
|
||||
@@ -34,7 +40,8 @@ import dev.patrickgold.florisboard.R
|
||||
* a theme change).
|
||||
*/
|
||||
class SmartbarView : LinearLayout {
|
||||
|
||||
private val florisboard: FlorisBoard? = FlorisBoard.getInstanceOrNull()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
private val smartbarManager = SmartbarManager.getInstance()
|
||||
|
||||
private var variants: MutableList<ViewGroup> = mutableListOf()
|
||||
@@ -100,12 +107,58 @@ class SmartbarView : LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the default smartbar height with the given [factor] and sets it.
|
||||
*/
|
||||
fun setHeightFactor(factor: Float) {
|
||||
val baseSize = resources.getDimension(R.dimen.smartbar_height)
|
||||
val size = (baseSize * factor).toInt()
|
||||
layoutParams?.height = size
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
|
||||
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
|
||||
val height = when (heightMode) {
|
||||
MeasureSpec.EXACTLY -> {
|
||||
// Must be this size
|
||||
heightSize
|
||||
}
|
||||
MeasureSpec.AT_MOST -> {
|
||||
// Can't be bigger than...
|
||||
(florisboard?.inputView?.desiredSmartbarHeight ?: 0).coerceAtMost(heightSize)
|
||||
}
|
||||
else -> {
|
||||
// Be whatever you want
|
||||
florisboard?.inputView?.desiredSmartbarHeight ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY))
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
super.onDraw(canvas)
|
||||
setBackgroundColor(prefs.theme.smartbarBgColor)
|
||||
for (container in containers) {
|
||||
when (container.id) {
|
||||
R.id.number_row -> {
|
||||
for (button in container.children) {
|
||||
if (button is Button) {
|
||||
button.setTextColor(prefs.theme.smartbarFgColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.clipboard_cursor_row -> {
|
||||
for (button in container.children) {
|
||||
if (button is ImageButton) {
|
||||
if (button.isEnabled) {
|
||||
setImageTintColor2(button, prefs.theme.smartbarFgColor)
|
||||
} else {
|
||||
setImageTintColor2(button, prefs.theme.smartbarFgColorAlt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.candidates -> {
|
||||
for (view in container.children) {
|
||||
if (view is Button) {
|
||||
view.setTextColor(prefs.theme.smartbarFgColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
310
app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt
Normal file
310
app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.theme
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
|
||||
/**
|
||||
* Data class which holds a parsed theme json file. Used for loading a theme
|
||||
* preset in Settings.
|
||||
* Note: this implementation is generic and allows for any group/attr names.
|
||||
* FlorisBoard itself expects certain groups and attrs to be able to
|
||||
* color the controls accordingly. See 'ime/themes/floris_day.json'
|
||||
* for a good example of which attributes FlorisBoard needs!
|
||||
*
|
||||
* @property name A unique id/name for this theme. Must only contain certain
|
||||
* characters: upper/lower case letters, numbers (not at the beginning!) or
|
||||
* an underline (_).
|
||||
* @property displayName The name of this theme when shown to the user. Can
|
||||
* contain any valid Unicode character.
|
||||
* @property author The name of the author of this theme. Should be your
|
||||
* username on GitHub/GitLab/BitBucket/... or your full name.
|
||||
* @property isNightTheme If this theme is meant for display at day (false)
|
||||
* or night (true). This property is only used to auto-assign this theme to
|
||||
* either the day or night theme list in Settings, which is used when the
|
||||
* user wants to auto-set his theme based on the current time.
|
||||
* @property rawAttrs Map which holds the raw attributes of this theme. Note
|
||||
* that the name of this property is 'attributes' within the json file!
|
||||
* Attributes are always grouped together. This ensures a better structure
|
||||
* and easier storage. The group- as well as the attr-name has the same
|
||||
* limitations as the theme [name].
|
||||
* Attribute values can be of different format:
|
||||
* 1. A color
|
||||
* Either #RRGGBB or #AARRGGBB (case-insensitive) -> e.g. #A034FF23
|
||||
* 2. A static word
|
||||
* - transparent (=0x00000000)
|
||||
* - true (=0x1)
|
||||
* - false (=0x0)
|
||||
* 3. A reference to another attribute within the SAME theme, as follows:
|
||||
* @group/attrName -> e.g. @window/textColor
|
||||
* Note that referencing attributes has its limitations:
|
||||
* a. Recursive references will cause an exception.
|
||||
* b. Referencing an previously defined attribute is fine.
|
||||
* c. Referencing an attribute not-yet defined is also ok, as long as
|
||||
* the reference can be resolved at the next iteration.
|
||||
* d. If the next iteration cannot resolve a value, an exception is
|
||||
* thrown.
|
||||
* 4. If the value is of any other format, an exception will be thrown.
|
||||
*
|
||||
* @throws IllegalArgumentException either at an invalid value or when a
|
||||
* reference cannot be resolved.
|
||||
*/
|
||||
data class Theme(
|
||||
val name: String,
|
||||
val displayName: String,
|
||||
val author: String,
|
||||
val isNightTheme: Boolean = false,
|
||||
@Json(name = "attributes")
|
||||
private val rawAttrs: Map<String, Map<String, String>>
|
||||
) {
|
||||
/**
|
||||
* Holds the parsed attributes after init.
|
||||
*/
|
||||
val parsedAttrs: MutableMap<String, MutableMap<String, Int>> = mutableMapOf()
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Loads a theme from the specified [path].
|
||||
*
|
||||
* @param context A reference to the current [Context]. Used to request
|
||||
* asset file.
|
||||
* @param path The path to the json theme file in the asset folder.
|
||||
* @returns A parsed [Theme] or null. A null value may indicate that
|
||||
* the file does not exist or that an error during the reading
|
||||
* of the file occurred.
|
||||
*/
|
||||
fun fromJsonFile(context: Context, path: String): Theme? {
|
||||
val rawJsonData: String = try {
|
||||
context.assets.open(path).bufferedReader().use { it.readText() }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} ?: return null
|
||||
return fromJsonString(rawJsonData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a theme from the given [rawData].
|
||||
*
|
||||
* @param rawData The raw json theme file as a string.
|
||||
* @returns A parsed [Theme] or null. A null value may indicate that an error
|
||||
* during the reading of the [rawData] occurred.
|
||||
*/
|
||||
fun fromJsonString(rawData: String): Theme? {
|
||||
val moshi = Moshi.Builder()
|
||||
.add(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
val layoutAdapter = moshi.adapter(Theme::class.java)
|
||||
return layoutAdapter.fromJson(rawData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a given [theme] to the [prefs]. The default color values are based off the
|
||||
* Floris Day theme and are not intended to be modified. Instead, themes should be defined
|
||||
* in assets/ime/theme/<theme_id>.json
|
||||
*
|
||||
* @param theme The theme data.
|
||||
* @param prefs The preference object to write the theme to.
|
||||
*/
|
||||
fun writeThemeToPrefs(prefs: PrefHelper, theme: Theme) {
|
||||
// Internal prefs part I
|
||||
prefs.internal.themeCurrentBasedOn = theme.name
|
||||
prefs.internal.themeCurrentIsNight = theme.isNightTheme
|
||||
|
||||
// Theme attributes
|
||||
prefs.theme.colorPrimary = theme.getAttr("window/colorPrimary", "#4CAF50")
|
||||
prefs.theme.colorPrimaryDark = theme.getAttr("window/colorPrimaryDark", "#388E3C")
|
||||
prefs.theme.colorAccent = theme.getAttr("window/colorAccent", "#FF9800")
|
||||
prefs.theme.navBarColor = theme.getAttr("window/navigationBarColor", "#E0E0E0")
|
||||
prefs.theme.navBarIsLight = (theme.getAttrOrNull("window/navigationBarLight") ?: 0) > 0
|
||||
|
||||
prefs.theme.keyboardBgColor = theme.getAttr("keyboard/bgColor", "#E0E0E0")
|
||||
|
||||
prefs.theme.keyBgColor = theme.getAttr("key/bgColor", "#FFFFFF")
|
||||
prefs.theme.keyBgColorPressed = theme.getAttr("key/bgColorPressed", "#F5F5F5")
|
||||
prefs.theme.keyFgColor = theme.getAttr("key/fgColor", "#000000")
|
||||
|
||||
prefs.theme.keyEnterBgColor = theme.getAttr("keyEnter/bgColor", "#4CAF50")
|
||||
prefs.theme.keyEnterBgColorPressed = theme.getAttr("keyEnter/bgColorPressed", "#388E3C")
|
||||
prefs.theme.keyEnterFgColor = theme.getAttr("keyEnter/fgColor", "#FFFFFF")
|
||||
|
||||
prefs.theme.keyPopupBgColor = theme.getAttr("keyPopup/bgColor", "#EEEEEE")
|
||||
prefs.theme.keyPopupBgColorActive = theme.getAttr("keyPopup/bgColorActive", "#BDBDBD")
|
||||
prefs.theme.keyPopupFgColor = theme.getAttr("keyPopup/fgColor", "#000000")
|
||||
|
||||
prefs.theme.keyShiftBgColor = theme.getAttr("keyShift/bgColor", "#FFFFFF")
|
||||
prefs.theme.keyShiftBgColorPressed = theme.getAttr("keyShift/bgColorPressed", "#F5F5F5")
|
||||
prefs.theme.keyShiftFgColor = theme.getAttr("keyShift/fgColor", "#000000")
|
||||
prefs.theme.keyShiftFgColorCapsLock = theme.getAttr("keyShift/fgColorCapsLock", "#FF9800")
|
||||
|
||||
prefs.theme.mediaFgColor = theme.getAttr("media/fgColor", "#000000")
|
||||
prefs.theme.mediaFgColorAlt = theme.getAttr("media/fgColorAlt", "#757575")
|
||||
|
||||
prefs.theme.oneHandedBgColor = theme.getAttr("oneHanded/bgColor", "#E8F5E9")
|
||||
|
||||
prefs.theme.oneHandedButtonFgColor = theme.getAttr("oneHandedButton/fgColor", "#424242")
|
||||
|
||||
prefs.theme.smartbarBgColor = theme.getAttr("smartbar/bgColor", "#E0E0E0")
|
||||
prefs.theme.smartbarFgColor = theme.getAttr("smartbar/fgColor", "#000000")
|
||||
prefs.theme.smartbarFgColorAlt = theme.getAttr("smartbar/fgColorAlt", "#4A000000")
|
||||
|
||||
prefs.theme.smartbarButtonBgColor = theme.getAttr("smartbarButton/bgColor", "#FFFFFF")
|
||||
prefs.theme.smartbarButtonFgColor = theme.getAttr("smartbarButton/fgColor", "#000000")
|
||||
|
||||
// Internal prefs part II (must be written at the end!!)
|
||||
prefs.internal.themeCurrentIsModified = false
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val listOfAttrsToReevaluate = mutableListOf<Triple<String, String, String>>()
|
||||
for (group in rawAttrs) {
|
||||
val groupMap = mutableMapOf<String, Int>()
|
||||
parsedAttrs[group.key] = groupMap
|
||||
for (attr in group.value) {
|
||||
val colorRegex = """[#]([0-9a-fA-F]{8}|[0-9a-fA-F]{6})""".toRegex()
|
||||
val refRegex = """[@]([a-zA-Z_][a-zA-Z0-9_]*)[/]([a-zA-Z_][a-zA-Z0-9_]*)""".toRegex()
|
||||
when {
|
||||
attr.value.matches(colorRegex) -> {
|
||||
groupMap[attr.key] = Color.parseColor(attr.value)
|
||||
}
|
||||
attr.value == "transparent" -> {
|
||||
groupMap[attr.key] = Color.TRANSPARENT
|
||||
}
|
||||
attr.value == "true" -> {
|
||||
groupMap[attr.key] = 0x1
|
||||
}
|
||||
attr.value == "false" -> {
|
||||
groupMap[attr.key] = 0x0
|
||||
}
|
||||
attr.value.matches(refRegex) -> {
|
||||
val attrValue = getAttrOrNull(attr.value.substring(1))
|
||||
if (attrValue != null) {
|
||||
groupMap[attr.key] = attrValue
|
||||
} else {
|
||||
listOfAttrsToReevaluate.add(Triple(group.key, attr.key, attr.value))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
throw IllegalArgumentException("The specified attr '${attr.key}' = '${attr.value}' is not valid!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (attrToReevaluate in listOfAttrsToReevaluate) {
|
||||
val attrValue = getAttrOrNull(attrToReevaluate.third.substring(1))
|
||||
if (attrValue != null) {
|
||||
parsedAttrs[attrToReevaluate.first]?.put(attrToReevaluate.second, attrValue)
|
||||
} else {
|
||||
throw IllegalArgumentException("The specified attr '${attrToReevaluate.second}' = '${attrToReevaluate.third}' is not valid!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getAttr(key: String, defaultColor: String): Int {
|
||||
return getAttrOrNull(key) ?: Color.parseColor(defaultColor)
|
||||
}
|
||||
fun getAttr(group: String, attr: String, defaultColor: String): Int {
|
||||
return getAttrOrNull(group, attr) ?: Color.parseColor(defaultColor)
|
||||
}
|
||||
|
||||
fun getAttrOrNull(key: String): Int? {
|
||||
val regex = """([a-zA-Z_][a-zA-Z0-9_]*)[/]([a-zA-Z_][a-zA-Z0-9_]*)""".toRegex()
|
||||
return if (key.matches(regex)) {
|
||||
val split = key.split("/")
|
||||
getAttrOrNull(split[0], split[1])
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
fun getAttrOrNull(group: String, attr: String): Int? {
|
||||
return parsedAttrs[group]?.get(attr)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data class which is used to quickly parse only the relevant meta data to
|
||||
* display a theme in a selection list.
|
||||
*
|
||||
* @see [Theme] for details regarding the attributes and the theme structure.
|
||||
*/
|
||||
data class ThemeMetaOnly(
|
||||
val name: String,
|
||||
val displayName: String,
|
||||
val author: String,
|
||||
val isNightTheme: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* Loads the theme meta data from the specified [path].
|
||||
*
|
||||
* @param context A reference to the current [Context]. Used to request
|
||||
* asset file.
|
||||
* @param path The path to the json theme file in the asset folder.
|
||||
* @returns [ThemeMetaOnly] or null. A null value may indicate that
|
||||
* the file does not exist or that an error during the reading
|
||||
* of the file occurred.
|
||||
*/
|
||||
fun loadFromJsonFile(context: Context, path: String): ThemeMetaOnly? {
|
||||
val rawJsonData: String = try {
|
||||
context.assets.open(path).bufferedReader().use { it.readText() }
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
} ?: return null
|
||||
val moshi = Moshi.Builder()
|
||||
.add(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
val layoutAdapter = moshi.adapter(ThemeMetaOnly::class.java)
|
||||
return layoutAdapter.fromJson(rawJsonData)
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all theme meta data from the specified [path].
|
||||
*
|
||||
* @param context A reference to the current [Context]. Used to request
|
||||
* asset file.
|
||||
* @param path The path to the dir in the asset folder.
|
||||
* @returns [ThemeMetaOnly] or null. A null value may indicate that
|
||||
* the file does not exist or that an error during the reading
|
||||
* of the file occurred.
|
||||
*/
|
||||
fun loadAllFromDir(context: Context, path: String): List<ThemeMetaOnly> {
|
||||
val ret = mutableListOf<ThemeMetaOnly>()
|
||||
try {
|
||||
val list = context.assets.list(path)
|
||||
if (list != null && list.isNotEmpty()) {
|
||||
// Is a folder
|
||||
for (file in list) {
|
||||
val subList = context.assets.list("$path/$file")
|
||||
if (subList?.isEmpty() == true) {
|
||||
// Is file
|
||||
val metaData = loadFromJsonFile(context, "$path/$file")
|
||||
if (metaData != null) {
|
||||
ret.add(metaData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: java.lang.Exception) {}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.AdvancedActivityBinding
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.util.PackageManagerUtils
|
||||
|
||||
class AdvancedActivity : AppCompatActivity(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private lateinit var binding: AdvancedActivityBinding
|
||||
private lateinit var prefs: PrefHelper
|
||||
|
||||
companion object {
|
||||
const val RESULT_APPLY_THEME = 0x322D
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
prefs = PrefHelper.getDefaultInstance(this)
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = AdvancedActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val toolbar = findViewById<Toolbar>(R.id.toolbar)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
supportActionBar?.setTitle(R.string.settings__advanced__title)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sp: SharedPreferences?, key: String?) {
|
||||
prefs.sync()
|
||||
if (key == PrefHelper.Advanced.SETTINGS_THEME) {
|
||||
setResult(RESULT_APPLY_THEME)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
prefs.shared.registerOnSharedPreferenceChangeListener(this)
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
prefs.shared.unregisterOnSharedPreferenceChangeListener(this)
|
||||
updateLauncherIconStatus()
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
private fun updateLauncherIconStatus() {
|
||||
// Set LauncherAlias enabled/disabled state just before destroying/pausing this activity
|
||||
if (prefs.advanced.showAppIcon) {
|
||||
PackageManagerUtils.showAppIcon(this)
|
||||
} else {
|
||||
PackageManagerUtils.hideAppIcon(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentAdvancedBinding
|
||||
|
||||
class AdvancedFragment : SettingsMainActivity.SettingsFragment() {
|
||||
private lateinit var binding: SettingsFragmentAdvancedBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = SettingsFragmentAdvancedBinding.inflate(inflater, container, false)
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
transaction.replace(
|
||||
binding.prefsAdvancedFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_advanced)
|
||||
)
|
||||
transaction.commit()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentLooknfeelBinding
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
|
||||
import dev.patrickgold.florisboard.ime.text.layout.LayoutManager
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class LooknfeelFragment : SettingsMainActivity.SettingsFragment(), CoroutineScope by MainScope() {
|
||||
private lateinit var binding: SettingsFragmentLooknfeelBinding
|
||||
private lateinit var keyboardView: KeyboardView
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = SettingsFragmentLooknfeelBinding.inflate(inflater, container, false)
|
||||
|
||||
launch(Dispatchers.Default) {
|
||||
val themeContext = ContextThemeWrapper(context, prefs.theme.getSelectedThemeResId())
|
||||
val layoutManager = LayoutManager(themeContext)
|
||||
keyboardView = KeyboardView(themeContext)
|
||||
keyboardView.prefs = prefs
|
||||
keyboardView.isPreviewMode = true
|
||||
keyboardView.computedLayout = layoutManager.fetchComputedLayoutAsync(KeyboardMode.CHARACTERS, Subtype.DEFAULT).await()
|
||||
keyboardView.updateVisibility()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.themeLinearLayout.addView(keyboardView, 0)
|
||||
}
|
||||
}
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
transaction.replace(
|
||||
binding.prefsLooknfeelFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_looknfeel)
|
||||
)
|
||||
transaction.replace(
|
||||
binding.prefsThemeFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_theme)
|
||||
)
|
||||
transaction.commit()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -28,32 +28,33 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsActivityBinding
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.core.SubtypeManager
|
||||
import dev.patrickgold.florisboard.settings.fragments.*
|
||||
import dev.patrickgold.florisboard.util.AppVersionUtils
|
||||
import dev.patrickgold.florisboard.util.PackageManagerUtils
|
||||
|
||||
private const val FRAGMENT_TAG = "FRAGMENT_TAG"
|
||||
internal const val FRAGMENT_TAG = "FRAGMENT_TAG"
|
||||
private const val PREF_RES_ID = "PREF_RES_ID"
|
||||
private const val SELECTED_ITEM_ID = "SELECTED_ITEM_ID"
|
||||
private const val ADVANCED_REQ_CODE = 0x145F
|
||||
|
||||
class SettingsMainActivity : AppCompatActivity(),
|
||||
BottomNavigationView.OnNavigationItemSelectedListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
lateinit var binding: SettingsActivityBinding
|
||||
lateinit var prefs: PrefHelper
|
||||
private lateinit var prefs: PrefHelper
|
||||
lateinit var subtypeManager: SubtypeManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
prefs = PrefHelper(this, PreferenceManager.getDefaultSharedPreferences(this))
|
||||
prefs = PrefHelper.getDefaultInstance(this)
|
||||
prefs.initDefaultPreferences()
|
||||
subtypeManager =
|
||||
SubtypeManager(this, prefs)
|
||||
prefs.sync()
|
||||
subtypeManager = SubtypeManager(this, prefs)
|
||||
|
||||
val mode = when (prefs.advanced.settingsTheme) {
|
||||
"light" -> AppCompatDelegate.MODE_NIGHT_NO
|
||||
@@ -99,9 +100,14 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
loadFragment(KeyboardFragment())
|
||||
true
|
||||
}
|
||||
R.id.settings__navigation__looknfeel -> {
|
||||
supportActionBar?.setTitle(R.string.settings__looknfeel__title)
|
||||
loadFragment(LooknfeelFragment())
|
||||
R.id.settings__navigation__typing -> {
|
||||
supportActionBar?.setTitle(R.string.settings__typing__title)
|
||||
loadFragment(TypingFragment())
|
||||
true
|
||||
}
|
||||
R.id.settings__navigation__theme -> {
|
||||
supportActionBar?.setTitle(R.string.settings__theme__title)
|
||||
loadFragment(ThemeFragment())
|
||||
true
|
||||
}
|
||||
R.id.settings__navigation__gestures -> {
|
||||
@@ -109,20 +115,15 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
loadFragment(GesturesFragment())
|
||||
true
|
||||
}
|
||||
R.id.settings__navigation__advanced -> {
|
||||
supportActionBar?.setTitle(R.string.settings__advanced__title)
|
||||
loadFragment(AdvancedFragment())
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadFragment(fragment: Fragment) {
|
||||
val transaction = supportFragmentManager.beginTransaction()
|
||||
transaction.replace(binding.pageFrame.id, fragment, FRAGMENT_TAG)
|
||||
//transaction.addToBackStack(null)
|
||||
transaction.commit()
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(binding.pageFrame.id, fragment, FRAGMENT_TAG)
|
||||
.commit()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
@@ -130,6 +131,14 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (binding.bottomNavigation.selectedItemId != R.id.settings__navigation__home) {
|
||||
binding.bottomNavigation.selectedItemId = R.id.settings__navigation__home
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
@@ -144,6 +153,10 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
startActivity(browserIntent)
|
||||
true
|
||||
}
|
||||
R.id.settings__menu_advanced -> {
|
||||
startActivityForResult(Intent(this, AdvancedActivity::class.java), ADVANCED_REQ_CODE)
|
||||
true
|
||||
}
|
||||
R.id.settings__menu_about -> {
|
||||
startActivity(Intent(this, AboutActivity::class.java))
|
||||
true
|
||||
@@ -152,22 +165,18 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sp: SharedPreferences?, key: String?) {
|
||||
if (key == PrefHelper.Advanced.SETTINGS_THEME) {
|
||||
recreate()
|
||||
}
|
||||
val fragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)
|
||||
if (fragment != null && fragment.isVisible) {
|
||||
if (fragment is LooknfeelFragment) {
|
||||
if (key == PrefHelper.Theme.NAME) {
|
||||
// TODO: recreate() is only a lazy solution, better would be to only recreate
|
||||
// the keyboard view
|
||||
recreate()
|
||||
}
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == ADVANCED_REQ_CODE) {
|
||||
if (resultCode == AdvancedActivity.RESULT_APPLY_THEME) {
|
||||
recreate()
|
||||
}
|
||||
} else {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sp: SharedPreferences?, key: String?) {}
|
||||
|
||||
private fun updateLauncherIconStatus() {
|
||||
// Set LauncherAlias enabled/disabled state just before destroying/pausing this activity
|
||||
if (prefs.advanced.showAppIcon) {
|
||||
@@ -195,7 +204,6 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
}
|
||||
|
||||
abstract class SettingsFragment : Fragment() {
|
||||
protected lateinit var prefs: PrefHelper
|
||||
protected lateinit var settingsMainActivity: SettingsMainActivity
|
||||
protected lateinit var subtypeManager: SubtypeManager
|
||||
|
||||
@@ -203,7 +211,6 @@ class SettingsMainActivity : AppCompatActivity(),
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
settingsMainActivity = activity as SettingsMainActivity
|
||||
prefs = settingsMainActivity.prefs
|
||||
subtypeManager = settingsMainActivity.subtypeManager
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.components
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceManager
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.ThemeSelectorDialogBinding
|
||||
import dev.patrickgold.florisboard.databinding.ThemeSelectorListItemBinding
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.theme.Theme
|
||||
import dev.patrickgold.florisboard.ime.theme.ThemeMetaOnly
|
||||
|
||||
/**
|
||||
* Custom preference which handles the theme preset selection dialog and shows a summary in the
|
||||
* list.
|
||||
*/
|
||||
class ThemePresetSelectorPreference : Preference, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private var dialog: AlertDialog? = null
|
||||
private val metaDataCache: MutableMap<String, ThemeMetaOnly> = mutableMapOf()
|
||||
private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context)
|
||||
|
||||
@Suppress("unused")
|
||||
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) {
|
||||
layoutResource = R.layout.list_item
|
||||
onPreferenceClickListener = OnPreferenceClickListener {
|
||||
showThemeSelectorDialog()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToHierarchy(preferenceManager: PreferenceManager?) {
|
||||
super.onAttachedToHierarchy(preferenceManager)
|
||||
summary = generateSummaryText()
|
||||
prefs.shared.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onDetached() {
|
||||
if (dialog?.isShowing == true) {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
prefs.shared.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onDetached()
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sp: SharedPreferences?, key: String?) {
|
||||
if (key == PrefHelper.Internal.THEME_CURRENT_IS_MODIFIED) {
|
||||
summary = generateSummaryText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the summary text to display and returns it. Based on the prefs.internal.theme*
|
||||
* values and the theme meta cache.
|
||||
*/
|
||||
private fun generateSummaryText(): String {
|
||||
val themeKey = prefs.internal.themeCurrentBasedOn
|
||||
val isModified = prefs.internal.themeCurrentIsModified
|
||||
var metaOnly: ThemeMetaOnly? = metaDataCache[themeKey]
|
||||
if (metaOnly == null) {
|
||||
try {
|
||||
metaOnly = ThemeMetaOnly.loadFromJsonFile(context, "ime/theme/$themeKey.json")
|
||||
} catch (e: Exception) {
|
||||
return context.resources.getString(R.string.settings__theme__undefined)
|
||||
}
|
||||
}
|
||||
metaOnly ?: return context.resources.getString(R.string.settings__theme__undefined)
|
||||
return if (isModified) {
|
||||
String.format(context.resources.getString(R.string.settings__theme__preset_summary), metaOnly.displayName)
|
||||
} else {
|
||||
metaOnly.displayName
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the theme selector dialog.
|
||||
*/
|
||||
private fun showThemeSelectorDialog() {
|
||||
val inflater =
|
||||
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
val dialogView = ThemeSelectorDialogBinding.inflate(inflater)
|
||||
val selectedThemeView = ThemeSelectorListItemBinding.inflate(inflater)
|
||||
selectedThemeView.title.text = generateSummaryText()
|
||||
dialogView.content.addView(selectedThemeView.root, 1)
|
||||
metaDataCache.clear()
|
||||
ThemeMetaOnly.loadAllFromDir(context, "ime/theme").forEach { metaData ->
|
||||
metaDataCache[metaData.name] = metaData
|
||||
}
|
||||
for ((themeKey, metaData) in metaDataCache) {
|
||||
if (themeKey == prefs.internal.themeCurrentBasedOn && !prefs.internal.themeCurrentIsModified) {
|
||||
continue
|
||||
}
|
||||
val availableThemeView = ThemeSelectorListItemBinding.inflate(inflater)
|
||||
availableThemeView.title.text = metaData.displayName
|
||||
availableThemeView.root.setOnClickListener {
|
||||
applyThemePreset(metaData.name)
|
||||
dialog?.dismiss()
|
||||
}
|
||||
dialogView.content.addView(availableThemeView.root)
|
||||
}
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(this@ThemePresetSelectorPreference.title)
|
||||
setCancelable(true)
|
||||
setView(dialogView.root)
|
||||
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
//
|
||||
}
|
||||
setNeutralButton(R.string.settings__default) { _, _ ->
|
||||
//
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
setOnDismissListener { summary = generateSummaryText() }
|
||||
create()
|
||||
dialog = show()
|
||||
dialog?.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the Theme for given [themeKey] to the preferences. Overrides any custom user-defined
|
||||
* theme in the shared prefs, if existent.
|
||||
*
|
||||
* @param themeKey The key of the Theme preset to be applied.
|
||||
*/
|
||||
private fun applyThemePreset(themeKey: String) {
|
||||
val theme = Theme.fromJsonFile(context, "ime/theme/$themeKey.json") ?: return
|
||||
Theme.writeThemeToPrefs(prefs, theme)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
class AdvancedFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.prefs_advanced)
|
||||
}
|
||||
}
|
||||
@@ -14,25 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.settings
|
||||
package dev.patrickgold.florisboard.settings.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentGesturesBinding
|
||||
|
||||
class GesturesFragment : SettingsMainActivity.SettingsFragment() {
|
||||
private lateinit var binding: SettingsFragmentGesturesBinding
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = SettingsFragmentGesturesBinding.inflate(inflater, container, false)
|
||||
|
||||
return binding.root
|
||||
class GesturesFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.prefs_gestures)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.settings
|
||||
package dev.patrickgold.florisboard.settings.fragments
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
@@ -25,6 +25,7 @@ import android.view.ViewGroup
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentHomeBinding
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.settings.SettingsMainActivity
|
||||
import dev.patrickgold.florisboard.setup.SetupActivity
|
||||
|
||||
class HomeFragment : SettingsMainActivity.SettingsFragment() {
|
||||
@@ -56,6 +57,12 @@ class HomeFragment : SettingsMainActivity.SettingsFragment() {
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
binding.localizationCard.setOnClickListener {
|
||||
settingsMainActivity.binding.bottomNavigation.selectedItemId = R.id.settings__navigation__typing
|
||||
}
|
||||
binding.themeCard.setOnClickListener {
|
||||
settingsMainActivity.binding.bottomNavigation.selectedItemId = R.id.settings__navigation__theme
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
class KeyboardFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.prefs_keyboard)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.fragments
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import dev.patrickgold.florisboard.R
|
||||
|
||||
class ThemeCustomizeFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.prefs_theme)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.settings.fragments
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentThemeBinding
|
||||
import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
import dev.patrickgold.florisboard.ime.core.PrefHelper
|
||||
import dev.patrickgold.florisboard.ime.core.Subtype
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardMode
|
||||
import dev.patrickgold.florisboard.ime.text.keyboard.KeyboardView
|
||||
import dev.patrickgold.florisboard.ime.text.layout.LayoutManager
|
||||
import dev.patrickgold.florisboard.settings.SettingsMainActivity
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
class ThemeFragment : SettingsMainActivity.SettingsFragment(), CoroutineScope by MainScope(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private lateinit var binding: SettingsFragmentThemeBinding
|
||||
private lateinit var keyboardView: KeyboardView
|
||||
private lateinit var prefs: PrefHelper
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
prefs = PrefHelper.getDefaultInstance(requireContext())
|
||||
binding = SettingsFragmentThemeBinding.inflate(inflater, container, false)
|
||||
|
||||
launch(Dispatchers.Default) {
|
||||
val themeContext = ContextThemeWrapper(context, FlorisBoard.getDayNightBaseThemeId(prefs.internal.themeCurrentIsNight))
|
||||
val layoutManager = LayoutManager(themeContext)
|
||||
keyboardView = KeyboardView(themeContext)
|
||||
keyboardView.layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
val m = resources.getDimension(R.dimen.keyboard_preview_margin).toInt()
|
||||
setMargins(m, m, m, m)
|
||||
}
|
||||
prefs.sync()
|
||||
keyboardView.isPreviewMode = true
|
||||
val subtype = subtypeManager.getActiveSubtype() ?: Subtype.DEFAULT
|
||||
keyboardView.computedLayout = layoutManager.fetchComputedLayoutAsync(KeyboardMode.CHARACTERS, subtype).await()
|
||||
keyboardView.updateVisibility()
|
||||
keyboardView.onApplyThemeAttributes()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.root.addView(keyboardView, 0)
|
||||
}
|
||||
}
|
||||
|
||||
loadThemePrefFragment()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
private fun loadThemePrefFragment() {
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
binding.prefsFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_theme)
|
||||
)
|
||||
.commit()
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sp: SharedPreferences?, key: String?) {
|
||||
prefs.sync()
|
||||
key ?: return
|
||||
if (key == PrefHelper.Internal.THEME_CURRENT_BASED_ON ||
|
||||
key == PrefHelper.Internal.THEME_CURRENT_IS_MODIFIED && !prefs.internal.themeCurrentIsModified) {
|
||||
loadThemePrefFragment()
|
||||
}
|
||||
if (key.startsWith("theme__")) {
|
||||
prefs.internal.themeCurrentIsModified = true
|
||||
keyboardView.onApplyThemeAttributes()
|
||||
keyboardView.invalidate()
|
||||
keyboardView.invalidateAllKeys()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
prefs.shared.registerOnSharedPreferenceChangeListener(this)
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
prefs.shared.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.settings
|
||||
package dev.patrickgold.florisboard.settings.fragments
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.os.Bundle
|
||||
@@ -25,12 +25,13 @@ import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import dev.patrickgold.florisboard.R
|
||||
import dev.patrickgold.florisboard.databinding.ListItemBinding
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentKeyboardBinding
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentKeyboardSubtypeDialogBinding
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentTypingBinding
|
||||
import dev.patrickgold.florisboard.databinding.SettingsFragmentTypingSubtypeDialogBinding
|
||||
import dev.patrickgold.florisboard.settings.SettingsMainActivity
|
||||
import dev.patrickgold.florisboard.util.LocaleUtils
|
||||
|
||||
class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
private lateinit var binding: SettingsFragmentKeyboardBinding
|
||||
class TypingFragment : SettingsMainActivity.SettingsFragment() {
|
||||
private lateinit var binding: SettingsFragmentTypingBinding
|
||||
/**
|
||||
* Must always have a reference to the open AlertDialog to dismiss the AlertDialog in the event
|
||||
* of onDestroy(), if this is not done a memory leak will most likely happen!
|
||||
@@ -42,17 +43,18 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
binding = SettingsFragmentKeyboardBinding.inflate(inflater, container, false)
|
||||
binding = SettingsFragmentTypingBinding.inflate(inflater, container, false)
|
||||
binding.subtypeAddBtn.setOnClickListener { showAddSubtypeDialog() }
|
||||
|
||||
updateSubtypeListView()
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
transaction.replace(
|
||||
binding.prefsKeyboardFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_keyboard)
|
||||
)
|
||||
transaction.commit()
|
||||
childFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
binding.prefsFrame.id,
|
||||
SettingsMainActivity.PrefFragment.createFromResource(R.xml.prefs_typing)
|
||||
)
|
||||
.commit()
|
||||
|
||||
return binding.root
|
||||
}
|
||||
@@ -64,7 +66,7 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
|
||||
private fun showAddSubtypeDialog() {
|
||||
val dialogView =
|
||||
SettingsFragmentKeyboardSubtypeDialogBinding.inflate(layoutInflater)
|
||||
SettingsFragmentTypingSubtypeDialogBinding.inflate(layoutInflater)
|
||||
val languageAdapter: ArrayAdapter<String> = ArrayAdapter(
|
||||
requireContext(),
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
@@ -93,11 +95,11 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
)
|
||||
dialogView.layoutSpinner.adapter = layoutAdapter
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.settings__keyboard__subtype_add_title)
|
||||
setTitle(R.string.settings__localization__subtype_add_title)
|
||||
setCancelable(true)
|
||||
setView(dialogView.root)
|
||||
setPositiveButton(R.string.settings__keyboard__subtype_add, null)
|
||||
setNegativeButton(R.string.settings__keyboard__subtype_cancel) { _, _ -> }
|
||||
setPositiveButton(R.string.settings__localization__subtype_add, null)
|
||||
setNegativeButton(R.string.settings__localization__subtype_cancel) { _, _ -> }
|
||||
setOnDismissListener { activeDialogWindow = null }
|
||||
create()
|
||||
activeDialogWindow = show()
|
||||
@@ -108,7 +110,7 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
val layoutName = subtypeManager.imeConfig.characterLayouts.keys.toList()[dialogView.layoutSpinner.selectedItemPosition]
|
||||
val success = subtypeManager.addSubtype(LocaleUtils.stringToLocale(languageCode), layoutName)
|
||||
if (!success) {
|
||||
dialogView.errorBox.setText(R.string.settings__keyboard__subtype_error_already_exists)
|
||||
dialogView.errorBox.setText(R.string.settings__localization__subtype_error_already_exists)
|
||||
dialogView.errorBox.visibility = View.VISIBLE
|
||||
} else {
|
||||
updateSubtypeListView()
|
||||
@@ -121,7 +123,7 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
private fun showEditSubtypeDialog(id: Int) {
|
||||
val subtype = subtypeManager.getSubtypeById(id) ?: return
|
||||
val dialogView =
|
||||
SettingsFragmentKeyboardSubtypeDialogBinding.inflate(layoutInflater)
|
||||
SettingsFragmentTypingSubtypeDialogBinding.inflate(layoutInflater)
|
||||
val languageAdapter: ArrayAdapter<String> = ArrayAdapter(
|
||||
requireContext(),
|
||||
android.R.layout.simple_spinner_dropdown_item,
|
||||
@@ -141,10 +143,10 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
subtypeManager.imeConfig.characterLayouts.keys.toList().indexOf(subtype.layout)
|
||||
)
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.settings__keyboard__subtype_edit_title)
|
||||
setTitle(R.string.settings__localization__subtype_edit_title)
|
||||
setCancelable(true)
|
||||
setView(dialogView.root)
|
||||
setPositiveButton(R.string.settings__keyboard__subtype_apply) { _, _ ->
|
||||
setPositiveButton(R.string.settings__localization__subtype_apply) { _, _ ->
|
||||
val languageCode = subtypeManager.imeConfig.defaultSubtypesLanguageCodes[dialogView.languageSpinner.selectedItemPosition]
|
||||
val layoutName = subtypeManager.imeConfig.characterLayouts.keys.toList()[dialogView.layoutSpinner.selectedItemPosition]
|
||||
subtype.locale = LocaleUtils.stringToLocale(languageCode)
|
||||
@@ -152,11 +154,11 @@ class KeyboardFragment : SettingsMainActivity.SettingsFragment() {
|
||||
subtypeManager.modifySubtypeWithSameId(subtype)
|
||||
updateSubtypeListView()
|
||||
}
|
||||
setNeutralButton(R.string.settings__keyboard__subtype_delete) { _, _ ->
|
||||
setNeutralButton(R.string.settings__localization__subtype_delete) { _, _ ->
|
||||
subtypeManager.removeSubtype(subtype)
|
||||
updateSubtypeListView()
|
||||
}
|
||||
setNegativeButton(R.string.settings__keyboard__subtype_cancel) { _, _ -> }
|
||||
setNegativeButton(R.string.settings__localization__subtype_cancel) { _, _ -> }
|
||||
setOnDismissListener { activeDialogWindow = null }
|
||||
create()
|
||||
activeDialogWindow = show()
|
||||
@@ -22,6 +22,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import dev.patrickgold.florisboard.databinding.SetupFragmentFinishBinding
|
||||
import dev.patrickgold.florisboard.ime.theme.Theme
|
||||
|
||||
class FinishFragment : Fragment() {
|
||||
private lateinit var binding: SetupFragmentFinishBinding
|
||||
@@ -33,6 +34,12 @@ class FinishFragment : Fragment() {
|
||||
): View? {
|
||||
binding = SetupFragmentFinishBinding.inflate(inflater, container, false)
|
||||
|
||||
// Set theme to floris_day
|
||||
Theme.writeThemeToPrefs(
|
||||
(activity as SetupActivity).prefs,
|
||||
Theme.fromJsonFile(requireContext(), "ime/theme/floris_day.json")!!
|
||||
)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package dev.patrickgold.florisboard.setup
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -26,6 +27,7 @@ import dev.patrickgold.florisboard.ime.core.FlorisBoard
|
||||
|
||||
class MakeDefaultFragment : Fragment(), SetupActivity.EventListener {
|
||||
private lateinit var binding: SetupFragmentMakeDefaultBinding
|
||||
private var osHandler: Handler? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -60,6 +62,11 @@ class MakeDefaultFragment : Fragment(), SetupActivity.EventListener {
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
if (hasFocus && context != null) {
|
||||
updateState()
|
||||
if (osHandler == null) {
|
||||
osHandler = Handler()
|
||||
}
|
||||
osHandler?.postDelayed({ updateState() }, 250)
|
||||
osHandler?.postDelayed({ updateState() }, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class SetupActivity : AppCompatActivity() {
|
||||
private lateinit var adapter: ViewPagerAdapter
|
||||
private lateinit var binding: SetupActivityBinding
|
||||
lateinit var imm: InputMethodManager
|
||||
private lateinit var prefs: PrefHelper
|
||||
lateinit var prefs: PrefHelper
|
||||
private var shouldFinish: Boolean = false
|
||||
private var shouldLaunchSettings: Boolean = true
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.children
|
||||
|
||||
fun getColorFromAttr(
|
||||
@@ -33,16 +34,28 @@ fun setBackgroundTintColor(view: View, colorId: Int) {
|
||||
getColorFromAttr(view.context, colorId)
|
||||
)
|
||||
}
|
||||
fun setBackgroundTintColor2(view: View, colorInt: Int) {
|
||||
view.backgroundTintList = ColorStateList.valueOf(colorInt)
|
||||
}
|
||||
fun setDrawableTintColor(view: Button, colorId: Int) {
|
||||
view.compoundDrawableTintList = ColorStateList.valueOf(
|
||||
getColorFromAttr(view.context, colorId)
|
||||
)
|
||||
}
|
||||
fun setDrawableTintColor2(view: Button, colorInt: Int) {
|
||||
view.compoundDrawableTintList = ColorStateList.valueOf(colorInt)
|
||||
}
|
||||
fun setImageTintColor2(view: ImageView, colorInt: Int) {
|
||||
view.imageTintList = ColorStateList.valueOf(colorInt)
|
||||
}
|
||||
fun setTextTintColor(view: View, colorId: Int) {
|
||||
view.foregroundTintList = ColorStateList.valueOf(
|
||||
getColorFromAttr(view.context, colorId)
|
||||
)
|
||||
}
|
||||
fun setTextTintColor2(view: View, colorInt: Int) {
|
||||
view.foregroundTintList = ColorStateList.valueOf(colorInt)
|
||||
}
|
||||
|
||||
fun refreshLayoutOf(view: View?) {
|
||||
if (view is ViewGroup) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="?android:colorButtonNormal"/>
|
||||
<item android:color="?smartbar_button_fgColor"/>
|
||||
<item android:color="#FFFFFF"/>
|
||||
</selector>
|
||||
5
app/src/main/res/drawable/ic_spellcheck.xml
Normal file
5
app/src/main/res/drawable/ic_spellcheck.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12.45,16h2.09L9.43,3L7.57,3L2.46,16h2.09l1.12,-3h5.64l1.14,3zM6.43,11L8.5,5.48 10.57,11L6.43,11zM21.59,11.59l-8.09,8.09L9.83,16l-1.41,1.41 5.09,5.09L23,13l-1.41,-1.41z"/>
|
||||
</vector>
|
||||
@@ -2,16 +2,16 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
|
||||
<solid android:color="?key_popup_extended_shadowColor" />
|
||||
<corners android:radius="@dimen/key_borderRadius" />
|
||||
<padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp"/>
|
||||
<solid android:color="#CDAFAFAF"/>
|
||||
<corners android:radius="@dimen/key_borderRadius"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="?key_popup_bgColor" />
|
||||
<corners android:radius="@dimen/key_borderRadius" />
|
||||
<solid android:color="@android:color/white"/>
|
||||
<corners android:radius="@dimen/key_borderRadius"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
||||
16
app/src/main/res/layout/advanced_activity.xml
Normal file
16
app/src/main/res/layout/advanced_activity.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/advanced_fragment_frame"
|
||||
android:name="dev.patrickgold.florisboard.settings.fragments.AdvancedFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,12 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyboardView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyboardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/editing"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:backgroundTintMode="multiply">
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/arrow_left"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.2"
|
||||
@@ -16,7 +18,7 @@
|
||||
app:layout_constraintBottom_toTopOf="@+id/move_home"
|
||||
android:src="@drawable/ic_keyboard_arrow_left"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/arrow_up"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -25,7 +27,7 @@
|
||||
app:layout_constraintLeft_toRightOf="@+id/arrow_left"
|
||||
android:src="@drawable/ic_keyboard_arrow_up"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/select"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -34,7 +36,7 @@
|
||||
app:layout_constraintLeft_toRightOf="@+id/arrow_left"
|
||||
android:text="@android:string/selectTextMode"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/arrow_down"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -43,7 +45,7 @@
|
||||
app:layout_constraintLeft_toRightOf="@+id/arrow_left"
|
||||
android:src="@drawable/ic_keyboard_arrow_down"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/arrow_right"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.2"
|
||||
@@ -53,7 +55,7 @@
|
||||
app:layout_constraintLeft_toRightOf="@+id/select"
|
||||
android:src="@drawable/ic_keyboard_arrow_right"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/move_home"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.35"
|
||||
@@ -62,7 +64,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:src="@drawable/ic_first_page"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/move_end"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.35"
|
||||
@@ -71,7 +73,7 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:src="@drawable/ic_last_page"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/select_all"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -82,7 +84,7 @@
|
||||
android:text="@android:string/selectAll"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/clipboard_cut"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -100,7 +102,7 @@
|
||||
app:barrierDirection="bottom"
|
||||
app:constraint_referenced_ids="select_all,clipboard_cut"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/clipboard_copy"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -111,7 +113,7 @@
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:text="@android:string/copy"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/clipboard_paste"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -122,7 +124,7 @@
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:text="@android:string/paste"/>
|
||||
|
||||
<dev.patrickgold.florisboard.ime.editing.EditingKeyView
|
||||
<dev.patrickgold.florisboard.ime.text.editing.EditingKeyView
|
||||
android:id="@+id/backspace"
|
||||
style="@style/TextEditingButton"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
@@ -133,4 +135,4 @@
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:src="@drawable/ic_backspace"/>
|
||||
|
||||
</dev.patrickgold.florisboard.ime.editing.EditingKeyboardView>
|
||||
</dev.patrickgold.florisboard.ime.text.editing.EditingKeyboardView>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<dev.patrickgold.florisboard.ime.core.InputView
|
||||
<dev.patrickgold.florisboard.ime.core.InputWindowView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/florisboard"
|
||||
android:layout_width="match_parent"
|
||||
@@ -8,13 +8,13 @@
|
||||
android:gravity="bottom"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<dev.patrickgold.florisboard.ime.core.InputView
|
||||
android:id="@+id/inner_input_view_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:orientation="horizontal"
|
||||
android:background="?keyboard_bgColor"
|
||||
android:background="?inputView_bgColorFallback"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
@@ -25,32 +25,34 @@
|
||||
<ImageButton
|
||||
android:id="@+id/one_handed_ctrl_close_start"
|
||||
style="@style/OneHandedPanelButton"
|
||||
android:src="@drawable/ic_zoom_out_map"/>
|
||||
android:src="@drawable/ic_zoom_out_map"
|
||||
android:contentDescription="@string/one_handed__close_btn_content_description"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/one_handed_button_height"
|
||||
android:visibility="invisible" />
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/one_handed_ctrl_move_start"
|
||||
style="@style/OneHandedPanelButton"
|
||||
android:src="@drawable/ic_keyboard_arrow_left"/>
|
||||
android:src="@drawable/ic_keyboard_arrow_left"
|
||||
android:contentDescription="@string/one_handed__move_start_btn_content_description"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ViewFlipper
|
||||
<dev.patrickgold.florisboard.ime.core.FlorisViewFlipper
|
||||
android:id="@+id/main_view_flipper"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:measureAllChildren="false">
|
||||
|
||||
<include layout="@layout/text_input_layout" />
|
||||
<include layout="@layout/text_input_layout"/>
|
||||
|
||||
<include layout="@layout/media_input_layout" />
|
||||
<include layout="@layout/media_input_layout"/>
|
||||
|
||||
</ViewFlipper>
|
||||
</dev.patrickgold.florisboard.ime.core.FlorisViewFlipper>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/one_handed_ctrl_panel_end"
|
||||
@@ -60,20 +62,22 @@
|
||||
<ImageButton
|
||||
android:id="@+id/one_handed_ctrl_close_end"
|
||||
style="@style/OneHandedPanelButton"
|
||||
android:src="@drawable/ic_zoom_out_map"/>
|
||||
android:src="@drawable/ic_zoom_out_map"
|
||||
android:contentDescription="@string/one_handed__close_btn_content_description"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/one_handed_button_height"
|
||||
android:visibility="invisible" />
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/one_handed_ctrl_move_end"
|
||||
style="@style/OneHandedPanelButton"
|
||||
android:src="@drawable/ic_keyboard_arrow_right"/>
|
||||
android:src="@drawable/ic_keyboard_arrow_right"
|
||||
android:contentDescription="@string/one_handed__move_end_btn_content_description"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</dev.patrickgold.florisboard.ime.core.InputView>
|
||||
|
||||
</dev.patrickgold.florisboard.ime.core.InputView>
|
||||
</dev.patrickgold.florisboard.ime.core.InputWindowView>
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<dev.patrickgold.florisboard.ime.popup.KeyPopupView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/key_popup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/key_popup_bgshape">
|
||||
android:background="@drawable/key_popup_bgshape"
|
||||
android:backgroundTintMode="multiply">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/key_popup_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/key_height"
|
||||
android:gravity="center"
|
||||
android:textColor="?attr/key_popup_fgColor"
|
||||
android:textSize="@dimen/key_popup_textSize"/>
|
||||
|
||||
<ImageView
|
||||
@@ -23,7 +24,6 @@
|
||||
android:layout_gravity="end"
|
||||
android:padding="0dp"
|
||||
android:src="@drawable/ic_more_horiz"
|
||||
android:tint="?attr/key_popup_fgColor"
|
||||
android:visibility="visible" />
|
||||
android:visibility="visible"/>
|
||||
|
||||
</LinearLayout>
|
||||
</dev.patrickgold.florisboard.ime.popup.KeyPopupView>
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.flexbox.FlexboxLayout
|
||||
<dev.patrickgold.florisboard.ime.popup.KeyPopupExtendedView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/key_popup_extended"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/key_popup_bgshape"
|
||||
android:backgroundTintMode="multiply"
|
||||
android:padding="0dp"
|
||||
android:textSize="@dimen/key_popup_textSize"
|
||||
app:flexDirection="row"
|
||||
app:flexWrap="wrap"
|
||||
app:showDivider="none" />
|
||||
app:showDivider="none"/>
|
||||
|
||||
@@ -3,15 +3,20 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:listPreferredItemHeightSmall"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="?android:listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:listPreferredItemPaddingEnd"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
@@ -22,7 +27,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<dev.patrickgold.florisboard.ime.media.MediaInputView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/media_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ViewFlipper
|
||||
<dev.patrickgold.florisboard.ime.core.FlorisViewFlipper
|
||||
android:id="@+id/media_input_view_flipper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:measureAllChildren="true"/>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"
|
||||
android:measureAllChildren="false"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.0"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
@@ -87,4 +90,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</dev.patrickgold.florisboard.ime.media.MediaInputView>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="GESTURES | not yet implemented..."/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -50,4 +50,28 @@
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/localization_card"
|
||||
style="@style/SettingsCardView.Clickable">
|
||||
|
||||
<!-- TODO: create lang preview and make nice feature graphic for this card -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Localization prefs -->"/>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/theme_card"
|
||||
style="@style/SettingsCardView.Clickable">
|
||||
|
||||
<!-- TODO: create theme preview and make nice feature graphic for this card -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Theme prefs -->"/>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
style="@style/SettingsCardView"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/themeLinearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- KeyboardView preview will be inserted here programmatically -->
|
||||
|
||||
<!-- Must be RelativeLayout, because it blocks RecyclerView to create a second scrollbar -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/prefs_theme_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Must be RelativeLayout, because it blocks RecyclerView to create a second scrollbar -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/prefs_looknfeel_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -4,9 +4,11 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- KeyboardView preview will be inserted here programmatically -->
|
||||
|
||||
<!-- Must be RelativeLayout, because it blocks RecyclerView to create a second scrollbar -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/prefs_advanced_frame"
|
||||
android:id="@+id/prefs_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@@ -12,20 +12,31 @@
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:theme="@style/PreferenceThemeOverlay">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtype_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/settings__localization__title"
|
||||
android:textAppearance="?preferenceCategoryTitleTextAppearance"
|
||||
android:textColor="?colorAccent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtype_not_conf_warning"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_margin="8dp"
|
||||
android:padding="8dp"
|
||||
android:background="@drawable/shape_rect_rounded"
|
||||
android:backgroundTint="?colorWarning"
|
||||
android:text="@string/settings__keyboard__subtype_no_subtypes_configured_warning"
|
||||
android:text="@string/settings__localization__subtype_no_subtypes_configured_warning"
|
||||
android:textColor="?textColorWarning"/>
|
||||
|
||||
<LinearLayout
|
||||
@@ -40,7 +51,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:textAllCaps="false"
|
||||
android:text="@string/settings__keyboard__subtype_add_title"
|
||||
android:text="@string/settings__localization__subtype_add_title"
|
||||
android:drawableStart="@drawable/ic_add"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableTint="?colorAccent"/>
|
||||
@@ -51,7 +62,7 @@
|
||||
|
||||
<!-- Must be RelativeLayout, because it blocks RecyclerView to create a second scrollbar -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/prefs_keyboard_frame"
|
||||
android:id="@+id/prefs_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/colorError"
|
||||
tools:text="@string/settings__keyboard__subtype_error_already_exists"
|
||||
tools:text="@string/settings__localization__subtype_error_already_exists"
|
||||
android:textColor="@color/textColorError"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:padding="8dp"
|
||||
@@ -27,7 +27,7 @@
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings__keyboard__subtype_locale"
|
||||
android:text="@string/settings__localization__subtype_locale"
|
||||
android:paddingHorizontal="8dp"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
@@ -46,7 +46,7 @@
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings__keyboard__subtype_layout"
|
||||
android:text="@string/settings__localization__subtype_layout"
|
||||
android:paddingHorizontal="8dp"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatSpinner
|
||||
@@ -4,8 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/smartbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/smartbar_height"
|
||||
android:background="?smartbar_bgColor">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/smartbar_variant_default"
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/smartbar" />
|
||||
<include layout="@layout/smartbar"/>
|
||||
|
||||
<!-- KeyboardViews will be inserted in ViewFlipper below dynamically -->
|
||||
<ViewFlipper
|
||||
<dev.patrickgold.florisboard.ime.core.FlorisViewFlipper
|
||||
android:id="@+id/text_input_view_flipper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -33,6 +33,6 @@
|
||||
|
||||
<include layout="@layout/editing_layout"/>
|
||||
|
||||
</ViewFlipper>
|
||||
</dev.patrickgold.florisboard.ime.core.FlorisViewFlipper>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
29
app/src/main/res/layout/theme_selector_dialog.xml
Normal file
29
app/src/main/res/layout/theme_selector_dialog.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/settings__theme__preset_dialog_selected_theme"
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:text="@string/settings__theme__preset_dialog_available_themes"
|
||||
android:textColor="?android:textColorPrimary"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
36
app/src/main/res/layout/theme_selector_list_item.xml
Normal file
36
app/src/main/res/layout/theme_selector_list_item.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:listPreferredItemPaddingEnd"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="?selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
tools:text="Theme Name"
|
||||
android:textColor="?android:textColorSecondary"/>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:src="@drawable/ic_keyboard_arrow_right"
|
||||
android:contentDescription="@string/settings__theme__preset_dialog_alt_arrow_right"
|
||||
app:tint="?android:textColorSecondary"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -6,17 +6,24 @@
|
||||
android:icon="@drawable/ic_more_vert"
|
||||
android:title="@string/settings__menu"
|
||||
app:showAsAction="always">
|
||||
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/settings__menu_help"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/settings__menu_help" />
|
||||
android:title="@string/settings__menu_help"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__menu_advanced"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/settings__menu_advanced"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__menu_about"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/settings__menu_about" />
|
||||
android:orderInCategory="3"
|
||||
android:title="@string/settings__menu_about"/>
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
<item
|
||||
android:id="@+id/settings__navigation__home"
|
||||
android:icon="@drawable/ic_home"
|
||||
android:title="@string/settings__navigation__home" />
|
||||
android:title="@string/settings__navigation__home"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__navigation__keyboard"
|
||||
android:icon="@drawable/ic_keyboard"
|
||||
android:title="@string/settings__navigation__keyboard" />
|
||||
android:title="@string/settings__navigation__keyboard"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__navigation__looknfeel"
|
||||
android:id="@+id/settings__navigation__typing"
|
||||
android:icon="@drawable/ic_spellcheck"
|
||||
android:title="@string/settings__navigation__typing"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__navigation__theme"
|
||||
android:icon="@drawable/ic_palette"
|
||||
android:title="@string/settings__navigation__looknfeel" />
|
||||
android:title="@string/settings__navigation__theme"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__navigation__gestures"
|
||||
android:icon="@drawable/ic_gesture"
|
||||
android:title="@string/settings__navigation__gestures" />
|
||||
|
||||
<item
|
||||
android:id="@+id/settings__navigation__advanced"
|
||||
android:icon="@drawable/ic_more_vert"
|
||||
android:title="@string/settings__navigation__advanced" />
|
||||
android:title="@string/settings__navigation__gestures"/>
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -32,51 +32,54 @@
|
||||
<string name="settings__menu_help">Aiuto & feedback</string>
|
||||
<string name="settings__navigation__home">Home</string>
|
||||
<string name="settings__navigation__keyboard">Tastiera</string>
|
||||
<string name="settings__navigation__looknfeel">Aspetto & funzionalità</string>
|
||||
<string name="settings__navigation__typing">Digitazione</string>
|
||||
<string name="settings__navigation__theme">Tema</string>
|
||||
<string name="settings__navigation__gestures">Gesti</string>
|
||||
<string name="settings__navigation__advanced">Avanzate</string>
|
||||
|
||||
<string name="settings__home__title">Benvenuto in %s</string>
|
||||
<string name="settings__home__ime_not_enabled">FlorisBoard non è abilitato nel sistema e quindi non sarà disponibile come metodo di immissione.Clicca quì per risolvere questo problema.</string>
|
||||
<string name="settings__home__ime_not_selected">FlorisBoard non è la tastiera predefinita. Clicca quì per risolvere questo problema.</string>
|
||||
<string name="settings__home__contribute">Grazie per aver provato FlorisBoard! Questo progetto è ancora in fase alfa e quindi manca di alcune funzionalità. Se trovate qualche bug o volete dare un suggerimento, date un\'occhiata al repo su GitHub e segnalate un problema. Questo aiuta a rendere FlorisBoard migliore. Grazie!</string>
|
||||
|
||||
<string name="settings__keyboard__title">Tastiera & Correzione del testo</string>
|
||||
<string name="settings__keyboard__subtype_no_subtypes_configured_warning">Sembra che tu non abbia configurato nessuno stile di input personalizzato. Come ripiego verrà utilizzato lo stile input English/QWERTY!</string>
|
||||
<string name="settings__keyboard__subtype_add">Aggiungi</string>
|
||||
<string name="settings__keyboard__subtype_add_title">Aggiungi stile input</string>
|
||||
<string name="settings__keyboard__subtype_apply">Applica</string>
|
||||
<string name="settings__keyboard__subtype_cancel">Annulla</string>
|
||||
<string name="settings__keyboard__subtype_delete">Elimina</string>
|
||||
<string name="settings__keyboard__subtype_edit_title">Modifica stile di input</string>
|
||||
<string name="settings__keyboard__subtype_locale">Locale</string>
|
||||
<string name="settings__keyboard__subtype_layout">Layout della tastiera</string>
|
||||
<string name="settings__keyboard__subtype_error_already_exists">Questo stile di input esiste già !</string>
|
||||
<string name="settings__localization__title">Lingue & Layout della tastiera</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning">Sembra che tu non abbia configurato nessuno stile di input personalizzato. Come ripiego verrà utilizzato lo stile input English/QWERTY!</string>
|
||||
<string name="settings__localization__subtype_add">Aggiungi</string>
|
||||
<string name="settings__localization__subtype_add_title">Aggiungi stile input</string>
|
||||
<string name="settings__localization__subtype_apply">Applica</string>
|
||||
<string name="settings__localization__subtype_cancel">Annulla</string>
|
||||
<string name="settings__localization__subtype_delete">Elimina</string>
|
||||
<string name="settings__localization__subtype_edit_title">Modifica stile di input</string>
|
||||
<string name="settings__localization__subtype_locale">Locale</string>
|
||||
<string name="settings__localization__subtype_layout">Layout della tastiera</string>
|
||||
<string name="settings__localization__subtype_error_already_exists">Questo stile di input esiste già !</string>
|
||||
|
||||
<string name="settings__theme__title">Tema tastiera</string>
|
||||
<string name="pref__theme__name__label">Tema tastiera</string>
|
||||
|
||||
<string name="settings__keyboard__title">Tastiera preferenze</string>
|
||||
<string name="pref__keyboard__group_layout__label">Layout</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label">Modalità ad una mano</string>
|
||||
<string name="pref__keyboard__height_factor__label">Altezza tastiera</string>
|
||||
<string name="pref__keyboard__group_keypress__label">Pressione tasti</string>
|
||||
<string name="pref__keyboard__sound_enabled__label">Suono pressione tasti</string>
|
||||
<string name="pref__keyboard__sound_volume__label">Volume del suono alla pressione dei tasti</string>
|
||||
<string name="pref__keyboard__vibration_enabled__label">Vibrazione alla pressione dei tasti</string>
|
||||
<string name="pref__keyboard__vibration_strength__label">Intensità della vibrazione alla pressione dei tasti</string>
|
||||
<string name="pref__keyboard__popup_visible__label">Visibilità Popup</string>
|
||||
<string name="pref__keyboard__popup_visible__summary">Mostra popup quando si preme un tasto</string>
|
||||
<string name="pref__keyboard__long_press_delay__label">Ritardo lunga pressione tasti</string>
|
||||
|
||||
<string name="settings__typing__title">Esperienza di digitazione</string>
|
||||
<string name="pref__suggestion__title">Suggerimenti</string>
|
||||
<string name="pref__suggestion__enabled__label">Visualizza suggerimenti mentre digiti</string>
|
||||
<string name="pref__suggestion__enabled__summary">Verrà visualizzato nella parte superiore della tastiera</string>
|
||||
<string name="pref__suggestion__use_pref_words__label">Suggerimenti per la parola successiva</string>
|
||||
<string name="pref__suggestion__use_pref_words__summary">Utilizzare le parole precedenti per generare suggerimenti</string>
|
||||
<string name="pref__correction__title">Correzioni</string>
|
||||
<string name="pref__popup__title">PopUp</string>
|
||||
<string name="pref__correction__double_space_period__label">Doppio tocco barra spaziatrice</string>
|
||||
<string name="pref__correction__double_space_period__summary">Doppio tocco su barra spaziatrice per mettere il punto (.) seguito da uno spazio</string>
|
||||
<string name="pref__popup__visible__label">Visibilità Popup</string>
|
||||
<string name="pref__popup__visible__summary">Mostra popup quando si preme un tasto</string>
|
||||
|
||||
<string name="settings__looknfeel__title">Aspetto & funzionalità</string>
|
||||
<string name="pref__looknfeel__group_layout__label">Layout</string>
|
||||
<string name="pref__looknfeel__height_factor__label">Altezza tastiera</string>
|
||||
<string name="pref__looknfeel__one_handed_mode__label">Modalità ad una mano</string>
|
||||
<string name="pref__looknfeel__group_keypress__label">Pressione tasti</string>
|
||||
<string name="pref__looknfeel__long_press_delay__label">Ritardo lunga pressione tasti</string>
|
||||
<string name="pref__looknfeel__sound_enabled__label">Suono pressione tasti</string>
|
||||
<string name="pref__looknfeel__sound_volume__label">Volume del suono alla pressione dei tasti</string>
|
||||
<string name="pref__looknfeel__vibration_enabled__label">Vibrazione alla pressione dei tasti</string>
|
||||
<string name="pref__looknfeel__vibration_strength__label">Intensità della vibrazione alla pressione dei tasti</string>
|
||||
<string name="pref__theme__name__label">Tema tastiera</string>
|
||||
|
||||
<string name="settings__gestures__title">Gesti</string>
|
||||
<string name="settings__gestures__title">Gesti & Digitazione a scorrimento</string>
|
||||
|
||||
<string name="settings__advanced__title">Avanzate</string>
|
||||
<string name="pref__advanced__settings_theme__label">Impostazioni tema</string>
|
||||
@@ -100,7 +103,7 @@
|
||||
<string name="setup__ok_button">OK</string>
|
||||
|
||||
<string name="setup__welcome__title">Benvenuto!</string>
|
||||
<string name="setup__welcome__intro">TGrazie per aver provato FlorisBoard! Prima che possiate iniziare ad usarlo, dobbiamo fare le solite cose e abilitarlo nelle impostazioni di sistema, impostare la vostra lingua/ il layout preferito, ecc... Ma non preoccuparti: segui questa procedura guidata </string>
|
||||
<string name="setup__welcome__intro">Grazie per aver provato FlorisBoard! Prima che possiate iniziare ad usarlo, dobbiamo fare le solite cose e abilitarlo nelle impostazioni di sistema, impostare la vostra lingua/ il layout preferito, ecc... Ma non preoccuparti: segui questa procedura guidata </string>
|
||||
<string name="setup__welcome__privacy">[[ TODO: inserisci quì la descrizione della privacy ]]</string>
|
||||
<string name="setup__welcome__trust">Il codice sorgente di FlorisBoard è accessibile pubblicamente a chiunque, quindi puoi facilmente rivedere cosa fa FlorisBoard in background. Controlla il link nel repository in basso.</string>
|
||||
<string name="setup__welcome__contribute">Un\'ultima cosa prima di iniziare l\'installazione - se riscontri errori / arresti anomali / problemi con FlorisBoard o hai una richiesta di funzionalità - vai al repository GitHub collegato di seguito e presenta un problema. Questo aiuta a migliorare l\'esperienza per tutti gli utenti!</string>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="pref__looknfeel__height_factor__entries">
|
||||
<item>@string/pref__looknfeel__height_factor__extra_short</item>
|
||||
<item>@string/pref__looknfeel__height_factor__short</item>
|
||||
<item>@string/pref__looknfeel__height_factor__mid_short</item>
|
||||
<item>@string/pref__looknfeel__height_factor__normal</item>
|
||||
<item>@string/pref__looknfeel__height_factor__mid_tall</item>
|
||||
<item>@string/pref__looknfeel__height_factor__tall</item>
|
||||
<item>@string/pref__looknfeel__height_factor__extra_tall</item>
|
||||
<string-array name="pref__keyboard__height_factor__entries">
|
||||
<item>@string/pref__keyboard__height_factor__extra_short</item>
|
||||
<item>@string/pref__keyboard__height_factor__short</item>
|
||||
<item>@string/pref__keyboard__height_factor__mid_short</item>
|
||||
<item>@string/pref__keyboard__height_factor__normal</item>
|
||||
<item>@string/pref__keyboard__height_factor__mid_tall</item>
|
||||
<item>@string/pref__keyboard__height_factor__tall</item>
|
||||
<item>@string/pref__keyboard__height_factor__extra_tall</item>
|
||||
</string-array>
|
||||
<string-array name="pref__looknfeel__height_factor__values">
|
||||
<string-array name="pref__keyboard__height_factor__values">
|
||||
<item>extra_short</item>
|
||||
<item>short</item>
|
||||
<item>mid_short</item>
|
||||
@@ -19,12 +19,12 @@
|
||||
<item>extra_tall</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref__looknfeel__one_handed_mode__entries">
|
||||
<item>@string/pref__looknfeel__one_handed_mode__off</item>
|
||||
<item>@string/pref__looknfeel__one_handed_mode__right</item>
|
||||
<item>@string/pref__looknfeel__one_handed_mode__left</item>
|
||||
<string-array name="pref__keyboard__one_handed_mode__entries">
|
||||
<item>@string/pref__keyboard__one_handed_mode__off</item>
|
||||
<item>@string/pref__keyboard__one_handed_mode__right</item>
|
||||
<item>@string/pref__keyboard__one_handed_mode__left</item>
|
||||
</string-array>
|
||||
<string-array name="pref__looknfeel__one_handed_mode__values">
|
||||
<string-array name="pref__keyboard__one_handed_mode__values">
|
||||
<item>off</item>
|
||||
<item>end</item>
|
||||
<item>start</item>
|
||||
@@ -50,12 +50,58 @@
|
||||
<item>clipboard_cursor_tools</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref__theme__name__entries">
|
||||
<item>Floris Light</item>
|
||||
<item>Floris Dark</item>
|
||||
<string-array name="pref__gestures__swipe_action__entries">
|
||||
<item>@string/pref__gestures__swipe_action__no_action</item>
|
||||
<item>@string/pref__gestures__swipe_action__delete_word</item>
|
||||
<item>@string/pref__gestures__swipe_action__hide_keyboard</item>
|
||||
<item>@string/pref__gestures__swipe_action__move_cursor_up</item>
|
||||
<item>@string/pref__gestures__swipe_action__move_cursor_down</item>
|
||||
<item>@string/pref__gestures__swipe_action__move_cursor_left</item>
|
||||
<item>@string/pref__gestures__swipe_action__move_cursor_right</item>
|
||||
<item>@string/pref__gestures__swipe_action__shift</item>
|
||||
<item>@string/pref__gestures__swipe_action__switch_to_prev_subtype</item>
|
||||
<item>@string/pref__gestures__swipe_action__switch_to_next_subtype</item>
|
||||
</string-array>
|
||||
<string-array name="pref__theme__name__values">
|
||||
<item>floris_light</item>
|
||||
<item>floris_dark</item>
|
||||
<string-array name="pref__gestures__swipe_action__values">
|
||||
<item>no_action</item>
|
||||
<item>delete_word</item>
|
||||
<item>hide_keyboard</item>
|
||||
<item>move_cursor_up</item>
|
||||
<item>move_cursor_down</item>
|
||||
<item>move_cursor_left</item>
|
||||
<item>move_cursor_right</item>
|
||||
<item>shift</item>
|
||||
<item>switch_to_prev_subtype</item>
|
||||
<item>switch_to_next_subtype</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref__gestures__swipe_velocity_threshold__entries">
|
||||
<item>@string/pref__gestures__swipe_velocity_threshold__very_slow</item>
|
||||
<item>@string/pref__gestures__swipe_velocity_threshold__slow</item>
|
||||
<item>@string/pref__gestures__swipe_velocity_threshold__normal</item>
|
||||
<item>@string/pref__gestures__swipe_velocity_threshold__fast</item>
|
||||
<item>@string/pref__gestures__swipe_velocity_threshold__very_fast</item>
|
||||
</string-array>
|
||||
<string-array name="pref__gestures__swipe_velocity_threshold__values">
|
||||
<item>very_slow</item>
|
||||
<item>slow</item>
|
||||
<item>normal</item>
|
||||
<item>fast</item>
|
||||
<item>very_fast</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref__gestures__swipe_distance_threshold__entries">
|
||||
<item>@string/pref__gestures__swipe_distance_threshold__very_short</item>
|
||||
<item>@string/pref__gestures__swipe_distance_threshold__short</item>
|
||||
<item>@string/pref__gestures__swipe_distance_threshold__normal</item>
|
||||
<item>@string/pref__gestures__swipe_distance_threshold__long</item>
|
||||
<item>@string/pref__gestures__swipe_distance_threshold__very_long</item>
|
||||
</string-array>
|
||||
<string-array name="pref__gestures__swipe_distance_threshold__values">
|
||||
<item>very_short</item>
|
||||
<item>short</item>
|
||||
<item>normal</item>
|
||||
<item>long</item>
|
||||
<item>very_long</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -14,39 +14,12 @@
|
||||
<attr name="android:text" format="string|reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="KeyboardTheme">
|
||||
<attr name="keyboardViewStyle" format="reference" />
|
||||
<attr name="keyboardRowViewStyle" format="reference" />
|
||||
<declare-styleable name="KeyboardThemeBase">
|
||||
<attr name="keyboardViewStyle" format="reference"/>
|
||||
<attr name="keyboardRowViewStyle" format="reference"/>
|
||||
|
||||
<attr name="semiTransparentColor" format="color" />
|
||||
|
||||
<attr name="key_bgColor" format="color" />
|
||||
<attr name="key_bgColorPressed" format="color" />
|
||||
<attr name="key_fgColor" format="color" />
|
||||
<attr name="key_enter_fgColor" format="color" />
|
||||
|
||||
<attr name="key_popup_bgColor" format="color" />
|
||||
<attr name="key_popup_fgColor" format="color" />
|
||||
|
||||
<attr name="key_popup_extended_bgColor" format="color" />
|
||||
<attr name="key_popup_extended_bgColorActive" format="color" />
|
||||
<attr name="key_popup_extended_shadowColor" format="color" />
|
||||
|
||||
<attr name="keyboard_bgColor" format="color" />
|
||||
|
||||
<attr name="emoji_key_bgColor" format="color" />
|
||||
<attr name="emoji_key_bgColorPressed" format="color" />
|
||||
<attr name="emoji_key_fgColor" format="color" />
|
||||
|
||||
<attr name="one_handed_bgColor" format="color" />
|
||||
<attr name="one_handed_button_fgColor" format="color" />
|
||||
|
||||
<attr name="smartbar_bgColor" format="color" />
|
||||
<attr name="smartbar_fgColor" format="color" />
|
||||
<attr name="smartbar_button_bgColor" format="color" />
|
||||
<attr name="smartbar_button_bgColorPressed" format="color" />
|
||||
<attr name="smartbar_button_fgColor" format="color" />
|
||||
<attr name="smartbar_candidate_fgColor" format="color" />
|
||||
<attr name="semiTransparentColor" format="color"/>
|
||||
<attr name="inputView_bgColorFallback" format="color"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="SettingsTheme">
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="inputView_baseHeight">248dp</dimen>
|
||||
<dimen name="smartbar_baseHeight">40dp</dimen>
|
||||
<dimen name="textKeyboardView_baseHeight">208dp</dimen>
|
||||
<dimen name="mediaKeyboardView_baseHeight">@dimen/inputView_baseHeight</dimen>
|
||||
|
||||
<dimen name="key_width">33dp</dimen>
|
||||
<dimen name="key_height">42dp</dimen>
|
||||
<dimen name="emoji_key_width">@dimen/key_height</dimen>
|
||||
@@ -8,6 +13,7 @@
|
||||
<dimen name="key_marginH">2dp</dimen>
|
||||
<dimen name="key_marginV">5dp</dimen>
|
||||
<dimen name="keyboard_row_marginH">@dimen/key_marginH</dimen>
|
||||
<dimen name="keyboard_preview_margin">16dp</dimen>
|
||||
|
||||
<dimen name="key_borderRadius">6dp</dimen>
|
||||
|
||||
@@ -28,4 +34,16 @@
|
||||
<dimen name="smartbar_height">40dp</dimen>
|
||||
<dimen name="smartbar_button_margin">4dp</dimen>
|
||||
<dimen name="smartbar_button_padding">6dp</dimen>
|
||||
|
||||
<dimen name="gesture_distance_threshold_very_short">24dp</dimen>
|
||||
<dimen name="gesture_distance_threshold_short">28dp</dimen>
|
||||
<dimen name="gesture_distance_threshold_normal">32dp</dimen>
|
||||
<dimen name="gesture_distance_threshold_long">36dp</dimen>
|
||||
<dimen name="gesture_distance_threshold_very_long">40dp</dimen>
|
||||
|
||||
<integer name="gesture_velocity_threshold_very_slow">50</integer>
|
||||
<integer name="gesture_velocity_threshold_slow">60</integer>
|
||||
<integer name="gesture_velocity_threshold_normal">70</integer>
|
||||
<integer name="gesture_velocity_threshold_fast">80</integer>
|
||||
<integer name="gesture_velocity_threshold_very_fast">90</integer>
|
||||
</resources>
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
<string name="key__phone_wait">Wait</string>
|
||||
<string name="key_popup__threedots_alt">Three-dot icon. If visible, indicates that more letters can be used if longer pressed.</string>
|
||||
|
||||
<!-- One-handed strings -->
|
||||
<string name="one_handed__close_btn_content_description">Close one-handed mode.</string>
|
||||
<string name="one_handed__move_start_btn_content_description">Move keyboard to the left.</string>
|
||||
<string name="one_handed__move_end_btn_content_description">Move keyboard to the right.</string>
|
||||
|
||||
<!-- Media strings -->
|
||||
<string name="media__tab__emojis">Emojis</string>
|
||||
<string name="media__tab__emoticons">Emoticons</string>
|
||||
@@ -31,12 +36,13 @@
|
||||
<string name="settings__title">Settings</string>
|
||||
<string name="settings__menu">More options</string>
|
||||
<string name="settings__menu_about">About</string>
|
||||
<string name="settings__menu_advanced">@string/settings__advanced__title</string>
|
||||
<string name="settings__menu_help">Help & feedback</string>
|
||||
<string name="settings__navigation__home">Home</string>
|
||||
<string name="settings__navigation__keyboard">Keyboard</string>
|
||||
<string name="settings__navigation__looknfeel">Look & feel</string>
|
||||
<string name="settings__navigation__typing">Typing</string>
|
||||
<string name="settings__navigation__theme">Theme</string>
|
||||
<string name="settings__navigation__gestures">Gestures</string>
|
||||
<string name="settings__navigation__advanced">Advanced</string>
|
||||
<string name="settings__default">Default</string>
|
||||
<string name="settings__system_default">System default</string>
|
||||
|
||||
@@ -45,19 +51,81 @@
|
||||
<string name="settings__home__ime_not_selected">FlorisBoard is not selected as the default input method. Click here to resolve this issue.</string>
|
||||
<string name="settings__home__contribute">Thanks for trying out FlorisBoard! This project is still in alpha and therefore missing features. If you find any bugs or want to make a suggestion, please check out the repo on GitHub and file an issue. This helps making FlorisBoard better. Thank you!</string>
|
||||
|
||||
<string name="settings__keyboard__title">Keyboard & Text Correction</string>
|
||||
<string name="settings__keyboard__subtype_no_subtypes_configured_warning">It seems that you haven\'t configured any subtypes. As a fallback the subtype English/QWERTY will be used!</string>
|
||||
<string name="settings__keyboard__subtype_add">Add</string>
|
||||
<string name="settings__keyboard__subtype_add_title">Add subtype</string>
|
||||
<string name="settings__keyboard__subtype_apply">Apply</string>
|
||||
<string name="settings__keyboard__subtype_cancel">Cancel</string>
|
||||
<string name="settings__keyboard__subtype_delete">Delete</string>
|
||||
<string name="settings__keyboard__subtype_edit_title">Edit subtype</string>
|
||||
<string name="settings__keyboard__subtype_locale">Locale</string>
|
||||
<string name="settings__keyboard__subtype_layout">Keyboard layout</string>
|
||||
<string name="settings__keyboard__subtype_error_already_exists">This subtype already exists!</string>
|
||||
<string name="settings__localization__title">Languages & Keyboard layouts</string>
|
||||
<string name="settings__localization__subtype_no_subtypes_configured_warning">It seems that you haven\'t configured any subtypes. As a fallback the subtype English/QWERTY will be used!</string>
|
||||
<string name="settings__localization__subtype_add">Add</string>
|
||||
<string name="settings__localization__subtype_add_title">Add subtype</string>
|
||||
<string name="settings__localization__subtype_apply">Apply</string>
|
||||
<string name="settings__localization__subtype_cancel">Cancel</string>
|
||||
<string name="settings__localization__subtype_delete">Delete</string>
|
||||
<string name="settings__localization__subtype_edit_title">Edit subtype</string>
|
||||
<string name="settings__localization__subtype_locale">Locale</string>
|
||||
<string name="settings__localization__subtype_layout">Keyboard layout</string>
|
||||
<string name="settings__localization__subtype_error_already_exists">This subtype already exists!</string>
|
||||
|
||||
<string name="settings__theme__title">Keyboard theme</string>
|
||||
<string name="settings__theme__undefined">Undefined</string>
|
||||
<string name="settings__theme__preset_title">Theme</string>
|
||||
<string name="settings__theme__preset_summary">Custom (based on %s)</string>
|
||||
<string name="settings__theme__preset_dialog_selected_theme">Selected theme:</string>
|
||||
<string name="settings__theme__preset_dialog_available_themes">Available themes:</string>
|
||||
<string name="settings__theme__preset_dialog_alt_arrow_right">Arrow right</string>
|
||||
<string name="settings__theme__background">Background color</string>
|
||||
<string name="settings__theme__background_active">Background color when active</string>
|
||||
<string name="settings__theme__background_pressed">Background color when pressed</string>
|
||||
<string name="settings__theme__foreground">Foreground color</string>
|
||||
<string name="settings__theme__foreground_alt">Foreground color (alternative)</string>
|
||||
<string name="settings__theme__foreground_capslock">Foreground color (caps lock)</string>
|
||||
<string name="settings__theme__dialog_title">Select a color</string>
|
||||
<string name="settings__theme__group_window">Window & System</string>
|
||||
<string name="settings__theme__group_keyboard">Keyboard</string>
|
||||
<string name="settings__theme__group_key">Key</string>
|
||||
<string name="settings__theme__group_key_enter">Enter key</string>
|
||||
<string name="settings__theme__group_key_popup">Key popup</string>
|
||||
<string name="settings__theme__group_key_shift">Shift key</string>
|
||||
<string name="settings__theme__group_media">Media context</string>
|
||||
<string name="settings__theme__group_one_handed">One-handed</string>
|
||||
<string name="settings__theme__group_one_handed_button">One-handed button</string>
|
||||
<string name="settings__theme__group_smartbar">Smartbar</string>
|
||||
<string name="settings__theme__group_smartbar_button">Smartbar button</string>
|
||||
<string name="pref__theme__name__label">Keyboard Theme</string>
|
||||
<string name="pref__theme__colorPrimary_title">Primary color</string>
|
||||
<string name="pref__theme__colorPrimary_summary">Applied to main media tab ripple and selection highlight</string>
|
||||
<string name="pref__theme__colorPrimaryDark_title">Primary color (dark)</string>
|
||||
<string name="pref__theme__colorPrimaryDark_summary">Currently not used, reserved for future implementation</string>
|
||||
<string name="pref__theme__colorAccent_title">Accent color</string>
|
||||
<string name="pref__theme__colorAccent_summary">Applied to emoji tab ripple</string>
|
||||
<string name="pref__theme__navBarColor_title">Navigation bar color</string>
|
||||
<string name="pref__theme__navBarColor_summary">The background of the navigation bar.</string>
|
||||
<string name="pref__theme__navBarIsLight_title">Navigation bar dark foreground</string>
|
||||
<string name="pref__theme__navBarIsLight_summary">Set to ON for dark or to OFF for light foreground.</string>
|
||||
|
||||
<string name="settings__keyboard__title">Keyboard Preferences</string>
|
||||
<string name="pref__keyboard__group_layout__label">Layout</string>
|
||||
<string name="pref__keyboard__one_handed_mode__label">One-handed mode</string>
|
||||
<string name="pref__keyboard__one_handed_mode__off">Off</string>
|
||||
<string name="pref__keyboard__one_handed_mode__right">Right-handed mode</string>
|
||||
<string name="pref__keyboard__one_handed_mode__left">Left-handed mode</string>
|
||||
<string name="pref__keyboard__height_factor__label">Keyboard height</string>
|
||||
<string name="pref__keyboard__height_factor__extra_short">Extra-short</string>
|
||||
<string name="pref__keyboard__height_factor__short">Short</string>
|
||||
<string name="pref__keyboard__height_factor__mid_short">Mid-short</string>
|
||||
<string name="pref__keyboard__height_factor__normal">Normal</string>
|
||||
<string name="pref__keyboard__height_factor__mid_tall">Mid-tall</string>
|
||||
<string name="pref__keyboard__height_factor__tall">Tall</string>
|
||||
<string name="pref__keyboard__height_factor__extra_tall">Extra-tall</string>
|
||||
<string name="pref__keyboard__group_keypress__label">Key press</string>
|
||||
<string name="pref__keyboard__sound_enabled__label">Sound on key press</string>
|
||||
<string name="pref__keyboard__sound_volume__label">Sound volume on key press</string>
|
||||
<string name="pref__keyboard__vibration_enabled__label">Vibrate on key press</string>
|
||||
<string name="pref__keyboard__vibration_strength__label">Vibration strength on key press</string>
|
||||
<string name="pref__keyboard__popup_visible__label">PopUp Visibility</string>
|
||||
<string name="pref__keyboard__popup_visible__summary">Show popup when you press a key</string>
|
||||
<string name="pref__keyboard__long_press_delay__label">Long key press delay</string>
|
||||
|
||||
<string name="settings__typing__title">Typing experience</string>
|
||||
<string name="pref__suggestion__title">Suggestions</string>
|
||||
<string name="pref__suggestion__enabled__label">Display suggestions while you type</string>
|
||||
<string name="pref__suggestion__enabled__label">[NYI] Display suggestions while you type</string>
|
||||
<string name="pref__suggestion__enabled__summary">Will show on top of the keyboard</string>
|
||||
<string name="pref__suggestion__show_instead__label">What to show instead of suggestions</string>
|
||||
<string name="pref__suggestion__show_instead__number_row">Number row</string>
|
||||
@@ -65,35 +133,45 @@
|
||||
<string name="pref__suggestion__use_pref_words__label">[NYI] Next-word suggestions</string>
|
||||
<string name="pref__suggestion__use_pref_words__summary">Use previous words for generating suggestions</string>
|
||||
<string name="pref__correction__title">Corrections</string>
|
||||
<string name="pref__popup__title">PopUp</string>
|
||||
<string name="pref__correction__double_space_period__label">Double-space period</string>
|
||||
<string name="pref__correction__double_space_period__summary">Tapping twice on spacebar inserts a period followed by a space</string>
|
||||
<string name="pref__popup__visible__label">PopUp Visibility</string>
|
||||
<string name="pref__popup__visible__summary">Show popup when you press a key</string>
|
||||
|
||||
<string name="settings__looknfeel__title">Look & feel</string>
|
||||
<string name="pref__looknfeel__group_layout__label">Layout</string>
|
||||
<string name="pref__looknfeel__height_factor__label">Keyboard height</string>
|
||||
<string name="pref__looknfeel__height_factor__extra_short">Extra-short</string>
|
||||
<string name="pref__looknfeel__height_factor__short">Short</string>
|
||||
<string name="pref__looknfeel__height_factor__mid_short">Mid-short</string>
|
||||
<string name="pref__looknfeel__height_factor__normal">Normal</string>
|
||||
<string name="pref__looknfeel__height_factor__mid_tall">Mid-tall</string>
|
||||
<string name="pref__looknfeel__height_factor__tall">Tall</string>
|
||||
<string name="pref__looknfeel__height_factor__extra_tall">Extra-tall</string>
|
||||
<string name="pref__looknfeel__one_handed_mode__label">One-handed mode</string>
|
||||
<string name="pref__looknfeel__one_handed_mode__off">Off</string>
|
||||
<string name="pref__looknfeel__one_handed_mode__right">Right-handed mode</string>
|
||||
<string name="pref__looknfeel__one_handed_mode__left">Left-handed mode</string>
|
||||
<string name="pref__looknfeel__group_keypress__label">Key press</string>
|
||||
<string name="pref__looknfeel__long_press_delay__label">Long key press delay</string>
|
||||
<string name="pref__looknfeel__sound_enabled__label">Sound on key press</string>
|
||||
<string name="pref__looknfeel__sound_volume__label">Sound volume on key press</string>
|
||||
<string name="pref__looknfeel__vibration_enabled__label">Vibrate on key press</string>
|
||||
<string name="pref__looknfeel__vibration_strength__label">Vibration strength on key press</string>
|
||||
<string name="pref__theme__name__label">Keyboard Theme</string>
|
||||
|
||||
<string name="settings__gestures__title">Gestures</string>
|
||||
<string name="settings__gestures__title">Gestures & Glide typing</string>
|
||||
<string name="pref__glide__title">Glide typing</string>
|
||||
<string name="pref__glide__enabled__label">[NYI] Enable glide typing</string>
|
||||
<string name="pref__glide__enabled__summary">Type in a word by sliding your finger through its letters</string>
|
||||
<string name="pref__glide__show_trail__label">[NYI] Show glide trail</string>
|
||||
<string name="pref__glide__show_trail__summary">Will disappear after each word</string>
|
||||
<string name="pref__gestures__title">Gestures</string>
|
||||
<string name="pref__gestures__swipe_action__no_action">No action</string>
|
||||
<string name="pref__gestures__swipe_action__delete_word">Delete word</string>
|
||||
<string name="pref__gestures__swipe_action__hide_keyboard">Hide keyboard</string>
|
||||
<string name="pref__gestures__swipe_action__move_cursor_up">Move cursor up</string>
|
||||
<string name="pref__gestures__swipe_action__move_cursor_down">Move cursor down</string>
|
||||
<string name="pref__gestures__swipe_action__move_cursor_left">Move cursor left</string>
|
||||
<string name="pref__gestures__swipe_action__move_cursor_right">Move cursor right</string>
|
||||
<string name="pref__gestures__swipe_action__shift">Shift</string>
|
||||
<string name="pref__gestures__swipe_action__switch_to_prev_subtype">Switch to previous subtype</string>
|
||||
<string name="pref__gestures__swipe_action__switch_to_next_subtype">Switch to next subtype</string>
|
||||
<string name="pref__gestures__swipe_up__label">Swipe up</string>
|
||||
<string name="pref__gestures__swipe_down__label">Swipe down</string>
|
||||
<string name="pref__gestures__swipe_left__label">Swipe left</string>
|
||||
<string name="pref__gestures__swipe_right__label">Swipe right</string>
|
||||
<string name="pref__gestures__space_bar_swipe_left__label">Space bar swipe left</string>
|
||||
<string name="pref__gestures__space_bar_swipe_right__label">Space bar swipe right</string>
|
||||
<string name="pref__gestures__delete_key_swipe_left__label">Delete key swipe left</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__label">Swipe velocity threshold</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__very_slow">Very slow</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__slow">Slow</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__normal">Normal</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__fast">Fast</string>
|
||||
<string name="pref__gestures__swipe_velocity_threshold__very_fast">Very fast</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__label">Swipe distance threshold</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__very_short">Very short</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__short">Short</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__normal">Normal</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__long">Long</string>
|
||||
<string name="pref__gestures__swipe_distance_threshold__very_long">Very long</string>
|
||||
|
||||
<string name="settings__advanced__title">Advanced</string>
|
||||
<string name="pref__advanced__settings_theme__label">Settings theme</string>
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:layout_weight">0</item>
|
||||
<item name="android:layout_alignParentBottom">true</item>
|
||||
<item name="android:background">?one_handed_bgColor</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:orientation">vertical</item>
|
||||
</style>
|
||||
@@ -17,7 +16,7 @@
|
||||
<item name="android:autoMirrored">true</item>
|
||||
<item name="android:background">@drawable/button_transparent_bg_on_press</item>
|
||||
<item name="android:padding">0dp</item>
|
||||
<item name="android:tint">?one_handed_button_fgColor</item>
|
||||
<item name="android:tint">#000000</item>
|
||||
</style>
|
||||
|
||||
<style name="SmartbarCandidate">
|
||||
@@ -53,10 +52,10 @@
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:layout_margin">@dimen/smartbar_button_margin</item>
|
||||
<item name="android:background">@drawable/shape_oval</item>
|
||||
<item name="android:backgroundTint">?smartbar_button_bgColor</item>
|
||||
<item name="android:backgroundTint">#FFFFFF</item>
|
||||
<item name="android:padding">@dimen/smartbar_button_padding</item>
|
||||
<item name="android:scaleType">fitCenter</item>
|
||||
<item name="android:tint">?smartbar_button_fgColor</item>
|
||||
<item name="android:tint">#000000</item>
|
||||
</style>
|
||||
|
||||
<style name="SmartbarQuickAction.Toggle">
|
||||
|
||||
@@ -1,90 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="KeyboardTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardTheme.FlorisLight">
|
||||
<style name="KeyboardThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="android:navigationBarColor" tools:targetApi="o_mr1">?keyboard_bgColor</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardThemeBase.Day">
|
||||
<item name="android:navigationBarColor" tools:targetApi="o_mr1">#FFFFFF</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">true</item>
|
||||
<item name="android:colorControlNormal">#8A000000</item><!-- Black, semi transparent -->
|
||||
<item name="android:colorButtonNormal">#4A000000</item><!-- Black, semi transparent -->
|
||||
<item name="android:textColor">#000000</item><!-- Black -->
|
||||
<item name="semiTransparentColor">#20000000</item><!-- Black, semi transparent -->
|
||||
|
||||
<item name="key_bgColor">#FFFFFF</item><!-- White -->
|
||||
<item name="key_bgColorPressed">#F5F5F5</item><!-- Gray 100 -->
|
||||
<item name="key_fgColor">?android:textColor</item>
|
||||
<item name="key_enter_fgColor">#FFFFFF</item><!-- White -->
|
||||
|
||||
<item name="key_popup_bgColor">#EEEEEE</item><!-- Gray 200 -->
|
||||
<item name="key_popup_fgColor">?android:textColor</item>
|
||||
|
||||
<item name="key_popup_extended_bgColor">@android:color/transparent</item>
|
||||
<item name="key_popup_extended_bgColorActive">#BDBDBD</item><!-- Gray 400 -->
|
||||
<item name="key_popup_extended_shadowColor">#CDCACACA</item>
|
||||
|
||||
<item name="keyboard_bgColor">#E0E0E0</item><!-- Gray 300 -->
|
||||
|
||||
<item name="emoji_key_bgColor">?keyboard_bgColor</item>
|
||||
<item name="emoji_key_bgColorPressed">?key_popup_extended_bgColorActive</item>
|
||||
<item name="emoji_key_fgColor">#757575</item><!-- Gray 600 -->
|
||||
|
||||
<item name="one_handed_bgColor">#E8F5E9</item><!-- Green 50 -->
|
||||
<item name="one_handed_button_fgColor">#424242</item><!-- Gray 800 -->
|
||||
|
||||
<item name="smartbar_bgColor">?keyboard_bgColor</item>
|
||||
<item name="smartbar_fgColor">?android:textColor</item>
|
||||
<item name="smartbar_button_bgColor">?key_bgColor</item>
|
||||
<item name="smartbar_button_bgColorPressed">?key_bgColorPressed</item>
|
||||
<item name="smartbar_button_fgColor">?key_fgColor</item>
|
||||
<item name="smartbar_candidate_fgColor">?android:textColor</item>
|
||||
<item name="inputView_bgColorFallback">#FFFFFF</item>
|
||||
</style>
|
||||
|
||||
<style name="KeyboardTheme.FlorisDark">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
|
||||
<item name="android:navigationBarColor" tools:targetApi="o_mr1">?keyboard_bgColor</item>
|
||||
<style name="KeyboardThemeBase.Night">
|
||||
<item name="android:navigationBarColor" tools:targetApi="o_mr1">#000000</item>
|
||||
<item name="android:windowLightNavigationBar" tools:targetApi="o_mr1">false</item>
|
||||
<item name="android:colorControlNormal">#B3FFFFFF</item><!-- White, semi transparent -->
|
||||
<item name="android:colorButtonNormal">#73FFFFFF</item><!-- White, semi transparent -->
|
||||
<item name="android:textColor">#FFFFFF</item><!-- White -->
|
||||
<item name="semiTransparentColor">#20FFFFFF</item><!-- White, semi transparent -->
|
||||
|
||||
<item name="key_bgColor">#424242</item><!-- Gray 800 -->
|
||||
<item name="key_bgColorPressed">#616161</item><!-- Gray 700 -->
|
||||
<item name="key_fgColor">?android:textColor</item>
|
||||
<item name="key_enter_fgColor">#FFFFFF</item><!-- White -->
|
||||
|
||||
<item name="key_popup_bgColor">#757575</item><!-- Gray 600 -->
|
||||
<item name="key_popup_fgColor">?android:textColor</item>
|
||||
|
||||
<item name="key_popup_extended_bgColor">@android:color/transparent</item>
|
||||
<item name="key_popup_extended_bgColorActive">#BDBDBD</item><!-- Gray 400 -->
|
||||
<item name="key_popup_extended_shadowColor">#CD353535</item>
|
||||
|
||||
<item name="keyboard_bgColor">#212121</item><!-- Gray 900 -->
|
||||
|
||||
<item name="emoji_key_bgColor">?keyboard_bgColor</item>
|
||||
<item name="emoji_key_bgColorPressed">?key_popup_extended_bgColorActive</item>
|
||||
<item name="emoji_key_fgColor">#BDBDBD</item><!-- Gray 400 -->
|
||||
|
||||
<item name="one_handed_bgColor">#1B5E20</item><!-- Green 900 -->
|
||||
<item name="one_handed_button_fgColor">#EEEEEE</item><!-- Gray 200 -->
|
||||
|
||||
<item name="smartbar_bgColor">?keyboard_bgColor</item>
|
||||
<item name="smartbar_fgColor">?android:textColor</item>
|
||||
<item name="smartbar_button_bgColor">?key_bgColor</item>
|
||||
<item name="smartbar_button_bgColorPressed">?key_bgColorPressed</item>
|
||||
<item name="smartbar_button_fgColor">?key_fgColor</item>
|
||||
<item name="smartbar_candidate_fgColor">?android:textColor</item>
|
||||
<item name="inputView_bgColorFallback">#000000</item>
|
||||
</style>
|
||||
|
||||
<style name="SettingsToolbarTheme" parent="ThemeOverlay.AppCompat.DayNight.ActionBar">
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
app:fragment="dev.patrickgold.florisboard.settings.SettingsMainActivity$KeyboardFragment"
|
||||
app:key="pref__keyboard"
|
||||
app:icon="@drawable/ic_keyboard"
|
||||
app:title="@string/settings__keyboard__title" />
|
||||
|
||||
<Preference
|
||||
app:fragment="dev.patrickgold.florisboard.settings.SettingsMainActivity$AdvancedFragment"
|
||||
app:key="pref__advanced"
|
||||
app:icon="@drawable/ic_more_horiz"
|
||||
app:title="@string/settings__advanced__title" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -9,13 +9,13 @@
|
||||
app:key="advanced__settings_theme"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__advanced__settings_theme__label"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="advanced__show_app_icon"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__advanced__show_app_icon__label"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
119
app/src/main/res/xml/prefs_gestures.xml
Normal file
119
app/src/main/res/xml/prefs_gestures.xml
Normal file
@@ -0,0 +1,119 @@
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="glide"
|
||||
app:title="@string/pref__glide__title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="false"
|
||||
app:disableDependentsState="true"
|
||||
app:key="glide__enabled"
|
||||
app:title="@string/pref__glide__enabled__label"
|
||||
android:summary="@string/pref__glide__enabled__summary"/>
|
||||
|
||||
<!--<SwitchPreferenceCompat
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
app:key="glide__show_trail"
|
||||
app:title="@string/pref__glide__show_trail__label"
|
||||
android:summary="@string/pref__glide__show_trail__summary"/>-->
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="gestures"
|
||||
app:title="@string/pref__gestures__title">
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="shift"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:dependency="glide__enabled"
|
||||
app:key="gestures__swipe_up"
|
||||
app:title="@string/pref__gestures__swipe_up__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="hide_keyboard"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:dependency="glide__enabled"
|
||||
app:key="gestures__swipe_down"
|
||||
app:title="@string/pref__gestures__swipe_down__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="switch_to_next_subtype"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:dependency="glide__enabled"
|
||||
app:key="gestures__swipe_left"
|
||||
app:title="@string/pref__gestures__swipe_left__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="switch_to_prev_subtype"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:dependency="glide__enabled"
|
||||
app:key="gestures__swipe_right"
|
||||
app:title="@string/pref__gestures__swipe_right__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="move_cursor_left"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:key="gestures__space_bar_swipe_left"
|
||||
app:title="@string/pref__gestures__space_bar_swipe_left__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="move_cursor_right"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:key="gestures__space_bar_swipe_right"
|
||||
app:title="@string/pref__gestures__space_bar_swipe_right__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="delete_word"
|
||||
app:entries="@array/pref__gestures__swipe_action__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_action__values"
|
||||
app:key="gestures__delete_key_swipe_left"
|
||||
app:title="@string/pref__gestures__delete_key_swipe_left__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="normal"
|
||||
app:entries="@array/pref__gestures__swipe_velocity_threshold__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_velocity_threshold__values"
|
||||
app:key="gestures__swipe_velocity_threshold"
|
||||
app:title="@string/pref__gestures__swipe_velocity_threshold__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="normal"
|
||||
app:entries="@array/pref__gestures__swipe_distance_threshold__entries"
|
||||
app:entryValues="@array/pref__gestures__swipe_distance_threshold__values"
|
||||
app:key="gestures__swipe_distance_threshold"
|
||||
app:title="@string/pref__gestures__swipe_distance_threshold__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -4,60 +4,90 @@
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="suggestion__enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__enabled__label"
|
||||
app:summary="@string/pref__suggestion__enabled__summary"/>
|
||||
app:title="@string/pref__keyboard__group_layout__label">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="number_row"
|
||||
app:entries="@array/pref__suggestion__show_instead__entries"
|
||||
app:entryValues="@array/pref__suggestion__show_instead__values"
|
||||
app:key="suggestion__show_instead"
|
||||
android:defaultValue="off"
|
||||
app:entries="@array/pref__keyboard__one_handed_mode__entries"
|
||||
app:entryValues="@array/pref__keyboard__one_handed_mode__values"
|
||||
app:key="keyboard__one_handed_mode"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__show_instead__label"
|
||||
app:title="@string/pref__keyboard__one_handed_mode__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:dependency="suggestion__enabled"
|
||||
app:key="suggestion__use_prev_words"
|
||||
<ListPreference
|
||||
android:defaultValue="normal"
|
||||
app:entries="@array/pref__keyboard__height_factor__entries"
|
||||
app:entryValues="@array/pref__keyboard__height_factor__values"
|
||||
app:key="keyboard__height_factor"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__use_pref_words__label"
|
||||
app:summary="@string/pref__suggestion__use_pref_words__summary"/>
|
||||
app:title="@string/pref__keyboard__height_factor__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__title">
|
||||
app:title="@string/pref__keyboard__group_keypress__label">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="correction__double_space_period"
|
||||
android:key="keyboard__sound_enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__double_space_period__label"
|
||||
app:summary="@string/pref__correction__double_space_period__summary"/>
|
||||
app:title="@string/pref__keyboard__sound_enabled__label"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__popup__title">
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="-1"
|
||||
app:systemDefaultValue="-1"
|
||||
app:systemDefaultValueText="@string/settings__system_default"
|
||||
app:dependency="keyboard__sound_enabled"
|
||||
app:key="keyboard__sound_volume"
|
||||
app:min="0"
|
||||
app:max="100"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__keyboard__sound_volume__label"
|
||||
app:seekBarIncrement="1"
|
||||
app:unit="%"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="popup__enabled"
|
||||
android:key="keyboard__vibration_enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__popup__visible__label"
|
||||
app:summary="@string/pref__popup__visible__summary"/>
|
||||
app:title="@string/pref__keyboard__vibration_enabled__label"/>
|
||||
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="-1"
|
||||
app:systemDefaultValue="-1"
|
||||
app:systemDefaultValueText="@string/settings__system_default"
|
||||
app:dependency="keyboard__vibration_enabled"
|
||||
app:key="keyboard__vibration_strength"
|
||||
app:min="0"
|
||||
app:max="100"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__keyboard__vibration_strength__label"
|
||||
app:seekBarIncrement="1"
|
||||
app:unit="%"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="keyboard__popup_enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__keyboard__popup_visible__label"
|
||||
app:summary="@string/pref__keyboard__popup_visible__summary"/>
|
||||
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="300"
|
||||
app:key="keyboard__long_press_delay"
|
||||
app:min="100"
|
||||
app:max="700"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__keyboard__long_press_delay__label"
|
||||
app:seekBarIncrement="10"
|
||||
app:unit=" ms"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__group_layout__label">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="off"
|
||||
app:entries="@array/pref__looknfeel__one_handed_mode__entries"
|
||||
app:entryValues="@array/pref__looknfeel__one_handed_mode__values"
|
||||
app:key="looknfeel__one_handed_mode"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__one_handed_mode__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="normal"
|
||||
app:entries="@array/pref__looknfeel__height_factor__entries"
|
||||
app:entryValues="@array/pref__looknfeel__height_factor__values"
|
||||
app:key="looknfeel__height_factor"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__height_factor__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__group_keypress__label">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="looknfeel__sound_enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__sound_enabled__label"/>
|
||||
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="-1"
|
||||
app:systemDefaultValue="-1"
|
||||
app:systemDefaultValueText="@string/settings__system_default"
|
||||
app:dependency="looknfeel__sound_enabled"
|
||||
app:key="looknfeel__sound_volume"
|
||||
app:min="0"
|
||||
app:max="100"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__sound_volume__label"
|
||||
app:seekBarIncrement="1"
|
||||
app:unit="%"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="looknfeel__vibration_enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__vibration_enabled__label"/>
|
||||
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="-1"
|
||||
app:systemDefaultValue="-1"
|
||||
app:systemDefaultValueText="@string/settings__system_default"
|
||||
app:dependency="looknfeel__vibration_enabled"
|
||||
app:key="looknfeel__vibration_strength"
|
||||
app:min="0"
|
||||
app:max="100"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__vibration_strength__label"
|
||||
app:seekBarIncrement="1"
|
||||
app:unit="%"/>
|
||||
|
||||
<dev.patrickgold.florisboard.settings.components.DialogSeekBarPreference
|
||||
app:allowDividerAbove="false"
|
||||
android:defaultValue="300"
|
||||
app:key="looknfeel__long_press_delay"
|
||||
app:min="100"
|
||||
app:max="700"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__looknfeel__long_press_delay__label"
|
||||
app:seekBarIncrement="10"
|
||||
app:unit=" ms"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,14 +1,225 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="floris_light"
|
||||
app:entries="@array/pref__theme__name__entries"
|
||||
app:entryValues="@array/pref__theme__name__values"
|
||||
app:key="theme__name"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__theme__name__label"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<dev.patrickgold.florisboard.settings.components.ThemePresetSelectorPreference
|
||||
app:key="theme__preset"
|
||||
app:title="@string/settings__theme__preset_title"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_window"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
app:key="theme__colorPrimary"
|
||||
app:title="@string/pref__theme__colorPrimary_title"
|
||||
app:summary="@string/pref__theme__colorPrimary_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
app:key="theme__colorPrimaryDark"
|
||||
app:title="@string/pref__theme__colorPrimaryDark_title"
|
||||
app:summary="@string/pref__theme__colorPrimaryDark_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
app:key="theme__colorAccent"
|
||||
app:title="@string/pref__theme__colorAccent_title"
|
||||
app:summary="@string/pref__theme__colorAccent_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="theme__navBarIsLight"
|
||||
app:title="@string/pref__theme__navBarIsLight_title"
|
||||
app:summary="@string/pref__theme__navBarIsLight_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__navBarColor"
|
||||
android:title="@string/pref__theme__navBarColor_title"
|
||||
android:summary="@string/pref__theme__navBarColor_summary"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_keyboard"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyboard_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_key"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__key_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__key_bgColorPressed"
|
||||
android:title="@string/settings__theme__background_pressed"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__key_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_key_enter"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyEnter_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyEnter_bgColorPressed"
|
||||
android:title="@string/settings__theme__background_pressed"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyEnter_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_key_shift"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyShift_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyShift_bgColorPressed"
|
||||
android:title="@string/settings__theme__background_pressed"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyShift_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyShift_fgColorCapsLock"
|
||||
android:title="@string/settings__theme__foreground_capslock"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_key_popup"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyPopup_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyPopup_bgColorActive"
|
||||
android:title="@string/settings__theme__background_active"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__keyPopup_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_media"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__media_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__media_fgColorAlt"
|
||||
android:title="@string/settings__theme__foreground_alt"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_one_handed"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__oneHanded_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_one_handed_button"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__oneHandedButton_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_smartbar"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__smartbar_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"
|
||||
app:cpv_showAlphaSlider="true"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__smartbar_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"
|
||||
app:cpv_showAlphaSlider="true"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__smartbar_fgColorAlt"
|
||||
android:title="@string/settings__theme__foreground_alt"
|
||||
app:iconSpaceReserved="false"
|
||||
app:cpv_showAlphaSlider="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings__theme__group_smartbar_button"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__smartbarButton_bgColor"
|
||||
android:title="@string/settings__theme__background"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
||||
android:key="theme__smartbarButton_fgColor"
|
||||
android:title="@string/settings__theme__foreground"
|
||||
app:iconSpaceReserved="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
48
app/src/main/res/xml/prefs_typing.xml
Normal file
48
app/src/main/res/xml/prefs_typing.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
app:key="suggestion__enabled"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__enabled__label"
|
||||
app:summary="@string/pref__suggestion__enabled__summary"/>
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="clipboard_cursor_tools"
|
||||
app:entries="@array/pref__suggestion__show_instead__entries"
|
||||
app:entryValues="@array/pref__suggestion__show_instead__values"
|
||||
app:key="suggestion__show_instead"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__show_instead__label"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:dependency="suggestion__enabled"
|
||||
app:key="suggestion__use_prev_words"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__suggestion__use_pref_words__label"
|
||||
app:summary="@string/pref__suggestion__use_pref_words__summary"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
app:key="correction__double_space_period"
|
||||
app:iconSpaceReserved="false"
|
||||
app:title="@string/pref__correction__double_space_period__label"
|
||||
app:summary="@string/pref__correction__double_space_period__summary"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -36,7 +36,7 @@ class SubtypeManagerTest {
|
||||
|
||||
@Test
|
||||
fun testSubtypesGetter() {
|
||||
doReturn("1/de-DE/qwertz;23/fr-CH/swiss_french").`when`(prefs.keyboard).subtypes
|
||||
doReturn("1/de-DE/qwertz;23/fr-CH/swiss_french").`when`(prefs.localization).subtypes
|
||||
assertThat(subtypeManagerUnderTest.subtypes, `is`(listOf(
|
||||
Subtype(1, Locale("de", "DE"), "qwertz"),
|
||||
Subtype(23, Locale("fr", "CH"), "swiss_french")
|
||||
@@ -49,38 +49,38 @@ class SubtypeManagerTest {
|
||||
Subtype(1, Locale("de", "DE"), "qwertz"),
|
||||
Subtype(23, Locale("fr", "CH"), "swiss_french")
|
||||
)
|
||||
verify(prefs.keyboard).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
verify(prefs.localization).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddSubtype() {
|
||||
doReturn("1/de-DE/qwertz;23/fr-CH/swiss_french").`when`(prefs.keyboard).subtypes
|
||||
doReturn("1/de-DE/qwertz;23/fr-CH/swiss_french").`when`(prefs.localization).subtypes
|
||||
|
||||
// First test adding a non-existing subtype to the list.
|
||||
val locale = Locale("pt", "PT")
|
||||
val layout = "qwerty"
|
||||
val id = locale.hashCode() + layout.hashCode()
|
||||
subtypeManagerUnderTest.addSubtype(locale, layout)
|
||||
verify(prefs.keyboard).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french;$id/pt-PT/qwerty"
|
||||
verify(prefs.localization).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french;$id/pt-PT/qwerty"
|
||||
|
||||
// Now test to add the same subtype twice. It should work fine for the first call but should fail
|
||||
// on the second call.
|
||||
val locale2 = Locale("pt", "PT")
|
||||
val layout2 = "qwerty"
|
||||
val id2 = locale.hashCode() + layout.hashCode()
|
||||
doReturn("").`when`(prefs.keyboard).subtypes
|
||||
doReturn("").`when`(prefs.localization).subtypes
|
||||
assertThat(subtypeManagerUnderTest.addSubtype(locale2, layout2), `is`(true))
|
||||
doReturn("$id2/pt-PT/qwerty").`when`(prefs.keyboard).subtypes
|
||||
doReturn("$id2/pt-PT/qwerty").`when`(prefs.localization).subtypes
|
||||
assertThat(subtypeManagerUnderTest.addSubtype(locale2, layout2), `is`(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetActiveSubtype() {
|
||||
doReturn("42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french")
|
||||
.`when`(prefs.keyboard).subtypes
|
||||
.`when`(prefs.localization).subtypes
|
||||
|
||||
// First test activeSubtypeId pointing to existing subtype in list
|
||||
doReturn(1).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn(1).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.getActiveSubtype(),
|
||||
`is`(Subtype(1, Locale("de", "DE"), "qwertz"))
|
||||
@@ -88,28 +88,28 @@ class SubtypeManagerTest {
|
||||
|
||||
// Now test that the first subtype in the list is returned if activeSubtypeId points to a
|
||||
// non-existent subtype and that activeSubtypeId value is updated accordingly.
|
||||
doReturn(99).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn(99).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.getActiveSubtype(),
|
||||
`is`(Subtype(42, Locale("en", "CA"), "qwerty"))
|
||||
)
|
||||
verify(prefs.keyboard).activeSubtypeId = 42
|
||||
verify(prefs.localization).activeSubtypeId = 42
|
||||
|
||||
// Now test that the subtype list is empty. null should be returned and activeSubtypeId
|
||||
// should be returned.
|
||||
doReturn("").`when`(prefs.keyboard).subtypes
|
||||
doReturn(99).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn("").`when`(prefs.localization).subtypes
|
||||
doReturn(99).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.getActiveSubtype(),
|
||||
`is`(nullValue())
|
||||
)
|
||||
verify(prefs.keyboard).activeSubtypeId = -1
|
||||
verify(prefs.localization).activeSubtypeId = -1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetSubtypeById() {
|
||||
doReturn("42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french")
|
||||
.`when`(prefs.keyboard).subtypes
|
||||
.`when`(prefs.localization).subtypes
|
||||
|
||||
// First test a existing subtype for given id.
|
||||
assertThat(
|
||||
@@ -127,67 +127,67 @@ class SubtypeManagerTest {
|
||||
@Test
|
||||
fun testModifySubtypeWithSameId() {
|
||||
doReturn("42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french")
|
||||
.`when`(prefs.keyboard).subtypes
|
||||
.`when`(prefs.localization).subtypes
|
||||
|
||||
// First test a subtype with id that does not exist in subtype list.
|
||||
subtypeManagerUnderTest.modifySubtypeWithSameId(
|
||||
Subtype(99, Locale("de", "AT"), "qwertz")
|
||||
)
|
||||
verify(prefs.keyboard).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
verify(prefs.localization).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
|
||||
// Now test a subtype with id that does exist in subtype list.
|
||||
subtypeManagerUnderTest.modifySubtypeWithSameId(
|
||||
Subtype(23, Locale("de", "AT"), "qwertz")
|
||||
)
|
||||
verify(prefs.keyboard).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/de-AT/qwertz"
|
||||
verify(prefs.localization).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/de-AT/qwertz"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoveSubtype() {
|
||||
doReturn("42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french")
|
||||
.`when`(prefs.keyboard).subtypes
|
||||
.`when`(prefs.localization).subtypes
|
||||
|
||||
// First test that subtype is removed from list.
|
||||
subtypeManagerUnderTest.removeSubtype(
|
||||
Subtype(42, Locale("en", "CA"), "qwerty")
|
||||
)
|
||||
verify(prefs.keyboard).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
verify(prefs.localization).subtypes = "1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
|
||||
// Now test that list stays untouched when attempting to remove non-existent subtype.
|
||||
subtypeManagerUnderTest.removeSubtype(
|
||||
Subtype(99, Locale("es", "ES"), "spanish")
|
||||
)
|
||||
verify(prefs.keyboard).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
verify(prefs.localization).subtypes = "42/en-CA/qwerty;1/de-DE/qwertz;23/fr-CH/swiss_french"
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSwitchToNextSubtype() {
|
||||
doReturn("1/en-CA/qwerty;2/de-DE/qwertz;3/fr-CH/swiss_french")
|
||||
.`when`(prefs.keyboard).subtypes
|
||||
.`when`(prefs.localization).subtypes
|
||||
|
||||
// First test that next subtype is returned from existing id.
|
||||
doReturn(2).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn(2).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.switchToNextSubtype(),
|
||||
`is`(Subtype(3, Locale("fr", "CH"), "swiss_french"))
|
||||
)
|
||||
verify(prefs.keyboard).activeSubtypeId = 3
|
||||
verify(prefs.localization).activeSubtypeId = 3
|
||||
|
||||
// Now test that second subtype is selected when id points to non-existent.
|
||||
doReturn(99).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn(99).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.switchToNextSubtype(),
|
||||
`is`(Subtype(2, Locale("de", "DE"), "qwertz"))
|
||||
)
|
||||
verify(prefs.keyboard).activeSubtypeId = 2
|
||||
verify(prefs.localization).activeSubtypeId = 2
|
||||
|
||||
// Now test that null / -1 is used when list is empty.
|
||||
doReturn("").`when`(prefs.keyboard).subtypes
|
||||
doReturn(99).`when`(prefs.keyboard).activeSubtypeId
|
||||
doReturn("").`when`(prefs.localization).subtypes
|
||||
doReturn(99).`when`(prefs.localization).activeSubtypeId
|
||||
assertThat(
|
||||
subtypeManagerUnderTest.switchToNextSubtype(),
|
||||
`is`(nullValue())
|
||||
)
|
||||
verify(prefs.keyboard).activeSubtypeId = -1
|
||||
verify(prefs.localization).activeSubtypeId = -1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,21 +12,21 @@ class TestablePrefHelper(
|
||||
private val context: Context,
|
||||
val shared: SharedPreferences = mock(SharedPreferences::class.java)
|
||||
) {
|
||||
val instance: PrefHelper = mock(PrefHelper::class.java)
|
||||
val advanced: PrefHelper.Advanced = mock(PrefHelper.Advanced::class.java)
|
||||
val correction: PrefHelper.Correction = mock(PrefHelper.Correction::class.java)
|
||||
val internal: PrefHelper.Internal = mock(PrefHelper.Internal::class.java)
|
||||
val keyboard: PrefHelper.Keyboard = mock(PrefHelper.Keyboard::class.java)
|
||||
val looknfeel: PrefHelper.Looknfeel = mock(PrefHelper.Looknfeel::class.java)
|
||||
val suggestion: PrefHelper.Suggestion = mock(PrefHelper.Suggestion::class.java)
|
||||
val theme: PrefHelper.Theme = mock(PrefHelper.Theme::class.java)
|
||||
val instance: PrefHelper = mock(PrefHelper::class.java)
|
||||
val advanced: PrefHelper.Advanced = mock(PrefHelper.Advanced::class.java)
|
||||
val correction: PrefHelper.Correction = mock(PrefHelper.Correction::class.java)
|
||||
val internal: PrefHelper.Internal = mock(PrefHelper.Internal::class.java)
|
||||
val localization: PrefHelper.Localization = mock(PrefHelper.Localization::class.java)
|
||||
val keyboard: PrefHelper.Keyboard = mock(PrefHelper.Keyboard::class.java)
|
||||
val suggestion: PrefHelper.Suggestion = mock(PrefHelper.Suggestion::class.java)
|
||||
val theme: PrefHelper.Theme = mock(PrefHelper.Theme::class.java)
|
||||
|
||||
init {
|
||||
doReturn(advanced).`when`(instance).advanced
|
||||
doReturn(correction).`when`(instance).correction
|
||||
doReturn(internal).`when`(instance).internal
|
||||
doReturn(localization).`when`(instance).localization
|
||||
doReturn(keyboard).`when`(instance).keyboard
|
||||
doReturn(looknfeel).`when`(instance).looknfeel
|
||||
doReturn(suggestion).`when`(instance).suggestion
|
||||
doReturn(theme).`when`(instance).theme
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.72'
|
||||
ext.kotlin_version = '1.4.10'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
9
fastlane/metadata/android/en-US/changelogs/12.txt
Normal file
9
fastlane/metadata/android/en-US/changelogs/12.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
- Add theming capability
|
||||
- Preset selection
|
||||
- Modify each color individually
|
||||
- Themes are now defined in assets/ime/theme/ as a json file, which allows for a more convenient way to add custom themes (base for future feature)
|
||||
- Restructure settings naming scheme and structure
|
||||
- Add back button functionality in settings
|
||||
- Add clipboard/cursor tools
|
||||
- Improve layout measurement and height behaviour
|
||||
- Fix enter action key bug (#17)
|
||||
4
fastlane/metadata/android/en-US/changelogs/13.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/13.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
- Add gestures & scrolling space bar
|
||||
- Swipe up / down / left / right
|
||||
- Swipe left from delete key (defaults to deleting current word)
|
||||
- Moving your finger along the space bar will move the cursor
|
||||
@@ -1,17 +1,12 @@
|
||||
FlorisBoard is an open-source keyboard aimed at providing you with an easy way to type while respecting your privacy.
|
||||
|
||||
Note: This project is currently in alpha stage. If you want to see a feature being implemented or want to report a bug, please visit this project's repository (linked in the end of the description) on GitHub and file an issue. This helps making FlorisBoard even better! Thank you!
|
||||
|
||||
Currently implemented and fully working features:
|
||||
* Latin keyboard layouts
|
||||
* QWERTY, QWERTZ, AZERTY, Spanish, Norwegian, Swedish/Finnish, Danish, Icelandic and Swiss. More coming in future releases
|
||||
* Easy switching between languages/layouts by defining subtypes in the settings
|
||||
* Keyboard layouts for typing in a (phone) number
|
||||
* Special characters input
|
||||
* Emoji/Emoticon keyboard
|
||||
* One-handed/compact mode for easier typing on large devices
|
||||
* Light and dark theme for the input UI (more themes will come in future releases)
|
||||
* Customization of key press sound/vibration
|
||||
|
||||
Source code (Apache 2.0) and project management:
|
||||
https://github.com/florisboard/florisboard
|
||||
<p><i>FlorisBoard</i> is an open-source keyboard aimed at providing you with an easy way to type while respecting your privacy.</p>
|
||||
<p><b>Note:</b> This project is currently in alpha stage. If you want to see a feature being implemented or want to report a bug, please visit this project's repository (linked in the end of the description) on GitHub and file an issue. This helps making FlorisBoard even better! Thank you!</p>
|
||||
<p><br><b>Currently implemented and fully working features:</b></p><ul>
|
||||
<li>Latin keyboard layouts</li>
|
||||
<li>QWERTY, QWERTZ, AZERTY, Spanish, Norwegian, Swedish/Finnish, Danish, Icelandic and Swiss. More coming in future releases</li>
|
||||
<li>Easy switching between languages/layouts by defining subtypes in the settings</li>
|
||||
<li>Keyboard layouts for typing in a (phone) number</li>
|
||||
<li>Special characters input</li>
|
||||
<li>Emoji/Emoticon keyboard</li>
|
||||
<li>One-handed/compact mode for easier typing on large devices</li>
|
||||
<li>Light and dark theme for the input UI (more themes will come in future releases)</li>
|
||||
<li>Customization of key press sound/vibration</li></ul>
|
||||
9
fastlane/metadata/android/it/changelogs/12.txt
Normal file
9
fastlane/metadata/android/it/changelogs/12.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
- Aggiunta di capacità di tematizzazione
|
||||
- Selezione delle preimpostazioni
|
||||
- Modificare ogni colore individualmente
|
||||
- I temi sono ora definiti in asset/imo/tema/ come un file json, che permette un modo più conveniente per aggiungere temi personalizzati (base per la funzione futura)
|
||||
- Schema di denominazione e struttura delle impostazioni della ristrutturazione
|
||||
- Aggiungere la funzionalità del pulsante indietro nelle impostazioni
|
||||
- Aggiunta di strumenti per appunti/cursori
|
||||
- Migliorare la misurazione del layout e il comportamento in altezza
|
||||
- Correggere il bug del tasto azione (#17)
|
||||
4
fastlane/metadata/android/it/changelogs/13.txt
Normal file
4
fastlane/metadata/android/it/changelogs/13.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
- Aggiungi gesti e barra spaziatrice a scorrimento
|
||||
- Scorri su / giù / sinistra / destra
|
||||
- Passare il dito a sinistra dal tasto di cancellazione (default per cancellare la parola corrente)
|
||||
- Muovendo il dito lungo la barra spaziatrice, il cursore si sposta
|
||||
@@ -1,17 +1,12 @@
|
||||
FlorisBoard è una tastiera open source mirata a fornirti un modo semplice per digitare nel rispetto della tua privacy.
|
||||
|
||||
Nota: questo progetto è attualmente in fase alpha. Se desideri vedere una funzionalità implementata o segnalare un bug, visita il repository di questo progetto (link alla fine della descrizione) su GitHub e segnala un problema. Questo aiuta a rendere FlorisBoard ancora migliore! Grazie!
|
||||
|
||||
Funzionalità attualmente implementate e completamente funzionanti:
|
||||
* Layout della tastiera
|
||||
* QWERTY, QWERTZ, AZERTY, Spagnolo, norvegese, svedese,finlandese, danese, islandese e svizzero. Altre novità in arrivo nelle versioni future
|
||||
* Facile passaggio tra lingue / layout nelle impostazioni
|
||||
* Layout di tastiera tipo tastierino telefonico per digitazione di un numero
|
||||
* Inserimento di caratteri speciali
|
||||
* Tastiera Emoji/Emoticon
|
||||
* Modalità con una sola mano per digitare più facilmente su dispositivi di grandi dimensioni
|
||||
* Tema chiaro e scuro per l'interfaccia utente e per tastiera (altri temi arriveranno nelle versioni future)
|
||||
* Personalizzazione del suono / vibrazione della pressione dei tasti
|
||||
|
||||
Codice sorgente (Apache 2.0) e gestione del progetto:
|
||||
https://github.com/florisboard/florisboard
|
||||
<p><i>FlorisBoard</i> è una tastiera open source mirata a fornirti un modo semplice per digitare nel rispetto della tua privacy.</p>
|
||||
<p><b>Nota:</b> questo progetto è attualmente in fase alpha. Se desideri vedere una funzionalità implementata o segnalare un bug, visita il repository di questo progetto (link alla fine della descrizione) su GitHub e segnala un problema. Questo aiuta a rendere FlorisBoard ancora migliore! Grazie!</p>
|
||||
<p><br><b>Funzionalità attualmente implementate e completamente funzionanti:</b></p><ul>
|
||||
<li>Layout della tastiera</li>
|
||||
<li>QWERTY, QWERTZ, AZERTY, Spagnolo, norvegese, svedese,finlandese, danese, islandese e svizzero. Altre novità in arrivo nelle versioni future</li>
|
||||
<li>Facile passaggio tra lingue / layout nelle impostazioni</li>
|
||||
<li>Layout di tastiera tipo tastierino telefonico per digitazione di un numero</li>
|
||||
<li>Inserimento di caratteri speciali</li>
|
||||
<li>Tastiera Emoji/Emoticon</li>
|
||||
<li>Modalità con una sola mano per digitare più facilmente su dispositivi di grandi dimensioni</li>
|
||||
<li>Tema chiaro e scuro per l'interfaccia utente e per tastiera (altri temi arriveranno nelle versioni future)</li>
|
||||
<li>Personalizzazione del suono / vibrazione della pressione dei tasti</li></ul>
|
||||
Reference in New Issue
Block a user