Skip to content

Commit 7524310

Browse files
committed
support 代码高亮&colormode
1 parent f016a6d commit 7524310

File tree

5 files changed

+287
-77
lines changed

5 files changed

+287
-77
lines changed

composeApp/src/wasmJsMain/kotlin/love/forte/simbot/codegen/App.kt

Lines changed: 35 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
11
package love.forte.simbot.codegen
22

33
import androidx.compose.animation.AnimatedContent
4-
import androidx.compose.animation.ExperimentalSharedTransitionApi
5-
import androidx.compose.foundation.isSystemInDarkTheme
6-
import androidx.compose.foundation.layout.Arrangement
7-
import androidx.compose.foundation.layout.Box
8-
import androidx.compose.foundation.layout.Column
9-
import androidx.compose.foundation.layout.Spacer
10-
import androidx.compose.foundation.layout.fillMaxSize
11-
import androidx.compose.foundation.layout.padding
12-
import androidx.compose.material3.CircularProgressIndicator
13-
import androidx.compose.material3.MaterialTheme
14-
import androidx.compose.material3.Text
15-
import androidx.compose.material3.darkColorScheme
16-
import androidx.compose.material3.lightColorScheme
17-
import androidx.compose.runtime.Composable
18-
import androidx.compose.runtime.getValue
4+
import androidx.compose.foundation.layout.*
5+
import androidx.compose.material3.*
6+
import androidx.compose.runtime.*
197
import androidx.compose.ui.Alignment
208
import androidx.compose.ui.Modifier
219
import androidx.compose.ui.graphics.Color
@@ -24,57 +12,27 @@ import androidx.compose.ui.unit.dp
2412
import love.forte.simbot.codegen.gen.view.GradleSettingsView
2513
import org.jetbrains.compose.resources.ExperimentalResourceApi
2614
import org.jetbrains.compose.resources.preloadFont
27-
import simbot_codegen.composeapp.generated.resources.JetBrainsMono_Medium
2815
import simbot_codegen.composeapp.generated.resources.LXGWNeoXiHeiScreen
2916
import simbot_codegen.composeapp.generated.resources.Res
3017

31-
////
32-
33-
@OptIn(ExperimentalSharedTransitionApi::class)
3418
@Composable
3519
fun App() {
3620
@OptIn(ExperimentalResourceApi::class)
3721
val lxgwNeo by preloadFont(resource = Res.font.LXGWNeoXiHeiScreen)
3822
val fm = lxgwNeo?.let { FontFamily(it) }
3923

40-
val darkTheme = isSystemInDarkTheme()
41-
42-
val colorScheme = if (darkTheme) {
43-
darkColorScheme(
44-
primary = Color(0xFF5B9EE1), // 柔和的蓝色
45-
secondary = Color(0xFF80CBBF), // 淡绿蓝色
46-
tertiary = Color(0xFFEFB196), // 淡橙色
47-
background = Color(0xFF1A1A1A), // 稍微柔和的黑色
48-
surface = Color(0xFF252525), // 柔和的暗色表面
49-
error = Color(0xFFE57373), // 淡红色错误提示
50-
onPrimary = Color(0xFFF5F5F5), // 主色上的文本
51-
onSecondary = Color(0xFF121212), // 次要色上的文本
52-
onTertiary = Color(0xFF121212), // 第三色上的文本
53-
onBackground = Color(0xFFE0E0E0), // 背景上的文本
54-
onSurface = Color(0xFFE0E0E0), // 表面上的文本
55-
surfaceVariant = Color(0xFF3A3A3A), // 表面变体
56-
primaryContainer = Color(0xFF2F4D6F), // 主色容器
57-
secondaryContainer = Color(0xFF396458) // 次要色容器
58-
)
59-
} else {
60-
lightColorScheme(
61-
primary = Color(0xFF3B7DD8), // 优雅的蓝色
62-
secondary = Color(0xFF4DB6A5), // 平衡的绿松石色
63-
tertiary = Color(0xFFEF9265), // 温和的橙色
64-
background = Color(0xFFF8F8F8), // 温和的白色背景
65-
surface = Color(0xFFFFFFFF), // 纯白色表面
66-
error = Color(0xFFD32F2F), // 标准错误色
67-
onPrimary = Color(0xFFFFFFFF), // 主色上的文本
68-
onSecondary = Color(0xFFFFFFFF), // 次要色上的文本
69-
onTertiary = Color(0xFFFFFFFF), // 第三色上的文本
70-
onBackground = Color(0xFF212121), // 背景上的文本
71-
onSurface = Color(0xFF212121), // 表面上的文本
72-
surfaceVariant = Color(0xFFE6E6E6), // 表面变体
73-
primaryContainer = Color(0xFFD4E3F8), // 主色容器
74-
secondaryContainer = Color(0xFFD4F0EB) // 次要色容器
24+
// 创建主题状态管理
25+
var colorMode by remember { mutableStateOf(ColorMode.LIGHT) }
26+
val appContext = remember(colorMode) {
27+
AppContext(
28+
colorMode = colorMode,
29+
toggleColorMode = { colorMode = colorMode.toggle() }
7530
)
7631
}
7732

33+
// 使用带动画过渡的颜色方案
34+
val colorScheme = rememberAnimatedColorScheme(colorMode)
35+
7836
AnimatedContent(fm) { fm ->
7937
if (fm == null) {
8038
Box(modifier = Modifier.fillMaxSize()) {
@@ -89,27 +47,29 @@ fun App() {
8947
}
9048
}
9149
} else {
92-
MaterialTheme(
93-
colorScheme = colorScheme,
94-
typography = MaterialTheme.typography.copy(
95-
displayLarge = MaterialTheme.typography.displayLarge.copy(fontFamily = fm),
96-
displayMedium = MaterialTheme.typography.displayMedium.copy(fontFamily = fm),
97-
displaySmall = MaterialTheme.typography.displaySmall.copy(fontFamily = fm),
98-
headlineLarge = MaterialTheme.typography.headlineLarge.copy(fontFamily = fm),
99-
headlineMedium = MaterialTheme.typography.headlineMedium.copy(fontFamily = fm),
100-
headlineSmall = MaterialTheme.typography.headlineSmall.copy(fontFamily = fm),
101-
titleLarge = MaterialTheme.typography.titleLarge.copy(fontFamily = fm),
102-
titleMedium = MaterialTheme.typography.titleMedium.copy(fontFamily = fm),
103-
titleSmall = MaterialTheme.typography.titleSmall.copy(fontFamily = fm),
104-
bodyLarge = MaterialTheme.typography.bodyLarge.copy(fontFamily = fm),
105-
bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontFamily = fm),
106-
bodySmall = MaterialTheme.typography.bodySmall.copy(fontFamily = fm),
107-
labelLarge = MaterialTheme.typography.labelLarge.copy(fontFamily = fm),
108-
labelMedium = MaterialTheme.typography.labelMedium.copy(fontFamily = fm),
109-
labelSmall = MaterialTheme.typography.labelSmall.copy(fontFamily = fm),
110-
)
111-
) {
112-
GradleSettingsView()
50+
CompositionLocalProvider(LocalAppContext provides appContext) {
51+
MaterialTheme(
52+
colorScheme = colorScheme,
53+
typography = MaterialTheme.typography.copy(
54+
displayLarge = MaterialTheme.typography.displayLarge.copy(fontFamily = fm),
55+
displayMedium = MaterialTheme.typography.displayMedium.copy(fontFamily = fm),
56+
displaySmall = MaterialTheme.typography.displaySmall.copy(fontFamily = fm),
57+
headlineLarge = MaterialTheme.typography.headlineLarge.copy(fontFamily = fm),
58+
headlineMedium = MaterialTheme.typography.headlineMedium.copy(fontFamily = fm),
59+
headlineSmall = MaterialTheme.typography.headlineSmall.copy(fontFamily = fm),
60+
titleLarge = MaterialTheme.typography.titleLarge.copy(fontFamily = fm),
61+
titleMedium = MaterialTheme.typography.titleMedium.copy(fontFamily = fm),
62+
titleSmall = MaterialTheme.typography.titleSmall.copy(fontFamily = fm),
63+
bodyLarge = MaterialTheme.typography.bodyLarge.copy(fontFamily = fm),
64+
bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontFamily = fm),
65+
bodySmall = MaterialTheme.typography.bodySmall.copy(fontFamily = fm),
66+
labelLarge = MaterialTheme.typography.labelLarge.copy(fontFamily = fm),
67+
labelMedium = MaterialTheme.typography.labelMedium.copy(fontFamily = fm),
68+
labelSmall = MaterialTheme.typography.labelSmall.copy(fontFamily = fm),
69+
)
70+
) {
71+
GradleSettingsView()
72+
}
11373
}
11474
}
11575
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package love.forte.simbot.codegen
2+
3+
import androidx.compose.animation.animateColorAsState
4+
import androidx.compose.animation.core.tween
5+
import androidx.compose.material3.*
6+
import androidx.compose.runtime.*
7+
import androidx.compose.ui.graphics.Color
8+
9+
/**
10+
* 应用上下文数据类,包含全局应用状态
11+
*/
12+
data class AppContext(
13+
val colorMode: ColorMode,
14+
val toggleColorMode: () -> Unit
15+
)
16+
17+
/**
18+
* 用于提供全局应用上下文的 CompositionLocal
19+
*/
20+
val LocalAppContext = staticCompositionLocalOf<AppContext> {
21+
error("LocalAppContext not provided")
22+
}
23+
24+
/**
25+
* 颜色模式枚举
26+
*/
27+
enum class ColorMode {
28+
DARK,
29+
LIGHT;
30+
31+
fun toggle(): ColorMode = when (this) {
32+
DARK -> LIGHT
33+
LIGHT -> DARK
34+
}
35+
}
36+
37+
// 定义基础颜色
38+
val lightColors = lightColorScheme(
39+
primary = Color(0xFF3B7DD8), // 优雅的蓝色
40+
secondary = Color(0xFF4DB6A5), // 平衡的绿松石色
41+
tertiary = Color(0xFFEF9265), // 温和的橙色
42+
background = Color(0xFFF8F8F8), // 温和的白色背景
43+
surface = Color(0xFFFFFFFF), // 纯白色表面
44+
error = Color(0xFFD32F2F), // 标准错误色
45+
onPrimary = Color(0xFFFFFFFF), // 主色上的文本
46+
onSecondary = Color(0xFFFFFFFF), // 次要色上的文本
47+
onTertiary = Color(0xFFFFFFFF), // 第三色上的文本
48+
onBackground = Color(0xFF212121), // 背景上的文本
49+
onSurface = Color(0xFF212121), // 表面上的文本
50+
surfaceVariant = Color(0xFFE6E6E6), // 表面变体
51+
primaryContainer = Color(0xFFD4E3F8), // 主色容器
52+
secondaryContainer = Color(0xFFD4F0EB) // 次要色容器
53+
)
54+
55+
val darkColors = darkColorScheme(
56+
primary = Color(0xFF5B9EE1), // 柔和的蓝色
57+
secondary = Color(0xFF80CBBF), // 淡绿蓝色
58+
tertiary = Color(0xFFEFB196), // 淡橙色
59+
background = Color(0xFF1A1A1A), // 稍微柔和的黑色
60+
surface = Color(0xFF252525), // 柔和的暗色表面
61+
error = Color(0xFFE57373), // 淡红色错误提示
62+
onPrimary = Color(0xFFF5F5F5), // 主色上的文本
63+
onSecondary = Color(0xFF121212), // 次要色上的文本
64+
onTertiary = Color(0xFF121212), // 第三色上的文本
65+
onBackground = Color(0xFFE0E0E0), // 背景上的文本
66+
onSurface = Color(0xFFE0E0E0), // 表面上的文本
67+
surfaceVariant = Color(0xFF3A3A3A), // 表面变体
68+
primaryContainer = Color(0xFF2F4D6F), // 主色容器
69+
secondaryContainer = Color(0xFF396458) // 次要色容器
70+
)
71+
72+
/**
73+
* 创建带动画过渡的颜色方案
74+
*/
75+
@Composable
76+
fun rememberAnimatedColorScheme(colorMode: ColorMode): ColorScheme {
77+
78+
79+
val targetColors = when (colorMode) {
80+
ColorMode.LIGHT -> lightColors
81+
ColorMode.DARK -> darkColors
82+
}
83+
84+
// 为每个颜色添加动画过渡
85+
val animationDuration = 300
86+
val animationSpec = tween<Color>(durationMillis = animationDuration)
87+
88+
val animatedPrimary by animateColorAsState(targetColors.primary, animationSpec, label = "primary")
89+
val animatedSecondary by animateColorAsState(targetColors.secondary, animationSpec, label = "secondary")
90+
val animatedTertiary by animateColorAsState(targetColors.tertiary, animationSpec, label = "tertiary")
91+
val animatedBackground by animateColorAsState(targetColors.background, animationSpec, label = "background")
92+
val animatedSurface by animateColorAsState(targetColors.surface, animationSpec, label = "surface")
93+
val animatedError by animateColorAsState(targetColors.error, animationSpec, label = "error")
94+
val animatedOnPrimary by animateColorAsState(targetColors.onPrimary, animationSpec, label = "onPrimary")
95+
val animatedOnSecondary by animateColorAsState(targetColors.onSecondary, animationSpec, label = "onSecondary")
96+
val animatedOnTertiary by animateColorAsState(targetColors.onTertiary, animationSpec, label = "onTertiary")
97+
val animatedOnBackground by animateColorAsState(targetColors.onBackground, animationSpec, label = "onBackground")
98+
val animatedOnSurface by animateColorAsState(targetColors.onSurface, animationSpec, label = "onSurface")
99+
val animatedSurfaceVariant by animateColorAsState(targetColors.surfaceVariant, animationSpec, label = "surfaceVariant")
100+
val animatedPrimaryContainer by animateColorAsState(targetColors.primaryContainer, animationSpec, label = "primaryContainer")
101+
val animatedSecondaryContainer by animateColorAsState(targetColors.secondaryContainer, animationSpec, label = "secondaryContainer")
102+
103+
return ColorScheme(
104+
primary = animatedPrimary,
105+
onPrimary = animatedOnPrimary,
106+
primaryContainer = animatedPrimaryContainer,
107+
onPrimaryContainer = targetColors.onPrimaryContainer,
108+
inversePrimary = targetColors.inversePrimary,
109+
secondary = animatedSecondary,
110+
onSecondary = animatedOnSecondary,
111+
secondaryContainer = animatedSecondaryContainer,
112+
onSecondaryContainer = targetColors.onSecondaryContainer,
113+
tertiary = animatedTertiary,
114+
onTertiary = animatedOnTertiary,
115+
tertiaryContainer = targetColors.tertiaryContainer,
116+
onTertiaryContainer = targetColors.onTertiaryContainer,
117+
background = animatedBackground,
118+
onBackground = animatedOnBackground,
119+
surface = animatedSurface,
120+
onSurface = animatedOnSurface,
121+
surfaceVariant = animatedSurfaceVariant,
122+
onSurfaceVariant = targetColors.onSurfaceVariant,
123+
surfaceTint = targetColors.surfaceTint,
124+
inverseSurface = targetColors.inverseSurface,
125+
inverseOnSurface = targetColors.inverseOnSurface,
126+
error = animatedError,
127+
onError = targetColors.onError,
128+
errorContainer = targetColors.errorContainer,
129+
onErrorContainer = targetColors.onErrorContainer,
130+
outline = targetColors.outline,
131+
outlineVariant = targetColors.outlineVariant,
132+
scrim = targetColors.scrim,
133+
surfaceBright = targetColors.surfaceBright,
134+
surfaceDim = targetColors.surfaceDim,
135+
surfaceContainer = targetColors.surfaceContainer,
136+
surfaceContainerHigh = targetColors.surfaceContainerHigh,
137+
surfaceContainerHighest = targetColors.surfaceContainerHighest,
138+
surfaceContainerLow = targetColors.surfaceContainerLow,
139+
surfaceContainerLowest = targetColors.surfaceContainerLowest
140+
)
141+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package love.forte.simbot.codegen.components
2+
3+
import androidx.compose.animation.core.animateFloatAsState
4+
import androidx.compose.animation.core.tween
5+
import androidx.compose.foundation.layout.size
6+
import androidx.compose.material.icons.Icons
7+
import androidx.compose.material.icons.filled.DarkMode
8+
import androidx.compose.material.icons.filled.LightMode
9+
import androidx.compose.material3.*
10+
import androidx.compose.runtime.*
11+
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.draw.rotate
13+
import androidx.compose.ui.unit.dp
14+
import love.forte.simbot.codegen.ColorMode
15+
import love.forte.simbot.codegen.LocalAppContext
16+
17+
/**
18+
* 主题切换按钮组件
19+
* 提供光滑的动画过渡和直观的图标切换
20+
*/
21+
@Composable
22+
fun ThemeToggleButton(
23+
modifier: Modifier = Modifier
24+
) {
25+
val appContext = LocalAppContext.current
26+
27+
// 图标和描述根据当前主题模式决定
28+
val (icon, contentDescription) = when (appContext.colorMode) {
29+
ColorMode.LIGHT -> Icons.Default.DarkMode to "切换到暗色主题"
30+
ColorMode.DARK -> Icons.Default.LightMode to "切换到亮色主题"
31+
}
32+
33+
// 旋转动画,增加视觉反馈
34+
val rotationAngle by animateFloatAsState(
35+
targetValue = when (appContext.colorMode) {
36+
ColorMode.LIGHT -> 0f
37+
ColorMode.DARK -> 360f
38+
},
39+
animationSpec = tween(durationMillis = 300),
40+
label = "iconRotation"
41+
)
42+
43+
IconButton(
44+
onClick = appContext.toggleColorMode,
45+
modifier = modifier
46+
) {
47+
Icon(
48+
imageVector = icon,
49+
contentDescription = contentDescription,
50+
modifier = Modifier
51+
.size(24.dp)
52+
.rotate(rotationAngle),
53+
tint = MaterialTheme.colorScheme.onSurface
54+
)
55+
}
56+
}

composeApp/src/wasmJsMain/kotlin/love/forte/simbot/codegen/gen/view/GradleSettingsView.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
2121
import js.date.Date
2222
import love.forte.simbot.codegen.components.GroupCard
2323
import love.forte.simbot.codegen.components.GroupGrid
24+
import love.forte.simbot.codegen.components.ThemeToggleButton
2425
import love.forte.simbot.codegen.components.WindowSize
2526
import love.forte.simbot.codegen.components.rememberWindowSize
2627
import love.forte.simbot.codegen.gen.GradleProjectViewModel
@@ -55,6 +56,9 @@ fun GradleSettingsView(
5556
else -> MaterialTheme.typography.headlineMedium
5657
}
5758
)
59+
},
60+
actions = {
61+
ThemeToggleButton()
5862
}
5963
)
6064
},

0 commit comments

Comments
 (0)