From 702e9810d09ff899e89682dc673cf561dcffc91d Mon Sep 17 00:00:00 2001
From: beyond
Date: Sun, 6 Sep 2026 18:47:45 +0800
Subject: [PATCH] =?UTF-8?q?=E6=92=AD=E6=94=BE=E5=99=A8:=20=E6=97=B6?=
=?UTF-8?q?=E9=97=B4/=E7=BD=91=E9=80=9F/=E7=94=B5=E9=87=8F=E5=B8=83?=
=?UTF-8?q?=E5=B1=80=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- PlayerStatusBar拆分为PlayerTimeDisplay和PlayerNetworkInfo两个独立组件
- 时间显示在关闭按钮上方(左侧)
- 网速+电量显示在播放工具按钮上方(右侧)
- 减少间距从8dp到2dp
Co-Authored-By: Claude Opus 5 (1M context)
---
.../screens/VideoPlayerScreen.kt | 93 ++++++++++---------
1 file changed, 47 insertions(+), 46 deletions(-)
diff --git a/app/src/main/kotlin/com/example/myapplication/screens/VideoPlayerScreen.kt b/app/src/main/kotlin/com/example/myapplication/screens/VideoPlayerScreen.kt
index 166efe0..47538f3 100644
--- a/app/src/main/kotlin/com/example/myapplication/screens/VideoPlayerScreen.kt
+++ b/app/src/main/kotlin/com/example/myapplication/screens/VideoPlayerScreen.kt
@@ -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))
}
}
}