fix: theme issues

This commit is contained in:
玖叁 2024-12-24 16:57:40 +08:00
parent 61f37f71de
commit d0fe216097
15 changed files with 163 additions and 230 deletions

View File

@ -65,6 +65,7 @@ dependencies {
implementation(libs.androidx.datastore.preferences.core.jvm)
implementation(libs.androidx.datastore.preferences)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.accompanist.systemuicontroller)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)

View File

@ -1,35 +1,29 @@
package icu.fur93.esp32_car
import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import androidx.compose.ui.graphics.Color
import android.app.Activity
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.ParcelUuid
import android.util.Log
import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.app.ActivityCompat
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@ -44,12 +38,11 @@ import icu.fur93.esp32_car.page.ControlSingleJoystickModePage
import icu.fur93.esp32_car.page.HomePage
import icu.fur93.esp32_car.page.SettingsPage
import icu.fur93.esp32_car.repository.BluetoothRepositoryImpl
import icu.fur93.esp32_car.ui.component.BottomNavigationBar
import icu.fur93.esp32_car.ui.theme.Esp32carTheme
import icu.fur93.esp32_car.viewmodel.CarControlUseCase
import icu.fur93.esp32_car.viewmodel.CarViewModel
import java.util.UUID
import kotlinx.coroutines.launch
import kotlinx.coroutines.flow.collect
class MainActivity : ComponentActivity() {
private val preferencesDataStore by lazy {
@ -76,6 +69,17 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(
lightScrim = Color.Transparent.toArgb(), // 浅色主题下状态栏的微弱遮罩
darkScrim = Color.Transparent.toArgb(), // 深色主题下状态栏的微弱遮罩
),
navigationBarStyle = SystemBarStyle.auto(
lightScrim = Color.Transparent.toArgb(), // 浅色主题下导航栏的微弱遮罩
darkScrim = Color.Transparent.toArgb(), // 深色主题下导航栏的微弱遮罩
)
)
// 设置全屏显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
@ -142,24 +146,51 @@ class MainActivity : ComponentActivity() {
@Composable
fun App(viewModel: CarViewModel) {
val activity = LocalContext.current as MainActivity
activity.window.statusBarColor = MaterialTheme.colorScheme.background.toArgb()
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Route.Home.route
) {
composable(Route.Home.route) { HomePage(navController, viewModel) }
composable(Route.Control.route) { ControlPage(navController, viewModel) }
composable(Route.Settings.route) { SettingsPage(navController, viewModel) }
composable(Route.ControlPathfinderMode.route) { ControlPathfinderModePage(navController) }
composable(Route.ControlSingleJoystickMode.route) {
ControlSingleJoystickModePage(
navController
)
val isDarkTheme = isSystemInDarkTheme()
val view = LocalView.current
val window = (LocalContext.current as? MainActivity)?.window
DisposableEffect(isDarkTheme) {
window?.apply {
// 2. 设置导航栏颜色为透明
navigationBarColor = Color.Transparent.toArgb()
// 3. 根据主题设置导航栏图标颜色
WindowCompat.getInsetsController(this, view).apply {
isAppearanceLightNavigationBars = !isDarkTheme
}
}
composable(Route.ControlGamepadMode.route) { ControlGamepadModePage(navController) }
onDispose {}
}
Scaffold(
bottomBar = {
BottomNavigationBar(navController)
},
modifier = Modifier
.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.surface,
) { innerPadding ->
Box(Modifier.padding(innerPadding)) {
NavHost(
navController = navController,
startDestination = Route.Home.route
) {
composable(Route.Home.route) { HomePage(viewModel) }
composable(Route.Control.route) { ControlPage(viewModel) }
composable(Route.Settings.route) { SettingsPage(viewModel) }
composable(Route.ControlPathfinderMode.route) {
ControlPathfinderModePage(viewModel)
}
composable(Route.ControlSingleJoystickMode.route) {
ControlSingleJoystickModePage(viewModel)
}
composable(Route.ControlGamepadMode.route) { ControlGamepadModePage(viewModel) }
}
}
}
}

View File

@ -1,14 +1,8 @@
package icu.fur93.esp32_car.page
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import icu.fur93.esp32_car.ui.layout.ControlModeLayout
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun ControlGamepadModePage(navController: NavController) {
ControlModeLayout(
content = {
},
onBack = { navController.navigateUp() }
)
fun ControlGamepadModePage(viewModel: CarViewModel) {
}

View File

@ -1,14 +1,8 @@
package icu.fur93.esp32_car.page
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import icu.fur93.esp32_car.ui.layout.ControlModeLayout
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun ControlGyroscopeModePage(navController: NavController) {
ControlModeLayout(
content = {
},
onBack = { navController.navigateUp() }
)
fun ControlGyroscopeModePage(viewModel: CarViewModel) {
}

View File

@ -1,5 +1,6 @@
package icu.fur93.esp32_car.page
import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
@ -8,43 +9,30 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import icu.fur93.esp32_car.R
import icu.fur93.esp32_car.Route
import icu.fur93.esp32_car.repository.ConnectionState
import icu.fur93.esp32_car.ui.card.UnconnectedStatusCard
import icu.fur93.esp32_car.ui.component.BottomNavigationBar
import icu.fur93.esp32_car.ui.component.CardButtonGroup
import icu.fur93.esp32_car.ui.component.CardButtonItem
import icu.fur93.esp32_car.ui.component.PageTitle
import icu.fur93.esp32_car.ui.layout.MainLayout
import icu.fur93.esp32_car.ui.theme.LayoutContentModifier
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun ControlPage(navController: NavHostController, viewModel: CarViewModel) {
fun ControlPage(viewModel: CarViewModel) {
val connectionState by viewModel.connectionState.collectAsState()
MainLayout(
content = {
Column (LayoutContentModifier) {
PageTitle("控制")
if (connectionState == ConnectionState.CONNECTED) {
ControlPageStatusCard()
} else {
UnconnectedStatusCard(viewModel)
}
}
},
bottomBar = {
BottomNavigationBar(
currentRoute = Route.Control.route,
navController = navController
)
Column(LayoutContentModifier) {
PageTitle("控制")
if (connectionState == ConnectionState.CONNECTED) {
ControlPageStatusCard()
} else {
UnconnectedStatusCard(viewModel)
}
)
}
}
@Composable
@ -56,12 +44,16 @@ fun ControlPageStatusCard() {
@Composable
fun ControlPageAutoControl() {
val context = LocalContext.current
return CardButtonGroup(
title = "自动控制",
buttons = listOf(
CardButtonItem(
text = "循迹模式",
icon = ImageVector.vectorResource(R.drawable.outline_route_24)
icon = ImageVector.vectorResource(R.drawable.outline_route_24),
onClick = {
Toast.makeText(context, "暂未实现", Toast.LENGTH_SHORT).show()
}
)
)
)
@ -69,6 +61,7 @@ fun ControlPageAutoControl() {
@Composable
fun ControlPageManualControl() {
val context = LocalContext.current
CardButtonGroup(
title = "手动控制",
buttons = listOf(
@ -82,7 +75,10 @@ fun ControlPageManualControl() {
),
CardButtonItem(
text = "陀螺仪模式",
icon = ImageVector.vectorResource(R.drawable.motion_sensor_active_24)
icon = ImageVector.vectorResource(R.drawable.motion_sensor_active_24),
onClick = {
Toast.makeText(context, "暂未实现", Toast.LENGTH_SHORT).show()
}
)
)
)

View File

@ -1,14 +1,8 @@
package icu.fur93.esp32_car.page
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import icu.fur93.esp32_car.ui.layout.ControlModeLayout
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun ControlPathfinderModePage(navController: NavController) {
ControlModeLayout(
content = {
},
onBack = { navController.navigateUp() }
)
fun ControlPathfinderModePage(viewModel: CarViewModel) {
}

View File

@ -1,14 +1,8 @@
package icu.fur93.esp32_car.page
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import icu.fur93.esp32_car.ui.layout.ControlModeLayout
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun ControlSingleJoystickModePage(navController: NavController) {
ControlModeLayout(
content = {
},
onBack = { navController.navigateUp() }
)
fun ControlSingleJoystickModePage(viewModel: CarViewModel) {
}

View File

@ -12,35 +12,23 @@ import icu.fur93.esp32_car.ui.carditem.StatusCardInfo
import icu.fur93.esp32_car.ui.carditem.StatusCardInfraredStatus
import icu.fur93.esp32_car.ui.carditem.StatusCardMotorStatus
import icu.fur93.esp32_car.ui.carditem.StatusCardUltrasoundStatus
import icu.fur93.esp32_car.ui.component.BottomNavigationBar
import icu.fur93.esp32_car.ui.component.PageTitle
import icu.fur93.esp32_car.ui.component.StatusCard
import icu.fur93.esp32_car.ui.layout.MainLayout
import icu.fur93.esp32_car.ui.theme.LayoutContentModifier
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun HomePage(navController: NavHostController, viewModel: CarViewModel) {
fun HomePage(viewModel: CarViewModel) {
val connectionState by viewModel.connectionState.collectAsState()
MainLayout(
content = {
Column(LayoutContentModifier) {
PageTitle("标题还没想好")
if (connectionState == ConnectionState.CONNECTED) {
HomePageStatusCard(viewModel)
} else {
UnconnectedStatusCard(viewModel)
}
}
},
bottomBar = {
BottomNavigationBar(
currentRoute = Route.Home.route,
navController = navController
)
Column(LayoutContentModifier) {
PageTitle("标题还没想好")
if (connectionState == ConnectionState.CONNECTED) {
HomePageStatusCard(viewModel)
} else {
UnconnectedStatusCard(viewModel)
}
)
}
}
@Composable

View File

@ -21,41 +21,28 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.navigation.NavHostController
import icu.fur93.esp32_car.R
import icu.fur93.esp32_car.Route
import icu.fur93.esp32_car.repository.BluetoothRepositoryImpl
import icu.fur93.esp32_car.repository.ConnectionState
import icu.fur93.esp32_car.ui.component.BottomNavigationBar
import icu.fur93.esp32_car.ui.component.PageTitle
import icu.fur93.esp32_car.ui.dialog.BleDeviceScanDialog
import icu.fur93.esp32_car.ui.layout.MainLayout
import icu.fur93.esp32_car.ui.theme.LayoutContentPadding
import icu.fur93.esp32_car.ui.theme.LayoutTopPadding
import icu.fur93.esp32_car.viewmodel.CarViewModel
@Composable
fun SettingsPage(navController: NavHostController, viewModel: CarViewModel) {
MainLayout(
content = {
Column {
Column (
Modifier.padding(
top = LayoutTopPadding,
start = LayoutContentPadding,
end = LayoutContentPadding
)
) {
PageTitle("设置")
}
SettingsList(viewModel)
}
},
bottomBar = {
BottomNavigationBar(
currentRoute = Route.Settings.route,
navController = navController
fun SettingsPage(viewModel: CarViewModel) {
Column {
Column(
Modifier.padding(
top = LayoutTopPadding,
start = LayoutContentPadding,
end = LayoutContentPadding
)
) {
PageTitle("设置")
}
)
SettingsList(viewModel)
}
}
@Composable
@ -108,7 +95,11 @@ fun SettingConnectDeviceItem(viewModel: CarViewModel) {
ListItem(
headlineContent = { Text("连接设备") },
supportingContent = { if (connectionState == ConnectionState.CONNECTED) Text("已连接") else Text("未连接") },
supportingContent = {
if (connectionState == ConnectionState.CONNECTED) Text("已连接") else Text(
"未连接"
)
},
trailingContent = {
Icon(
ImageVector.vectorResource(R.drawable.arrow_right_24),

View File

@ -8,14 +8,17 @@ import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import icu.fur93.esp32_car.Route
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.ui.unit.dp
data class BottomNavigationItem(
val title: String,
@ -26,7 +29,6 @@ data class BottomNavigationItem(
@Composable
fun BottomNavigationBar(
currentRoute: String,
navController: NavHostController
) {
val navItems = listOf(
@ -50,12 +52,25 @@ fun BottomNavigationBar(
)
)
NavigationBar() {
navItems.forEachIndexed{ _, item ->
val currentRoute = navController
.currentBackStackEntryFlow
.collectAsState(initial = navController.currentBackStackEntry)
.value?.destination?.route
NavigationBar(
containerColor = MaterialTheme.colorScheme.surface,
) {
navItems.forEachIndexed { _, item ->
NavigationBarItem(
icon = { Icon(if (currentRoute == item.route.route) item.selectedIcon else item.icon, item.title) },
icon = {
Icon(
if ((currentRoute
?: "").startsWith(item.route.route)
) item.selectedIcon else item.icon, item.title
)
},
label = { Text(item.title) },
selected = currentRoute == item.route.route,
selected = (currentRoute?:"").startsWith(item.route.route),
onClick = {
navController.navigate(item.route.route)
}

View File

@ -10,16 +10,21 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import icu.fur93.esp32_car.ui.theme.CardButtonTypography
data class CardButtonItem(
val text: String,
@ -46,53 +51,27 @@ fun CardButtonGroup(
verticalArrangement = Arrangement.spacedBy(CardButtonGroupGap)
) {
items(buttons.size) { index ->
M3CardButton(buttons[index])
CardButton(buttons[index])
}
}
}
@Composable
fun M3CardButton(item: CardButtonItem) {
ElevatedCard(
modifier = item.modifier ?: Modifier
) {
FilledTonalButton(
onClick = { item.onClick?.invoke() },
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = item.text,
style = MaterialTheme.typography.titleMedium
)
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.CenterEnd
) {
Icon(
imageVector = item.icon,
contentDescription = item.text,
modifier = Modifier.size(24.dp)
)
}
}
}
}
}
/* 原代码注释
@Composable
fun CardButton(
item: CardButtonItem
) {
Card {
Button(
onClick = { item.onClick?.invoke() },
shape = MaterialTheme.shapes.medium,
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.contentColorFor(MaterialTheme.colorScheme.surfaceVariant)
)
) {
Column(
modifier = Modifier.fillMaxWidth().padding(12.dp),
modifier = Modifier
.fillMaxWidth()
.padding(top = 10.dp, bottom = 10.dp),
verticalArrangement = Arrangement.SpaceBetween
) {
Text(
@ -107,10 +86,10 @@ fun CardButton(
Icon(
imageVector = item.icon,
contentDescription = item.text,
modifier = Modifier.size(24.dp)
modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary
)
}
}
}
}
*/

View File

@ -24,7 +24,9 @@ fun StatusCard(
cardItems: List<CardItem>,
bottomControl: @Composable() (() -> Unit?)? = null
) {
Card (Modifier.fillMaxWidth()) {
Card (
modifier = Modifier.fillMaxWidth()
) {
Column(Modifier.fillMaxWidth().padding(20.dp)) {
cardItems.forEachIndexed { index, item ->
StatusCardTitle(item.title)

View File

@ -1,21 +0,0 @@
package icu.fur93.esp32_car.ui.layout
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun ControlModeLayout(
content: @Composable () -> Unit,
onBack: () -> Unit
) {
Column(
modifier = Modifier.fillMaxSize()
) {
Box(modifier = Modifier.weight(1f)) {
content()
}
}
}

View File

@ -1,27 +0,0 @@
package icu.fur93.esp32_car.ui.layout
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun MainLayout(
content: @Composable () -> Unit,
bottomBar: @Composable () -> Unit
) {
Column(
modifier = Modifier.fillMaxSize()
) {
Scaffold(
bottomBar = bottomBar
) { innerPadding ->
Box(Modifier.padding(innerPadding)) {
content()
}
}
}
}

View File

@ -14,6 +14,7 @@ datastoreCoreAndroid = "1.1.1"
datastorePreferencesCoreJvm = "1.1.1"
datastorePreferences = "1.1.1"
lifecycleViewmodelCompose = "2.9.0-alpha08"
accompanistSystemuicontroller = "0.36.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@ -36,6 +37,7 @@ androidx-datastore-core-android = { group = "androidx.datastore", name = "datast
androidx-datastore-preferences-core-jvm = { group = "androidx.datastore", name = "datastore-preferences-core-jvm", version.ref = "datastorePreferencesCoreJvm" }
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" }
androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version = "2.7.0" }
accompanist-systemuicontroller = { group = "com.google.accompanist", name = "accompanist-systemuicontroller", version.ref = "accompanistSystemuicontroller" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }