ui(phone): переключение сессий ступенчатым свайпом (порог 120dp, ±1 сессия за жест) + крупнее текст сообщений (14→20sp)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package pw.binom.viewmate.phone.ui
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -33,6 +34,8 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@@ -48,7 +51,9 @@ import pw.binom.viewmate.phone.agent.Session
|
||||
/**
|
||||
* Экран «Чат с Порфирием»: история из SQLite, ввод текста, отправка в
|
||||
* локального ассистента (та же очередь, что и голос с очков). Управление
|
||||
* сессиями: новая, переключение (выпадающий список), сброс текущей.
|
||||
* сессиями: новая, переключение (выпадающий список ИЛИ ступенчатый горизонтальный
|
||||
* свайп ленты сообщений — на одну сессию за жест, без инерции; TZ-ui-four п.3),
|
||||
* сброс текущей.
|
||||
*/
|
||||
@Composable
|
||||
fun ChatScreen() {
|
||||
@@ -104,6 +109,25 @@ fun ChatScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
// Ступенчатое переключение сессий свайпом (TZ-ui-four п.3): фиксированный
|
||||
// порог смещения в px (плотность экрана).
|
||||
val thresholdPx = with(LocalDensity.current) { CHAT_SESSION_SWIPE_THRESHOLD.toPx() }
|
||||
|
||||
/**
|
||||
* Ступенчатое переключение: ровно ОДИН шаг (+1 — следующая, −1 — предыдущая),
|
||||
* без перескока сразу на несколько сессий, без инерции/флинга;
|
||||
* за границей списка — ничего.
|
||||
*/
|
||||
fun switchSessionBy(delta: Int) {
|
||||
if (sessions.size < 2) return
|
||||
val idx = sessions.indexOfFirst { it.id == activeId }.let { if (it >= 0) it else 0 }
|
||||
val target = idx + delta
|
||||
if (target < 0 || target >= sessions.size) return
|
||||
val s = sessions[target]
|
||||
activeId = s.id
|
||||
app.selectChatSession(s.id)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
@@ -173,7 +197,31 @@ fun ChatScreen() {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
// Лента сообщений
|
||||
Box(modifier = Modifier.weight(1f).fillMaxWidth()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth()
|
||||
// Ступенчатая смена сессии (TZ-ui-four п.3): горизонтальный свайп
|
||||
// ленты за фиксированный порог = ±одна сессия (свайп влево —
|
||||
// следующая, вправо — предыдущая), мгновенно, без физики/инерции.
|
||||
// foundation 1.8: onHorizontalDrag даёт (change, суммарный сдвиг x с
|
||||
// начала жеста) — берём суммарный сдвиг без накопления по кадрам.
|
||||
.pointerInput(sessions.size) {
|
||||
var draggedPx = 0f
|
||||
detectHorizontalDragGestures(
|
||||
onHorizontalDrag = { _, amount -> draggedPx = amount },
|
||||
onDragCancel = { draggedPx = 0f },
|
||||
onDragEnd = {
|
||||
when {
|
||||
draggedPx <= -thresholdPx -> switchSessionBy(1)
|
||||
draggedPx >= thresholdPx -> switchSessionBy(-1)
|
||||
else -> Unit
|
||||
}
|
||||
draggedPx = 0f
|
||||
},
|
||||
)
|
||||
},
|
||||
) {
|
||||
if (messages.isEmpty()) {
|
||||
Text(
|
||||
text = "Спроси что-нибудь — например, «сколько сейчас время?»",
|
||||
@@ -228,7 +276,9 @@ private fun MessageBubble(role: ChatRole, text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
color = PhoneText,
|
||||
fontSize = 14.sp,
|
||||
// Базовый шрифт сообщений (TZ-ui-four п.2): крупнее, чтобы читалось
|
||||
// без напряжения (14.sp → 20.sp, ~+43%); вёртка баллонов не менялась.
|
||||
fontSize = 20.sp,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 10.dp, vertical = 6.dp)
|
||||
.background(
|
||||
@@ -239,3 +289,9 @@ private fun MessageBubble(role: ChatRole, text: String) {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Фиксированный порог ступенчатого свайпа переключения сессий (TZ-ui-four п.3):
|
||||
* жест «перетолкал» ленту на него — смена ровно на одну сессию; меньше — назад.
|
||||
*/
|
||||
private val CHAT_SESSION_SWIPE_THRESHOLD = 120.dp
|
||||
|
||||
Reference in New Issue
Block a user