fix: magnifier правильные координаты + haptic при изменении выделения

Magnifier:
- Конвертация overlay-local → view-local координаты для Magnifier.show()
- Builder: 240×64px, cornerRadius 12, elevation 4, offset -80 (над текстом)

Haptic:
- TEXT_HANDLE_MOVE при каждом изменении selectionStart/selectionEnd
- Как в Telegram: вибрация при перемещении handle по словам

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 16:12:29 +05:00
parent 1ac3d93f74
commit 78925dd61d

View File

@@ -127,7 +127,9 @@ class TextSelectionHelper {
var newStart = charOffset.coerceIn(0, text.length)
while (newStart > 0 && Character.isLetterOrDigit(text[newStart - 1])) newStart--
if (newStart >= selectionEnd) return
val changed = newStart != selectionStart
selectionStart = newStart
if (changed) hapticOnSelectionChange()
}
fun updateSelectionEnd(charOffset: Int) {
@@ -136,7 +138,16 @@ class TextSelectionHelper {
var newEnd = charOffset.coerceIn(0, text.length)
while (newEnd < text.length && Character.isLetterOrDigit(text[newEnd])) newEnd++
if (newEnd <= selectionStart) return
val changed = newEnd != selectionEnd
selectionEnd = newEnd
if (changed) hapticOnSelectionChange()
}
private fun hapticOnSelectionChange() {
magnifierView?.performHapticFeedback(
HapticFeedbackConstants.TEXT_HANDLE_MOVE,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
fun beginHandleDrag(isStart: Boolean, touchX: Float, touchY: Float) {
@@ -180,24 +191,30 @@ class TextSelectionHelper {
magnifierView = view
}
fun showMagnifier(x: Float, y: Float) {
fun showMagnifier(overlayLocalX: Float, overlayLocalY: Float) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.P) return
val view = magnifierView ?: return
if (!movingHandle) return
if (magnifier == null) {
magnifier = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
android.widget.Magnifier.Builder(view)
.setSize(200, 80)
.setCornerRadius(16f)
.setSize(240, 64)
.setCornerRadius(12f)
.setElevation(4f)
.setDefaultSourceToMagnifierOffset(0, -80)
.build()
} else {
@Suppress("DEPRECATION")
android.widget.Magnifier(view)
}
}
val info = layoutInfo ?: return
val localX = (x - info.windowX).coerceIn(0f, view.width.toFloat())
val localY = (y - info.windowY).coerceIn(0f, view.height.toFloat())
magnifier?.show(localX, localY)
// Convert overlay-local → view-local (magnifierView coords)
val viewLoc = IntArray(2)
view.getLocationInWindow(viewLoc)
val sourceX = (overlayLocalX + overlayWindowX - viewLoc[0]).coerceIn(0f, view.width.toFloat())
val sourceY = (overlayLocalY + overlayWindowY - viewLoc[1]).coerceIn(0f, view.height.toFloat())
magnifier?.show(sourceX, sourceY)
}
fun hideMagnifier() {