From 76dbf5fe120f18facac224b9355b11fca43385a7 Mon Sep 17 00:00:00 2001 From: jjangddu Date: Wed, 25 Mar 2026 10:36:53 +0900 Subject: [PATCH] feat: responsive layout for foldable phones (compact < 400dp) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce padding, icon sizes, and chart dimensions on narrow screens. Hide title text and battery % in compact mode to prevent top bar overflow. Scale donut chart 240→180dp and SpO2 text 56→40sp. Co-Authored-By: Claude Opus 4.6 --- .../views/monitoring/PiezoMonitoringView.kt | 61 ++++++++++--------- .../views/monitoring/VivamyoMonitoringView.kt | 41 +++++++------ 2 files changed, 56 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt index f79cb4d..343ecc6 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/PiezoMonitoringView.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -48,6 +49,9 @@ fun PiezoMonitoringView(appState: AppState) { var reconnectionState by remember { mutableStateOf(BleReconnectionState.DISCONNECTED) } var isAutoMeasuring by remember { mutableStateOf(false) } + val screenWidth = LocalConfiguration.current.screenWidthDp + val isCompact = screenWidth < 400 + val isDemoMode = appState.isDemoMode val urgency = appState.bladderLevel.urgency val batteryLvl by bleManager.batteryLevel @@ -131,30 +135,31 @@ fun PiezoMonitoringView(appState: AppState) { .background(urgency.backgroundColor) ) { // Top bar + val hPad = if (isCompact) 12.dp else 24.dp Row( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 24.dp, vertical = 16.dp), + .padding(horizontal = hPad, vertical = if (isCompact) 8.dp else 16.dp), verticalAlignment = Alignment.CenterVertically ) { - IconButton(onClick = { appState.goHome() }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MlPrimary) + IconButton(onClick = { appState.goHome() }, modifier = Modifier.size(if (isCompact) 36.dp else 48.dp)) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MlPrimary, modifier = Modifier.size(if (isCompact) 20.dp else 24.dp)) + } + if (!isCompact) { + Text("Bladder Monitor", fontSize = 20.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp)) } - Text("Bladder Monitor", fontSize = 20.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 8.dp)) Spacer(modifier = Modifier.weight(1f)) if (isAutoMeasuring) { - Row( + Box( modifier = Modifier .clip(RoundedCornerShape(8.dp)) .background(Color.Red.copy(alpha = 0.12f)) - .padding(horizontal = 8.dp, vertical = 4.dp), - verticalAlignment = Alignment.CenterVertically + .padding(horizontal = 6.dp, vertical = 3.dp) ) { - Box(modifier = Modifier.size(8.dp).clip(CircleShape).background(Color.Red)) - Spacer(modifier = Modifier.width(4.dp)) - Text("Auto", fontSize = 12.sp, fontWeight = FontWeight.Bold, color = Color.Red) + Text(if (isCompact) "A" else "Auto", fontSize = 11.sp, fontWeight = FontWeight.Bold, color = Color.Red) } + Spacer(modifier = Modifier.width(4.dp)) } // Catheter count @@ -163,27 +168,26 @@ fun PiezoMonitoringView(appState: AppState) { .clip(RoundedCornerShape(8.dp)) .background(MlPrimary.copy(alpha = 0.1f)) .clickable { showAddCatheterDialog = true } - .padding(horizontal = 8.dp, vertical = 4.dp), + .padding(horizontal = 6.dp, vertical = 3.dp), verticalAlignment = Alignment.CenterVertically ) { - Icon(Icons.Default.Add, "Add catheter", tint = MlPrimary, modifier = Modifier.size(14.dp)) - Spacer(modifier = Modifier.width(2.dp)) - Text("$catheterCount", fontSize = 13.sp, fontWeight = FontWeight.Bold, color = MlPrimary) + Icon(Icons.Default.Add, "Add catheter", tint = MlPrimary, modifier = Modifier.size(12.dp)) + Text("$catheterCount", fontSize = 12.sp, fontWeight = FontWeight.Bold, color = MlPrimary) } Spacer(modifier = Modifier.width(4.dp)) - IconButton(onClick = { appState.showHistory() }) { - Icon(Icons.Default.History, "History", tint = MlSecondaryText) + IconButton(onClick = { appState.showHistory() }, modifier = Modifier.size(if (isCompact) 36.dp else 48.dp)) { + Icon(Icons.Default.History, "History", tint = MlSecondaryText, modifier = Modifier.size(if (isCompact) 20.dp else 24.dp)) } - IconButton(onClick = { showSettings = !showSettings }) { - Icon(Icons.Default.Settings, "Settings", tint = if (showSettings) MlPrimary else MlSecondaryText) + IconButton(onClick = { showSettings = !showSettings }, modifier = Modifier.size(if (isCompact) 36.dp else 48.dp)) { + Icon(Icons.Default.Settings, "Settings", tint = if (showSettings) MlPrimary else MlSecondaryText, modifier = Modifier.size(if (isCompact) 20.dp else 24.dp)) } - // Battery + // Battery / Demo if (isDemoMode) { - Text("DEMO", fontSize = 11.sp, fontWeight = FontWeight.Bold, color = Color.White, - modifier = Modifier.clip(RoundedCornerShape(4.dp)).background(Color(0xFFFF9500)).padding(horizontal = 6.dp, vertical = 2.dp)) - } else { + Text("DEMO", fontSize = 10.sp, fontWeight = FontWeight.Bold, color = Color.White, + modifier = Modifier.clip(RoundedCornerShape(4.dp)).background(Color(0xFFFF9500)).padding(horizontal = 4.dp, vertical = 2.dp)) + } else if (!isCompact) { Text("$batteryLvl%", fontSize = 13.sp, color = MlSecondaryText) } Spacer(modifier = Modifier.width(4.dp)) @@ -212,10 +216,10 @@ fun PiezoMonitoringView(appState: AppState) { modifier = Modifier .weight(1f) .verticalScroll(rememberScrollState()) - .padding(horizontal = 24.dp) - .padding(top = 16.dp, bottom = 32.dp), + .padding(horizontal = hPad) + .padding(top = if (isCompact) 8.dp else 16.dp, bottom = if (isCompact) 16.dp else 32.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(20.dp) + verticalArrangement = Arrangement.spacedBy(if (isCompact) 12.dp else 20.dp) ) { // Settings panel if (showSettings) { @@ -261,15 +265,16 @@ fun PiezoMonitoringView(appState: AppState) { ) // Donut chart with Bladdy + val donutSize = if (isCompact) 180.dp else 240.dp Box(contentAlignment = Alignment.Center) { DonutChartView( progress = appState.bladderLevel.progress, urgency = urgency, - lineWidth = 28.dp, - size = 240.dp + lineWidth = if (isCompact) 20.dp else 28.dp, + size = donutSize ) Column(horizontalAlignment = Alignment.CenterHorizontally) { - BladdyRiveView(urgency = urgency, size = 100.dp) + BladdyRiveView(urgency = urgency, size = if (isCompact) 70.dp else 100.dp) Spacer(modifier = Modifier.height(4.dp)) Text( "${appState.estimatedVolume} ml", diff --git a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt index 6dcd5df..eb8659f 100644 --- a/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt +++ b/app/src/main/java/com/example/medilightv2android/ui/views/monitoring/VivamyoMonitoringView.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -45,6 +46,9 @@ fun VivamyoMonitoringView(appState: AppState) { val nirsManager = remember { NirsManager.instance } val handler = remember { Handler(Looper.getMainLooper()) } + val screenWidth = LocalConfiguration.current.screenWidthDp + val isCompact = screenWidth < 400 + var selectedTab by remember { mutableIntStateOf(0) } var showClearConfirm by remember { mutableStateOf(false) } var isToggling by remember { mutableStateOf(false) } @@ -227,28 +231,29 @@ fun VivamyoMonitoringView(appState: AppState) { .background(Color.White) ) { // Top bar + val hPad = if (isCompact) 12.dp else 24.dp Row( - modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp, vertical = 16.dp), + modifier = Modifier.fillMaxWidth().padding(horizontal = hPad, vertical = if (isCompact) 8.dp else 16.dp), verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = { nirsManager.reset() appState.goHome() - }) { - Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MlPrimary) + }, modifier = Modifier.size(if (isCompact) 36.dp else 48.dp)) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back", tint = MlPrimary, modifier = Modifier.size(if (isCompact) 20.dp else 24.dp)) } - Column(modifier = Modifier.padding(start = 8.dp)) { - Text("Vivamyo", fontSize = 20.sp, fontWeight = FontWeight.Bold) - Text("NIRS Monitoring", fontSize = 13.sp, color = MlSecondaryText) + Column(modifier = Modifier.padding(start = if (isCompact) 4.dp else 8.dp)) { + Text("Vivamyo", fontSize = if (isCompact) 16.sp else 20.sp, fontWeight = FontWeight.Bold) + if (!isCompact) Text("NIRS Monitoring", fontSize = 13.sp, color = MlSecondaryText) } Spacer(modifier = Modifier.weight(1f)) if (isDemoMode) { - Text("DEMO", fontSize = 11.sp, fontWeight = FontWeight.Bold, color = Color.White, - modifier = Modifier.clip(RoundedCornerShape(4.dp)).background(Color(0xFFFF9500)).padding(horizontal = 6.dp, vertical = 2.dp)) + Text("DEMO", fontSize = 10.sp, fontWeight = FontWeight.Bold, color = Color.White, + modifier = Modifier.clip(RoundedCornerShape(4.dp)).background(Color(0xFFFF9500)).padding(horizontal = 4.dp, vertical = 2.dp)) } else { - Text("$batteryLvl%", fontSize = 13.sp, color = MlSecondaryText) + Text("$batteryLvl%", fontSize = if (isCompact) 11.sp else 13.sp, color = MlSecondaryText) } - Spacer(modifier = Modifier.width(8.dp)) + Spacer(modifier = Modifier.width(if (isCompact) 4.dp else 8.dp)) Box(modifier = Modifier.size(10.dp).clip(CircleShape).background(if (isDemoMode || isConnected) Color.Green else Color.Red)) } @@ -265,27 +270,27 @@ fun VivamyoMonitoringView(appState: AppState) { } // Tab picker - TabRow(selectedTabIndex = selectedTab, modifier = Modifier.padding(horizontal = 24.dp)) { - Tab(selected = selectedTab == 0, onClick = { selectedTab = 0 }) { Text("SpO2", modifier = Modifier.padding(12.dp)) } - Tab(selected = selectedTab == 1, onClick = { selectedTab = 1 }) { Text("Oxy/Deoxy", modifier = Modifier.padding(12.dp)) } + TabRow(selectedTabIndex = selectedTab, modifier = Modifier.padding(horizontal = hPad)) { + Tab(selected = selectedTab == 0, onClick = { selectedTab = 0 }) { Text("SpO2", modifier = Modifier.padding(if (isCompact) 8.dp else 12.dp)) } + Tab(selected = selectedTab == 1, onClick = { selectedTab = 1 }) { Text("Oxy/Deoxy", modifier = Modifier.padding(if (isCompact) 8.dp else 12.dp)) } } Column( modifier = Modifier .weight(1f) .verticalScroll(rememberScrollState()) - .padding(horizontal = 24.dp, vertical = 16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp) + .padding(horizontal = hPad, vertical = if (isCompact) 8.dp else 16.dp), + verticalArrangement = Arrangement.spacedBy(if (isCompact) 10.dp else 16.dp) ) { if (selectedTab == 0) { // SpO2 tab BladdyIdleRiveView( - size = 120.dp, + size = if (isCompact) 80.dp else 120.dp, modifier = Modifier.align(Alignment.CenterHorizontally) ) Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) { - Text(String.format("%.1f", currentOxy.stO2), fontSize = 56.sp, fontWeight = FontWeight.Bold, color = stO2Color) + Text(String.format("%.1f", currentOxy.stO2), fontSize = if (isCompact) 40.sp else 56.sp, fontWeight = FontWeight.Bold, color = stO2Color) Text("% StO2", fontSize = 18.sp, color = MlSecondaryText) Text(stO2StatusText, fontSize = 14.sp, fontWeight = FontWeight.SemiBold, color = stO2Color, modifier = Modifier.clip(RoundedCornerShape(8.dp)).background(stO2Color.copy(alpha = 0.15f)).padding(horizontal = 12.dp, vertical = 4.dp)) @@ -320,7 +325,7 @@ fun VivamyoMonitoringView(appState: AppState) { // Control bar Row( - modifier = Modifier.padding(horizontal = 24.dp).padding(bottom = 32.dp), + modifier = Modifier.padding(horizontal = hPad).padding(bottom = if (isCompact) 16.dp else 32.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { Button(