Repository navigation
Expand file tree
/
Copy pathheight-isolation.patch
More file actions
327 lines (325 loc) · 21.5 KB
/
Copy pathheight-isolation.patch
File metadata and controls
327 lines (325 loc) · 21.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
--- /dev/null
+++ b/app/src/main/java/com/kingzcheung/xime/settings/KeyboardHeightProfiles.kt
@@ -0,0 +1,85 @@
+package com.kingzcheung.xime.settings
+
+import android.content.Context
+import com.kingzcheung.xime.ui.keyboard.floatingResizeHeightBounds
+import com.kingzcheung.xime.ui.keyboard.keyboardHeightBounds
+
+/** 固定键盘继续使用原有高度键;悬浮高度独立保存,横竖屏互不覆盖。 */
+internal object KeyboardHeightProfiles {
+ const val FLOATING_HEIGHT = "floating_height_dp"
+ const val FLOATING_HEIGHT_LANDSCAPE = "floating_height_dp_landscape"
+
+ private fun fixedKey(landscape: Boolean) =
+ if (landscape) "keyboard_height_dp_landscape" else "keyboard_height_dp"
+
+ private fun floatingKey(landscape: Boolean) =
+ if (landscape) FLOATING_HEIGHT_LANDSCAPE else FLOATING_HEIGHT
+
+ fun fixedBounds(context: Context, landscape: Boolean): IntRange =
+ keyboardHeightBounds(context.resources.configuration.screenHeightDp, landscape)
+
+ fun fixed(context: Context, landscape: Boolean): Int =
+ SettingsPreferences.getKeyboardHeightDp(context, landscape)
+ .coerceIn(fixedBounds(context, landscape))
+
+ fun floating(context: Context, landscape: Boolean, hostHeightDp: Int): Int {
+ val bounds = floatingResizeHeightBounds(hostHeightDp, landscape)
+ val stored = SettingsPreferences.getPrefsPublic(context).getInt(floatingKey(landscape), 0)
+ val height = stored.takeIf { it > 0 }
+ ?: SettingsPreferences.getDefaultKeyboardHeightDp(context, landscape)
+ return height.coerceIn(bounds)
+ }
+
+ fun selected(context: Context, floating: Boolean, landscape: Boolean, hostHeightDp: Int): Int =
+ if (floating) floating(context, landscape, hostHeightDp) else fixed(context, landscape)
+
+ /** 只有确认才调用。悬浮确认绝不写 keyboard_height_dp*。 */
+ fun save(
+ context: Context,
+ floating: Boolean,
+ landscape: Boolean,
+ heightDp: Int,
+ hostHeightDp: Int,
+ ): Int {
+ val height = if (floating) {
+ heightDp.coerceIn(floatingResizeHeightBounds(hostHeightDp, landscape))
+ } else {
+ heightDp.coerceIn(fixedBounds(context, landscape))
+ }
+ if (floating) {
+ SettingsPreferences.getPrefsPublic(context).edit()
+ .putInt(floatingKey(landscape), height).apply()
+ } else {
+ SettingsPreferences.setKeyboardHeightDp(context, height, landscape)
+ }
+ return height
+ }
+
+ /**
+ * 仅首次加载当前方向时修复旧版共用高度键造成的越界值。
+ * 合法固定高度原样保留;低于固定下限的旧值先备份,再恢复固定默认高度。
+ * 旧版已覆盖且仍在合法范围内的值无法可靠辨别,不擅自改写。
+ */
+ fun migrateLegacy(context: Context, landscape: Boolean, hostHeightDp: Int) {
+ val prefs = SettingsPreferences.getPrefsPublic(context)
+ val suffix = if (landscape) "_landscape" else ""
+ val marker = "height_profiles_v1$suffix"
+ if (prefs.getBoolean(marker, false)) return
+
+ val key = fixedKey(landscape)
+ val raw = prefs.getInt(key, 0)
+ val bounds = fixedBounds(context, landscape)
+ val editor = prefs.edit().putBoolean(marker, true)
+ val hasFloatingSettings = prefs.getBoolean("floating_mode$suffix", false) ||
+ prefs.getInt("floating_width_dp$suffix", 0) > 0
+ if (!prefs.contains(floatingKey(landscape)) && hasFloatingSettings && raw > 0) {
+ editor.putInt(floatingKey(landscape), raw.coerceIn(floatingResizeHeightBounds(hostHeightDp, landscape)))
+ }
+ if (prefs.contains(key) && raw < bounds.first) {
+ editor.putInt("${key}_before_height_profiles", raw)
+ editor.putInt(key, SettingsPreferences.getDefaultKeyboardHeightDp(context, landscape).coerceIn(bounds))
+ }
+ // 同一 editor 批量写入,监听器不会读到“已打迁移标记但高度尚未修复”的半成品。
+ editor.apply()
+ }
+}
--- a/app/src/main/java/com/kingzcheung/xime/service/XimeInputMethodService.kt
+++ b/app/src/main/java/com/kingzcheung/xime/service/XimeInputMethodService.kt
@@ -9,6 +9,7 @@
import android.os.SystemClock
import android.os.Looper
import android.util.Log
+import com.kingzcheung.xime.settings.KeyboardHeightProfiles
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.CursorAnchorInfo
@@ -399,7 +400,8 @@
private fun loadDarkModePreference() {
val isLandscape = resources.configuration.screenWidthDp > resources.configuration.screenHeightDp
- val isFloatingMode = SettingsPreferences.isFloatingMode(this, isLandscape)
+ val isFloatingMode = if (uiState.value.showKeyboardResize) uiState.value.isFloatingMode
+ else SettingsPreferences.isFloatingMode(this, isLandscape)
val loadedX = SettingsPreferences.getFloatingOffsetX(this, isLandscape)
val loadedY = SettingsPreferences.getFloatingOffsetY(this, isLandscape)
val screenW = resources.configuration.screenWidthDp
@@ -416,7 +418,8 @@
val cardWidth = savedWidth.takeIf { it > 0 } ?: (screenW * defaultWidthRatio).roundToInt()
val halfMargin = maxOf(0, (screenW - cardWidth) / 2)
- val kbH = SettingsPreferences.getKeyboardHeightDp(this, isLandscape)
+ KeyboardHeightProfiles.migrateLegacy(this, isLandscape, effectiveH)
+ val kbH = KeyboardHeightProfiles.selected(this, isFloatingMode, isLandscape, effectiveH)
val floatingBounds = com.kingzcheung.xime.ui.keyboard.floatingResizeHeightBounds(effectiveH, isLandscape)
val cappedKbH = if (isFloatingMode) kbH.coerceIn(floatingBounds) else kbH.coerceAtMost((screenH * 8) / 10)
val cardH = cappedKbH + FLOATING_DRAG_BAR_HEIGHT_DP
@@ -433,7 +436,7 @@
darkMode = SettingsPreferences.getDarkMode(this),
themeId = SettingsPreferences.getKeyboardTheme(this),
isSttEnabled = SettingsPreferences.isSttEnabled(this@XimeInputMethodService),
- keyboardHeightDp = SettingsPreferences.getKeyboardHeightDp(this, isLandscape),
+ keyboardHeightDp = kbH,
keyboardBottomPaddingDp = SettingsPreferences.getKeyboardBottomPaddingDp(this),
keyboardOpacity = SettingsPreferences.getKeyboardOpacity(this),
toolbarButtons = SettingsPreferences.getToolbarButtons(this),
@@ -448,11 +451,12 @@
val prefs = SettingsPreferences.getPrefsPublic(this)
sharedPrefsListener = android.content.SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) {
- "dark_mode", "keyboard_theme", "show_bottom_buttons", "keyboard_height_dp", "keyboard_bottom_padding_dp", "keyboard_opacity" -> {
+ "dark_mode", "keyboard_theme", "show_bottom_buttons", "keyboard_height_dp", "keyboard_height_dp_landscape", "keyboard_bottom_padding_dp", "keyboard_opacity" -> {
loadDarkModePreference()
applyWindowBackground()
}
- "floating_mode", "floating_mode_landscape", "floating_width_dp", "floating_width_dp_landscape" -> {
+ "floating_mode", "floating_mode_landscape", "floating_width_dp", "floating_width_dp_landscape",
+ KeyboardHeightProfiles.FLOATING_HEIGHT, KeyboardHeightProfiles.FLOATING_HEIGHT_LANDSCAPE -> {
loadDarkModePreference()
applyWindowBackground()
}
@@ -1248,21 +1252,24 @@
val screenIsLandscape = screenWidthDp > screenHeightDp
val portraitScreenHeightDp = if (screenIsLandscape) screenWidthDp else screenHeightDp
val isLandscape = !state.isFloatingMode && screenIsLandscape
- val orientationHeight = SettingsPreferences.getKeyboardHeightDp(this@XimeInputMethodService, screenIsLandscape)
+ val orientationHeight = KeyboardHeightProfiles.selected(
+ this@XimeInputMethodService, state.isFloatingMode, screenIsLandscape, effectiveScreenH
+ )
val displayHeight = orientationHeight.coerceAtMost((if (state.isFloatingMode) portraitScreenHeightDp else screenHeightDp) * 8 / 10)
- val heightBounds = com.kingzcheung.xime.ui.keyboard.keyboardHeightBounds(screenHeightDp, screenIsLandscape, floatingMinY)
+ val heightBounds = KeyboardHeightProfiles.fixedBounds(this@XimeInputMethodService, screenIsLandscape)
// 悬浮模式必须按当前“可见高度”限制内容高;旧逻辑按竖屏长边上限计算,
// 横屏时会得到比实际窗口还高的卡片,导致顶部/底部被裁切。
val floatingHeightBounds = com.kingzcheung.xime.ui.keyboard.floatingResizeHeightBounds(
effectiveScreenH, screenIsLandscape
)
- val keyboardHeight = (if (state.showKeyboardResize) state.resizePreviewHeightDp else displayHeight)
+ // 悬浮拖动仅由 Compose 的 previewRect 驱动,不能把进入调节时的固定高度当作悬浮高度。
+ val keyboardHeight = (if (state.showKeyboardResize && !state.isFloatingMode)
+ state.resizePreviewHeightDp else displayHeight)
.let {
when {
// 悬浮高度使用专用范围:比旧的普通键盘范围宽,但绝不允许拉成整屏长条。
state.isFloatingMode -> it.coerceIn(floatingHeightBounds)
- screenIsLandscape -> it.coerceIn(heightBounds)
- else -> it
+ else -> it.coerceIn(heightBounds)
}
}
// 浮动只收窄宽度,不再压缩按键行高或带入普通模式的底部留白。
@@ -1464,7 +1471,7 @@
val resizeControls: (@Composable () -> Unit)? = if (state.showKeyboardResize) {
{
KeyboardResizeOverlay(
- initialHeightDp = state.resizePreviewHeightDp,
+ initialHeightDp = effectiveKeyboardHeight,
// 左右边/四角可调宽度:边界与屏宽一致,与几何纯函数同源。
initialWidthDp = state.resizePreviewWidthDp,
minWidthDp = com.kingzcheung.xime.ui.keyboard.keyboardWidthBounds(resources.configuration.screenWidthDp).first,
@@ -1473,7 +1480,16 @@
currentBottomPaddingDp = contentBottomPaddingDp,
isFloatingMode = state.isFloatingMode,
initialOpacity = state.keyboardOpacity,
- onFloatingModeChange = { enabled -> schemaController.toggleFloatingMode(enabled, floatingMinY, persist = false) },
+ onFloatingModeChange = { enabled ->
+ schemaController.toggleFloatingMode(enabled, floatingMinY, persist = false)
+ val targetHeight = KeyboardHeightProfiles.selected(
+ this@XimeInputMethodService, enabled, screenIsLandscape, effectiveScreenH
+ )
+ uiState.value = uiState.value.copy(
+ keyboardHeightDp = targetHeight,
+ resizePreviewHeightDp = targetHeight,
+ )
+ },
isSplitKeyboard = SettingsPreferences.isSplitKeyboardEnabled(this@XimeInputMethodService),
// 始终传入回调:当前方案不支持分体时由覆盖层禁用按钮,
// 而不是让按钮整个消失(用户无法判断是禁用还是坏了)。
@@ -1522,30 +1538,40 @@
)
},
onConfirm = { newHeight, newPadding, floatingMode, opacity ->
- // 宽度已随拖动写入 resizePreviewWidthDp,未调过则保持原值。
- val savedWidth = uiState.value.resizePreviewWidthDp
- if (savedWidth > 0) {
- SettingsPreferences.setFloatingWidthDp(this@XimeInputMethodService, savedWidth, screenIsLandscape)
- }
- SettingsPreferences.setFloatingOffsetX(this@XimeInputMethodService, uiState.value.floatingOffsetX, screenIsLandscape)
- SettingsPreferences.setFloatingOffsetY(this@XimeInputMethodService, uiState.value.floatingOffsetY, screenIsLandscape)
- schemaController.setKeyboardHeight(newHeight)
- val savedPadding = if (floatingMode) SettingsPreferences.getKeyboardBottomPaddingDp(this@XimeInputMethodService) else newPadding
- SettingsPreferences.setKeyboardBottomPaddingDp(this@XimeInputMethodService, savedPadding)
+ // 先快照:写偏好会触发监听器,不能再读被监听器重载过的预览偏移。
+ val preview = uiState.value
+ val savedHeight = KeyboardHeightProfiles.save(
+ this@XimeInputMethodService, floatingMode, screenIsLandscape,
+ newHeight, effectiveScreenH,
+ )
+ val savedWidth = preview.resizePreviewWidthDp
+ .takeIf { floatingMode && it > 0 } ?: preview.floatingWidthDp
+ if (floatingMode) {
+ SettingsPreferences.setFloatingWidthDp(this@XimeInputMethodService, savedWidth, screenIsLandscape)
+ SettingsPreferences.setFloatingOffsetX(this@XimeInputMethodService, preview.floatingOffsetX, screenIsLandscape)
+ SettingsPreferences.setFloatingOffsetY(this@XimeInputMethodService, preview.floatingOffsetY, screenIsLandscape)
+ }
+ val savedPadding = if (floatingMode) {
+ SettingsPreferences.getKeyboardBottomPaddingDp(this@XimeInputMethodService)
+ } else newPadding
+ if (!floatingMode) SettingsPreferences.setKeyboardBottomPaddingDp(this@XimeInputMethodService, savedPadding)
SettingsPreferences.setKeyboardOpacity(this@XimeInputMethodService, opacity)
+ SettingsPreferences.setFloatingMode(this@XimeInputMethodService, floatingMode, screenIsLandscape)
uiState.value = uiState.value.copy(
showKeyboardResize = false,
isFloatingMode = floatingMode,
- keyboardHeightDp = newHeight,
+ keyboardHeightDp = savedHeight,
+ resizePreviewHeightDp = 0,
keyboardBottomPaddingDp = savedPadding,
- floatingWidthDp = if (savedWidth > 0) savedWidth else uiState.value.floatingWidthDp,
- resizePreviewWidthDp = 0,
+ floatingWidthDp = savedWidth,
+ resizePreviewWidthDp = 0,
+ floatingOffsetX = preview.floatingOffsetX,
+ floatingOffsetY = preview.floatingOffsetY,
keyboardOpacity = opacity,
)
- // 确认时才持久化悬浮模式;关闭/重新唤起输入法必须保持用户刚确认的状态。
- SettingsPreferences.setFloatingMode(this@XimeInputMethodService, floatingMode, screenIsLandscape)
- schemaController.toggleFloatingMode(floatingMode, floatingMinY, persist = true)
+ // 不再重复 toggleFloatingMode;它会重新读取设置并覆盖刚确认的预览位置。
refreshKeyboardGeometry()
+ applyWindowBackground()
},
onCancel = { cancelKeyboardResize() },
modifier = Modifier
@@ -1638,8 +1664,7 @@
// 按偏好高度预设首帧真实几何,之后仍由 SideEffect 统一维护。
val isLandscape =
resources.configuration.screenWidthDp > resources.configuration.screenHeightDp
- val displayHeight = SettingsPreferences.getKeyboardHeightDp(this, isLandscape)
- .coerceAtMost((resources.configuration.screenHeightDp * 8) / 10)
+ val displayHeight = KeyboardHeightProfiles.fixed(this, isLandscape)
val density = resources.displayMetrics.density
val rawDp = if (bottomInsetPxState.value > 0)
(bottomInsetPxState.value / density).toInt() else 0
@@ -1681,7 +1706,12 @@
floatingOffsetX = uiState.value.resizeInitialX,
floatingOffsetY = uiState.value.resizeInitialY,
resizePreviewWidthDp = 0,
- keyboardHeightDp = SettingsPreferences.getKeyboardHeightDp(this, isLandscape),
+ resizePreviewHeightDp = 0,
+ keyboardHeightDp = KeyboardHeightProfiles.selected(
+ this, uiState.value.resizeInitialFloating, isLandscape,
+ ((resources.displayMetrics.heightPixels / resources.displayMetrics.density).roundToInt() -
+ tryGetStatusBarHeightDp(this, window.window)).coerceAtLeast(1),
+ ),
keyboardBottomPaddingDp = SettingsPreferences.getKeyboardBottomPaddingDp(this),
keyboardOpacity = SettingsPreferences.getKeyboardOpacity(this),
)
@@ -1710,7 +1740,7 @@
state.isFloatingMode -> floatingHostHeight
state.isCompact -> screenHeight
else -> {
- val content = SettingsPreferences.getKeyboardHeightDp(this, landscape).coerceAtMost(screenHeight * 8 / 10)
+ val content = KeyboardHeightProfiles.fixed(this, landscape)
content + state.keyboardBottomPaddingDp + activeBottom
}
}
@@ -2506,8 +2536,11 @@
val decor = window.window?.decorView ?: return
if (currentEffectiveKeyboardHeight <= 0) {
val isLandscape = resources.configuration.screenWidthDp > resources.configuration.screenHeightDp
- val kbH = SettingsPreferences.getKeyboardHeightDp(this@XimeInputMethodService, isLandscape)
- .coerceAtMost((resources.configuration.screenHeightDp * 8) / 10)
+ val kbH = KeyboardHeightProfiles.floating(
+ this@XimeInputMethodService, isLandscape,
+ ((resources.displayMetrics.heightPixels / resources.displayMetrics.density).roundToInt() -
+ tryGetStatusBarHeightDp(this@XimeInputMethodService, window.window)).coerceAtLeast(1),
+ )
currentEffectiveKeyboardHeight = kbH + FLOATING_DRAG_BAR_HEIGHT_DP
}
val density = resources.displayMetrics.density
--- a/app/src/main/java/com/kingzcheung/xime/ui/keyboard/FloatingKeyboardContainer.kt
+++ b/app/src/main/java/com/kingzcheung/xime/ui/keyboard/FloatingKeyboardContainer.kt
@@ -39,6 +39,8 @@
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalConfiguration
+import androidx.compose.ui.platform.LocalContext
+import com.kingzcheung.xime.settings.KeyboardHeightProfiles
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.unit.Density
@@ -158,8 +160,10 @@
}
if (isDragging && edge != null) {
val progress = dockProgress.value
- val restoredHeight = (cardTotalHeight.value - FLOATING_DRAG_BAR_HEIGHT_DP)
- .coerceIn(48f, screenHeightDp * 0.8f)
+ val config = LocalConfiguration.current
+ val restoredHeight = KeyboardHeightProfiles.fixed(
+ LocalContext.current, config.screenWidthDp > config.screenHeightDp
+ ).toFloat()
val previewColor = MaterialTheme.colorScheme.primary
Box(
modifier = Modifier