Files
view-mate/TASK-gestures-modes.md

4.8 KiB
Raw Permalink Blame History

Задача: жесты и режимы общения с ассистентом на очках (design в docs/gestures-and-modes.md)

Прочитай docs/gestures-and-modes.md — там согласованная с пользователем матрица жестов и все решения. Реализуй в app-glasses. Механику тулсетов/ассистента (app-phone) НЕ трогать.

Что сделать

1. Переразметка жестов по матрице (MainActivity.kt, collectTempleActions)

Состояние Click DoubleClick TripleClick Свайпы/SlideContinuous
Кино (listening=false, assistantText пуст) TOGGLE (как сейчас) игнор вызов ассистента (как сейчас) ±30с (как сейчас)
Прослушивание (listening=true) отправить (как сейчас) отмена, остаёмся в диалоге (как сейчас) игнор игнор
Ответ виден (listening=false, assistantText непуст) новая фраза: стереть assistantText, открыть микрофон, listening=true выход из режима: закрыть оверлей, стереть assistantText, фильм на паузе (НЕ трогать play/pause — пауза уже стоит с момента входа) игнор скролл ответа (плавный SlideContinuous, запасной — дискретные свайпы)

Важно: состояние «ответ виден» определяется !listening && assistantText.isNotBlank().

2. Скролл ответа (плавный)

  • SlideContinuous: накапливать delta (float) → смещать scrollState текста ответа. Направление: SlideForward = вниз по тексту (к концу), SlideBackward = вверх (к началу) — уточнить знак дельты на железе.
  • Ограничить скролл границами текста (0..maxScroll).
  • Запасной вариант: SlideForward/SlideBackward — скролл на страницу (например, ±200px или высоту видимой области), если SlideContinuous окажется шумным.
  • Текст ответа в оверлее должен быть в scrollable-контейнере (Column + verticalScroll(rememberScrollState()) или LazyColumn — на твой выбор, но скролл обязателен).

3. Индикатор «думаю...»

  • Состояние thinking: true с момента отправки фразы (Click при прослушивании / SttPhrase ушёл) до прихода ShowText.
  • В оверлее: если thinking и assistantText пуст — показывать «думаю...» (вместо «слушаю...» после того как фраза отправлена).
  • Как определить: пока listening=true — «слушаю...»/текст фразы; когда listening стал false, а ShowText ещё не пришёл — «думаю...».

4. Выход из режима

DoubleClick при «ответ виден»: закрыть оверлей (listening=false, sttText="", assistantText=""), НЕ трогать movieController (фильм остаётся на паузе — он уже на паузе с момента входа в режим).

Ограничения

  • Код только Kotlin
  • НЕ трогать app-phone (ассистент, тулсеты, скиллы)
  • НЕ трогать MovieController/playback-логику
  • Тесты: юнит-тесты на чистую логику разметки жестов (новое состояние «ответ виден», переходы, скролл-дельта → смещение) — в духе GestureCommandsTest. Если логика в MainActivity (не чистая) — вынеси чистую часть (решение по жесту из состояния) в отдельный файл/функцию для тестируемости.
  • Сборка: ./gradlew :app-glasses:assembleDebug — зелёная; ./gradlew :app-glasses:testDebugUnitTest — зелёный (старые + новые)
  • НЕ коммитить

Проверка

  1. ./gradlew :app-glasses:testDebugUnitTest — зелёные
  2. ./gradlew :app-glasses:assembleDebug — собирается
  3. Опиши в ответе: какие файлы создал/изменил, как определил состояние «ответ виден», как работает скролл (SlideContinuous или запасной), что осталось проверить на железе.