Skip to content

Commit a4f13f8

Browse files
committed
移动端友好
1 parent 03aa431 commit a4f13f8

File tree

1 file changed

+152
-41
lines changed

1 file changed

+152
-41
lines changed

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

Lines changed: 152 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,12 @@ import androidx.compose.material.icons.filled.Done
1717
import androidx.compose.material.icons.filled.Download
1818
import androidx.compose.material.icons.outlined.Search
1919
import androidx.compose.material3.*
20-
import androidx.compose.material3.HorizontalDivider
2120
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
2221
import androidx.compose.runtime.*
2322
import androidx.compose.ui.Alignment
2423
import androidx.compose.ui.Modifier
2524
import androidx.compose.ui.draw.shadow
2625
import androidx.compose.ui.graphics.Color
27-
import androidx.compose.ui.platform.LocalFocusManager
2826
import androidx.compose.ui.text.ExperimentalTextApi
2927
import androidx.compose.ui.text.buildAnnotatedString
3028
import androidx.compose.ui.text.font.FontWeight
@@ -76,6 +74,8 @@ fun GradleSettingsView(
7674
projectViewModel: GradleProjectViewModel = viewModel { GradleProjectViewModel() },
7775
loadingCounter: LoadingCounter = remember { LoadingCounter() },
7876
) {
77+
val windowSize = rememberWindowSize()
78+
7979
Scaffold(
8080
topBar = {
8181
CenterAlignedTopAppBar(
@@ -87,7 +87,10 @@ fun GradleSettingsView(
8787
Text(
8888
"Simbot Codegen",
8989
fontWeight = FontWeight.Bold,
90-
style = MaterialTheme.typography.headlineMedium
90+
style = when (windowSize) {
91+
WindowSize.Mobile -> MaterialTheme.typography.headlineSmall
92+
else -> MaterialTheme.typography.headlineMedium
93+
}
9194
)
9295
}
9396
)
@@ -101,9 +104,9 @@ fun GradleSettingsView(
101104
.padding(innerPaddings)
102105
.padding(top = 8.dp, bottom = 8.dp)
103106
.verticalScroll(scrollState),
104-
// .onClick {
105-
// focusManager.clearFocus()
106-
// },
107+
// .onClick {
108+
// focusManager.clearFocus()
109+
// },
107110
contentAlignment = Alignment.TopCenter,
108111
) {
109112
SettingViewContent(projectViewModel, loadingCounter)
@@ -118,27 +121,61 @@ private fun SettingViewContent(
118121
project: GradleProjectViewModel,
119122
loadingCounter: LoadingCounter,
120123
) {
124+
val windowSize = rememberWindowSize()
125+
121126
Box(
122-
modifier = Modifier.fillMaxWidth(.45f)
127+
modifier = Modifier.fillMaxWidth(
128+
when (windowSize) {
129+
WindowSize.Mobile -> 0.95f
130+
WindowSize.Tablet -> 0.75f
131+
WindowSize.Desktop -> 0.45f
132+
}
133+
)
123134
) {
124-
SettingsForm(project, loadingCounter)
135+
SettingsForm(project, loadingCounter, windowSize)
125136
}
126137
}
127138

128139
@Composable
129-
private fun SettingsForm(project: GradleProjectViewModel, loadingCounter: LoadingCounter) {
140+
private fun SettingsForm(
141+
project: GradleProjectViewModel,
142+
loadingCounter: LoadingCounter,
143+
windowSize: WindowSize
144+
) {
130145
Column(
131146
modifier = Modifier
132147
.focusGroup()
133-
.padding(16.dp)
148+
.padding(
149+
// 移动端使用更小的内边距
150+
when (windowSize) {
151+
WindowSize.Mobile -> 8.dp
152+
else -> 16.dp
153+
}
154+
155+
)
134156
.border(
135157
width = 1.dp,
136158
color = MaterialTheme.colorScheme.outlineVariant,
137159
shape = RoundedCornerShape(16.dp)
138160
)
139-
.padding(24.dp),
161+
.padding(
162+
// 移动端使用更小的内边距
163+
when (windowSize) {
164+
WindowSize.Mobile -> 16.dp
165+
else -> 24.dp
166+
}
167+
168+
),
140169
horizontalAlignment = Alignment.Start,
141-
verticalArrangement = Arrangement.spacedBy(20.dp, Alignment.Top),
170+
verticalArrangement = Arrangement.spacedBy(
171+
// 移动端使用更小的间距
172+
when (windowSize) {
173+
WindowSize.Mobile -> 12.dp
174+
else -> 20.dp
175+
},
176+
Alignment.Top
177+
178+
),
142179
)
143180
{
144181
Text(
@@ -155,23 +192,23 @@ private fun SettingsForm(project: GradleProjectViewModel, loadingCounter: Loadin
155192
SimbotVersion(project, loadingCounter)
156193
GradleVersion(project)
157194
WithSpring(project)
158-
ComponentSelection(project, loadingCounter)
195+
ComponentSelection(project, loadingCounter, windowSize)
159196

160197
Spacer(modifier = Modifier.height(8.dp))
161198

162199
// Do download
163-
DoDownload(project, loadingCounter)
164-
200+
DoDownload(project, loadingCounter, windowSize)
201+
165202
Spacer(modifier = Modifier.height(24.dp))
166-
203+
167204
// Footer at the bottom of the content
168205
HorizontalDivider(
169206
thickness = 1.dp,
170207
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)
171208
)
172209

173210
Spacer(modifier = Modifier.height(16.dp))
174-
211+
175212
Row(
176213
modifier = Modifier.fillMaxWidth(),
177214
horizontalArrangement = Arrangement.Center,
@@ -184,7 +221,7 @@ private fun SettingsForm(project: GradleProjectViewModel, loadingCounter: Loadin
184221
withLink(text = "Simple Robot", url = "https://github.com/simple-robot")
185222
append(" All rights reserved.")
186223
}
187-
224+
188225
Text(
189226
text = textWithLink,
190227
style = MaterialTheme.typography.bodySmall,
@@ -218,7 +255,7 @@ private fun ProjectName(project: GradleProjectViewModel) {
218255
Text("建议仅包含大小写英文、数字和下划线,不以数字为开头,且长度不可大于60。")
219256
AnimatedVisibility(isDanger) {
220257
Text(
221-
"项目名称不可为空!",
258+
"项目名称不可为空!",
222259
fontWeight = FontWeight.Bold,
223260
color = MaterialTheme.colorScheme.error
224261
)
@@ -365,7 +402,7 @@ private fun SimbotVersion(
365402
label = "simbot版本",
366403
enabled = !isLoading,
367404
trailingIcon = {
368-
AnimatedVisibility(isLoading) {
405+
AnimatedVisibility(isLoading) {
369406
SearchingIcon()
370407
}
371408
},
@@ -399,7 +436,7 @@ private fun GradleVersion(project: GradleProjectViewModel) {
399436
isError = isDanger,
400437
singleLine = true,
401438
supportingText = {
402-
Column {
439+
Column {
403440
Text(
404441
"输入一个要使用的Gradle版本"
405442
)
@@ -470,7 +507,11 @@ private fun WithSpring(project: GradleProjectViewModel) {
470507

471508
@OptIn(ExperimentalLayoutApi::class)
472509
@Composable
473-
private fun ComponentSelection(project: GradleProjectViewModel, loadingCounter: LoadingCounter) {
510+
private fun ComponentSelection(
511+
project: GradleProjectViewModel,
512+
loadingCounter: LoadingCounter,
513+
windowSize: WindowSize
514+
) {
474515
val components = project.components
475516

476517
Column(
@@ -510,9 +551,25 @@ private fun ComponentSelection(project: GradleProjectViewModel, loadingCounter:
510551
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
511552
) {
512553
FlowRow(
513-
modifier = Modifier.padding(16.dp),
514-
horizontalArrangement = Arrangement.spacedBy(12.dp),
515-
verticalArrangement = Arrangement.spacedBy(12.dp),
554+
modifier = Modifier.padding(
555+
// 移动设备使用更小的内边距
556+
when (windowSize) {
557+
WindowSize.Mobile -> 8.dp
558+
else -> 16.dp
559+
}
560+
),
561+
horizontalArrangement = Arrangement.spacedBy(
562+
when (windowSize) {
563+
WindowSize.Mobile -> 8.dp
564+
else -> 12.dp
565+
}
566+
),
567+
verticalArrangement = Arrangement.spacedBy(
568+
when (windowSize) {
569+
WindowSize.Mobile -> 8.dp
570+
else -> 12.dp
571+
}
572+
),
516573
) {
517574
SimbotComponent.entries.forEach { simbotComponent ->
518575
val isSelected = components.any { it.component == simbotComponent }
@@ -617,12 +674,12 @@ private fun ComponentSelection(project: GradleProjectViewModel, loadingCounter:
617674
val component = componentWithVersion.component
618675
val version = componentWithVersion.version
619676

620-
var loadingVersion by remember(component) { mutableStateOf(false) }
677+
var loadingVersion by remember(component) { mutableStateOf(false) }
621678

622-
val versionDisplay = when (version) {
623-
ComponentVersion.UNKNOWN -> ""
624-
is ComponentVersion.Value -> version.value
625-
}
679+
val versionDisplay = when (version) {
680+
ComponentVersion.UNKNOWN -> ""
681+
is ComponentVersion.Value -> version.value
682+
}
626683

627684
if (version is ComponentVersion.UNKNOWN) {
628685
LaunchedEffect(component) {
@@ -631,7 +688,8 @@ private fun ComponentSelection(project: GradleProjectViewModel, loadingCounter:
631688
try {
632689
withTimeout(5.seconds) {
633690
val latest = fetchLatest(component.owner, component.repo)
634-
componentWithVersion.version = ComponentVersion.Value(latest.tagName.removePrefix("v"))
691+
componentWithVersion.version =
692+
ComponentVersion.Value(latest.tagName.removePrefix("v"))
635693
}
636694
} catch (e: Throwable) {
637695
e.printStackTrace()
@@ -702,7 +760,8 @@ private fun ComponentSelection(project: GradleProjectViewModel, loadingCounter:
702760
@Composable
703761
private fun DoDownload(
704762
project: GradleProjectViewModel,
705-
loadingCounter: LoadingCounter
763+
loadingCounter: LoadingCounter,
764+
windowSize: WindowSize,
706765
) {
707766
val scope = rememberCoroutineScope()
708767
val interactionSource = remember { MutableInteractionSource() }
@@ -723,7 +782,14 @@ private fun DoDownload(
723782
},
724783
modifier = Modifier
725784
.fillMaxWidth()
726-
.height(56.dp).shadow(
785+
.height(
786+
// 移动设备使用更大的高度以便于触摸
787+
when (windowSize) {
788+
WindowSize.Mobile -> 64.dp
789+
else -> 56.dp
790+
}
791+
)
792+
.shadow(
727793
elevation = if (isPressed) 0.dp else 4.dp,
728794
shape = RoundedCornerShape(12.dp),
729795
spotColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f)
@@ -841,9 +907,10 @@ private fun EnhancedTextField(
841907
trailingIcon: @Composable (() -> Unit)? = null,
842908
leadingIcon: @Composable (() -> Unit)? = null,
843909
) {
910+
val windowSize = rememberWindowSize()
844911
val interactionSource = remember { MutableInteractionSource() }
845912
val isFocused by interactionSource.collectIsFocusedAsState()
846-
913+
847914
val borderColor by animateColorAsState(
848915
targetValue = when {
849916
isError -> MaterialTheme.colorScheme.error
@@ -853,16 +920,16 @@ private fun EnhancedTextField(
853920
animationSpec = tween(durationMillis = 200),
854921
label = "边框颜色动画"
855922
)
856-
923+
857924
val backgroundColor by animateColorAsState(
858925
targetValue = when {
859-
isFocused -> MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
926+
isFocused -> MaterialTheme.colorScheme.surfaceVariant // .copy(alpha = 0.3f)
860927
else -> MaterialTheme.colorScheme.surface
861928
},
862929
animationSpec = tween(durationMillis = 200),
863930
label = "背景颜色动画"
864931
)
865-
932+
866933
OutlinedTextField(
867934
value = value,
868935
onValueChange = onValueChange,
@@ -874,11 +941,16 @@ private fun EnhancedTextField(
874941
stiffness = Spring.StiffnessLow
875942
)
876943
),
877-
label = {
944+
label = {
878945
Text(
879946
text = label,
880-
fontWeight = if (isFocused) FontWeight.Medium else FontWeight.Normal
881-
)
947+
fontWeight = if (isFocused) FontWeight.Medium else FontWeight.Normal,
948+
// 在移动设备上使用更小的字体
949+
fontSize = when (windowSize) {
950+
WindowSize.Mobile -> 14.sp
951+
else -> 16.sp
952+
}
953+
)
882954
},
883955
placeholder = placeholder?.let { { Text(it) } },
884956
supportingText = supportingText,
@@ -888,7 +960,13 @@ private fun EnhancedTextField(
888960
interactionSource = interactionSource,
889961
trailingIcon = trailingIcon,
890962
leadingIcon = leadingIcon,
891-
shape = RoundedCornerShape(12.dp),
963+
shape = RoundedCornerShape(
964+
// 在移动设备上使用更小的圆角
965+
when (windowSize) {
966+
WindowSize.Mobile -> 8.dp
967+
else -> 12.dp
968+
}
969+
),
892970
colors = OutlinedTextFieldDefaults.colors(
893971
focusedBorderColor = borderColor,
894972
unfocusedBorderColor = borderColor.copy(alpha = 0.7f),
@@ -905,4 +983,37 @@ private fun EnhancedTextField(
905983
unfocusedTextColor = MaterialTheme.colorScheme.onSurface,
906984
),
907985
)
986+
}
987+
988+
@Composable
989+
fun rememberWindowSize(): WindowSize {
990+
var windowSize by remember { mutableStateOf(WindowSize.Desktop) }
991+
992+
DisposableEffect(Unit) {
993+
val resizeListener: (JsAny?) -> Unit = {
994+
val width = window.innerWidth
995+
windowSize = when {
996+
width < 600 -> WindowSize.Mobile
997+
width < 840 -> WindowSize.Tablet
998+
else -> WindowSize.Desktop
999+
}
1000+
}
1001+
1002+
// 初始化窗口大小
1003+
resizeListener(null)
1004+
1005+
// 添加窗口调整大小的监听器
1006+
window.addEventListener("resize", resizeListener)
1007+
1008+
// 清理监听器
1009+
onDispose {
1010+
window.removeEventListener("resize", resizeListener)
1011+
}
1012+
}
1013+
1014+
return windowSize
1015+
}
1016+
1017+
enum class WindowSize {
1018+
Mobile, Tablet, Desktop
9081019
}

0 commit comments

Comments
 (0)