Better components for question dialog

This commit is contained in:
Oliver Rümpelein 2021-08-17 21:50:01 +02:00
parent ada58149f0
commit 8fed21551f
16 changed files with 340 additions and 253 deletions

View file

@ -103,7 +103,7 @@ fun main() = application {
val playerPointMap: MutableMap<Player, Long> = game.players.map { it to 0L }.toMutableStateMap() val playerPointMap: MutableMap<Player, Long> = game.players.map { it to 0L }.toMutableStateMap()
var questionsPlayed by remember { mutableStateOf(0) } var questionsPlayed by remember { mutableStateOf(0) }
val doublePoints by remember { derivedStateOf { questionsPlayed >= game.doubleAfter } } val secondRoundDouble by remember { derivedStateOf { questionsPlayed >= game.doubleAfter } }
val gameEnded by remember { derivedStateOf { questionsPlayed >= game.endGameAfter } } val gameEnded by remember { derivedStateOf { questionsPlayed >= game.endGameAfter } }
if (!gameEnded) { if (!gameEnded) {
@ -123,10 +123,10 @@ fun main() = application {
Column(Modifier.fillMaxWidth(0.8f)) { Column(Modifier.fillMaxWidth(0.8f)) {
QuestionGrid( QuestionGrid(
game, game,
doublePoints, secondRoundDouble,
onResolveQuestion = { onResolveQuestion = {
questionsPlayed++ questionsPlayed++
println("Questions: $questionsPlayed, Double: $doublePoints") println("Questions: $questionsPlayed, Double: $secondRoundDouble")
}, },
onPointsChange = { player, points -> onPointsChange = { player, points ->
playerPointMap[player] = playerPointMap[player]?.plus(points) ?: 0 playerPointMap[player] = playerPointMap[player]?.plus(points) ?: 0

View file

@ -22,7 +22,7 @@ private fun Modifier.setButtonSize(heightFraction: Float) = this.fillMaxWidth(1f
@Suppress("FunctionName") @Suppress("FunctionName")
fun Question( fun Question(
questionData: QuestionData, questionData: QuestionData,
doublePoints: Boolean, secondRoundDouble: Boolean,
players: List<Player>, players: List<Player>,
topic: Topic, topic: Topic,
heightFraction: Float, heightFraction: Float,
@ -62,7 +62,7 @@ fun Question(
) )
) { ) {
Text( Text(
text = "${questionData.actualDisplayPoints(doublePoints)}", text = "${questionData.actualDisplayPoints(secondRoundDouble)}",
color = if (pointsButtonActive) Color.Gray else Color.LightGray color = if (pointsButtonActive) Color.Gray else Color.LightGray
) )
} }
@ -72,7 +72,7 @@ fun Question(
topic = topic, topic = topic,
questionData = questionData, questionData = questionData,
players = players, players = players,
doublePoints = doublePoints, secondRoundDouble = secondRoundDouble,
onResolve = { onResolve = {
questionResolved = true questionResolved = true
questionVisible = false questionVisible = false

View file

@ -9,7 +9,7 @@ import data.Player
@Composable @Composable
fun QuestionGrid( fun QuestionGrid(
game: Game, game: Game,
doublePoints: Boolean, secondRoundDouble: Boolean,
onPointsChange: (player: Player, points: Long) -> Unit, onPointsChange: (player: Player, points: Long) -> Unit,
onResolveQuestion: () -> Unit onResolveQuestion: () -> Unit
) { ) {
@ -21,7 +21,7 @@ fun QuestionGrid(
val maxColumnFraction = 1f / (numberOfColumns - index) val maxColumnFraction = 1f / (numberOfColumns - index)
TopicRow( TopicRow(
topic = topic, topic = topic,
doublePoints = doublePoints, secondRoundDouble = secondRoundDouble,
users = users, users = users,
columnFraction = maxColumnFraction, columnFraction = maxColumnFraction,
onPointsChange = onPointsChange, onPointsChange = onPointsChange,

View file

@ -17,7 +17,7 @@ import data.toColor
@Suppress("FunctionName") @Suppress("FunctionName")
fun TopicRow( fun TopicRow(
topic: Topic, topic: Topic,
doublePoints: Boolean, secondRoundDouble: Boolean,
users: List<Player>, users: List<Player>,
columnFraction: Float, columnFraction: Float,
onPointsChange: (Player, Long) -> Unit, onPointsChange: (Player, Long) -> Unit,
@ -49,7 +49,7 @@ fun TopicRow(
Question( Question(
questionData = question, questionData = question,
topic = topic, topic = topic,
doublePoints = doublePoints, secondRoundDouble = secondRoundDouble,
players = users, players = users,
heightFraction = buttonHeightFraction, heightFraction = buttonHeightFraction,
color = topicColor, color = topicColor,

View file

@ -7,7 +7,6 @@ import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.UndecoratedWindowAlertDialogProvider import androidx.compose.material.UndecoratedWindowAlertDialogProvider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import components.QuestionDialogButtons
import data.Player import data.Player
import data.QuestionData import data.QuestionData
import data.Topic import data.Topic
@ -19,7 +18,7 @@ fun QuestionDialogue(
topic: Topic, topic: Topic,
questionData: QuestionData, questionData: QuestionData,
players: List<Player>, players: List<Player>,
doublePoints: Boolean, secondRoundDouble: Boolean,
onResolve: () -> Unit, onResolve: () -> Unit,
onPointsChange: (Player, Long) -> Unit onPointsChange: (Player, Long) -> Unit
) { ) {
@ -35,7 +34,7 @@ fun QuestionDialogue(
players = players, players = players,
onPointsChange = onPointsChange, onPointsChange = onPointsChange,
onResolve = onResolve, onResolve = onResolve,
doublePoints = doublePoints secondRoundDouble = secondRoundDouble
) )
} }
) )

View file

@ -0,0 +1,74 @@
package components.questiondialog
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import components.questiondialog.assets.HintText
import components.questiondialog.buttons.DismissButton
import components.questiondialog.player.DeferredDoubleQuestionDialogPlayer
import components.questiondialog.player.QuestionDialogPlayer
import data.Player
import data.QuestionData
import data.Topic
import data.toColor
@Suppress("FunctionName")
@Composable
fun QuestionDialogButtons(
topic: Topic,
questionData: QuestionData,
players: List<Player>,
onPointsChange: (Player, Long) -> Unit,
onResolve: () -> Unit,
secondRoundDouble: Boolean
) {
val fontSize = 5.em
Box(
modifier = Modifier.fillMaxHeight().fillMaxWidth()
.border(
border = BorderStroke(150.dp, topic.color.toColor())
)
.padding(150.dp),
contentAlignment = Alignment.Center,
) {
Column(
modifier = Modifier.fillMaxWidth().fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
HintText(
topicName = topic.topic,
points = questionData.actualUsagePoints(secondRoundDouble),
deferredDouble = questionData.isDeferredDouble,
hint = questionData.hint
)
for (player in players) {
if (questionData.isDeferredDouble) {
DeferredDoubleQuestionDialogPlayer(
player = player,
fontSize = fontSize,
onPointsChange = onPointsChange,
questionPoints = questionData.actualUsagePoints(secondRoundDouble).toLong(),
onQuestionAnswered = onResolve
)
} else {
QuestionDialogPlayer(
player = player,
fontSize = fontSize,
onPointsChange = onPointsChange,
questionPoints = questionData.actualUsagePoints(secondRoundDouble).toLong(),
onQuestionAnswered = onResolve
)
}
Spacer(Modifier.height(20.dp))
}
DismissButton(onResolve, fontSize)
}
}
}

View file

@ -1,74 +0,0 @@
package components.questiondialog
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import components.common.DisabledButton
import data.Player
import data.QuestionData
@Suppress("FunctionName")
@Composable
fun QuestionDialogPlayer(
player: Player,
fontSize: TextUnit,
questionData: QuestionData,
onPointsChange: (Player, Long) -> Unit,
questionPoints: Long
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
var hadSuccess by remember { mutableStateOf(false) }
var hadFail by remember { mutableStateOf(false) }
Text(
text = player.name,
modifier = Modifier.fillMaxWidth(0.6f),
fontSize = fontSize
)
Spacer(modifier = Modifier.width(5.dp))
if (hadFail || (hadSuccess && !questionData.isDeferredDouble)) {
DisabledButton(maxWidthFraction = 1f, fontSize = fontSize)
} else {
if (hadSuccess && questionData.isDeferredDouble) {
DisabledButton(0.7f, fontSize)
} else {
Button(
modifier = Modifier.fillMaxWidth(0.7f),
onClick = {
hadFail = true
onPointsChange(
player,
-questionPoints
)
},
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red)
) {
Text("Wrong", color = Color.White, fontSize = fontSize)
}
}
Spacer(modifier = Modifier.width(5.dp))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
hadSuccess = true
onPointsChange(player, questionPoints)
},
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Green)
) {
Text("OK", color = Color.White, fontSize = fontSize)
}
}
}
}

View file

@ -0,0 +1,36 @@
package components.questiondialog.assets
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.em
@Composable
@Suppress("FunctionName")
fun HintText(
topicName: String,
points: UInt,
hint: String,
deferredDouble: Boolean = false,
doubleJeopardy: Boolean = false
) {
Text(
text = """"$topicName" for $points Pts.""",
fontSize = 2.em
)
if (deferredDouble) {
Text(
text = """Deferred Double!""",
fontSize = 3.em
)
}
if (doubleJeopardy) {
Text(
text = """Double Jeopardy!""",
fontSize = 3.em
)
}
Text(
text = hint,
fontSize = 5.em
)
}

View file

@ -0,0 +1,22 @@
package components.questiondialog.buttons
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
@Suppress("FunctionName")
@Composable
fun BadAnswerButton(onClick: () -> Unit, fontSize: TextUnit) {
Button(
modifier = Modifier.fillMaxWidth(0.7f),
onClick = onClick,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red)
) {
Text("Wrong", color = Color.White, fontSize = fontSize)
}
}

View file

@ -0,0 +1,13 @@
package components.questiondialog.buttons
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Suppress("FunctionName")
@Composable
fun ButtonSpacer() {
Spacer(modifier = Modifier.width(5.dp))
}

View file

@ -0,0 +1,27 @@
package components.questiondialog.buttons
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
@Suppress("FunctionName")
@Composable
fun DismissButton(onResolve: () -> Unit, fontSize: TextUnit) {
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Button(
onClick = {
onResolve()
}
) {
Text("Dismiss Question", color = Color.LightGray, fontSize = fontSize)
}
}
}

View file

@ -0,0 +1,22 @@
package components.questiondialog.buttons
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.TextUnit
@Suppress("FunctionName")
@Composable
fun GoodAnswerButton(onClick: () -> Unit, fontSize: TextUnit) {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = onClick,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Green)
) {
Text("OK", color = Color.White, fontSize = fontSize)
}
}

View file

@ -1,83 +0,0 @@
package components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import components.questiondialog.QuestionDialogPlayer
import data.Player
import data.QuestionData
import data.Topic
import data.toColor
@Suppress("FunctionName")
@Composable
fun QuestionDialogButtons(
topic: Topic,
questionData: QuestionData,
players: List<Player>,
onPointsChange: (Player, Long) -> Unit,
onResolve: () -> Unit,
doublePoints: Boolean
) {
val fontSize = 5.em
Box(
modifier = Modifier.fillMaxHeight().fillMaxWidth()
.border(
border = BorderStroke(150.dp, topic.color.toColor())
)
.padding(150.dp),
contentAlignment = Alignment.Center,
) {
Column(
modifier = Modifier.fillMaxWidth().fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
Text(
text = """"${topic.topic}" for ${questionData.actualUsagePoints(doublePoints)} Pts.""",
fontSize = 2.em
)
if (questionData.isDeferredDouble) {
Text(
text = """Deferred Double!""",
fontSize = 3.em
)
}
Text(
text = questionData.hint,
fontSize = 5.em
)
for (player in players) {
QuestionDialogPlayer(
player = player,
fontSize = fontSize,
questionData = questionData,
onPointsChange = onPointsChange,
questionPoints = questionData.actualUsagePoints(doublePoints).toLong()
)
Spacer(Modifier.height(20.dp))
}
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Button(
onClick = {
onResolve()
}
) {
Text("Dismiss", color = Color.LightGray, fontSize = fontSize)
}
}
}
}
}

View file

@ -1,83 +0,0 @@
package components.questiondialog.buttons
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.em
import components.questiondialog.QuestionDialogPlayer
import data.Player
import data.QuestionData
import data.Topic
import data.toColor
@Suppress("FunctionName")
@Composable
fun QuestionDialogDeferredButtons(
topic: Topic,
questionData: QuestionData,
players: List<Player>,
onPointsChange: (Player, Long) -> Unit,
onResolve: () -> Unit,
doublePoints: Boolean
) {
val fontSize = 5.em
Box(
modifier = Modifier.fillMaxHeight().fillMaxWidth()
.border(
border = BorderStroke(150.dp, topic.color.toColor())
)
.padding(150.dp),
contentAlignment = Alignment.Center,
) {
Column(
modifier = Modifier.fillMaxWidth().fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
) {
Text(
text = """"${topic.topic}" for ${questionData.actualUsagePoints(doublePoints)} Pts.""",
fontSize = 2.em
)
if (questionData.isDeferredDouble) {
Text(
text = """Deferred Double!""",
fontSize = 3.em
)
}
Text(
text = questionData.hint,
fontSize = 5.em
)
for (player in players) {
QuestionDialogPlayer(
player = player,
fontSize = fontSize,
questionData = questionData,
onPointsChange = onPointsChange,
questionPoints = questionData.actualUsagePoints(doublePoints).toLong()
)
Spacer(Modifier.height(20.dp))
}
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Button(
onClick = {
onResolve()
}
) {
Text("Dismiss", color = Color.LightGray, fontSize = fontSize)
}
}
}
}
}

View file

@ -0,0 +1,75 @@
package components.questiondialog.player
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.TextUnit
import components.common.DisabledButton
import components.questiondialog.buttons.BadAnswerButton
import components.questiondialog.buttons.ButtonSpacer
import components.questiondialog.buttons.GoodAnswerButton
import data.Player
@Suppress("FunctionName")
@Composable
fun DeferredDoubleQuestionDialogPlayer(
player: Player,
fontSize: TextUnit,
onPointsChange: (Player, Long) -> Unit,
onQuestionAnswered: () -> Unit,
questionPoints: Long
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
var deferredGuess by remember { mutableStateOf(false) }
var hadFail by remember { mutableStateOf(false) }
Text(
text = player.name,
modifier = Modifier.fillMaxWidth(0.6f),
fontSize = fontSize
)
ButtonSpacer()
if (hadFail) {
DisabledButton(maxWidthFraction = 1f, fontSize = fontSize)
} else {
if (deferredGuess) {
DisabledButton(0.7f, fontSize)
} else {
BadAnswerButton(
fontSize = fontSize,
onClick = {
hadFail = true
onPointsChange(
player,
-questionPoints
)
}
)
}
ButtonSpacer()
if (!deferredGuess) {
GoodAnswerButton(
fontSize = fontSize,
onClick = {
deferredGuess = true
onPointsChange(player, questionPoints)
}
)
} else {
GoodAnswerButton(
fontSize = fontSize,
onClick = {
onPointsChange(player, questionPoints)
onQuestionAnswered()
}
)
}
}
}
}

View file

@ -0,0 +1,59 @@
package components.questiondialog.player
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.TextUnit
import components.common.DisabledButton
import components.questiondialog.buttons.BadAnswerButton
import components.questiondialog.buttons.ButtonSpacer
import components.questiondialog.buttons.GoodAnswerButton
import data.Player
@Suppress("FunctionName")
@Composable
fun QuestionDialogPlayer(
player: Player,
fontSize: TextUnit,
onPointsChange: (Player, Long) -> Unit,
questionPoints: Long,
onQuestionAnswered: () -> Unit
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
var hadFail by remember { mutableStateOf(false) }
Text(
text = player.name,
modifier = Modifier.fillMaxWidth(0.6f),
fontSize = fontSize
)
ButtonSpacer()
if (hadFail) {
DisabledButton(maxWidthFraction = 1f, fontSize = fontSize)
} else {
BadAnswerButton(
fontSize = fontSize,
onClick = {
hadFail = true
onPointsChange(
player,
-questionPoints
)
}
)
ButtonSpacer()
GoodAnswerButton(
fontSize = fontSize,
onClick = {
onPointsChange(player, questionPoints)
onQuestionAnswered()
}
)
}
}
}