refactor: 功能按钮全面布局优化 — 均布四周+平行四边形样式+互斥合并
- 起立/趴下合并为切换按钮,移至左上角 - 模式选择器(3个互斥无缝隙)移至左上角最上方 - 步态切换(4个互斥无缝隙)移至模式选择器下方,仅普通模式可点击 - 照明/休眠/充电移至右上角,紧凑排列 - 所有功能按钮使用平行四边形形状(左侧向右倾斜,右侧向左倾斜) - 底部控制区移除更多展开区域,仅保留摇杆 - 所有控制按钮未连接时灰色不可点击 Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -200,8 +200,15 @@ gradlew installDebug
|
||||
- [x] UI 布局:连接按钮合并到顶部 StatusBar 的 ConnectionIndicator,删除底部独立连接按钮
|
||||
- [x] UI 布局:ConnectionIndicator 改为按钮形态(Surface + 圆角边框),仅指示器区域可点击切换连接
|
||||
- [x] UI 布局:隐藏系统状态栏(WindowInsetsControllerCompat),压缩自定义 StatusBar 高度,扩展可视区域
|
||||
- [x] UI 布局:功能按钮均布在四周——左上角模式选择+步态切换+起立/趴下,右上角灯光+休眠+充电,充分利用屏幕空间,优化单手操作体验
|
||||
- [x] UI 布局:起立/趴下合并为切换按钮(琥珀色=站立时显示"趴下",暗色=非站立时显示"起立"),移至左上角 StatusBar 下方
|
||||
- [x] UI 布局:模式选择器(常规/导航/辅助,3个互斥按钮,无缝隙,底色显示当前模式)移至左上角,位于起立/趴上方
|
||||
- [x] UI 布局:步态切换(基础/楼梯/平地敏捷/楼梯敏捷,4个互斥按钮,无缝隙)移至模式选择器下方,始终显示,仅普通模式+RL控制时可点击
|
||||
- [x] UI 布局:照明/休眠/充电移至右上角,紧凑排列(前灯后灯无缝隙一行,休眠/唤醒切换,充电/充电中切换)
|
||||
- [x] UI 布局:底部控制区移除"更多"展开区域,仅保留左右摇杆
|
||||
- [x] UI 布局:所有功能按钮统一使用平行四边形形状(左侧按钮斜边左下→右上,右侧按钮斜边左上→右下)
|
||||
- [x] UI 布局:所有控制按钮在未连接时灰色不可点击
|
||||
|
||||
### 待办
|
||||
|
||||
- [ ] UI 布局:功能按钮均布在四周,充分利用屏幕空间,优化单手操作体验
|
||||
- [ ] 视频进一步延迟优化:探索更激进的低延迟策略(如降低帧率、缩小分辨率、调整 ExoPlayer 缓冲策略等)
|
||||
|
||||
@@ -17,10 +17,8 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Info
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
@@ -40,12 +38,19 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.Path
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -66,6 +71,38 @@ import com.example.m20_gamepad.video.RtspVideoPlayer
|
||||
private val OverlayBg = Color(0x88000000)
|
||||
private val OverlayText = Color.White
|
||||
|
||||
/** 平行四边形形状,用于功能按钮。skewLeft=true → 左下-右上斜边(左侧按钮);
|
||||
* skewLeft=false → 左上-右下斜边(右侧按钮)。 */
|
||||
private class ParallelogramShape(
|
||||
private val skewDp: Dp = 10.dp,
|
||||
private val skewLeft: Boolean = true
|
||||
) : Shape {
|
||||
override fun createOutline(
|
||||
size: Size,
|
||||
layoutDirection: LayoutDirection,
|
||||
density: Density
|
||||
): Outline {
|
||||
val skewPx = with(density) { skewDp.toPx() }
|
||||
val path = Path().apply {
|
||||
if (skewLeft) {
|
||||
// 左下 → 右上 斜边(平行四边形向右倾斜)
|
||||
moveTo(skewPx, 0f)
|
||||
lineTo(size.width, 0f)
|
||||
lineTo(size.width - skewPx, size.height)
|
||||
lineTo(0f, size.height)
|
||||
} else {
|
||||
// 左上 → 右下 斜边(平行四边形向左倾斜)
|
||||
moveTo(0f, 0f)
|
||||
lineTo(size.width - skewPx, 0f)
|
||||
lineTo(size.width, size.height)
|
||||
lineTo(skewPx, size.height)
|
||||
}
|
||||
close()
|
||||
}
|
||||
return Outline.Generic(path)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主界面:RTSP 视频背景 + 双摇杆覆盖层 + 状态栏 + 控制按钮。
|
||||
*
|
||||
@@ -144,12 +181,89 @@ fun MainScreen(
|
||||
modifier = Modifier.align(Alignment.TopCenter)
|
||||
)
|
||||
|
||||
// ---- 左上角控制区:模式选择 + 步态切换 + 起立/趴下 ----
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(top = 56.dp, start = 12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||
) {
|
||||
ModeSelector(
|
||||
currentMode = status?.basicStatus?.controlUsageMode ?: 0,
|
||||
connected = connectionState == ProtocolClient.State.CONNECTED,
|
||||
onSelectMode = { mode -> viewModel.sendSwitchMode(mode) }
|
||||
)
|
||||
// 步态切换——始终显示,仅普通模式 + RL 控制时可点击
|
||||
GaitSelector(
|
||||
currentGait = status?.basicStatus?.gait ?: 0,
|
||||
enabled = connectionState == ProtocolClient.State.CONNECTED &&
|
||||
motionState == ControlCommands.MOTION_RL_CONTROL &&
|
||||
status?.basicStatus?.controlUsageMode == ControlCommands.MODE_NORMAL,
|
||||
onSelectGait = { gait -> viewModel.sendSwitchGait(gait) }
|
||||
)
|
||||
StandToggleButton(
|
||||
motionState = motionState,
|
||||
connected = connectionState == ProtocolClient.State.CONNECTED,
|
||||
onToggle = {
|
||||
if (motionState == ControlCommands.MOTION_IDLE ||
|
||||
motionState == ControlCommands.MOTION_LIE_DOWN
|
||||
) {
|
||||
viewModel.sendMotionControl(ControlCommands.MOTION_STAND)
|
||||
} else {
|
||||
viewModel.sendMotionControl(ControlCommands.MOTION_LIE_DOWN)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// ---- 右上角控制区:照明 + 休眠 + 充电 ----
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = 56.dp, end = 12.dp),
|
||||
horizontalAlignment = Alignment.End,
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||
) {
|
||||
// 照明:前灯+后灯,无缝隙
|
||||
val frontOn = ledStatus?.front == 1
|
||||
val backOn = ledStatus?.back == 1
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(0.dp)) {
|
||||
LightToggleButton(
|
||||
text = "前灯",
|
||||
isOn = frontOn,
|
||||
enabled = connectionState == ProtocolClient.State.CONNECTED
|
||||
) {
|
||||
viewModel.sendLightControl(if (frontOn) 0 else 1, ledStatus?.back ?: 0)
|
||||
}
|
||||
LightToggleButton(
|
||||
text = "后灯",
|
||||
isOn = backOn,
|
||||
enabled = connectionState == ProtocolClient.State.CONNECTED
|
||||
) {
|
||||
viewModel.sendLightControl(ledStatus?.front ?: 0, if (backOn) 0 else 1)
|
||||
}
|
||||
}
|
||||
// 休眠/唤醒
|
||||
val isSleeping = status?.basicStatus?.sleep == 1
|
||||
SleepToggleButton(
|
||||
isSleeping = isSleeping,
|
||||
connected = connectionState == ProtocolClient.State.CONNECTED,
|
||||
onToggle = { viewModel.sendSleepSettings(!isSleeping) }
|
||||
)
|
||||
// 充电/结束充电
|
||||
val isCharging = status?.basicStatus?.charge == 1
|
||||
ChargeToggleButton(
|
||||
isCharging = isCharging,
|
||||
connected = connectionState == ProtocolClient.State.CONNECTED,
|
||||
onToggle = { viewModel.sendChargeControl(if (isCharging) 0 else 1) }
|
||||
)
|
||||
}
|
||||
|
||||
// ---- 底部控制区 ----
|
||||
BottomControls(
|
||||
viewModel = viewModel,
|
||||
connectionState = connectionState,
|
||||
motionState = motionState,
|
||||
ledStatus = ledStatus,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
@@ -336,7 +450,6 @@ private fun BottomControls(
|
||||
viewModel: MainViewModel,
|
||||
connectionState: ProtocolClient.State,
|
||||
motionState: Int,
|
||||
ledStatus: LedStatus?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
@@ -357,14 +470,6 @@ private fun BottomControls(
|
||||
}
|
||||
)
|
||||
|
||||
// 中间控制按钮组
|
||||
ControlButtons(
|
||||
viewModel = viewModel,
|
||||
connectionState = connectionState,
|
||||
motionState = motionState,
|
||||
ledStatus = ledStatus
|
||||
)
|
||||
|
||||
// 右摇杆(Yaw 旋转)
|
||||
Joystick(
|
||||
modifier = Modifier.size(180.dp),
|
||||
@@ -378,170 +483,6 @@ private fun BottomControls(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ControlButtons(
|
||||
viewModel: MainViewModel,
|
||||
connectionState: ProtocolClient.State,
|
||||
motionState: Int,
|
||||
ledStatus: LedStatus?
|
||||
) {
|
||||
val connected = connectionState == ProtocolClient.State.CONNECTED
|
||||
val isRlControl = motionState == ControlCommands.MOTION_RL_CONTROL
|
||||
var showMore by remember { mutableStateOf(false) }
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||
modifier = Modifier
|
||||
.verticalScroll(scrollState)
|
||||
.padding(top = 4.dp, bottom = 4.dp)
|
||||
) {
|
||||
// 运动状态转换
|
||||
ControlButton(
|
||||
"起立",
|
||||
enabled = connected && (motionState == ControlCommands.MOTION_IDLE ||
|
||||
motionState == ControlCommands.MOTION_LIE_DOWN)
|
||||
) {
|
||||
viewModel.sendMotionControl(ControlCommands.MOTION_STAND)
|
||||
}
|
||||
ControlButton(
|
||||
"RL控制",
|
||||
enabled = connected && motionState == ControlCommands.MOTION_STAND
|
||||
) {
|
||||
viewModel.sendMotionControl(ControlCommands.MOTION_RL_CONTROL)
|
||||
}
|
||||
ControlButton(
|
||||
"趴下",
|
||||
enabled = connected && motionState != ControlCommands.MOTION_LIE_DOWN
|
||||
) {
|
||||
viewModel.sendMotionControl(ControlCommands.MOTION_LIE_DOWN)
|
||||
}
|
||||
|
||||
// 步态切换——仅 RL 控制
|
||||
if (isRlControl) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
MiniButton("基础", enabled = isRlControl) {
|
||||
viewModel.sendSwitchGait(ControlCommands.GAIT_BASIC)
|
||||
}
|
||||
MiniButton("楼梯", enabled = isRlControl) {
|
||||
viewModel.sendSwitchGait(ControlCommands.GAIT_STAIRS)
|
||||
}
|
||||
MiniButton("平地敏捷", enabled = isRlControl) {
|
||||
viewModel.sendSwitchGait(ControlCommands.GAIT_FLAT_AGILE)
|
||||
}
|
||||
}
|
||||
MiniButton("楼梯敏捷", enabled = isRlControl) {
|
||||
viewModel.sendSwitchGait(ControlCommands.GAIT_STAIRS_AGILE)
|
||||
}
|
||||
}
|
||||
|
||||
// 更多/收起切换
|
||||
if (connected) {
|
||||
ControlButton(if (showMore) "收起" else "更多", enabled = connected) {
|
||||
showMore = !showMore
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 更多控制(可展开) ----
|
||||
if (showMore) {
|
||||
Separator()
|
||||
|
||||
// 使用模式
|
||||
SectionLabel("使用模式")
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
MiniButton("常规") {
|
||||
viewModel.sendSwitchMode(ControlCommands.MODE_NORMAL)
|
||||
}
|
||||
MiniButton("导航") {
|
||||
viewModel.sendSwitchMode(ControlCommands.MODE_NAVIGATION)
|
||||
}
|
||||
MiniButton("辅助") {
|
||||
viewModel.sendSwitchMode(ControlCommands.MODE_ASSIST)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
// 照明
|
||||
SectionLabel("照明")
|
||||
val frontOn = ledStatus?.front == 1
|
||||
val backOn = ledStatus?.back == 1
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
LightToggleButton(
|
||||
text = "前灯",
|
||||
isOn = frontOn,
|
||||
enabled = connected
|
||||
) {
|
||||
viewModel.sendLightControl(if (frontOn) 0 else 1, ledStatus?.back ?: 0)
|
||||
}
|
||||
LightToggleButton(
|
||||
text = "后灯",
|
||||
isOn = backOn,
|
||||
enabled = connected
|
||||
) {
|
||||
viewModel.sendLightControl(ledStatus?.front ?: 0, if (backOn) 0 else 1)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
// 充电
|
||||
SectionLabel("充电")
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
MiniButton("开始充电") { viewModel.sendChargeControl(1) }
|
||||
MiniButton("结束充电") { viewModel.sendChargeControl(0) }
|
||||
}
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
// 休眠
|
||||
SectionLabel("休眠")
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
MiniButton("进入休眠") { viewModel.sendSleepSettings(true) }
|
||||
MiniButton("唤醒") { viewModel.sendSleepSettings(false) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ControlButton(
|
||||
text: String,
|
||||
enabled: Boolean = true,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
modifier = Modifier.width(110.dp)
|
||||
) {
|
||||
Text(text, color = if (enabled) OverlayText else Color(0x88FFFFFF), fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MiniButton(text: String, enabled: Boolean = true, onClick: () -> Unit) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
color = if (enabled) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Normal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LightToggleButton(
|
||||
text: String,
|
||||
@@ -552,40 +493,205 @@ private fun LightToggleButton(
|
||||
Button(
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
shape = ParallelogramShape(skewLeft = false),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isOn) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
modifier = Modifier.width(110.dp)
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
"$text ${if (isOn) "开" else "关"}",
|
||||
color = if (enabled) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SectionLabel(text: String) {
|
||||
private fun StandToggleButton(
|
||||
motionState: Int,
|
||||
connected: Boolean,
|
||||
onToggle: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val isStanding = motionState == ControlCommands.MOTION_STAND ||
|
||||
motionState == ControlCommands.MOTION_RL_CONTROL
|
||||
Button(
|
||||
onClick = onToggle,
|
||||
enabled = connected,
|
||||
shape = ParallelogramShape(skewLeft = true),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isStanding) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
color = Color(0xFFB0B0B0),
|
||||
fontSize = 11.sp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
text = if (isStanding) "趴下" else "起立",
|
||||
color = if (connected) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 模式选择器(3个互斥无缝隙) ====================
|
||||
|
||||
@Composable
|
||||
private fun ModeSelector(
|
||||
currentMode: Int,
|
||||
connected: Boolean,
|
||||
onSelectMode: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
ModeButton("常规", ControlCommands.MODE_NORMAL, currentMode, connected, onSelectMode)
|
||||
ModeButton("导航", ControlCommands.MODE_NAVIGATION, currentMode, connected, onSelectMode)
|
||||
ModeButton("辅助", ControlCommands.MODE_ASSIST, currentMode, connected, onSelectMode)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Separator() {
|
||||
Spacer(Modifier.height(2.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(80.dp)
|
||||
.height(1.dp)
|
||||
.background(Color(0x44FFFFFF))
|
||||
private fun ModeButton(
|
||||
text: String,
|
||||
mode: Int,
|
||||
currentMode: Int,
|
||||
connected: Boolean,
|
||||
onClick: (Int) -> Unit
|
||||
) {
|
||||
val isActive = currentMode == mode
|
||||
Button(
|
||||
onClick = { onClick(mode) },
|
||||
enabled = connected,
|
||||
shape = ParallelogramShape(skewLeft = true),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isActive) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
color = if (connected) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = if (isActive) FontWeight.Bold else FontWeight.Normal
|
||||
)
|
||||
Spacer(Modifier.height(2.dp))
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 步态切换(4个互斥无缝隙,仅普通模式可用) ====================
|
||||
|
||||
@Composable
|
||||
private fun GaitSelector(
|
||||
currentGait: Int,
|
||||
enabled: Boolean,
|
||||
onSelectGait: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
GaitButton("基础", ControlCommands.GAIT_BASIC, currentGait, enabled, onSelectGait)
|
||||
GaitButton("楼梯", ControlCommands.GAIT_STAIRS, currentGait, enabled, onSelectGait)
|
||||
GaitButton("平地敏捷", ControlCommands.GAIT_FLAT_AGILE, currentGait, enabled, onSelectGait)
|
||||
GaitButton("楼梯敏捷", ControlCommands.GAIT_STAIRS_AGILE, currentGait, enabled, onSelectGait)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GaitButton(
|
||||
text: String,
|
||||
gait: Int,
|
||||
currentGait: Int,
|
||||
enabled: Boolean,
|
||||
onClick: (Int) -> Unit
|
||||
) {
|
||||
val isActive = currentGait == gait
|
||||
Button(
|
||||
onClick = { onClick(gait) },
|
||||
enabled = enabled,
|
||||
shape = ParallelogramShape(skewLeft = true),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isActive) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = Modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text,
|
||||
color = if (enabled) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = if (isActive) FontWeight.Bold else FontWeight.Normal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 休眠/唤醒切换 ====================
|
||||
|
||||
@Composable
|
||||
private fun SleepToggleButton(
|
||||
isSleeping: Boolean,
|
||||
connected: Boolean,
|
||||
onToggle: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Button(
|
||||
onClick = onToggle,
|
||||
enabled = connected,
|
||||
shape = ParallelogramShape(skewLeft = false),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isSleeping) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (isSleeping) "唤醒" else "休眠",
|
||||
color = if (connected) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 充电/结束充电切换 ====================
|
||||
|
||||
@Composable
|
||||
private fun ChargeToggleButton(
|
||||
isCharging: Boolean,
|
||||
connected: Boolean,
|
||||
onToggle: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Button(
|
||||
onClick = onToggle,
|
||||
enabled = connected,
|
||||
shape = ParallelogramShape(skewLeft = false),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = if (isCharging) Color(0xCCFFC107) else Color(0x66333333),
|
||||
disabledContainerColor = Color(0x33222222)
|
||||
),
|
||||
contentPadding = ButtonDefaults.TextButtonContentPadding,
|
||||
modifier = modifier.height(32.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (isCharging) "充电中" else "充电",
|
||||
color = if (connected) OverlayText else Color(0x88FFFFFF),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 辅助函数 ====================
|
||||
|
||||
Reference in New Issue
Block a user