mirror of
http://180.163.74.83:13000/zhangzhenghao/MPVN_Android.git
synced 2025-12-12 15:24:30 +00:00
增加天气 ip 查询
This commit is contained in:
parent
6393df34ea
commit
0b4fbe3be2
@ -68,6 +68,9 @@ dependencies {
|
||||
implementation("androidx.compose.material3:material3-window-size-class:1.3.0")
|
||||
|
||||
implementation("com.github.Dimezis:BlurView:version-3.2.0")
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("com.google.android.gms:play-services-location:21.0.1")
|
||||
|
||||
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12")
|
||||
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:name=".SmartHomeApp"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="SmartHome"
|
||||
android:label="TZSmartHome"
|
||||
android:theme="@style/Theme.SmartHome">
|
||||
<activity android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
|
||||
@ -66,6 +66,8 @@ import androidx.compose.animation.core.infiniteRepeatable
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.RepeatMode
|
||||
import com.example.smarthome.data.WeatherService
|
||||
import com.example.smarthome.data.WeatherInfo
|
||||
|
||||
@Composable
|
||||
fun MainScaffold(
|
||||
@ -86,6 +88,10 @@ fun MainScaffold(
|
||||
// 根据选中的导航项显示不同的内容
|
||||
when (selectedNavItem) {
|
||||
0 -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom)
|
||||
1 -> SceneScreen()
|
||||
2 -> AutomationScreen()
|
||||
3 -> StatisticsScreen()
|
||||
4 -> SecurityScreen()
|
||||
5 -> SettingsContent()
|
||||
else -> DashboardContent(selectedRoom, onRoomSelect, rooms, onAddRoom, onDeleteRoom)
|
||||
}
|
||||
@ -394,7 +400,7 @@ fun RoomTab(
|
||||
val mod = if (selected) {
|
||||
base.background(brush = Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF))))
|
||||
} else {
|
||||
base.background(color = Color(0x22121212))
|
||||
base.background(color = Color(0x50121212))
|
||||
}
|
||||
|
||||
Box(
|
||||
@ -454,7 +460,13 @@ data class Device(val name: String, val sub: String, val icon: Int, val on: Bool
|
||||
@Composable
|
||||
fun DeviceCard(d: Device) {
|
||||
var active by remember { mutableStateOf(d.on) }
|
||||
Box(modifier = Modifier.height(120.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).shadow(12.dp, RoundedCornerShape(24.dp), true).padding(16.dp)) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(120.dp)
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.background(Color(0x50121212))
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Image(painter = painterResource(id = d.icon), contentDescription = null, modifier = Modifier.size(40.dp))
|
||||
@ -483,7 +495,7 @@ fun Toggle(on: Boolean, change: (Boolean) -> Unit) {
|
||||
|
||||
@Composable
|
||||
fun BottomNav() {
|
||||
Row(modifier = Modifier.fillMaxWidth().padding(16.dp).clip(RoundedCornerShape(28.dp)).background(Color(0x33121212)).padding(8.dp), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
Row(modifier = Modifier.fillMaxWidth().padding(16.dp).clip(RoundedCornerShape(28.dp)).background(Color(0x50121212)).padding(8.dp), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
NavItem("首页", true)
|
||||
NavItem("设备", false)
|
||||
NavItem("我的", false)
|
||||
@ -502,10 +514,10 @@ fun SideNavRail(selectedNavItem: Int = 0, onNavItemSelect: (Int) -> Unit = {}) {
|
||||
Column(modifier = Modifier.width(120.dp).fillMaxHeight().padding(12.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
NavRailItem("控制台", R.drawable.ic_dashboard, selectedNavItem == 0, onClick = { onNavItemSelect(0) })
|
||||
NavRailItem("最近", R.drawable.ic_recent, selectedNavItem == 1, onClick = { onNavItemSelect(1) })
|
||||
NavRailItem("收藏", R.drawable.ic_bookmark, selectedNavItem == 2, onClick = { onNavItemSelect(2) })
|
||||
NavRailItem("下载", R.drawable.ic_download, selectedNavItem == 3, onClick = { onNavItemSelect(3) })
|
||||
NavRailItem("支持", R.drawable.ic_support, selectedNavItem == 4, onClick = { onNavItemSelect(4) })
|
||||
NavRailItem("场景", R.drawable.ic_scene, selectedNavItem == 1, onClick = { onNavItemSelect(1) })
|
||||
NavRailItem("自动化", R.drawable.ic_automation, selectedNavItem == 2, onClick = { onNavItemSelect(2) })
|
||||
NavRailItem("统计", R.drawable.ic_statistics, selectedNavItem == 3, onClick = { onNavItemSelect(3) })
|
||||
NavRailItem("安全", R.drawable.ic_security, selectedNavItem == 4, onClick = { onNavItemSelect(4) })
|
||||
NavRailItem("设置", R.drawable.ic_settings, selectedNavItem == 5, onClick = { onNavItemSelect(5) })
|
||||
}
|
||||
}
|
||||
@ -568,17 +580,117 @@ fun NavRailItem(text: String, iconRes: Int, selected: Boolean, onClick: () -> Un
|
||||
|
||||
@Composable
|
||||
fun TopBar() {
|
||||
var weatherInfo by remember { mutableStateOf(WeatherService.getSimulatedWeather()) }
|
||||
var isLoading by remember { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
try {
|
||||
weatherInfo = WeatherService.getWeather()
|
||||
} catch (e: Exception) {
|
||||
// 使用模拟数据
|
||||
}
|
||||
isLoading = false
|
||||
}
|
||||
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(text = "控制台", style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold, color = Color.White)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(modifier = Modifier.width(280.dp).height(40.dp).clip(RoundedCornerShape(20.dp)).background(Color(0x22121212)).padding(horizontal = 16.dp), contentAlignment = Alignment.CenterStart) {
|
||||
Text(text = "搜索关键词", color = Color(0xFF9AA0A6))
|
||||
}
|
||||
// 天气信息卡片
|
||||
WeatherCard(weatherInfo = weatherInfo, isLoading = isLoading)
|
||||
GradientButton("+ 添加设备")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WeatherCard(weatherInfo: WeatherInfo, isLoading: Boolean) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color(0x50121212))
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
// 温度和天气
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = if (isLoading) "--" else "${weatherInfo.temperature}°C",
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White
|
||||
)
|
||||
Text(
|
||||
text = if (isLoading) "加载中" else weatherInfo.weather,
|
||||
fontSize = 12.sp,
|
||||
color = Color(0xFF9AA0A6)
|
||||
)
|
||||
}
|
||||
|
||||
// 分隔线
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.height(30.dp)
|
||||
.background(Color(0x33FFFFFF))
|
||||
)
|
||||
|
||||
// 湿度
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = if (isLoading) "--" else "${weatherInfo.humidity}%",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color.White
|
||||
)
|
||||
Text(
|
||||
text = "湿度",
|
||||
fontSize = 11.sp,
|
||||
color = Color(0xFF9AA0A6)
|
||||
)
|
||||
}
|
||||
|
||||
// 分隔线
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(1.dp)
|
||||
.height(30.dp)
|
||||
.background(Color(0x33FFFFFF))
|
||||
)
|
||||
|
||||
// 空气质量
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
val aqiColor = when {
|
||||
weatherInfo.aqi <= 50 -> Color(0xFF00E676)
|
||||
weatherInfo.aqi <= 100 -> Color(0xFFFFEB3B)
|
||||
weatherInfo.aqi <= 150 -> Color(0xFFFF9800)
|
||||
else -> Color(0xFFFF5252)
|
||||
}
|
||||
Text(
|
||||
text = if (isLoading) "--" else weatherInfo.airQuality,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = aqiColor
|
||||
)
|
||||
Text(
|
||||
text = if (isLoading) "AQI" else "AQI ${weatherInfo.aqi}",
|
||||
fontSize = 11.sp,
|
||||
color = Color(0xFF9AA0A6)
|
||||
)
|
||||
}
|
||||
|
||||
// 城市
|
||||
Text(
|
||||
text = weatherInfo.city,
|
||||
fontSize = 12.sp,
|
||||
color = Color(0xFFB0B0B0)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GradientButton(text: String, onClick: () -> Unit = {}) {
|
||||
Box(modifier = Modifier.height(36.dp).clip(RoundedCornerShape(20.dp)).background(Brush.linearGradient(listOf(Color(0xFFA9F0FF), Color(0xFFB89CFF)))).clickable(indication = null, interactionSource = remember { MutableInteractionSource() }) { onClick() }.padding(horizontal = 16.dp), contentAlignment = Alignment.Center) {
|
||||
@ -641,30 +753,246 @@ fun MyDevicesGrid(selectedRoom: Int, modifier: Modifier = Modifier) {
|
||||
fun UsageStatusChart(modifier: Modifier = Modifier, roomName: String = "房间") {
|
||||
// 根据房间生成不同的数据
|
||||
val values = remember(roomName) {
|
||||
List(10) { (10..35).random().toFloat() }
|
||||
List(12) { (15..45).random().toFloat() }
|
||||
}
|
||||
val totalPower = remember(roomName) { (15.0 + Math.random() * 30).toString().take(5) }
|
||||
val maxValue = remember(values) { values.maxOrNull() ?: 45f }
|
||||
val totalPower = remember(roomName) { (15.0 + Math.random() * 30).toString().take(4) }
|
||||
val totalHours = remember(roomName) { (10 + (Math.random() * 40).toInt()) }
|
||||
val activeDevices = remember(roomName) { (3 + (Math.random() * 8).toInt()) }
|
||||
val trend = remember(roomName) { if (Math.random() > 0.5) "↑" else "↓" }
|
||||
val trendPercent = remember(roomName) { (5 + (Math.random() * 15).toInt()) }
|
||||
|
||||
Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).padding(16.dp)) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
Text(text = "使用状态", fontWeight = FontWeight.SemiBold, color = Color.White)
|
||||
Text(text = roomName, fontSize = 12.sp, color = Color(0xFF9AA0A6))
|
||||
}
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(24.dp)) {
|
||||
Column {
|
||||
Text(text = "${totalPower}kWh", color = Color.White)
|
||||
Text(text = "总消耗", color = Color(0xFF9AA0A6), fontSize = 12.sp)
|
||||
Box(
|
||||
modifier = modifier
|
||||
.height(220.dp)
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.background(
|
||||
Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(0x60121212),
|
||||
Color(0x50121212)
|
||||
)
|
||||
)
|
||||
)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(0x22FFFFFF),
|
||||
Color(0x0AFFFFFF)
|
||||
)
|
||||
),
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
// 标题区域
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
text = "能耗统计",
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color.White,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
Text(
|
||||
text = roomName,
|
||||
fontSize = 12.sp,
|
||||
color = Color(0xFF9AA0A6)
|
||||
)
|
||||
}
|
||||
Column {
|
||||
Text(text = "${totalHours}h", color = Color.White)
|
||||
Text(text = "总时长", color = Color(0xFF9AA0A6), fontSize = 12.sp)
|
||||
|
||||
// 趋势指示器
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(
|
||||
if (trend == "↑") Color(0x33FF5252) else Color(0x3300E676)
|
||||
)
|
||||
.padding(horizontal = 10.dp, vertical = 6.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = trend,
|
||||
color = if (trend == "↑") Color(0xFFFF5252) else Color(0xFF00E676),
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = "${trendPercent}%",
|
||||
color = if (trend == "↑") Color(0xFFFF5252) else Color(0xFF00E676),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.Bottom) {
|
||||
values.forEach { v ->
|
||||
Box(modifier = Modifier.weight(1f).height(v.dp).clip(RoundedCornerShape(6.dp)).background(Color(0xFF2A2A2A)))
|
||||
|
||||
// 数据指标区域
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
// 总消耗
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = totalPower,
|
||||
color = Color(0xFFA9F0FF),
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = "kWh",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "总消耗",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
}
|
||||
|
||||
// 运行时长
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "$totalHours",
|
||||
color = Color(0xFFB89CFF),
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = "小时",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "运行时长",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
}
|
||||
|
||||
// 活跃设备
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "$activeDevices",
|
||||
color = Color(0xFF00E676),
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = "台",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(bottom = 2.dp)
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = "活跃设备",
|
||||
color = Color(0xFF9AA0A6),
|
||||
fontSize = 11.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
// 图表区域
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||
verticalAlignment = Alignment.Bottom
|
||||
) {
|
||||
values.forEachIndexed { index, v ->
|
||||
val normalizedHeight = (v / maxValue) * 60
|
||||
val isHighlight = index == values.size - 1
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(normalizedHeight.dp)
|
||||
.clip(RoundedCornerShape(topStart = 4.dp, topEnd = 4.dp))
|
||||
.background(
|
||||
if (isHighlight) {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color(0xFFA9F0FF),
|
||||
Color(0xFF00D1FF)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color(0xFF3A3A3A),
|
||||
Color(0xFF2A2A2A)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 时间标签
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter)
|
||||
.offset(y = 16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = "12h前",
|
||||
fontSize = 10.sp,
|
||||
color = Color(0xFF666666)
|
||||
)
|
||||
Text(
|
||||
text = "现在",
|
||||
fontSize = 10.sp,
|
||||
color = Color(0xFFA9F0FF),
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -676,7 +1004,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间
|
||||
var temp by remember { mutableStateOf(24f) }
|
||||
var isOn by remember { mutableStateOf(true) }
|
||||
|
||||
Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x26121212)).padding(16.dp)) {
|
||||
Box(modifier = modifier.height(220.dp).clip(RoundedCornerShape(24.dp)).background(Color(0x50121212)).padding(16.dp)) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
Column {
|
||||
@ -704,7 +1032,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0x33FFFFFF))
|
||||
.background(Color(0x55FFFFFF))
|
||||
.clickable(enabled = isOn && temp > 16f) {
|
||||
if (temp > 16f) temp -= 1f
|
||||
},
|
||||
@ -718,7 +1046,7 @@ fun AirConditionerCard(modifier: Modifier = Modifier, roomName: String = "房间
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0x33FFFFFF))
|
||||
.background(Color(0x55FFFFFF))
|
||||
.clickable(enabled = isOn && temp < 32f) {
|
||||
if (temp < 32f) temp += 1f
|
||||
},
|
||||
@ -777,10 +1105,10 @@ fun CustomSlider(
|
||||
activeTrackColor = Brush.linearGradient(
|
||||
listOf(Color(0xFF00D1FF), Color(0xFFA9F0FF))
|
||||
).let { Color(0xFF00D1FF) },
|
||||
inactiveTrackColor = Color(0x33FFFFFF),
|
||||
inactiveTrackColor = Color(0x55FFFFFF),
|
||||
disabledThumbColor = Color(0x66FFFFFF),
|
||||
disabledActiveTrackColor = Color(0x33FFFFFF),
|
||||
disabledInactiveTrackColor = Color(0x22FFFFFF)
|
||||
disabledActiveTrackColor = Color(0x55FFFFFF),
|
||||
disabledInactiveTrackColor = Color(0x55FFFFFF)
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@ -806,7 +1134,7 @@ fun CustomSlider(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(if (enabled) Color(0x33FFFFFF) else Color(0x22FFFFFF))
|
||||
.background(if (enabled) Color(0x55FFFFFF) else Color(0x55FFFFFF))
|
||||
)
|
||||
// 激活轨道
|
||||
Box(
|
||||
@ -820,7 +1148,7 @@ fun CustomSlider(
|
||||
)
|
||||
} else {
|
||||
Brush.linearGradient(
|
||||
listOf(Color(0x33FFFFFF), Color(0x33FFFFFF))
|
||||
listOf(Color(0x55FFFFFF), Color(0x55FFFFFF))
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -843,9 +1171,9 @@ fun LightList(modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier.fillMaxHeight(), verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
Text(text = "灯光", fontWeight = FontWeight.SemiBold)
|
||||
lights.forEach { (name, percent) ->
|
||||
Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(RoundedCornerShape(16.dp)).background(Color(0x26121212)).padding(12.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clip(RoundedCornerShape(16.dp)).background(Color(0x50121212)).padding(12.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(modifier = Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(Color(0x22121212)))
|
||||
Box(modifier = Modifier.size(36.dp).clip(RoundedCornerShape(10.dp)).background(Color(0x50121212)))
|
||||
Column { Text(text = name); Text(text = "${(percent * 100).toInt()}%", color = Color(0xFF9AA0A6)) }
|
||||
}
|
||||
DotsProgress(percent)
|
||||
@ -965,6 +1293,14 @@ fun ModeButton(
|
||||
val interaction = remember { MutableInteractionSource() }
|
||||
var pressed by remember { mutableStateOf(false) }
|
||||
|
||||
// 根据文本确定图标
|
||||
val iconRes = when (text) {
|
||||
"回家" -> R.drawable.ic_mode_home
|
||||
"出门" -> R.drawable.ic_mode_away
|
||||
"玩乐" -> R.drawable.ic_mode_fun
|
||||
else -> R.drawable.ic_dashboard
|
||||
}
|
||||
|
||||
val scale by androidx.compose.animation.core.animateFloatAsState(
|
||||
targetValue = if (pressed) 0.96f else 1f,
|
||||
animationSpec = androidx.compose.animation.core.spring(
|
||||
@ -980,6 +1316,14 @@ fun ModeButton(
|
||||
label = "elevation"
|
||||
)
|
||||
|
||||
val iconScale by androidx.compose.animation.core.animateFloatAsState(
|
||||
targetValue = if (selected) 1.1f else 1f,
|
||||
animationSpec = androidx.compose.animation.core.spring(
|
||||
dampingRatio = androidx.compose.animation.core.Spring.DampingRatioMediumBouncy
|
||||
),
|
||||
label = "icon_scale"
|
||||
)
|
||||
|
||||
val view = LocalView.current
|
||||
|
||||
LaunchedEffect(interaction) {
|
||||
@ -995,38 +1339,25 @@ fun ModeButton(
|
||||
modifier = modifier
|
||||
.height(height)
|
||||
.scale(scale)
|
||||
.shadow(elevation, shape)
|
||||
.background(
|
||||
.clip(shape)
|
||||
.then(
|
||||
if (selected) {
|
||||
brush
|
||||
Modifier
|
||||
.shadow(elevation, shape, clip = false)
|
||||
.background(brush, shape)
|
||||
.border(
|
||||
width = 2.dp,
|
||||
brush = Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0x99FFFFFF),
|
||||
Color(0x66FFFFFF)
|
||||
)
|
||||
),
|
||||
shape = shape
|
||||
)
|
||||
} else {
|
||||
Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0x40FFFFFF),
|
||||
Color(0x20FFFFFF)
|
||||
)
|
||||
)
|
||||
},
|
||||
shape = shape
|
||||
)
|
||||
.border(
|
||||
width = if (selected) 2.dp else 1.dp,
|
||||
brush = if (selected) {
|
||||
Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0x99FFFFFF),
|
||||
Color(0x66FFFFFF)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Brush.linearGradient(
|
||||
listOf(
|
||||
Color(0x33FFFFFF),
|
||||
Color(0x11FFFFFF)
|
||||
)
|
||||
)
|
||||
},
|
||||
shape = shape
|
||||
Modifier.background(Color(0x50121212))
|
||||
}
|
||||
)
|
||||
.clickable(indication = null, interactionSource = interaction) {
|
||||
view.playSoundEffect(SoundEffectConstants.CLICK)
|
||||
@ -1035,13 +1366,95 @@ fun ModeButton(
|
||||
.padding(24.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
color = if (selected) Color.White else Color(0xFFB0B0B0),
|
||||
fontWeight = if (selected) FontWeight.Bold else FontWeight.Medium,
|
||||
fontSize = if (selected) 22.sp else 20.sp,
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
// 图标容器
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(if (selected) 72.dp else 64.dp)
|
||||
.scale(iconScale),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
// 外层光晕效果(仅选中时)
|
||||
if (selected) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(20.dp))
|
||||
.background(
|
||||
Brush.radialGradient(
|
||||
colors = listOf(
|
||||
Color.White.copy(alpha = 0.2f),
|
||||
Color.Transparent
|
||||
),
|
||||
radius = 100f
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// 图标背景
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(if (selected) 64.dp else 56.dp)
|
||||
.clip(RoundedCornerShape(18.dp))
|
||||
.background(
|
||||
if (selected) {
|
||||
Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color.White.copy(alpha = 0.25f),
|
||||
Color.White.copy(alpha = 0.15f)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color(0x55FFFFFF),
|
||||
Color(0x55FFFFFF)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (selected) {
|
||||
Modifier.border(
|
||||
width = 1.dp,
|
||||
brush = Brush.linearGradient(
|
||||
colors = listOf(
|
||||
Color.White.copy(alpha = 0.4f),
|
||||
Color.White.copy(alpha = 0.1f)
|
||||
)
|
||||
),
|
||||
shape = RoundedCornerShape(18.dp)
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = iconRes),
|
||||
contentDescription = text,
|
||||
modifier = Modifier.size(if (selected) 38.dp else 34.dp),
|
||||
colorFilter = androidx.compose.ui.graphics.ColorFilter.tint(
|
||||
Color.White
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 文字
|
||||
Text(
|
||||
text = text,
|
||||
color = Color.White,
|
||||
fontWeight = if (selected) FontWeight.Bold else FontWeight.Medium,
|
||||
fontSize = if (selected) 20.sp else 18.sp,
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1065,7 +1478,7 @@ fun LightRow(modifier: Modifier = Modifier, roomName: String = "房间") {
|
||||
fun LightCard(name: String, percent: Float, modifier: Modifier = Modifier) {
|
||||
var brightness by remember { mutableStateOf(percent) }
|
||||
|
||||
Box(modifier = modifier.height(100.dp).clip(RoundedCornerShape(16.dp)).background(Color(0x26121212)).padding(12.dp)) {
|
||||
Box(modifier = modifier.height(100.dp).clip(RoundedCornerShape(16.dp)).background(Color(0x50121212)).padding(12.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
// 灯光图标 - 带发光效果
|
||||
@ -1142,7 +1555,6 @@ fun AddRoomDialog(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(0x80000000))
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
@ -1176,8 +1588,8 @@ fun AddRoomDialog(
|
||||
placeholder = { Text("请输入房间名称", color = Color(0xFF9AA0A6)) },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
colors = androidx.compose.material3.TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color(0x22FFFFFF),
|
||||
unfocusedContainerColor = Color(0x22FFFFFF),
|
||||
focusedContainerColor = Color(0x55FFFFFF),
|
||||
unfocusedContainerColor = Color(0x55FFFFFF),
|
||||
focusedTextColor = Color.White,
|
||||
unfocusedTextColor = Color.White,
|
||||
cursorColor = Color(0xFFA9F0FF),
|
||||
@ -1197,7 +1609,7 @@ fun AddRoomDialog(
|
||||
.weight(1f)
|
||||
.height(48.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0x22FFFFFF))
|
||||
.background(Color(0x55FFFFFF))
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
|
||||
@ -130,7 +130,7 @@ fun SettingsTopBar(onBack: () -> Unit) {
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.background(Color(0x22FFFFFF))
|
||||
.background(Color(0x50121212))
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
@ -167,7 +167,7 @@ fun SettingsSection(title: String, content: @Composable ColumnScope.() -> Unit)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.background(Color(0x26FFFFFF))
|
||||
.background(Color(0x50121212))
|
||||
.padding(8.dp)
|
||||
) {
|
||||
Column(
|
||||
@ -190,7 +190,7 @@ fun SettingsItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color(0x11FFFFFF))
|
||||
.background(Color(0x33121212))
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
@ -237,7 +237,7 @@ fun SettingsSwitchItem(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color(0x11FFFFFF))
|
||||
.background(Color(0x33121212))
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
@ -312,13 +312,13 @@ fun LogoutButton(onClick: () -> Unit) {
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.shadow(8.dp, RoundedCornerShape(24.dp))
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.background(
|
||||
Brush.linearGradient(
|
||||
listOf(Color(0xFFFF6B6B), Color(0xFFFF5252))
|
||||
)
|
||||
)
|
||||
.shadow(8.dp, RoundedCornerShape(24.dp), clip = false)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
|
||||
@ -1,3 +1,22 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||
<solid android:color="#121212"/>
|
||||
</shape>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<!-- 渐变背景 -->
|
||||
<path
|
||||
android:pathData="M0,0 h108 v108 h-108 z">
|
||||
<aapt:attr name="android:fillColor" xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<gradient
|
||||
android:startY="0"
|
||||
android:startX="0"
|
||||
android:endY="108"
|
||||
android:endX="108"
|
||||
android:type="linear">
|
||||
<item android:offset="0" android:color="#FF1A1A2E"/>
|
||||
<item android:offset="1" android:color="#FF16213E"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
|
||||
@ -1,4 +1,46 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="108dp" android:height="108dp" android:viewportWidth="108" android:viewportHeight="108">
|
||||
<path android:pathData="M24,54 L84,54" android:strokeColor="#FFFFFFFF" android:strokeWidth="6" android:fillColor="#00000000"/>
|
||||
<path android:pathData="M54,24 L54,84" android:strokeColor="#FFFFFFFF" android:strokeWidth="6" android:fillColor="#00000000"/>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<group
|
||||
android:scaleX="0.08"
|
||||
android:scaleY="0.08"
|
||||
android:translateX="22"
|
||||
android:translateY="22">
|
||||
|
||||
<!-- 中心圆 -->
|
||||
<path
|
||||
android:fillColor="#bfbfbf"
|
||||
android:pathData="M512,540.44 m-312.89,0 a312.89,312.89 0,1,0 625.78,0 a312.89,312.89 0,1,0 -625.78,0 Z"/>
|
||||
|
||||
<!-- 中心环 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M512,398.22 c227.56,0 412.44,56.89 412.44,128 S739.56,654.22 512,654.22 99.56,597.33 99.56,526.22 284.44,398.22 512,398.22 m0,-56.89 c-174.36,0 -469.33,38.97 -469.33,184.89 S337.64,711.11 512,711.11 s469.33,-38.97 469.33,-184.89 S686.36,341.33 512,341.33 z"/>
|
||||
|
||||
<!-- 左侧轨道 -->
|
||||
<path
|
||||
android:fillColor="#7dc5eb"
|
||||
android:pathData="M312.89,117.48 a102.68,102.68 0,0,0 -56.89,16.5 c-36.12,23.89 -71.4,80.21 -32.71,213.9 a1077.48,1077.48 0,0,0 135.96,279.89 c93.01,142.22 241.78,307.2 354.99,307.2 a102.68,102.68 0,0,0 56.89,-16.5 c36.12,-23.89 71.4,-80.21 32.71,-213.9 a1077.48,1077.48 0,0,0 -135.96,-279.89 C573.44,284.44 424.68,117.48 312.89,117.48 z"/>
|
||||
|
||||
<!-- 右侧轨道 -->
|
||||
<path
|
||||
android:fillColor="#e89abe"
|
||||
android:pathData="M695.18,106.38 c113.78,0 256,176.36 343.32,327.4 s200.82,426.67 74.52,498.92 a102.12,102.12 0,0,1 -51.48,13.37 c-113.78,0 -256,-176.36 -343.32,-327.4 s-200.82,-426.67 -74.52,-498.92 a102.12,102.12 0,0,1 51.48,-13.37 z"/>
|
||||
|
||||
<!-- 装饰点 -->
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M170.67,625.78 m-56.89,0 a56.89,56.89 0,1,0 113.78,0 a56.89,56.89 0,1,0 -113.78,0 Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M597.33,170.67 m-56.89,0 a56.89,56.89 0,1,0 113.78,0 a56.89,56.89 0,1,0 -113.78,0 Z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M625.78,881.78 m-56.89,0 a56.89,56.89 0,1,0 113.78,0 a56.89,56.89 0,1,0 -113.78,0 Z"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
Loading…
Reference in New Issue
Block a user