Skip to content

Commit 5c5fe4f

Browse files
Merge pull request #875 from KazumaProject/fix/candidate-height
変換候補欄の高さの修正
2 parents b0a770d + aae1e18 commit 5c5fe4f

6 files changed

Lines changed: 114 additions & 46 deletions

File tree

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ android {
3131
applicationId "com.kazumaproject.markdownhelperkeyboard"
3232
minSdk 24
3333
targetSdk 36
34-
versionCode 787
35-
versionName "1.7.94"
34+
versionCode 788
35+
versionName "1.7.95"
3636
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
3737
}
3838

app/src/main/java/com/kazumaproject/markdownhelperkeyboard/converter/path_algorithm/FindPath.kt

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ class FindPath(
712712
)
713713

714714
if (foundStrings.add(stringFromNode)) {
715-
val bunsetsuPositions = getBunsetsuPositionsFromPath(element, mozcSegmenter)
715+
val bunsetsuPositions = getBunsetsuPositionsFromPath(element)
716716
if (splitPatterns.none { it == bunsetsuPositions } && splitPatterns.size < 4) {
717717
splitPatterns.add(bunsetsuPositions)
718718
}
@@ -1084,33 +1084,24 @@ class FindPath(
10841084

10851085
private fun getBunsetsuPositionsFromPath(
10861086
path: PathQueueElement,
1087-
mozcSegmenter: MozcSegmenter?,
10881087
): List<Int> {
10891088
val positions = mutableListOf<Int>()
10901089
var currentPosition = 0
1091-
var previousNode: Node? = null
10921090

10931091
var current: PathQueueElement? = path
10941092
while (current != null) {
10951093
val node = current.node
10961094
if (node.tango != "BOS" && node.tango != "EOS") {
1097-
val prev = previousNode
1098-
if (currentPosition > 0 && prev != null) {
1099-
val isBoundary = if (mozcSegmenter != null) {
1100-
mozcSegmenter.isBoundary(
1101-
left = prev,
1102-
right = node,
1103-
isSingleSegment = false,
1104-
)
1105-
} else {
1106-
isIndependentWord(node.l)
1107-
}
1095+
if (currentPosition > 0) {
1096+
// Mozc's boundary table constrains conversion paths; it does not represent
1097+
// the split points used by the IME's sequential bunsetsu conversion UI.
1098+
// Keep display splitting on the original POS-based rule.
1099+
val isBoundary = isIndependentWord(node.l)
11081100
if (isBoundary) {
11091101
positions.add(currentPosition)
11101102
}
11111103
}
11121104
currentPosition += node.len.toInt()
1113-
previousNode = node
11141105
}
11151106
current = current.next
11161107
}
@@ -1120,30 +1111,19 @@ class FindPath(
11201111

11211112
private fun getBunsetsuPositions(
11221113
bosNode: Node,
1123-
mozcSegmenter: MozcSegmenter? = null,
11241114
): List<Int> {
11251115
val positions = mutableListOf<Int>()
11261116
var currentPosition = 0
1127-
var previousNode = bosNode
11281117
var tempNode = bosNode.next
11291118

11301119
while (tempNode != null && tempNode.tango != "EOS") {
11311120
if (currentPosition > 0) {
1132-
val isBoundary = if (mozcSegmenter != null) {
1133-
mozcSegmenter.isBoundary(
1134-
left = previousNode,
1135-
right = tempNode,
1136-
isSingleSegment = false,
1137-
)
1138-
} else {
1139-
isIndependentWord(tempNode.l)
1140-
}
1121+
val isBoundary = isIndependentWord(tempNode.l)
11411122
if (isBoundary) {
11421123
positions.add(currentPosition)
11431124
}
11441125
}
11451126
currentPosition += tempNode.len.toInt()
1146-
previousNode = tempNode
11471127
tempNode = tempNode.next
11481128
}
11491129

app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/CandidateStripPresentationPolicy.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ data class CandidateStripPresentation(
2525
val showIntegratedShortcutEntry: Boolean
2626
)
2727

28+
internal fun resolveCandidateTabOffsetPx(
29+
presentation: CandidateStripPresentation,
30+
candidateTabHeightPx: Int
31+
): Int = if (presentation.showCandidateTab) candidateTabHeightPx.coerceAtLeast(0) else 0
32+
33+
internal fun resolveCandidateStripHeightDp(
34+
candidatesShown: Boolean,
35+
candidateHeightDp: Int,
36+
emptyHeightDp: Int
37+
): Int = if (candidatesShown) candidateHeightDp else emptyHeightDp
38+
2839
object CandidateStripPresentationPolicy {
2940

3041
fun resolve(state: CandidateStripPresentationState): CandidateStripPresentation {

app/src/main/java/com/kazumaproject/markdownhelperkeyboard/ime_service/IMEService.kt

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,7 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
18081808
val widthPref: Int,
18091809
val bottomMargin: Int,
18101810
val positionIsEnd: Boolean, // true: End, false: Start
1811+
val candidateHeight: Int,
18111812
val candidateEmptyHeight: Int,
18121813
val qwertyHeightPref: Int,
18131814
val qwertyWidthPref: Int,
@@ -13900,7 +13901,6 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1390013901
mainView.suggestionVisibility, true
1390113902
)
1390213903
}
13903-
setKeyboardHeightWithAdditional(mainView)
1390413904
}
1390513905

1390613906
(physicalKeyboardEnable.replayCache.isNotEmpty() && !physicalKeyboardEnable.replayCache.first()) &&
@@ -13909,7 +13909,6 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1390913909
animateSuggestionImageViewVisibility(
1391013910
mainView.suggestionVisibility, true
1391113911
)
13912-
setKeyboardHeightWithAdditional(mainView)
1391313912
}
1391413913

1391513914
}
@@ -13993,6 +13992,21 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1399313992
clearZeroQueryAllState(refresh = false)
1399413993
shortcutToolbarHiddenForCandidates = true
1399513994
refreshCandidateStripContent(candidatesShown = true)
13995+
val softwareKeyboardVisible =
13996+
physicalKeyboardEnable.replayCache.firstOrNull() != true
13997+
val normalKeyboardSurfaceVisible =
13998+
mainView.keyboardView.isVisible ||
13999+
mainView.tabletView.isVisible ||
14000+
mainView.qwertyView.isVisible ||
14001+
mainView.customLayoutDefault.isVisible
14002+
if (
14003+
softwareKeyboardVisible &&
14004+
isKeyboardFloatingMode != true &&
14005+
normalKeyboardSurfaceVisible
14006+
) {
14007+
// SharedFlow の最初の通知が Updating でも候補欄の高さを保証する。
14008+
setKeyboardHeightWithAdditional(mainView)
14009+
}
1399614010
setSuggestionOnView(insertString, mainView)
1399714011
}
1399814012
}
@@ -14930,6 +14944,7 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1493014944
widthPref = tenkeyWidthPreferenceValue ?: 100,
1493114945
bottomMargin = tenkeyBottomMarginPreferenceValue ?: 0,
1493214946
positionIsEnd = tenkeyPositionPreferenceValue ?: true,
14947+
candidateHeight = candidateViewHeightPreferenceValue ?: 110,
1493314948
candidateEmptyHeight = candidateViewHeightEmptyPreferenceValue ?: 110,
1493414949
qwertyHeightPref = qwertyHeightPreferenceValue ?: 280,
1493514950
qwertyWidthPref = qwertyWidthPreferenceValue ?: 100,
@@ -14946,6 +14961,7 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1494614961
widthPref = tenkeyWidthLandScapePreferenceValue ?: 100,
1494714962
bottomMargin = tenkeyLandScapeBottomMarginPreferenceValue ?: 0,
1494814963
positionIsEnd = tenkeyLandScapePositionPreferenceValue ?: true,
14964+
candidateHeight = candidateViewLandScapeHeightPreferenceValue ?: 110,
1494914965
candidateEmptyHeight = candidateViewLandScapeHeightEmptyPreferenceValue ?: 110,
1495014966
qwertyHeightPref = qwertyHeightLandScapePreferenceValue ?: 280,
1495114967
qwertyWidthPref = qwertyWidthLandScapePreferenceValue ?: 100,
@@ -15022,23 +15038,27 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1502215038
}
1502315039

1502415040
// 3. 最終的な高さ、幅、Gravity、マージンの決定
15041+
val candidatesShown = addCandidateTabHeight || shortcutToolbarHiddenForCandidates
15042+
val presentation = resolveCandidateStripPresentation(candidatesShown = candidatesShown)
15043+
val candidateStripHeightDp = resolveCandidateStripHeightDp(
15044+
candidatesShown = candidatesShown,
15045+
candidateHeightDp = prefs.candidateHeight,
15046+
emptyHeightDp = prefs.candidateEmptyHeight
15047+
)
1502515048
val baseKeyboardHeight = if (isPortrait) {
1502615049
if (isSymbol) heightPx + applicationContext.dpToPx(50) else heightPx + applicationContext.dpToPx(
15027-
prefs.candidateEmptyHeight
15050+
candidateStripHeightDp
1502815051
)
1502915052
} else {
15030-
if (isSymbol) heightPx else heightPx + applicationContext.dpToPx(prefs.candidateEmptyHeight)
15053+
if (isSymbol) heightPx else heightPx + applicationContext.dpToPx(candidateStripHeightDp)
1503115054
}
1503215055

15033-
val presentation = resolveCandidateStripPresentation(
15034-
candidatesShown = addCandidateTabHeight || shortcutToolbarHiddenForCandidates
15056+
// Insets や画面構成の変化による再計算でも、現在表示中の候補タブ領域を
15057+
// 失わないよう、呼び出し元のフラグではなく実際の表示状態から決定する。
15058+
val candidateTabOffset = resolveCandidateTabOffsetPx(
15059+
presentation = presentation,
15060+
candidateTabHeightPx = candidateTabHeightPx(mainView)
1503515061
)
15036-
val candidateTabOffset =
15037-
if (addCandidateTabHeight && presentation.showCandidateTab) {
15038-
candidateTabHeightPx(mainView)
15039-
} else {
15040-
0
15041-
}
1504215062
val finalKeyboardHeight = when {
1504315063
candidateTabOffset > 0 ->
1504415064
baseKeyboardHeight + candidateTabOffset
@@ -15341,11 +15361,10 @@ class IMEService : InputMethodService(), LifecycleOwner, InputConnection,
1534115361
}
1534215362

1534315363
val presentation = resolveCandidateStripPresentation(candidatesShown = true)
15344-
val candidateTabOffset = if (presentation.showCandidateTab) {
15345-
candidateTabHeightPx(mainView)
15346-
} else {
15347-
0
15348-
}
15364+
val candidateTabOffset = resolveCandidateTabOffsetPx(
15365+
presentation = presentation,
15366+
candidateTabHeightPx = candidateTabHeightPx(mainView)
15367+
)
1534915368
val finalKeyboardHeight = keyboardHeight + candidateTabOffset
1535015369
val backgroundSurfaceHeight = finalKeyboardHeight - candidateTabOffset
1535115370

app/src/test/java/com/kazumaproject/markdownhelperkeyboard/converter/ProductionConnectionMatrixRegressionTest.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ class ProductionConnectionMatrixRegressionTest {
6060
}
6161
}
6262

63+
@Test
64+
fun bunsetsuConversionExposesSequentialSplitPositionWithMozcParityEnabled() = runBlocking {
65+
val engine = TestEngineFactory.create()
66+
val userDictionaryRepository = mock<UserDictionaryRepository>()
67+
whenever(userDictionaryRepository.commonPrefixSearchInUserDict(any())).thenReturn(emptyList())
68+
69+
val result = engine.convertForRegression(
70+
input = "きょうはいいてんきですね",
71+
userDictionaryRepository = userDictionaryRepository,
72+
)
73+
74+
assertEquals("今日はいい天気ですね", result.candidates.first().string)
75+
assertEquals(listOf(4), result.primarySplitPositions)
76+
}
77+
6378
private suspend fun KanaKanjiEngine.convertForRegression(
6479
input: String,
6580
userDictionaryRepository: UserDictionaryRepository,

app/src/test/java/com/kazumaproject/markdownhelperkeyboard/ime_service/CandidateStripPresentationPolicyTest.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.kazumaproject.markdownhelperkeyboard.ime_service
22

3+
import org.junit.Assert.assertEquals
34
import org.junit.Assert.assertFalse
45
import org.junit.Assert.assertTrue
56
import org.junit.Test
@@ -185,6 +186,48 @@ class CandidateStripPresentationPolicyTest {
185186
assertTrue(presentation.showCandidateTab)
186187
}
187188

189+
@Test
190+
fun visibleCandidateTabAlwaysReservesItsHeight() {
191+
val presentation = CandidateStripPresentationPolicy.resolve(
192+
baseState(candidateTabVisible = true, candidatesShown = true)
193+
)
194+
195+
assertEquals(36, resolveCandidateTabOffsetPx(presentation, 36))
196+
}
197+
198+
@Test
199+
fun hiddenCandidateTabDoesNotReserveHeight() {
200+
val presentation = CandidateStripPresentationPolicy.resolve(
201+
baseState(candidateTabVisible = true, candidatesShown = false)
202+
)
203+
204+
assertEquals(0, resolveCandidateTabOffsetPx(presentation, 36))
205+
}
206+
207+
@Test
208+
fun candidatesUseConfiguredCandidateStripHeight() {
209+
assertEquals(
210+
160,
211+
resolveCandidateStripHeightDp(
212+
candidatesShown = true,
213+
candidateHeightDp = 160,
214+
emptyHeightDp = 110
215+
)
216+
)
217+
}
218+
219+
@Test
220+
fun emptyStateUsesConfiguredEmptyStripHeight() {
221+
assertEquals(
222+
110,
223+
resolveCandidateStripHeightDp(
224+
candidatesShown = false,
225+
candidateHeightDp = 160,
226+
emptyHeightDp = 110
227+
)
228+
)
229+
}
230+
188231
@Test
189232
fun idleReturnRequestsCandidateTabSelectionReset() {
190233
val presentation = CandidateStripPresentationPolicy.resolve(

0 commit comments

Comments
 (0)