播放器: 时间/网速/电量布局调整
- PlayerStatusBar拆分为PlayerTimeDisplay和PlayerNetworkInfo两个独立组件 - 时间显示在关闭按钮上方(左侧) - 网速+电量显示在播放工具按钮上方(右侧) - 减少间距从8dp到2dp Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7c991c04be
commit
702e9810d0
1 file changed
+47
-46
@@ -905,15 +905,22 @@ fun VideoPlayerScreen(
|
||||
}
|
||||
|
||||
Column(Modifier.fillMaxWidth().statusBarsPadding().padding(top = LumaSpacing.md)) {
|
||||
// P0: Delegated to extracted composable — only this component polls and recomposes
|
||||
PlayerStatusBar(
|
||||
playbackUrl = playbackUrl,
|
||||
networkSpeed = networkSpeed,
|
||||
isWifi = isWifi,
|
||||
batteryPercent = batteryPercent,
|
||||
isCharging = isCharging,
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
// 第一排:时间(左)| 网速+电量(右)
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(horizontal = capsuleInset),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
PlayerTimeDisplay(modifier = Modifier)
|
||||
PlayerNetworkInfo(
|
||||
playbackUrl = playbackUrl,
|
||||
networkSpeed = networkSpeed,
|
||||
isWifi = isWifi,
|
||||
batteryPercent = batteryPercent,
|
||||
isCharging = isCharging,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(2.dp))
|
||||
// 第二排:关闭按钮(左)|Emby 艺术字(紧跟关闭按钮右侧)|字幕/剧集按钮(右)
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(horizontal = capsuleInset),
|
||||
@@ -974,9 +981,8 @@ fun VideoPlayerScreen(
|
||||
}
|
||||
}
|
||||
if (serverName.isNotBlank()) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
// 第三排:服务器图标 + 服务器名字
|
||||
Row(Modifier.fillMaxWidth().padding(start = capsuleInset + 52.dp, end = capsuleInset), verticalAlignment = Alignment.CenterVertically) {
|
||||
Row(Modifier.fillMaxWidth().padding(start = capsuleInset + 52.dp, end = capsuleInset, top = 2.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(Modifier.size(30.dp).clip(CircleShape), contentAlignment = Alignment.Center) {
|
||||
if (serverIconUrl.isNotBlank()) {
|
||||
AsyncImage(
|
||||
@@ -1624,51 +1630,46 @@ private fun LiquidMenuItem(text: String, selected: Boolean, onClick: () -> Unit)
|
||||
}
|
||||
}
|
||||
|
||||
// P0: Extract status bar into its own composable so polling states (time/wifi/battery/speed)
|
||||
// only recompose this small component instead of the entire VideoPlayerScreen.
|
||||
// Extract status bar into separate composables so polling states only recompose their own component.
|
||||
@Composable
|
||||
private fun PlayerStatusBar(
|
||||
playbackUrl: String?,
|
||||
networkSpeed: Long,
|
||||
isWifi: Boolean,
|
||||
batteryPercent: Int,
|
||||
isCharging: Boolean,
|
||||
capsuleInset: Dp = 18.dp,
|
||||
) {
|
||||
private fun PlayerTimeDisplay(modifier: Modifier = Modifier) {
|
||||
val topTimeText = remember { mutableStateOf("") }
|
||||
val localNetworkSpeed by rememberUpdatedState(networkSpeed)
|
||||
val localIsWifi by rememberUpdatedState(isWifi)
|
||||
val localBatteryPercent by rememberUpdatedState(batteryPercent)
|
||||
val localIsCharging by rememberUpdatedState(isCharging)
|
||||
|
||||
// Clock update — only this composable recomposes
|
||||
LaunchedEffect(Unit) {
|
||||
while (true) {
|
||||
topTimeText.value = java.text.SimpleDateFormat("HH:mm", java.util.Locale.getDefault()).format(java.util.Date())
|
||||
delay(1000)
|
||||
}
|
||||
}
|
||||
Text(topTimeText.value, color = Color.White, fontSize = 13.sp, modifier = modifier)
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(horizontal = capsuleInset),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(topTimeText.value, color = Color.White, fontSize = 13.sp)
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
if (playbackUrl != null) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
LumaIconView(if (localIsWifi) LumaIcon.Wifi else LumaIcon.Signal, contentDescription = null, tint = Color.White, modifier = Modifier.size(16.dp))
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(formatNetworkSpeed(localNetworkSpeed), color = Color.White, fontSize = 13.sp)
|
||||
}
|
||||
@Composable
|
||||
private fun PlayerNetworkInfo(
|
||||
playbackUrl: String?,
|
||||
networkSpeed: Long,
|
||||
isWifi: Boolean,
|
||||
batteryPercent: Int,
|
||||
isCharging: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val localNetworkSpeed by rememberUpdatedState(networkSpeed)
|
||||
val localIsWifi by rememberUpdatedState(isWifi)
|
||||
val localBatteryPercent by rememberUpdatedState(batteryPercent)
|
||||
val localIsCharging by rememberUpdatedState(isCharging)
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), modifier = modifier) {
|
||||
if (playbackUrl != null) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
LumaIconView(if (localIsWifi) LumaIcon.Wifi else LumaIcon.Signal, contentDescription = null, tint = Color.White, modifier = Modifier.size(16.dp))
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(formatNetworkSpeed(localNetworkSpeed), color = Color.White, fontSize = 13.sp)
|
||||
}
|
||||
if (localBatteryPercent >= 0) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("$localBatteryPercent%", color = Color.White, fontSize = 13.sp)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
BatteryIcon(level = localBatteryPercent, charging = localIsCharging, modifier = Modifier.size(22.dp, 12.dp))
|
||||
}
|
||||
}
|
||||
if (localBatteryPercent >= 0) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("$localBatteryPercent%", color = Color.White, fontSize = 13.sp)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
BatteryIcon(level = localBatteryPercent, charging = localIsCharging, modifier = Modifier.size(22.dp, 12.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user