完成组合掷骰功能和 Android 支持
This commit is contained in:
+18
-1
@@ -1,4 +1,7 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.androidKmpLibrary)
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
alias(libs.plugins.composeMultiplatform)
|
||||
alias(libs.plugins.composeCompiler)
|
||||
@@ -7,6 +10,20 @@ plugins {
|
||||
kotlin {
|
||||
jvm()
|
||||
|
||||
android {
|
||||
namespace = "cn.itouc.git.diceroller.shared"
|
||||
compileSdk = 37
|
||||
minSdk = 24
|
||||
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
}
|
||||
|
||||
androidResources {
|
||||
enable = true
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.runtime)
|
||||
@@ -22,4 +39,4 @@ kotlin {
|
||||
implementation(libs.kotlin.test)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +1,229 @@
|
||||
package cn.itouc.git.diceroller
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.safeContentPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
import diceroller.shared.generated.resources.Res
|
||||
import diceroller.shared.generated.resources.compose_multiplatform
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.random.Random
|
||||
|
||||
data class DiceGroup(
|
||||
val count: Int,
|
||||
val sides: Int
|
||||
)
|
||||
|
||||
data class DiceGroupResult(
|
||||
val group: DiceGroup,
|
||||
val points: List<Int>
|
||||
) {
|
||||
val total: Long
|
||||
get() = points.sumOf { it.toLong() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun App() {
|
||||
MaterialTheme {
|
||||
var showContent by remember { mutableStateOf(false) }
|
||||
var randomInt by remember { mutableStateOf(Random.nextInt()) }
|
||||
var sidesInput by remember { mutableStateOf("6") }
|
||||
var countInput by remember { mutableStateOf("1") }
|
||||
|
||||
var groups by remember {
|
||||
mutableStateOf(emptyList<DiceGroup>())
|
||||
}
|
||||
|
||||
var results by remember {
|
||||
mutableStateOf(emptyList<DiceGroupResult>())
|
||||
}
|
||||
|
||||
val diceSides = sidesInput.toIntOrNull()
|
||||
val diceCount = countInput.toIntOrNull()
|
||||
|
||||
val validSides = diceSides != null &&
|
||||
diceSides >= 1 &&
|
||||
diceSides < Int.MAX_VALUE
|
||||
|
||||
val validCount = diceCount != null &&
|
||||
diceCount in 1..1000
|
||||
|
||||
val totalDiceCount = groups.sumOf { it.count }
|
||||
|
||||
val withinLimit = diceCount != null &&
|
||||
diceCount in 1..1000 &&
|
||||
totalDiceCount + diceCount <= 1000
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.primaryContainer)
|
||||
.safeContentPadding()
|
||||
.fillMaxSize(),
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "组合掷骰子",
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = sidesInput,
|
||||
onValueChange = { sidesInput = it },
|
||||
label = { Text("骰子面数") },
|
||||
singleLine = true,
|
||||
isError = !validSides
|
||||
)
|
||||
|
||||
if (!validSides) {
|
||||
Text(
|
||||
text = "面数请输入 1~2147483646 的整数",
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = countInput,
|
||||
onValueChange = { countInput = it },
|
||||
label = { Text("骰子数量") },
|
||||
singleLine = true,
|
||||
isError = !validCount
|
||||
)
|
||||
|
||||
if (!validCount) {
|
||||
Text(
|
||||
text = "数量请输入 1~1000 的整数",
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
} else if (!withinLimit) {
|
||||
Text(
|
||||
text = "添加后将超过总数限制,最多允许 1000 个骰子",
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
enabled = validSides && validCount && withinLimit,
|
||||
onClick = {
|
||||
showContent = !showContent
|
||||
if (showContent) randomInt = Random.nextInt()
|
||||
val sides = diceSides
|
||||
val count = diceCount
|
||||
|
||||
if (
|
||||
sides != null &&
|
||||
sides >= 1 &&
|
||||
sides < Int.MAX_VALUE &&
|
||||
count != null &&
|
||||
count in 1..1000 &&
|
||||
groups.sumOf { it.count } + count <= 1000
|
||||
) {
|
||||
groups = groups + DiceGroup(
|
||||
count = count,
|
||||
sides = sides
|
||||
)
|
||||
|
||||
results = emptyList()
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("Click me!")
|
||||
Text("添加骰子组")
|
||||
}
|
||||
AnimatedVisibility(showContent) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Image(painterResource(Res.drawable.compose_multiplatform), null)
|
||||
Text("a random int: $randomInt")
|
||||
|
||||
Text(
|
||||
text = "当前组合",
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
|
||||
if (groups.isEmpty()) {
|
||||
Text("还没有骰子组,请先添加")
|
||||
} else {
|
||||
groups.forEachIndexed { index, group ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "第 ${index + 1} 组:${group.count}D${group.sides}",
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
TextButton(
|
||||
onClick = {
|
||||
groups = groups.filterIndexed { groupIndex, _ ->
|
||||
groupIndex != index
|
||||
}
|
||||
results = emptyList()
|
||||
}
|
||||
) {
|
||||
Text("删除")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text("共 ${groups.size} 组,$totalDiceCount / 1000 个骰子")
|
||||
|
||||
Button(
|
||||
enabled = groups.isNotEmpty(),
|
||||
onClick = {
|
||||
results = groups.map { group ->
|
||||
DiceGroupResult(
|
||||
group = group,
|
||||
points = List(group.count) {
|
||||
Random.nextInt(1, group.sides + 1)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text("全部掷骰")
|
||||
}
|
||||
|
||||
if (results.isNotEmpty()) {
|
||||
Text(
|
||||
text = "掷骰结果",
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
|
||||
results.forEachIndexed { index, result ->
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "第 ${index + 1} 组:" +
|
||||
"${result.group.count}D${result.group.sides}",
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
|
||||
val pointsText = result.points
|
||||
.take(20)
|
||||
.joinToString(" + ")
|
||||
|
||||
val remainingHint =
|
||||
if (result.points.size > 20) {
|
||||
" + …"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
Text("点数:$pointsText$remainingHint")
|
||||
Text("小计:${result.total}")
|
||||
}
|
||||
}
|
||||
|
||||
val grandTotal = results.sumOf { it.total }
|
||||
|
||||
Text(
|
||||
text = "总和:$grandTotal",
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user