From d0aa93cd9d6004fa2973d50714b8ab54f2bf570a Mon Sep 17 00:00:00 2001 From: BBIT-Kai <2911862937@qq.com> Date: Fri, 29 May 2026 13:42:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bbitcn/f8/pad/base/BaseList.kt | 21 +- .../f8/pad/base/CustomMaterialComponents.kt | 10 +- .../f8/pad/receiver/SystemInfoReceiver.kt | 29 ++ .../bbitcn/f8/pad/ui/screen/LoginScreen.kt | 2 +- .../com/bbitcn/f8/pad/ui/screen/MainScreen.kt | 106 +---- .../com/bbitcn/f8/pad/ui/screen/TopBar.kt | 387 ++++++++++-------- .../f8/pad/ui/screen/dialog/ChatDialog.kt | 9 +- .../f8/pad/ui/screen/mainFunc/HomeScreen.kt | 29 +- .../screen/mainFunc/setting/SettingWeather.kt | 10 +- .../java/com/bbitcn/f8/pad/ui/theme/Theme.kt | 60 ++- .../res/{drawable => drawable-nodpi}/bg.png | Bin .../bg_weather.png | Bin 12 files changed, 333 insertions(+), 330 deletions(-) rename app/src/main/res/{drawable => drawable-nodpi}/bg.png (100%) rename app/src/main/res/{drawable => drawable-nodpi}/bg_weather.png (100%) diff --git a/app/src/main/java/com/bbitcn/f8/pad/base/BaseList.kt b/app/src/main/java/com/bbitcn/f8/pad/base/BaseList.kt index 3b0054e..7743f8d 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/base/BaseList.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/base/BaseList.kt @@ -204,6 +204,7 @@ fun MyTable( ratio: List, items: List>, verticalPadding: Dp = 5.dp, + itemKey: ((List, Int) -> Any)? = null, ) { Column(modifier = modifier) { TableHeadLine( @@ -211,7 +212,13 @@ fun MyTable( list = headerStrings.zip(ratio.map { it.toInt() }) ) LazyColumn { - items(count = items.size) { itIndex -> + items( + count = items.size, + key = { index -> + itemKey?.invoke(items[index], index) + ?: items[index].joinToString(separator = "|") { it.toString() } + "#$index" + } + ) { itIndex -> TableContent( verticalPadding = verticalPadding, modifier = M @@ -317,6 +324,7 @@ fun MyAnyTable( // 每行 info: List, + itemKey: ((T) -> Any)? = null, onLongClick: (T) -> Unit = {}, onClick: (T) -> Unit = {}, @@ -330,7 +338,10 @@ fun MyAnyTable( ) var selectIndex by rememberSaveable { mutableStateOf(-1) } LazyColumn { - items(count = info.size) { index -> + items( + count = info.size, + key = { index -> itemKey?.invoke(info[index]) ?: "${info[index].hashCode()}-$index" } + ) { index -> // 每行 val lineItem = info[index] Card( @@ -418,6 +429,7 @@ fun MyTable2( modifier: Modifier = Modifier, infos: List, items: List>, + itemKey: ((T) -> Any)? = null, onLongClick: (T) -> Unit = {}, onClick: (T) -> Unit = {}, onExpend: @Composable (T) -> Unit = {}, @@ -433,7 +445,10 @@ fun MyTable2( var selectIndex by rememberSaveable { mutableStateOf(-1) } LazyColumn { - items(count = infos.size) { index -> + items( + count = infos.size, + key = { index -> itemKey?.invoke(infos[index]) ?: "${infos[index].hashCode()}-$index" } + ) { index -> val lineItem = infos[index] Card( diff --git a/app/src/main/java/com/bbitcn/f8/pad/base/CustomMaterialComponents.kt b/app/src/main/java/com/bbitcn/f8/pad/base/CustomMaterialComponents.kt index dbab22c..dd1beab 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/base/CustomMaterialComponents.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/base/CustomMaterialComponents.kt @@ -172,15 +172,9 @@ fun MyButton( onClick: () -> Unit, ) { Button( - onClick = { - if (enabled) { - onClick() - } else { - Toasty.showToast("正在开发中,敬请期待") - } - }, + onClick = onClick, modifier = modifier, - enabled = true, + enabled = enabled, interactionSource = interactionSource, shape = shape, border = border, diff --git a/app/src/main/java/com/bbitcn/f8/pad/receiver/SystemInfoReceiver.kt b/app/src/main/java/com/bbitcn/f8/pad/receiver/SystemInfoReceiver.kt index 52ad9a8..c6b12c1 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/receiver/SystemInfoReceiver.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/receiver/SystemInfoReceiver.kt @@ -2,6 +2,8 @@ package com.bbitcn.f8.pad.receiver +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -35,10 +37,15 @@ class SystemInfoReceiver(private val context: Context) { private val _signalStrength = MutableStateFlow(0) val signalStrength = _signalStrength.asStateFlow() + private val _bluetoothEnabled = MutableStateFlow(false) + val bluetoothEnabled = _bluetoothEnabled.asStateFlow() + private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager private val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + private val bluetoothManager = + context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager /** * 信号强度监听器 @@ -78,6 +85,12 @@ class SystemInfoReceiver(private val context: Context) { } } + private val bluetoothReceiver = object : BroadcastReceiver() { + override fun onReceive(ctx: Context?, intent: Intent?) { + refreshBluetoothStatus() + } + } + fun register() { val batteryIntentFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED) @@ -85,10 +98,15 @@ class SystemInfoReceiver(private val context: Context) { batteryReceiver, batteryIntentFilter ) + context.registerReceiverCompat( + bluetoothReceiver, + IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED) + ) connectivityManager.registerDefaultNetworkCallback(networkCallback) registerSignalStrengthListener() refreshNetworkStatus() + refreshBluetoothStatus() // 开始轮询网络状态 防止状态假死 PollingTask.getInstance("SystemInfoReceiver").startPollingTaskOnIOThread("NetworkStatusPolling",30_000) { refreshNetworkStatus() @@ -97,6 +115,11 @@ class SystemInfoReceiver(private val context: Context) { fun unregister() { context.unregisterReceiver(batteryReceiver) + runCatching { + context.unregisterReceiver(bluetoothReceiver) + }.onFailure { + MyLog.appError("取消蓝牙监听失败:${it.message}") + } runCatching { connectivityManager.unregisterNetworkCallback(networkCallback) }.onFailure { @@ -159,6 +182,12 @@ class SystemInfoReceiver(private val context: Context) { } } + private fun refreshBluetoothStatus() { + _bluetoothEnabled.value = runCatching { + bluetoothManager.adapter?.isEnabled == true + }.getOrDefault(false) + } + private fun registerSignalStrengthListener() { runCatching { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/LoginScreen.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/LoginScreen.kt index afcae97..df7fa58 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/LoginScreen.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/LoginScreen.kt @@ -181,7 +181,7 @@ fun TabPagerScreen( } HorizontalPager( state = pagerState, - beyondViewportPageCount = tabs.size, + beyondViewportPageCount = 1, modifier = M .fillMaxWidth() .weight(1f) diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/MainScreen.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/MainScreen.kt index 2e7e9d0..a6ec6fd 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/MainScreen.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/MainScreen.kt @@ -19,14 +19,13 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.navigation.compose.rememberNavController import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.saveable.rememberSaveableStateHolder import androidx.compose.ui.Alignment -import androidx.compose.ui.draw.alpha import androidx.compose.ui.geometry.Rect import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import com.bbitcn.f8.pad.M @@ -48,7 +47,6 @@ import com.bbitcn.f8.pad.ui.screen.mainFunc.UserScreen import com.bbitcn.f8.pad.ui.screen.view.Toasty import com.bbitcn.f8.pad.ui.viewmodel.UpdateViewModel import com.cyberecho.ui.screen.ChatDialog -import kotlinx.coroutines.delay import kotlinx.coroutines.launch @Preview(showBackground = true, widthDp = 1280) @@ -75,41 +73,13 @@ fun MainScreen( } Box(modifier = M.fillMaxWidth(), contentAlignment = Alignment.BottomStart) { var selectedPage by rememberSaveable { mutableStateOf(0) } - var contentPage by rememberSaveable { mutableStateOf(0) } - var isSwitchingPage by remember { mutableStateOf(false) } - val cachedPages = remember { mutableStateListOf() } + val pageStateHolder = rememberSaveableStateHolder() val coroutineScope = rememberCoroutineScope() val menu by mainViewModel.menu.collectAsState() - LaunchedEffect(menu, selectedPage) { - if (menu.isEmpty()) { - contentPage = 0 - isSwitchingPage = false - cachedPages.clear() - return@LaunchedEffect - } - - val safeSelectedPage = selectedPage.coerceIn(0, menu.lastIndex) - if (safeSelectedPage != selectedPage) { - selectedPage = safeSelectedPage - return@LaunchedEffect - } - - cachedPages.removeAll { it !in menu.indices } - if (cachedPages.isEmpty()) { - cachedPages.add(safeSelectedPage) - } - - if (contentPage != safeSelectedPage && safeSelectedPage !in cachedPages) { - isSwitchingPage = true - withFrameNanos { } - delay(180) - cachedPages.add(safeSelectedPage) - contentPage = safeSelectedPage - isSwitchingPage = false - } else if (contentPage != safeSelectedPage) { - contentPage = safeSelectedPage - isSwitchingPage = false + LaunchedEffect(menu) { + if (menu.isNotEmpty() && selectedPage !in menu.indices) { + selectedPage = selectedPage.coerceIn(0, menu.lastIndex) } } Row(modifier = M.fillMaxWidth()) { @@ -137,35 +107,22 @@ fun MainScreen( onClick = { if (selectedPage != index) { selectedPage = index - isSwitchingPage = index !in cachedPages - if (index in cachedPages) { - contentPage = index - } } } ) } } Box(modifier = M.weight(1f).fillMaxSize()) { - val selectedMenu = menu.getOrNull(selectedPage) - if (isSwitchingPage && selectedMenu != null && selectedPage !in cachedPages) { - MainPageLoading(selectedMenu.title) - } else { - cachedPages.forEach { page -> - key(page) { - val pageIndex = menu.getOrNull(page)?.index ?: -1 - MainPageHost(visible = page == contentPage) { - MainPageContent( - index = pageIndex, - navController = navController, - drawerViewModel = drawerViewModel, - updateViewModel = updateViewModel, - topInfoViewmodel = topInfoViewmodel, - mainViewModel = mainViewModel - ) - } - } - } + val pageIndex = menu.getOrNull(selectedPage)?.index ?: -1 + pageStateHolder.SaveableStateProvider(pageIndex) { + MainPageContent( + index = pageIndex, + navController = navController, + drawerViewModel = drawerViewModel, + updateViewModel = updateViewModel, + topInfoViewmodel = topInfoViewmodel, + mainViewModel = mainViewModel + ) } } } @@ -246,39 +203,6 @@ fun MainScreen( ChatDialog(chatDialogData) } -@Composable -private fun MainPageLoading(title: String) { - Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) { - Text( - text = "正在加载$title...", - color = MyColors.Gray, - fontSize = MaterialTheme.typography.bodyLarge.fontSize - ) - } -} - -@Composable -private fun MainPageHost( - visible: Boolean, - content: @Composable () -> Unit -) { - Box( - modifier = if (visible) { - M - .fillMaxSize() - .alpha(1f) - .zIndex(1f) - } else { - M - .size(0.dp) - .alpha(0f) - .zIndex(0f) - } - ) { - content() - } -} - @Composable private fun MainPageContent( index: Int, diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/TopBar.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/TopBar.kt index 3665cc7..e84a1b7 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/TopBar.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/TopBar.kt @@ -43,7 +43,6 @@ import androidx.navigation.compose.rememberNavController import com.bbitcn.f8.pad.M import com.bbitcn.f8.pad.R import com.bbitcn.f8.pad.base.WhiteText -import com.bbitcn.f8.pad.base.isBluetoothEnabled import com.bbitcn.f8.pad.receiver.SystemInfoReceiver import com.bbitcn.f8.pad.ui.screen.view.drawer.DrawerViewModel import com.bbitcn.f8.pad.ui.theme.MyColors @@ -81,8 +80,6 @@ fun MyTopBar( ) { val context = LocalContext.current val systemInfoReceiver = remember { SystemInfoReceiver(context) } - val date by topInfoViewModel.date.collectAsState() - val time by topInfoViewModel.time.collectAsState() val logoState by topInfoViewModel.logoState.collectAsState() val versionName = remember { MyUtil.getVersionName() } @@ -99,183 +96,223 @@ fun MyTopBar( .background(color = MyColors.Black), verticalAlignment = Alignment.CenterVertically ) { - AnimatedContent( - logoState, - transitionSpec = { - EnterTransition.None togetherWith ExitTransition.None - }, - modifier = M.clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = null - ) { - if (logoState.first.first != R.drawable.logo_white) { - // 当前页面 -// val curPage = navController.currentDestination?.route ?: "main" -// Toasty.setCurPage(curPage) - topInfoViewModel.toScreen() - navController.popBackStack() - } - }, - ) { - Image( - modifier = M - .padding(5.dp) - .size(60.dp), - painter = painterResource(id = it.first.first), - contentDescription = "logo" - ) - } - AnimatedContent( - targetState = logoState, - transitionSpec = { - EnterTransition.None togetherWith ExitTransition.None - }, label = "animated content" - ) { value -> - Row(verticalAlignment = Alignment.Bottom) { - Text( - text = value.first.second, - M.padding(horizontal = 8.dp), - color = MyColors.White, - fontWeight = FontWeight.Bold, - fontSize = MaterialTheme.typography.headlineMedium.fontSize - ) - Text( - text = "v$versionName", - M.padding(bottom = 2.dp), - color = MyColors.LightGray, - fontSize = MaterialTheme.typography.bodySmall.fontSize - ) - } - - } + TopBarLogoTitle( + logoState = logoState, + versionName = versionName, + navController = navController, + topInfoViewModel = topInfoViewModel + ) Spacer(modifier = M.weight(1f)) if (curPageName != "login") { - Row( - horizontalArrangement = Arrangement.End, - verticalAlignment = Alignment.CenterVertically - ) { - val padding = M.padding(horizontal = 5.dp) -// Image( -// modifier = M -// .clickable{ -// topInfoViewModel.getFrpNewVersion() -// } -// .padding(end = 5.dp) -// .size(25.dp), -// painter = painterResource(id = R.drawable.icon_sos), -// contentDescription = "frp", -// ) - Image( - modifier = M - .padding(end = 5.dp) - .size(25.dp), - painter = painterResource(id = R.drawable.icon_lock), - contentDescription = "screen_lock", - ) - Row( - modifier = M.clickable { drawerViewModel.openSetDrawer() }, - horizontalArrangement = Arrangement.End, - verticalAlignment = Alignment.CenterVertically - ) { - if (isBluetoothEnabled()) { - Image( - modifier = M - .padding(end = 5.dp) - .size(25.dp), - painter = painterResource(id = R.drawable.bluetooth), - contentDescription = "蓝牙", - ) - } - val printer1 by PrinterBT.state.collectAsState() - val printer2 by JTPrinterUSB.state.collectAsState() - val printerState = if (printer1 == 1 || printer2 == 1) 1 else 0 - Image( - modifier = M - .padding(end = 5.dp) - .size(25.dp), - painter = painterResource(id = if (printerState == 1) R.drawable.print_on else R.drawable.print_off), - contentDescription = "打印机", - ) - val water by WaterCutMeterBT.state.collectAsState() - Image( - modifier = M - .padding(end = 5.dp) - .size(25.dp), - painter = painterResource(id = if (water == 1) R.drawable.water_on else R.drawable.water_off), - contentDescription = "含水仪", - ) - val scale1 by ScaleBT.state.collectAsState() - val scale2 by ScaleSerial.state.collectAsState() - val scaleState = if (scale1 == 1 || scale2 == 1) 1 else 0 - Image( - modifier = M - .padding(end = 5.dp) - .size(25.dp), - painter = painterResource(id = if (scaleState == 1) R.drawable.scale_on else R.drawable.scale_off), - contentDescription = "电子秤", - ) - //分隔符 - VerticalDivider( - modifier = padding - .width(1.dp), - color = MyColors.White - ) - // 电量显示 - val batteryVisible by topInfoViewModel.batteryVisible.collectAsState() - if (batteryVisible) { - val batteryLevel by systemInfoReceiver.batteryLevel.collectAsState() - BatteryLevelBoxWithImage(batteryLevel) - } - val signalStrength by systemInfoReceiver.signalStrength.collectAsState() - val networkType by systemInfoReceiver.networkType.collectAsState() - Image( - modifier = M - .padding(end = 10.dp) - .size(25.dp), - painter = painterResource( - id = - if (networkType == "WIFI") { - when (signalStrength) { - 0 -> R.drawable.server_0 - 1 -> R.drawable.wifi_2 - 2 -> R.drawable.wifi_2 - 3 -> R.drawable.wifi_3 - 4 -> R.drawable.wifi_4 - else -> R.drawable.server_0 - } - } else if (networkType == "Cellular") { - when (signalStrength) { - 0 -> R.drawable.server_0 - 1 -> R.drawable._4g_1 - 2 -> R.drawable._4g_2 - 3 -> R.drawable._4g_3 - 4 -> R.drawable._4g_4 - else -> R.drawable._4g_0 - } - } else if (networkType == "Ethernet") { - R.drawable.rj45 - } else { - R.drawable.server_0 - } - ), - contentDescription = "信号", - ) - } - WhiteText( - text = date, - fontSize = 15.sp, - modifier = M.padding(end = 5.dp) - ) - WhiteText( - text = time, - modifier = M.padding(end = 15.dp), - fontSize = 30.sp - ) - } + TopBarStatusArea( + drawerViewModel = drawerViewModel, + topInfoViewModel = topInfoViewModel, + systemInfoReceiver = systemInfoReceiver + ) } } } +@Composable +private fun TopBarLogoTitle( + logoState: Pair, Int>, + versionName: String, + navController: NavController, + topInfoViewModel: TopInfoViewModel +) { + AnimatedContent( + targetState = logoState, + transitionSpec = { + EnterTransition.None togetherWith ExitTransition.None + }, + modifier = M.clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { + if (logoState.first.first != R.drawable.logo_white) { + topInfoViewModel.toScreen() + navController.popBackStack() + } + }, + label = "topBarLogo" + ) { + Image( + modifier = M + .padding(5.dp) + .size(60.dp), + painter = painterResource(id = it.first.first), + contentDescription = "logo" + ) + } + AnimatedContent( + targetState = logoState, + transitionSpec = { + EnterTransition.None togetherWith ExitTransition.None + }, + label = "topBarTitle" + ) { value -> + Row(verticalAlignment = Alignment.Bottom) { + Text( + text = value.first.second, + M.padding(horizontal = 8.dp), + color = MyColors.White, + fontWeight = FontWeight.Bold, + fontSize = MaterialTheme.typography.headlineMedium.fontSize + ) + Text( + text = "v$versionName", + M.padding(bottom = 2.dp), + color = MyColors.LightGray, + fontSize = MaterialTheme.typography.bodySmall.fontSize + ) + } + } +} + +@Composable +private fun TopBarStatusArea( + drawerViewModel: DrawerViewModel, + topInfoViewModel: TopInfoViewModel, + systemInfoReceiver: SystemInfoReceiver +) { + Row( + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + modifier = M + .padding(end = 5.dp) + .size(25.dp), + painter = painterResource(id = R.drawable.icon_lock), + contentDescription = "screen_lock", + ) + DeviceStatusCluster( + drawerViewModel = drawerViewModel, + topInfoViewModel = topInfoViewModel, + systemInfoReceiver = systemInfoReceiver + ) + TopBarClock(topInfoViewModel) + } +} + +@Composable +private fun DeviceStatusCluster( + drawerViewModel: DrawerViewModel, + topInfoViewModel: TopInfoViewModel, + systemInfoReceiver: SystemInfoReceiver +) { + Row( + modifier = M.clickable { drawerViewModel.openSetDrawer() }, + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + val bluetoothEnabled by systemInfoReceiver.bluetoothEnabled.collectAsState() + if (bluetoothEnabled) { + TopBarIcon(R.drawable.bluetooth, "蓝牙") + } + + val printer1 by PrinterBT.state.collectAsState() + val printer2 by JTPrinterUSB.state.collectAsState() + val printerState = if (printer1 == 1 || printer2 == 1) 1 else 0 + TopBarIcon( + icon = if (printerState == 1) R.drawable.print_on else R.drawable.print_off, + contentDescription = "打印机" + ) + + val water by WaterCutMeterBT.state.collectAsState() + TopBarIcon( + icon = if (water == 1) R.drawable.water_on else R.drawable.water_off, + contentDescription = "含水仪" + ) + + val scale1 by ScaleBT.state.collectAsState() + val scale2 by ScaleSerial.state.collectAsState() + val scaleState = if (scale1 == 1 || scale2 == 1) 1 else 0 + TopBarIcon( + icon = if (scaleState == 1) R.drawable.scale_on else R.drawable.scale_off, + contentDescription = "电子秤" + ) + + VerticalDivider( + modifier = M + .padding(horizontal = 5.dp) + .width(1.dp), + color = MyColors.White + ) + + val batteryVisible by topInfoViewModel.batteryVisible.collectAsState() + if (batteryVisible) { + val batteryLevel by systemInfoReceiver.batteryLevel.collectAsState() + BatteryLevelBoxWithImage(batteryLevel) + } + + val signalStrength by systemInfoReceiver.signalStrength.collectAsState() + val networkType by systemInfoReceiver.networkType.collectAsState() + TopBarIcon( + icon = networkIconResource(networkType, signalStrength), + contentDescription = "信号", + endPadding = 10 + ) + } +} + +@Composable +private fun TopBarClock(topInfoViewModel: TopInfoViewModel) { + val date by topInfoViewModel.date.collectAsState() + val time by topInfoViewModel.time.collectAsState() + + WhiteText( + text = date, + fontSize = 15.sp, + modifier = M.padding(end = 5.dp) + ) + WhiteText( + text = time, + modifier = M.padding(end = 15.dp), + fontSize = 30.sp + ) +} + +@Composable +private fun TopBarIcon( + icon: Int, + contentDescription: String, + endPadding: Int = 5 +) { + Image( + modifier = M + .padding(end = endPadding.dp) + .size(25.dp), + painter = painterResource(id = icon), + contentDescription = contentDescription, + ) +} + +private fun networkIconResource(networkType: String, signalStrength: Int): Int { + return when (networkType) { + "WIFI" -> when (signalStrength) { + 0 -> R.drawable.server_0 + 1 -> R.drawable.wifi_2 + 2 -> R.drawable.wifi_2 + 3 -> R.drawable.wifi_3 + 4 -> R.drawable.wifi_4 + else -> R.drawable.server_0 + } + + "Cellular" -> when (signalStrength) { + 0 -> R.drawable.server_0 + 1 -> R.drawable._4g_1 + 2 -> R.drawable._4g_2 + 3 -> R.drawable._4g_3 + 4 -> R.drawable._4g_4 + else -> R.drawable._4g_0 + } + + "Ethernet" -> R.drawable.rj45 + else -> R.drawable.server_0 + } +} + @Composable fun BatteryLevelBoxWithImage(batteryLevel: Int) { Box( @@ -300,7 +337,7 @@ fun BatteryLevelBoxWithImage(batteryLevel: Int) { ) { val fillWidth = size.width * batteryLevel / 100 drawRect( - color = if (batteryLevel > 0.2f) MyColors.Green else MyColors.Red, // 低电量红色 + color = if (batteryLevel > 20) MyColors.Green else MyColors.Red, // 低电量红色 topLeft = Offset(0f, 0f), // 从左上角开始填充 size = Size(fillWidth, size.height) // 宽度根据电量动态变化 ) diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/dialog/ChatDialog.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/dialog/ChatDialog.kt index 28b58ad..dfa9cb4 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/dialog/ChatDialog.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/dialog/ChatDialog.kt @@ -24,7 +24,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape @@ -203,14 +203,17 @@ fun Messages( modifier = M .fillMaxSize() ) { - items(chatRecords) { + itemsIndexed( + items = chatRecords, + key = { index, message -> "${message.timestamp}-${message.isFromUser}-$index" } + ) { index, it -> Message( modifier = M, msg = it, isEndMessageByAuthor = true, isNewMessageByAuthor = true ) - if (chatRecords.indexOf(it) == chatRecords.size - 1) { + if (index == chatRecords.lastIndex) { DateHeader(System.currentTimeMillis()) } } diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/HomeScreen.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/HomeScreen.kt index b401a8d..368ca8d 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/HomeScreen.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/HomeScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material3.Icon @@ -137,7 +138,7 @@ fun HomeScreenInLandscape( .weight(1f) .fillMaxWidth() ) { - ShortCut(homeViewModel) + ShortCut(navController, homeViewModel) } } Column( @@ -227,7 +228,7 @@ fun HomeScreenInPortrait( .weight(0.5f) .fillMaxWidth() ) { - ShortCut(homeViewModel) + ShortCut(navController, homeViewModel) } } } @@ -358,8 +359,10 @@ fun WeatherInfo(homeViewModel: HomeViewModel) { }) } LazyRow { - items(weatherInfo.casts) { - val index = weatherInfo.casts.indexOf(it) + itemsIndexed( + items = weatherInfo.casts, + key = { index, item -> item.date.ifEmpty { "weather-$index" } } + ) { index, it -> WeatherItem( it.weekstr, it.date, @@ -430,8 +433,10 @@ fun MessageInfo(homeViewModel: HomeViewModel) { }) } LazyColumn { - items(count = notices.size) { index -> - val notice = notices[index] + items( + items = notices, + key = { it.id } + ) { notice -> MessageItem( homeViewModel, true, @@ -503,7 +508,7 @@ fun MessageItem( } @Composable -fun ShortCut(homeViewModel: HomeViewModel) { +fun ShortCut(navController: NavController, homeViewModel: HomeViewModel) { Row(modifier = M.fillMaxHeight(), verticalAlignment = Alignment.CenterVertically) { Box( modifier = M @@ -527,12 +532,10 @@ fun ShortCut(homeViewModel: HomeViewModel) { ) } LazyRow(verticalAlignment = Alignment.CenterVertically) { - item { -// ShowCutItem(R.drawable.user_add, "新增用户", onClick = {}) -// ShowCutItem(R.drawable.user_query, "用户查询", onClick = {}) -// ShowCutItem(R.drawable.silk_add, "新增收茧", onClick = {}) -// ShowCutItem(R.drawable.silk_trans, "茧转移", onClick = {}) -// ShowCutItem(R.drawable.device_link, "设备连接", onClick = {}) + item(key = "addUser") { + ShowCutItem(R.drawable.user_add, "新增农户") { + navController.navigate("addUser") + } } } } diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/setting/SettingWeather.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/setting/SettingWeather.kt index 1ba0c79..a00f7ea 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/setting/SettingWeather.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/screen/mainFunc/setting/SettingWeather.kt @@ -12,7 +12,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -111,8 +111,10 @@ fun SettingWeather( InputFrame("本周天气预报") { Column { LazyRow { - items(weatherInfo.casts) { - val index = weatherInfo.casts.indexOf(it) + itemsIndexed( + items = weatherInfo.casts, + key = { index, item -> item.date.ifEmpty { "weather-$index" } } + ) { index, it -> WeatherItem( it.weekstr, it.date, it.dayweatherpic, it.nighttemp + "~" + it.daytemp + "℃", index @@ -145,4 +147,4 @@ fun SettingWeather( } } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/bbitcn/f8/pad/ui/theme/Theme.kt b/app/src/main/java/com/bbitcn/f8/pad/ui/theme/Theme.kt index 1d37366..f3b5933 100644 --- a/app/src/main/java/com/bbitcn/f8/pad/ui/theme/Theme.kt +++ b/app/src/main/java/com/bbitcn/f8/pad/ui/theme/Theme.kt @@ -1,53 +1,49 @@ package com.bbitcn.f8.pad.ui.theme -import android.app.Activity -import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.graphics.Color private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 + primary = MyColors.BlueGreen, + onPrimary = MyColors.White, + primaryContainer = MyColors.LightBlueGreen, + secondary = MyColors.Green, + tertiary = MyColors.Orange, + background = MyColors.Black, + surface = Color(0xFF202625), + onBackground = MyColors.White, + onSurface = MyColors.White, ) private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ + primary = MyColors.BlueGreen, + onPrimary = MyColors.White, + primaryContainer = MyColors.LightBlueGreen, + secondary = MyColors.Green, + tertiary = MyColors.Orange, + background = Color(0xFFF7FAFA), + surface = MyColors.White, + surfaceVariant = MyColors.LightBlue, + onBackground = MyColors.Black, + onSurface = MyColors.Black, + outline = MyColors.Disabled, ) @Composable +@Suppress("UNUSED_PARAMETER") fun AppTheme( darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, + dynamicColor: Boolean = false, content: @Composable () -> Unit ) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - else -> LightColorScheme + val colorScheme = if (darkTheme) { + DarkColorScheme + } else { + LightColorScheme } MaterialTheme( @@ -55,4 +51,4 @@ fun AppTheme( typography = Typography, content = content ) -} \ No newline at end of file +} diff --git a/app/src/main/res/drawable/bg.png b/app/src/main/res/drawable-nodpi/bg.png similarity index 100% rename from app/src/main/res/drawable/bg.png rename to app/src/main/res/drawable-nodpi/bg.png diff --git a/app/src/main/res/drawable/bg_weather.png b/app/src/main/res/drawable-nodpi/bg_weather.png similarity index 100% rename from app/src/main/res/drawable/bg_weather.png rename to app/src/main/res/drawable-nodpi/bg_weather.png