add timestamp keycode and setting for adjusting format, fixes GH-846

This commit is contained in:
Helium314 2025-03-29 12:36:07 +01:00
parent 525c4e59b6
commit 8932fc84e1
11 changed files with 90 additions and 24 deletions

View file

@ -167,6 +167,7 @@ object KeyCode {
const val BACK = -10040
const val SELECT_LEFT = -10041
const val SELECT_RIGHT = -10042
const val TIMESTAMP = -10043
/** to make sure a FlorisBoard code works when reading a JSON layout */
fun Int.checkAndConvertCode(): Int = if (this > 0) this else when (this) {
@ -182,7 +183,8 @@ object KeyCode {
SYMBOL_ALPHA, TOGGLE_ONE_HANDED_MODE, SWITCH_ONE_HANDED_MODE, SPLIT_LAYOUT, SHIFT_ENTER,
ACTION_NEXT, ACTION_PREVIOUS, NOT_SPECIFIED, CLIPBOARD_COPY_ALL, WORD_LEFT, WORD_RIGHT, PAGE_UP,
PAGE_DOWN, META, TAB, ESCAPE, INSERT, SLEEP, MEDIA_PLAY, MEDIA_PAUSE, MEDIA_PLAY_PAUSE, MEDIA_NEXT,
MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK
MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK,
TIMESTAMP
-> this
// conversion
@ -194,8 +196,12 @@ object KeyCode {
else -> throw IllegalStateException("key code $this not yet supported")
}
// todo: three are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0
/** convert a keyCode / codePoint to a KeyEvent.KEYCODE_<xxx>, fallback to KeyEvent.KEYCODE_UNKNOWN */
// todo: there are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0
/**
* Convert a keyCode / codePoint to a KeyEvent.KEYCODE_<xxx>.
* Fallback to KeyEvent.KEYCODE_UNKNOWN.
* To be uses for fake hardware key press.
* */
fun Int.toKeyEventCode(): Int = if (this > 0)
when (this.toChar().uppercaseChar()) {
'/' -> KeyEvent.KEYCODE_SLASH

View file

@ -54,6 +54,7 @@ import helium314.keyboard.latin.utils.RecapitalizeStatus;
import helium314.keyboard.latin.utils.ScriptUtils;
import helium314.keyboard.latin.utils.StatsUtils;
import helium314.keyboard.latin.utils.TextRange;
import helium314.keyboard.latin.utils.TimestampKt;
import java.util.ArrayList;
import java.util.Locale;
@ -775,6 +776,9 @@ public final class InputLogic {
case KeyCode.SPLIT_LAYOUT:
KeyboardSwitcher.getInstance().toggleSplitKeyboardMode();
break;
case KeyCode.TIMESTAMP:
mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME));
break;
case KeyCode.VOICE_INPUT:
// switching to shortcut IME, shift state, keyboard,... is handled by LatinIME,
// {@link KeyboardSwitcher#onEvent(Event)}, or {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.

View file

@ -154,6 +154,7 @@ object Defaults {
const val PREF_ABC_AFTER_NUMPAD_SPACE = false
const val PREF_REMOVE_REDUNDANT_POPUPS = false
const val PREF_SPACE_BAR_TEXT = ""
const val PREF_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss"
@JvmField
val PREF_EMOJI_MAX_SDK = Build.VERSION.SDK_INT
const val PREF_EMOJI_RECENT_KEYS = ""

View file

@ -164,6 +164,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_ABC_AFTER_NUMPAD_SPACE = "abc_after_numpad_space";
public static final String PREF_REMOVE_REDUNDANT_POPUPS = "remove_redundant_popups";
public static final String PREF_SPACE_BAR_TEXT = "space_bar_text";
public static final String PREF_TIMESTAMP_FORMAT = "timestamp_format";
// Emoji
public static final String PREF_EMOJI_MAX_SDK = "emoji_max_sdk";

View file

@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin.utils
import android.content.Context
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import java.text.SimpleDateFormat
import java.util.Calendar
fun getTimestamp(context: Context): String {
val format = context.prefs().getString(Settings.PREF_TIMESTAMP_FORMAT, Defaults.PREF_TIMESTAMP_FORMAT)
val formatter = runCatching { SimpleDateFormat(format, Settings.getValues().mLocale) }.getOrNull()
?: SimpleDateFormat(Defaults.PREF_TIMESTAMP_FORMAT, Settings.getValues().mLocale)
return formatter.format(Calendar.getInstance().time)
}
fun checkTimestampFormat(format: String) = runCatching { SimpleDateFormat(format, Settings.getValues().mLocale) }.isSuccess

View file

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings.preferences
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import helium314.keyboard.keyboard.KeyboardSwitcher
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.dialogs.TextInputDialog
@Composable
fun TextInputPreference(setting: Setting, default: String, checkTextValid: (String) -> Boolean = { true }) {
var showDialog by rememberSaveable { mutableStateOf(false) }
val prefs = LocalContext.current.prefs()
Preference(
name = setting.title,
onClick = { showDialog = true },
description = prefs.getString(setting.key, default)?.takeIf { it.isNotEmpty() }
)
if (showDialog) {
TextInputDialog(
onDismissRequest = { showDialog = false },
onConfirmed = {
prefs.edit().putString(setting.key, it).apply()
KeyboardSwitcher.getInstance().setThemeNeedsReload()
},
initialText = prefs.getString(setting.key, default) ?: "",
title = { Text(setting.title) },
checkTextValid = checkTextValid
)
}
}

View file

@ -29,6 +29,7 @@ import helium314.keyboard.latin.common.splitOnWhitespace
import helium314.keyboard.latin.settings.DebugSettings
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.NextScreenIcon
import helium314.keyboard.settings.SettingsContainer
@ -45,6 +46,7 @@ import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.TextInputDialog
import helium314.keyboard.settings.preferences.BackupRestorePreference
import helium314.keyboard.settings.preferences.LoadGestureLibPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark
@Composable
@ -71,6 +73,7 @@ fun AdvancedSettingsScreen(
Settings.PREF_ABC_AFTER_CLIP,
Settings.PREF_CUSTOM_CURRENCY_KEY,
Settings.PREF_MORE_POPUP_KEYS,
Settings.PREF_TIMESTAMP_FORMAT,
SettingsWithoutKey.BACKUP_RESTORE,
if (BuildConfig.DEBUG || prefs.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, Defaults.PREF_SHOW_DEBUG_SETTINGS))
SettingsWithoutKey.DEBUG_SETTINGS else null,
@ -195,6 +198,9 @@ fun createAdvancedSettings(context: Context) = listOf(
Setting(context, SettingsWithoutKey.BACKUP_RESTORE, R.string.backup_restore_title) {
BackupRestorePreference(it)
},
Setting(context, Settings.PREF_TIMESTAMP_FORMAT, R.string.timestamp_format_title) {
TextInputPreference(it, Defaults.PREF_TIMESTAMP_FORMAT) { checkTimestampFormat(it) }
},
Setting(context, SettingsWithoutKey.DEBUG_SETTINGS, R.string.debug_settings_title) {
Preference(
name = it.title,

View file

@ -21,6 +21,7 @@ import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.prefs
@ -39,6 +40,7 @@ import helium314.keyboard.settings.dialogs.TextInputDialog
import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.preferences.BackgroundImagePref
import helium314.keyboard.settings.preferences.CustomFontPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark
@Composable
@ -263,26 +265,8 @@ fun createAppearanceSettings(context: Context) = listOf(
description = { "${(100 * it).toInt()}%" }
) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
},
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) { setting ->
var showDialog by rememberSaveable { mutableStateOf(false) }
val prefs = LocalContext.current.prefs()
Preference(
name = setting.title,
onClick = { showDialog = true },
description = prefs.getString(setting.key, Defaults.PREF_SPACE_BAR_TEXT)?.takeIf { it.isNotEmpty() }
)
if (showDialog) {
TextInputDialog(
onDismissRequest = { showDialog = false },
onConfirmed = {
prefs.edit().putString(setting.key, it).apply()
KeyboardSwitcher.getInstance().setThemeNeedsReload()
},
initialText = prefs.getString(setting.key, Defaults.PREF_SPACE_BAR_TEXT) ?: "",
title = { Text(setting.title) },
checkTextValid = { true }
)
}
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) {
TextInputPreference(it, Defaults.PREF_SPACE_BAR_TEXT)
},
Setting(context, SettingsWithoutKey.CUSTOM_FONT, R.string.custom_font) {
CustomFontPreference(it)

View file

@ -196,6 +196,8 @@
<string name="button_backup">Backup</string>
<!-- restore button -->
<string name="button_restore">Restore</string>
<!-- Preferences item for format for timestamp keycode -->
<string name="timestamp_format_title">Format for timestamp key</string>
<!-- Preferences item for choosing secondary language -->
<string name="secondary_locale">Multilingual typing</string>
<!-- Clarification which locales are available for multilingual typing -->

View file

@ -23,6 +23,7 @@ import helium314.keyboard.latin.inputlogic.InputLogic
import helium314.keyboard.latin.inputlogic.SpaceState
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.getTimestamp
import helium314.keyboard.latin.utils.prefs
import org.junit.runner.RunWith
import org.mockito.Mockito
@ -666,6 +667,13 @@ class InputLogicTest {
// need to avoid getting into the mWordComposer.isBatchMode() part of handleBackspaceEvent
}
@Test fun timestamp() {
reset()
chainInput("hello")
functionalKeyPress(KeyCode.TIMESTAMP)
assertEquals("hello" + getTimestamp(latinIME), text)
}
// ------- helper functions ---------
// should be called before every test, so the same state is guaranteed

View file

@ -103,7 +103,7 @@ Usually the label is what is displayed on the key. However, there are some speci
* In case a label clashes with text you want to add, put a `\` in front of the text you want, e.g. `\space` will write the label `space` instead of adding a space bar.
* Note that you need to escape the `\` in json files by adding a second `\`.
* If you want different key label and input text, set the label to [label]|[text], e.g. `aa|bb` will show `aa`, but pressing the key will input `bb`.
You can also specify special key codes like `a|!code/key_action_previous`, but it's cleaner to use a json layout and specify the code explicitly. Note that when specifying a code in the label, and a code in a json layout, the code in the label will be ignored.
You can also specify special key codes like `a|!code/key_action_previous` or `abc|!code/-10043`, but it's cleaner to use a json layout and specify the code explicitly. Note that when specifying a code in the label, and a code in a json layout, the code in the label will be ignored.
* It's also possible to specify an icon, like `!icon/previous_key|!code/key_action_previous`.
* You can find available icon names in [KeyboardIconsSet](/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardIconsSet.kt). You can also use toolbar key icons using the uppercase name of the [toolbar key](/app/src/main/java/helium314/keyboard/latin/utils/ToolbarUtils.kt#L109), e.g. `!icon/redo`