Compare commits

...

20 Commits

Author SHA1 Message Date
Patrick Goldinger
a25501d63c Release v0.2.0 2020-10-05 22:33:15 +02:00
Patrick Goldinger
e9a5f2161c Fix bugs in setup and settings / Change values for suggestion prefs 2020-10-05 22:25:17 +02:00
Patrick Goldinger
6f12f22937 Fix #17
Fix bug where the action defined for the enter key did not behave as
intended when the supplied action has flags set. Some apps ignored these
and worked flawlessly (Reddit, Chrome, Firefox, ...) while other
apps didn't behave that well (Twitter, F-Droid, ...).
2020-10-05 21:05:28 +02:00
Patrick Goldinger
25054ef679 Improve layout measurement and height factor calculation
- Height factor is now being used in the root InputView rather than
  repeatedly recalculating it on a per KeyboardView basis.
- Keyboard views had an empty space when in one-handed mode.
- Icon size in Smartbar is still messed up, but will be resolved
  when overhauling the Smartbar.
- Media layout may contain empty spaces, will be addressed when
  overhauling the media context UI.
2020-09-22 19:37:51 +02:00
Patrick Goldinger
3af17f99fe Add back Advanced Settings / Fix back button logic in Settings 2020-09-17 20:10:49 +02:00
Patrick Goldinger
06664ff521 Merge pull request #15 from florisboard/feat-theme-customization
Add theme customization feature
2020-09-16 20:04:30 +02:00
Patrick Goldinger
fde0749a3b Fix unhandled exceptions / Improve core layout view
- When detaching an InputView from the window, it will throw an
  exception when it is flipping while being detached. This has been
  fixed by extending the class and catching the exception.
- The core layout now has InputWindowView as the root and InputView
  as the real input view. While technically nothing has changed here,
  due to the better naming scheme it is more clearer now.
- Fix theme colors in both Floris Day and Night.
- Move ime.editing package into ime.text
2020-09-16 19:40:01 +02:00
Patrick Goldinger
c061e15263 Change used color picker pref / Fix bugs 2020-09-13 19:15:04 +02:00
Patrick Goldinger
7256c597c2 Add theme preset selector dialog / Add Floris Night theme
- Theme preset can now be selected and will be applied.
- Floris Night theme re-added (was previously defined in
  res/values/theme.xml)
- Various bug fixes / feature enhancement regarding themes
  and preferences.
2020-09-11 20:23:04 +02:00
Patrick Goldinger
2f9d32027b Add own fragment for theme prefs
- Advanced settings fragment is currently not accessible, will change
  at a later stage
- Partial support for one-handed colors
- Add method to write a Theme class to prefs
- Base theme now only sets the absolute minimum values and fallbacks
- Base Theme comes in Day and Night variant, is dependent on
  isNightTheme flag in <theme>.json
2020-09-09 21:01:24 +02:00
Patrick Goldinger
538912edc2 Add media context theme support / Fix various bugs 2020-09-04 19:45:54 +02:00
Patrick Goldinger
ee5ff81ee8 Improve applying pref color to View 2020-09-02 18:38:45 +02:00
Patrick Goldinger
d873dc54c5 Add theme prefs for KeyPopup, Smartbar, EditingLayout and NavBar 2020-09-01 20:10:44 +02:00
Patrick Goldinger
1e967463de Add theme prefs for core KeyboardView and KeyView 2020-08-31 21:09:24 +02:00
Patrick Goldinger
5c084a10dc Add Theme core class and sample theme file
- Theme class is responsible for parsing / packing a theme.
- The sample theme file will be the keyboards default and fallback theme
  in the future, with slight modifications.
2020-08-31 18:22:01 +02:00
Patrick Goldinger
f158a9deb3 Update Kotlin to 1.4.0 / Update other packages as well 2020-08-27 23:24:11 +02:00
Patrick Goldinger
66d328293c Merge pull request #14 from florisboard/feat-new-settings-screen
Revamp settings screen
2020-08-27 22:23:59 +02:00
Patrick Goldinger
e33b652bb3 Add localization and theme prefs to fragments / Improve layout
- Improve layout of list_item.xml (adheres more to predefined standard
  values now)
- Add localization card to typing fragment.
- Add theme card to keyboard fragment (will get revision and own sub-fragment)
  with next feature (theme customization).
2020-08-27 21:51:47 +02:00
Patrick Goldinger
65d8c02b95 Restructure settings naming scheme and structure (frontend)
- Home, Localization and Theme need a better UI, only temporary for now.
2020-08-26 23:49:10 +02:00
Patrick Goldinger
bd090132eb Restructure settings naming scheme and structure (backend)
- No setting added or removed, only renamed and possibly moved within the
  settings structure.
- Strings have also been updated (en, it-IT)
2020-08-26 22:47:43 +02:00
83 changed files with 2554 additions and 984 deletions

View File

@@ -69,7 +69,7 @@ timeline for this, but I aim for the 0.2.0 or 0.3.0 release.
* [x] Preferences screen
* [x] Customize look and behaviour of keyboard (currently only
light/dark theme)
* [ ] Theme customization
* [x] Theme customization
* [ ] Theme import/export (?)
* [x] Subtype selection (language/layout)
* [x] Keyboard behaviour preferences
@@ -97,13 +97,15 @@ timeline for this, but I aim for the 0.2.0 or 0.3.0 release.
Note: (?) = not sure if it will be implemented
## Used libraries and icons
## 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
```

View File

@@ -10,8 +10,8 @@ android {
applicationId "dev.patrickgold.florisboard"
minSdkVersion 23
targetSdkVersion 29
versionCode 11
versionName "0.1.2"
versionCode 12
versionName "0.2.0"
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'
}

View File

@@ -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"

View 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"
}
}
}

View 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"
}
}
}

View File

@@ -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.

View File

@@ -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
@@ -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)
@@ -427,26 +454,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 +484,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 +548,7 @@ class FlorisBoard : InputMethodService() {
candidatesEnd: Int
) {}
fun onApplyThemeAttributes() {}
fun onSubtypeChanged(newSubtype: Subtype) {}
}

View File

@@ -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()
}
}
}

View File

@@ -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))
}
}

View File

@@ -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)
}

View File

@@ -39,9 +39,8 @@ class PrefHelper(
val correction = Correction(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 +110,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 +141,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 +184,41 @@ class PrefHelper(
}
/**
* Wrapper class for internal preferences.
* 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 +226,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 +245,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 +264,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 +302,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)
}
}

View File

@@ -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,7 +212,7 @@ class SubtypeManager(
}
}
subtypes = subtypeList
if (subtypeToRemove.id == prefs.keyboard.activeSubtypeId) {
if (subtypeToRemove.id == prefs.localization.activeSubtypeId) {
getActiveSubtype()
}
}
@@ -238,7 +238,7 @@ class SubtypeManager(
if (triggerNextSubtype) {
newActiveSubtype = subtypeList[0]
}
prefs.keyboard.activeSubtypeId = when (newActiveSubtype) {
prefs.localization.activeSubtypeId = when (newActiveSubtype) {
null -> -1
else -> newActiveSubtype.id
}

View File

@@ -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
}

View File

@@ -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))
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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) {

View File

@@ -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)
}
}

View File

@@ -30,7 +30,7 @@ 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.key.KeyCode
import dev.patrickgold.florisboard.ime.text.key.KeyData
import dev.patrickgold.florisboard.ime.text.key.KeyType
@@ -137,8 +137,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 +178,6 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
osHandler.removeCallbacksAndMessages(null)
layoutManager.onDestroy()
smartbarManager.onDestroy()
florisboard.removeEventListener(this)
instance = null
}
@@ -483,25 +480,24 @@ class TextInputManager private constructor() : CoroutineScope by MainScope(),
*/
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()
}
/**

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -33,10 +33,10 @@ 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.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.*
/**
@@ -60,6 +60,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
@@ -174,8 +175,8 @@ class KeyView(
event ?: return false
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
florisboard?.prefs?.popup?.let {
if (it.enabled){
florisboard?.prefs?.keyboard?.let {
if (it.popupEnabled){
keyboardView.popupManager.show(this)
}
}
@@ -194,7 +195,7 @@ class KeyView(
}
}, 500, 50)
}
val delayMillis = keyboardView.prefs.looknfeel.longPressDelay
val delayMillis = prefs.keyboard.longPressDelay
if (osHandler == null) {
osHandler = Handler()
}
@@ -337,20 +338,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 +449,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 +463,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 +497,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 +507,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 +569,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

View File

@@ -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
@@ -34,23 +31,24 @@ import dev.patrickgold.florisboard.ime.core.PrefHelper
import dev.patrickgold.florisboard.ime.popup.KeyPopupManager
import dev.patrickgold.florisboard.ime.text.key.KeyView
import dev.patrickgold.florisboard.ime.text.layout.ComputedLayoutData
import dev.patrickgold.florisboard.util.getColorFromAttr
import kotlin.math.roundToInt
/**
* Manages the layout of the keyboard, key measurement, key selection and all touch events.
* Supports multi touch events.
* 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.
*
* TODO: Implement swipe gesture support
*
* @property florisboard Reference to instance of core class [FlorisBoard].
*/
class KeyboardView : LinearLayout {
class KeyboardView : LinearLayout, FlorisBoard.EventListener {
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 +56,20 @@ 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()
var isPreviewMode: Boolean = false
var popupManager = KeyPopupManager<KeyboardView, KeyView>(this)
lateinit var prefs: PrefHelper
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) {
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)
}
/**
@@ -237,32 +234,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 +295,4 @@ class KeyboardView : LinearLayout {
}
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
colorDrawable.color = getColorFromAttr(context, R.attr.keyboard_bgColor)
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}
}
}
}
}
}

View 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
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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
}
}

View File

@@ -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()
}
}

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -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()
}
}

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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)
}
}
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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>

View 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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"/>

View File

@@ -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"/>

View File

@@ -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

View File

@@ -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"

View File

@@ -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>

View 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>

View 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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -32,51 +32,54 @@
<string name="settings__menu_help">Aiuto &amp; feedback</string>
<string name="settings__navigation__home">Home</string>
<string name="settings__navigation__keyboard">Tastiera</string>
<string name="settings__navigation__looknfeel">Aspetto &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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>

View File

@@ -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>
@@ -49,13 +49,4 @@
<item>number_row</item>
<item>clipboard_cursor_tools</item>
</string-array>
<string-array name="pref__theme__name__entries">
<item>Floris Light</item>
<item>Floris Dark</item>
</string-array>
<string-array name="pref__theme__name__values">
<item>floris_light</item>
<item>floris_dark</item>
</string-array>
</resources>

View File

@@ -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">

View File

@@ -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>

View File

@@ -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 &amp; feedback</string>
<string name="settings__navigation__home">Home</string>
<string name="settings__navigation__keyboard">Keyboard</string>
<string name="settings__navigation__looknfeel">Look &amp; 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 &amp; 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 &amp; 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 &amp; 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,10 @@
<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 &amp; 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 &amp; Glide typing</string>
<string name="settings__advanced__title">Advanced</string>
<string name="pref__advanced__settings_theme__label">Settings theme</string>

View File

@@ -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">

View File

@@ -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">

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,9 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
app:title="Not yet implemented..."
app:iconSpaceReserved="false"/>
</PreferenceScreen>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -1,7 +1,7 @@
// 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.0'
repositories {
google()
jcenter()