feat(app-glasses): панель статуса — время + заряд (цвет по статусу)

Поверх видео (GL-оверлей в EglVideoRenderer: bitmap-текстура, правый
верхний угол, обе поверхности) и композ-панель на экране соединения.
Цвета (из удачной панели pair-view StatusComponent): CHARGING/FULL —
зелёный, DISCHARGING — белый, NOT_CHARGING — красный.
Данные: StatusPanelProvider (sticky ACTION_BATTERY_CHANGED + тик 1с,
HH:mm). Тесты 4 (chargeColorArgb). Железо: «00:02 94%» + зелёный
квадрат (очки на зарядке), скрин подтверждён.
This commit is contained in:
Hermes Agent
2026-08-20 00:03:23 +03:00
parent 2b6fdb7148
commit 3f858c4a1a
5 changed files with 392 additions and 15 deletions
@@ -17,19 +17,29 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
@@ -41,6 +51,9 @@ import com.rayneo.arsdk.android.ui.activity.BaseEventActivity
import kotlinx.coroutines.launch
import pw.binom.viewmate.glasses.gestures.actionName
import pw.binom.viewmate.glasses.gestures.templeActionToCommand
import pw.binom.viewmate.glasses.status.CHARGE_COLOR_DISCHARGING
import pw.binom.viewmate.glasses.status.StatusPanelData
import pw.binom.viewmate.glasses.status.StatusPanelProvider
import pw.binom.viewmate.glasses.ui.GlassesMovieScreen
class MainActivity : BaseEventActivity() {
@@ -245,18 +258,58 @@ fun ConnectionScreen() {
val status by connection.status.collectAsState()
val messages by connection.messages.collectAsState()
Column(
modifier = Modifier.fillMaxSize().background(Color.Black).padding(24.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text("ViewMate Glasses", style = MaterialTheme.typography.headlineMedium)
Text(if (connected) "подключено к телефону" else "нет соединения")
Text(status, style = MaterialTheme.typography.bodyMedium)
Text("Последние сообщения:", style = MaterialTheme.typography.titleMedium)
LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(messages) { msg ->
Text(msg, style = MaterialTheme.typography.bodySmall)
val context = LocalContext.current
var statusData by remember {
mutableStateOf(StatusPanelData("--:--", 0, CHARGE_COLOR_DISCHARGING))
}
val statusProvider = remember(context) {
StatusPanelProvider(context.applicationContext) { statusData = it }
}
DisposableEffect(statusProvider) {
statusProvider.start()
onDispose { statusProvider.stop() }
}
Box(modifier = Modifier.fillMaxSize().background(Color.Black)) {
Column(
modifier = Modifier.fillMaxSize().padding(24.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text("ViewMate Glasses", style = MaterialTheme.typography.headlineMedium)
Text(if (connected) "подключено к телефону" else "нет соединения")
Text(status, style = MaterialTheme.typography.bodyMedium)
Text("Последние сообщения:", style = MaterialTheme.typography.titleMedium)
LazyColumn(modifier = Modifier.fillMaxWidth()) {
items(messages) { msg ->
Text(msg, style = MaterialTheme.typography.bodySmall)
}
}
}
StatusPanelOverlay(
data = statusData,
modifier = Modifier.align(Alignment.TopEnd).padding(8.dp),
)
}
}
/** Маленькая панель статуса (время + цветной квадрат + заряд) в правом верхнем углу. */
@Composable
private fun StatusPanelOverlay(data: StatusPanelData, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.clip(RoundedCornerShape(6.dp))
.background(Color(0x80000000.toInt()))
.padding(horizontal = 6.dp, vertical = 3.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
Modifier
.size(12.dp)
.background(Color(data.chargeColorArgb))
)
Text(data.time, color = Color.White, style = MaterialTheme.typography.bodySmall)
Text("${data.percent}%", color = Color.White, style = MaterialTheme.typography.bodySmall)
}
}