Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ android {
applicationId "com.kazumaproject.markdownhelperkeyboard"
minSdk 24
targetSdk 36
versionCode 798
versionName "1.7.105"
versionCode 799
versionName "1.7.106"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Expand Down
Binary file modified app/src/main/assets/emoji/token_emoji.dat
Binary file not shown.
Binary file modified app/src/main/assets/emoticon/token_emoticon.dat
Binary file not shown.
Binary file modified app/src/main/assets/kotowaza/token_kotowaza.dat
Binary file not shown.
Binary file modified app/src/main/assets/neologd/token_neologd.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/ngram/system_ngram.dat
Binary file not shown.
Binary file modified app/src/main/assets/person_name/token_person_names.dat
Binary file not shown.
Binary file modified app/src/main/assets/places/token_places.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/pos_table.dat
Binary file not shown.
Binary file not shown.
Binary file modified app/src/main/assets/single_kanji/token_singleKanji.dat
Binary file not shown.
Binary file modified app/src/main/assets/symbol/token_symbol.dat
Binary file not shown.
Binary file modified app/src/main/assets/system/tango.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/system/token.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/system/yomi.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/web/token_web.dat.zip
Binary file not shown.
Binary file modified app/src/main/assets/wiki/token_wiki.dat.zip
Binary file not shown.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ data class PredictionConfig(
val proverbEnabled: Boolean = true,
val externalMozcEnabled: Boolean = true,
val symbolEmojiEnabled: Boolean = true,
val showSymbolCandidates: Boolean = true,
val showEmojiCandidates: Boolean = true,
val showEmoticonCandidates: Boolean = true,
) {
val normalizedMinimumInputLength: Int
get() = minimumInputLength.coerceIn(MIN_INPUT_LENGTH, MAX_INPUT_LENGTH)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateS
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateQueryModeResolver
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshCoordinator
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshRequest
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRefreshTransitionPolicy
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRequestToken
import com.kazumaproject.markdownhelperkeyboard.ime_service.candidate.CandidateRequestTracker
import com.kazumaproject.markdownhelperkeyboard.ime_service.clipboard.ClipboardUtil
Expand Down Expand Up @@ -956,7 +957,13 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
}
}
suggestionAdapter?.submitContent(content)
suggestionAdapterFull?.submitContent(fullContent)
// The full candidate view is hidden during normal composing. Submitting to its
// AsyncListDiffer on every keystroke still calculates a complete DiffUtil diff even
// though the user cannot see it. Keep the state current, but submit only when that
// view is actually visible; the visibility transition below refreshes it once.
if (isFullCandidateViewVisible()) {
suggestionAdapterFull?.submitContent(fullContent)
}
val presentation = resolveCandidateStripPresentation(
candidatesShown = effectiveCandidatesShown,
resetCandidateTabSelection = resetCandidateTabSelection,
Expand All @@ -965,6 +972,14 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
applyCandidateStripPresentation(presentation)
}

private fun isFullCandidateViewVisible(): Boolean {
return if (isKeyboardFloatingMode == true) {
floatingKeyboardBinding?.candidatesRowView?.isVisible == true
} else {
mainLayoutBinding?.candidatesRowView?.isVisible == true
}
}

private fun resolveCandidateStripContent(
candidates: List<Candidate>,
candidatesShown: Boolean,
Expand Down Expand Up @@ -14645,10 +14660,11 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
prevFlag,
currentFlag,
)
if (
prevFlag == CandidateShowFlag.Idle &&
currentFlag == CandidateShowFlag.Updating &&
insertString.isNotEmpty()
if (CandidateRefreshTransitionPolicy.shouldEnterActiveCandidatePhase(
previousFlag = prevFlag,
currentFlag = currentFlag,
input = insertString,
)
) {
clearZeroQueryAllState(refresh = false)
shortcutToolbarHiddenForCandidates = true
Expand Down Expand Up @@ -14798,7 +14814,10 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
}
}
}
prevFlag = currentFlag
prevFlag = CandidateRefreshTransitionPolicy.nextUiPreviousFlag(
currentFlag = currentFlag,
input = insertString,
)
}
}

Expand Down Expand Up @@ -16480,6 +16499,11 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
mainView.suggestionVisibility.apply {
this.setImageDrawable(if (isVisible) cachedArrowDropDownDrawable else cachedArrowDropUpDrawable)
}
if (!isVisible) {
// The full candidate view was intentionally not diffed while hidden. Submit the
// latest state after it becomes the active surface.
refreshCandidateStripContent(candidatesShown = true)
}
}

private fun animateViewVisibility(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,12 @@ data class ImePreferencesSnapshot(
appPreference.external_mozc_prediction_enable_preference,
symbolEmojiEnabled =
appPreference.symbol_emoji_prediction_enable_preference,
showSymbolCandidates =
appPreference.symbol_candidate_enable_preference,
showEmojiCandidates =
appPreference.emoji_candidate_enable_preference,
showEmoticonCandidates =
appPreference.emoticon_candidate_enable_preference,
),
flickSensitivityPreferenceValue = appPreference.flick_sensitivity_preference ?: 100,
flickThresholdShapePreferenceValue =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,24 +526,23 @@ class SuggestionAdapter internal constructor(
return when {
oldItem is SuggestionDisplayItem.CandidateItem &&
newItem is SuggestionDisplayItem.CandidateItem ->
oldItem.candidateIndex == newItem.candidateIndex &&
oldItem.candidate.string == newItem.candidate.string &&
oldItem.candidate.type == newItem.candidate.type
// Candidate rows are positional slots. The RecyclerView has no move
// animation, and onBindViewHolder installs the current candidate click
// listener, so a changed candidate at the same slot is a content change.
// Treating its text/type as identity made every keystroke look like a set
// of removals and insertions to DiffUtil.
oldItem.candidateIndex == newItem.candidateIndex

oldItem is SuggestionDisplayItem.GemmaActionItem &&
newItem is SuggestionDisplayItem.GemmaActionItem ->
oldItem.candidateIndex == newItem.candidateIndex &&
oldItem.candidate.string == newItem.candidate.string &&
oldItem.candidate.type == newItem.candidate.type
oldItem.candidateIndex == newItem.candidateIndex

oldItem is SuggestionDisplayItem.ZeroQueryCloseItem &&
newItem is SuggestionDisplayItem.ZeroQueryCloseItem -> true

oldItem is SuggestionDisplayItem.ZeroQueryCandidateItem &&
newItem is SuggestionDisplayItem.ZeroQueryCandidateItem ->
oldItem.candidateIndex == newItem.candidateIndex &&
oldItem.candidate.string == newItem.candidate.string &&
oldItem.candidate.type == newItem.candidate.type
oldItem.candidateIndex == newItem.candidateIndex

oldItem is SuggestionDisplayItem.QuickActionsItem &&
newItem is SuggestionDisplayItem.QuickActionsItem -> true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.kazumaproject.markdownhelperkeyboard.ime_service.candidate

import com.kazumaproject.markdownhelperkeyboard.ime_service.models.CandidateShowFlag

/**
* Keeps non-user candidate refreshes from changing the visible conversion phase.
*
* Dictionary loading can publish an Updating request while the composing input is empty. That
* request refreshes data, but it must not consume the Idle -> Updating transition used by the
* candidate-strip UI to show the full-candidate toggle.
*/
internal object CandidateRefreshTransitionPolicy {

fun shouldEnterActiveCandidatePhase(
previousFlag: CandidateShowFlag?,
currentFlag: CandidateShowFlag,
input: String,
): Boolean {
return previousFlag == CandidateShowFlag.Idle &&
currentFlag == CandidateShowFlag.Updating &&
input.isNotEmpty()
}

fun nextUiPreviousFlag(
currentFlag: CandidateShowFlag,
input: String,
): CandidateShowFlag {
return if (currentFlag == CandidateShowFlag.Updating && input.isEmpty()) {
CandidateShowFlag.Idle
} else {
currentFlag
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ object AppPreference {

private lateinit var preferences: SharedPreferences
private val gson = Gson()
private const val LEGACY_SYMBOL_EMOJI_CANDIDATE_ENABLE_KEY =
"symbol_emoji_candidate_enable_preference"
private val circularSlotActionEditableSlots = setOf(
CircularFlickDirection.SLOT_4,
CircularFlickDirection.SLOT_5,
Expand Down Expand Up @@ -156,6 +158,12 @@ object AppPreference {
Pair("external_mozc_prediction_enable_preference", true)
private val SYMBOL_EMOJI_PREDICTION_ENABLE_PREFERENCE =
Pair("symbol_emoji_prediction_enable_preference", true)
private val SYMBOL_CANDIDATE_ENABLE_PREFERENCE =
Pair("symbol_candidate_enable_preference", true)
private val EMOJI_CANDIDATE_ENABLE_PREFERENCE =
Pair("emoji_candidate_enable_preference", true)
private val EMOTICON_CANDIDATE_ENABLE_PREFERENCE =
Pair("emoticon_candidate_enable_preference", true)
private val CANDIDATE_ORDER_OVERRIDE_ENABLE =
Pair("candidate_order_override_enable_preference", false)
private val MOZCUT_PERSON_NAME = Pair("mozc_ut_person_name_preference", false)
Expand Down Expand Up @@ -857,9 +865,30 @@ object AppPreference {
preferences = PreferenceManager.getDefaultSharedPreferences(context)
removeUnsafeLegacyGemmaHandwritingPrompt()
migratePredictionLookaheadPreferenceIfNeeded()
migrateSymbolEmojiCandidatePreferenceIfNeeded()
migrateSumireKeymapGuideModesIfNeeded()
}

fun migrateSymbolEmojiCandidatePreferenceIfNeeded() {
if (!preferences.contains(LEGACY_SYMBOL_EMOJI_CANDIDATE_ENABLE_KEY)) return
val legacyValue = preferences.getBoolean(
LEGACY_SYMBOL_EMOJI_CANDIDATE_ENABLE_KEY,
true,
)
preferences.edit {
if (!preferences.contains(SYMBOL_CANDIDATE_ENABLE_PREFERENCE.first)) {
it.putBoolean(SYMBOL_CANDIDATE_ENABLE_PREFERENCE.first, legacyValue)
}
if (!preferences.contains(EMOJI_CANDIDATE_ENABLE_PREFERENCE.first)) {
it.putBoolean(EMOJI_CANDIDATE_ENABLE_PREFERENCE.first, legacyValue)
}
if (!preferences.contains(EMOTICON_CANDIDATE_ENABLE_PREFERENCE.first)) {
it.putBoolean(EMOTICON_CANDIDATE_ENABLE_PREFERENCE.first, legacyValue)
}
it.remove(LEGACY_SYMBOL_EMOJI_CANDIDATE_ENABLE_KEY)
}
}

private fun migrateSumireKeymapGuideModesIfNeeded() {
if (preferences.getBoolean(SUMIRE_KEYMAP_GUIDE_MIGRATION_KEY, false)) return
val legacyGuideEnabled = preferences.getBoolean(
Expand Down Expand Up @@ -1806,6 +1835,33 @@ object AppPreference {
it.putBoolean(SYMBOL_EMOJI_PREDICTION_ENABLE_PREFERENCE.first, value)
}

var symbol_candidate_enable_preference: Boolean
get() = preferences.getBoolean(
SYMBOL_CANDIDATE_ENABLE_PREFERENCE.first,
SYMBOL_CANDIDATE_ENABLE_PREFERENCE.second,
)
set(value) = preferences.edit {
it.putBoolean(SYMBOL_CANDIDATE_ENABLE_PREFERENCE.first, value)
}

var emoji_candidate_enable_preference: Boolean
get() = preferences.getBoolean(
EMOJI_CANDIDATE_ENABLE_PREFERENCE.first,
EMOJI_CANDIDATE_ENABLE_PREFERENCE.second,
)
set(value) = preferences.edit {
it.putBoolean(EMOJI_CANDIDATE_ENABLE_PREFERENCE.first, value)
}

var emoticon_candidate_enable_preference: Boolean
get() = preferences.getBoolean(
EMOTICON_CANDIDATE_ENABLE_PREFERENCE.first,
EMOTICON_CANDIDATE_ENABLE_PREFERENCE.second,
)
set(value) = preferences.edit {
it.putBoolean(EMOTICON_CANDIDATE_ENABLE_PREFERENCE.first, value)
}

var candidate_order_override_enable_preference: Boolean?
get() = preferences.getBoolean(
CANDIDATE_ORDER_OVERRIDE_ENABLE.first,
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,12 @@
<string name="external_mozc_prediction_enable_summary">有効な人名・地名・Wiki・NEologd・Web辞書を前方一致予測に使用します。</string>
<string name="symbol_emoji_prediction_enable_title">記号・絵文字・顔文字</string>
<string name="symbol_emoji_prediction_enable_summary">記号、絵文字、顔文字の辞書を前方一致予測に使用します。</string>
<string name="symbol_candidate_enable_title">記号の変換候補</string>
<string name="symbol_candidate_enable_summary">記号の変換候補を表示します。</string>
<string name="emoji_candidate_enable_title">絵文字の変換候補</string>
<string name="emoji_candidate_enable_summary">絵文字の変換候補を表示します。</string>
<string name="emoticon_candidate_enable_title">顔文字の変換候補</string>
<string name="emoticon_candidate_enable_summary">顔文字の変換候補を表示します。</string>
<string name="dictionary_prediction_candidate_limit_title">予測候補数</string>
<string name="user_dictionary_prediction_candidate_limit_summary">ユーザー辞書から前方一致で取得する予測候補の最大数です。</string>
<string name="learn_dictionary_prediction_candidate_limit_summary">学習辞書から前方一致で取得する予測候補の最大数です。</string>
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1586,6 +1586,12 @@
<string name="external_mozc_prediction_enable_summary">Use enabled person, place, wiki, NEologd, and web dictionaries for completion.</string>
<string name="symbol_emoji_prediction_enable_title">Symbols, emoji, and emoticons</string>
<string name="symbol_emoji_prediction_enable_summary">Use symbol, emoji, and emoticon dictionaries for completion candidates.</string>
<string name="symbol_candidate_enable_title">Symbol candidates</string>
<string name="symbol_candidate_enable_summary">Show symbol conversion candidates.</string>
<string name="emoji_candidate_enable_title">Emoji candidates</string>
<string name="emoji_candidate_enable_summary">Show emoji conversion candidates.</string>
<string name="emoticon_candidate_enable_title">Emoticon candidates</string>
<string name="emoticon_candidate_enable_summary">Show emoticon conversion candidates.</string>
<string name="dictionary_prediction_candidate_limit_title">Prediction candidates</string>
<string name="user_dictionary_prediction_candidate_limit_summary">Maximum number of prefix-match candidates fetched from the user dictionary.</string>
<string name="learn_dictionary_prediction_candidate_limit_summary">Maximum number of prefix-match candidates fetched from the learning dictionary.</string>
Expand Down
21 changes: 21 additions & 0 deletions app/src/main/res/xml/pref_conversion_engine.xml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@
android:title="@string/symbol_emoji_prediction_enable_title"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="true"
android:key="symbol_candidate_enable_preference"
android:summary="@string/symbol_candidate_enable_summary"
android:title="@string/symbol_candidate_enable_title"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="true"
android:key="emoji_candidate_enable_preference"
android:summary="@string/emoji_candidate_enable_summary"
android:title="@string/emoji_candidate_enable_title"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="true"
android:key="emoticon_candidate_enable_preference"
android:summary="@string/emoticon_candidate_enable_summary"
android:title="@string/emoticon_candidate_enable_title"
app:iconSpaceReserved="false" />

</PreferenceCategory>

</androidx.preference.PreferenceScreen>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.kazumaproject.markdownhelperkeyboard.converter.engine

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class SymbolEmojiCandidatePolicyTest {

@Test
fun exactSymbolEmojiReadingSurvivesConversionMode() {
val conversionConfig = PredictionConfig(
japanesePredictionEnabled = false,
symbolEmojiEnabled = false,
)

assertTrue(
shouldIncludeSymbolEmojiReading(
inputLength = 3,
readingLength = 3,
predictionConfig = conversionConfig,
)
)
assertFalse(
shouldIncludeSymbolEmojiReading(
inputLength = 3,
readingLength = 4,
predictionConfig = conversionConfig,
)
)
}

@Test
fun symbolEmojiSettingOnlyControlsCompletionReadings() {
val disabledConfig = PredictionConfig(symbolEmojiEnabled = false)
val enabledConfig = PredictionConfig(symbolEmojiEnabled = true)

assertTrue(
shouldIncludeSymbolEmojiReading(
inputLength = 3,
readingLength = 3,
predictionConfig = disabledConfig,
)
)
assertTrue(
shouldIncludeSymbolEmojiReading(
inputLength = 3,
readingLength = 4,
predictionConfig = enabledConfig,
)
)
assertFalse(
shouldIncludeSymbolEmojiReading(
inputLength = 3,
readingLength = 4,
predictionConfig = disabledConfig,
)
)
}

@Test
fun japaneseNumberReadingIncludesValueBasedSymbols() {
assertTrue(
createJapaneseNumberValueBasedCandidates("いち")
.any { it.string == "①" }
)
}
}
Loading
Loading