Skip to content

Implement Translate Mode Keyboard Switch #359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 11, 2025
18 changes: 14 additions & 4 deletions app/src/main/java/be/scri/helpers/HintUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ object HintUtils {
fun getPromptText(
currentState: GeneralKeyboardIME.ScribeState,
language: String,
context: Context,
): String =
when (currentState) {
GeneralKeyboardIME.ScribeState.TRANSLATE -> getTranslationPrompt(language)
GeneralKeyboardIME.ScribeState.TRANSLATE -> getTranslationPrompt(language, context)
GeneralKeyboardIME.ScribeState.CONJUGATE -> getConjugationPrompt(language)
GeneralKeyboardIME.ScribeState.PLURAL -> getPluralPrompt(language)
else -> ""
Expand All @@ -140,7 +141,10 @@ object HintUtils {
* @param language The language code (e.g., "English", "French").
* @return The translation prompt text for the given language.
*/
private fun getTranslationPrompt(language: String): String {
private fun getTranslationPrompt(
language: String,
context: Context,
): String {
val languageShorthand =
mapOf(
"English" to "en",
Expand All @@ -152,8 +156,14 @@ object HintUtils {
"Spanish" to "es",
"Swedish" to "sv",
)
val shorthand = languageShorthand[language] ?: "en" // default fallback to "en"
return "en -> $shorthand"
val preferredLanguage =
PreferencesHelper.getPreferredTranslationLanguage(
context = context,
language = language,
)
val keyboardLanguage = languageShorthand[preferredLanguage]
val sourceLanguage = languageShorthand[language] ?: "en" // default fallback to "en"
return "$keyboardLanguage -> $sourceLanguage"
}

/**
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/be/scri/helpers/KeyHandler.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
@file:Suppress("ktlint:standard:kdoc")

package be.scri.helpers

import android.util.Log
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/java/be/scri/helpers/PreferencesHelper.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
@file:Suppress("ktlint:standard:kdoc")

package be.scri.helpers

Expand Down Expand Up @@ -355,4 +356,23 @@ object PreferencesHelper {
val isEnabled = sharedPref.getBoolean(getLanguageSpecificPreferenceKey(EMOJI_SUGGESTIONS, language), true)
return isEnabled
}

/**
* Retrieves the preferred translation language for a given language.
*
* @param context The application context.
* @param language The language for which to get the preferred translation language.
*
* @return The preferred translation language.
* */
fun getPreferredTranslationLanguage(
context: Context,
language: String,
): String? {
val prefs = context.getSharedPreferences("app_preferences", MODE_PRIVATE)
return prefs.getString(
PreferencesHelper.getLanguageSpecificPreferenceKey(TRANSLATION_SOURCE, language),
"English",
)
}
}
92 changes: 74 additions & 18 deletions app/src/main/java/be/scri/services/GeneralKeyboardIME.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import be.scri.helpers.PERIOD_ON_DOUBLE_TAP
import be.scri.helpers.PreferencesHelper
import be.scri.helpers.PreferencesHelper.getIsDarkModeOrNot
import be.scri.helpers.PreferencesHelper.getIsEmojiSuggestionsEnabled
import be.scri.helpers.PreferencesHelper.getPreferredTranslationLanguage
import be.scri.helpers.SHIFT_OFF
import be.scri.helpers.SHIFT_ON_ONE_CHAR
import be.scri.helpers.SHIFT_ON_PERMANENT
Expand Down Expand Up @@ -460,7 +461,7 @@ abstract class GeneralKeyboardIME(
private fun updateCommandBarHintAndPrompt(isUserDarkMode: Boolean? = null) {
val commandBarButton = keyboardBinding.commandBar
val hintMessage = HintUtils.getCommandBarHint(currentState, language)
val promptText = HintUtils.getPromptText(currentState, language)
val promptText = HintUtils.getPromptText(currentState, language, context = this)
val promptTextView = keyboardBinding.promptText
promptTextView.text = promptText
commandBarButton.hint = hintMessage
Expand Down Expand Up @@ -519,6 +520,8 @@ abstract class GeneralKeyboardIME(
setupIdleView()
handleTextSizeForSuggestion(binding)
initializeEmojiButtons()
keyboard = KeyboardBase(this, getKeyboardLayoutXML(), enterKeyType)
keyboardView!!.setKeyboard(keyboard!!)
updateButtonVisibility(emojiAutoSuggestionEnabled)
updateButtonText(emojiAutoSuggestionEnabled, autoSuggestEmojis)
}
Expand All @@ -537,37 +540,64 @@ abstract class GeneralKeyboardIME(
* to have toolbar interface, allowing the user to interact with the toolbar.
*/
private fun switchToToolBar() {
this.keyboardBinding = initializeKeyboardBinding()
keyboardBinding = initializeKeyboardBinding()
val keyboardHolder = keyboardBinding.root

setupToolBarTheme(keyboardBinding)
handleTextSizeForSuggestion(binding)
var isUserDarkMode = getIsDarkModeOrNot(applicationContext)
binding.translateBtn.textSize = SUGGESTION_SIZE
when (isUserDarkMode) {
true -> {
keyboardBinding.topKeyboardDivider.setBackgroundColor(getColor(R.color.special_key_dark))
val color = ContextCompat.getColorStateList(this, R.color.light_key_color)
keyboardBinding.scribeKey.foregroundTintList = color

val isDarkMode = getIsDarkModeOrNot(applicationContext)
updateToolBarTheme(isDarkMode)

handleModeChange(keyboardSymbols, keyboardView, this)

val keyboardXmlId =
if (currentState == ScribeState.TRANSLATE) {
val language = getPreferredTranslationLanguage(this, language)
baseKeyboardOfAnyLanguage(language)
} else {
getKeyboardLayoutXML()
}

false -> {
keyboardBinding.topKeyboardDivider.setBackgroundColor(getColor(R.color.special_key_light))
val colorLight = ContextCompat.getColorStateList(this, R.color.light_key_text_color)
keyboardBinding.scribeKey.foregroundTintList = colorLight
keyboard = KeyboardBase(this, keyboardXmlId, enterKeyType)
keyboardView =
keyboardBinding.keyboardView.apply {
setKeyboard(keyboard!!)
mOnKeyboardActionListener = this@GeneralKeyboardIME
}
}
handleModeChange(keyboardSymbols, keyboardView, this)
keyboardView = keyboardBinding.keyboardView
keyboardView!!.setKeyboard(keyboard!!)
keyboardView!!.mOnKeyboardActionListener = this

keyboardBinding.scribeKey.setOnClickListener {
currentState = ScribeState.IDLE
switchToCommandToolBar()
handleTextSizeForSuggestion(binding)
updateUI()
}

setInputView(keyboardHolder)
updateCommandBarHintAndPrompt(isUserDarkMode)
updateCommandBarHintAndPrompt(isDarkMode)
}

/**
* Updates the toolbar theme based on the current system theme (dark or light).
*
* This function adjusts the toolbar's visual elements such as the top divider color
* and the tint of the custom scribe key, depending on whether dark mode is enabled.
*
* @param isDarkMode A boolean indicating if the system is in dark mode.
*/
private fun updateToolBarTheme(isDarkMode: Boolean) {
val dividerColor = if (isDarkMode) R.color.special_key_dark else R.color.special_key_light
keyboardBinding.topKeyboardDivider.setBackgroundColor(getColor(dividerColor))

val tintColor =
if (isDarkMode) {
ContextCompat.getColorStateList(this, R.color.light_key_color)
} else {
ContextCompat.getColorStateList(this, R.color.light_key_text_color)
}

keyboardBinding.scribeKey.foregroundTintList = tintColor
}

/**
Expand Down Expand Up @@ -1642,6 +1672,32 @@ abstract class GeneralKeyboardIME(
}
}

/**
* Returns the XML layout resource ID for the base keyboard of the specified language.
*
* This function maps a given language name to its corresponding keyboard layout XML file.
* If the provided language is `null` or doesn't match any of the predefined options,
* the function defaults to returning the English keyboard layout.
*
* @param language The name of the language for which the base keyboard layout is requested.
* Expected values are: "English", "French", "German", "Italian",
* "Portuguese", "Russian", "Spanish", and "Swedish".
*
* @return The resource ID of the XML layout file for the corresponding keyboard.
*/
private fun baseKeyboardOfAnyLanguage(language: String?): Int =
when (language) {
"English" -> R.xml.keys_letters_english
"French" -> R.xml.keys_letters_french
"German" -> R.xml.keys_letters_german
"Italian" -> R.xml.keys_letters_italian
"Portuguese" -> R.xml.keys_letters_portuguese
"Russian" -> R.xml.keys_letters_russian
"Spanish" -> R.xml.keys_letters_spanish
"Swedish" -> R.xml.keys_letters_swedish
else -> R.xml.keys_letters_english
}

internal companion object {
const val DEFAULT_SHIFT_PERM_TOGGLE_SPEED = 500
const val TEXT_LENGTH = 20
Expand Down
Loading