Style keyboard. Add Counter previerw.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-01-20 11:33:05 +01:00
parent 57bb4deebe
commit eac916d8ec
4 changed files with 263 additions and 151 deletions

View File

@@ -6,11 +6,15 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Surface
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.tooling.preview.Preview
import me.zobrist.tichucounter.data.Round
import me.zobrist.tichucounter.ui.AppTheme
@Composable
fun Counter(viewModel: CounterViewModel) {
fun Counter(viewModel: ICounterViewModel = PreviewViewModel()) {
var orientation by remember { mutableStateOf(Configuration.ORIENTATION_PORTRAIT) }
orientation = LocalConfiguration.current.orientation
@@ -25,7 +29,7 @@ fun Counter(viewModel: CounterViewModel) {
}
@Composable
fun Landscape(viewModel: CounterViewModel) {
fun Landscape(viewModel: ICounterViewModel) {
Row {
Column(Modifier.weight(1f)) {
TeamNamesView(
@@ -65,7 +69,7 @@ fun Landscape(viewModel: CounterViewModel) {
}
@Composable
fun Portrait(viewModel: CounterViewModel) {
fun Portrait(viewModel: ICounterViewModel) {
Column {
TeamNamesView(
@@ -98,4 +102,71 @@ fun Portrait(viewModel: CounterViewModel) {
{ viewModel.negateClicked() }
) { viewModel.submitClicked() }
}
}
@Preview(name = "Light Mode")
@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
@Composable
fun CounterViewPreview() {
AppTheme {
Counter()
}
}
internal class PreviewViewModel: ICounterViewModel {
override var roundScoreList: List<Round> = listOf(Round(1, 10, 90), Round(1,50,50), Round(1,70,30))
override var totalScoreA: Int = 350
override var totalScoreB: Int = 750
override var teamNameA: String = "Team A"
override var teamNameB: String = "Team B"
override var currentScoreA: String = ""
override var currentScoreB: String = "45"
override var enableSubmit: Boolean = false
override var isAFocused: Boolean = false
override var isBFocused: Boolean = false
override var requestFocusA: FocusRequester = FocusRequester()
override var activeValue: String = currentScoreA
override var inactiveValue: String = currentScoreB
override fun giveFocusToAIfNone() {
}
override fun updateOtherScore() {
}
override fun isValidTichuRound(): Boolean {
return true
}
override fun updateSubmitButton() {
}
override fun submitClicked() {
}
override fun digitClicked(digit: String) {
}
override fun negateClicked() {
}
override fun addSub100Clicked(toAdd: Int) {
}
override fun deleteClicked() {
}
override fun updateNameA(value: String) {
}
override fun updateNameB(value: String) {
}
override fun updateFocusStateA(state: Boolean) {
}
override fun updateFocusStateB(state: Boolean) {
}
}

View File

@@ -15,45 +15,67 @@ import me.zobrist.tichucounter.domain.Tichu
import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject
interface ICounterViewModel {
var roundScoreList: List<Round>
var totalScoreA: Int
var totalScoreB: Int
var teamNameA: String
var teamNameB: String
var currentScoreA: String
var currentScoreB: String
var enableSubmit: Boolean
var isAFocused: Boolean
var isBFocused: Boolean
var requestFocusA: FocusRequester
var activeValue: String
var inactiveValue: String
fun giveFocusToAIfNone()
fun updateOtherScore()
fun isValidTichuRound(): Boolean
fun updateSubmitButton()
fun submitClicked()
fun digitClicked(digit: String)
fun negateClicked()
fun addSub100Clicked(toAdd: Int)
fun deleteClicked()
fun updateNameA(value: String)
fun updateNameB(value: String)
fun updateFocusStateA(state: Boolean)
fun updateFocusStateB(state: Boolean)
}
@HiltViewModel
class CounterViewModel @Inject constructor(
private val gameRepository: GameRepository,
private val roundDao: RoundDao,
private val gameDao: GameDao
) :
ViewModel() {
ViewModel(), ICounterViewModel {
var roundScoreList by mutableStateOf(emptyList<Round>())
override var roundScoreList by mutableStateOf(emptyList<Round>())
var totalScoreA by mutableStateOf(0)
private set
override var totalScoreA by mutableStateOf(0)
var totalScoreB by mutableStateOf(0)
private set
override var totalScoreB by mutableStateOf(0)
var teamNameA by mutableStateOf("")
private set
override var teamNameA by mutableStateOf("")
var teamNameB by mutableStateOf("")
private set
override var teamNameB by mutableStateOf("")
var currentScoreA by mutableStateOf("")
private set
override var currentScoreA by mutableStateOf("")
var currentScoreB by mutableStateOf("")
private set
override var currentScoreB by mutableStateOf("")
var enableSubmit by mutableStateOf(false)
private set
override var enableSubmit by mutableStateOf(false)
var isAFocused by mutableStateOf(false)
override var isAFocused by mutableStateOf(false)
var isBFocused by mutableStateOf(false)
override var isBFocused by mutableStateOf(false)
var requestFocusA by mutableStateOf(FocusRequester())
private set
override var requestFocusA by mutableStateOf(FocusRequester())
private var activeValue: String
override var activeValue: String
get() {
return if (isBFocused) {
currentScoreB
@@ -69,7 +91,7 @@ class CounterViewModel @Inject constructor(
}
}
private var inactiveValue: String
override var inactiveValue: String
get() {
return if (isAFocused) {
currentScoreB
@@ -109,13 +131,13 @@ class CounterViewModel @Inject constructor(
}
}
private fun giveFocusToAIfNone() {
override fun giveFocusToAIfNone() {
if (!isAFocused && !isBFocused) {
requestFocusA.requestFocus()
}
}
private fun updateOtherScore() {
override fun updateOtherScore() {
inactiveValue = try {
val tichu = Tichu()
val myScore = activeValue.toInt()
@@ -130,7 +152,7 @@ class CounterViewModel @Inject constructor(
}
}
private fun isValidTichuRound(): Boolean {
override fun isValidTichuRound(): Boolean {
return try {
val tichu = Tichu()
tichu.isValidRound(currentScoreA.toInt(), currentScoreB.toInt())
@@ -139,11 +161,11 @@ class CounterViewModel @Inject constructor(
}
}
private fun updateSubmitButton() {
override fun updateSubmitButton() {
enableSubmit = isValidTichuRound()
}
fun submitClicked() {
override fun submitClicked() {
viewModelScope.launch {
gameRepository.addRoundToActiveGame(currentScoreA.toInt(), currentScoreB.toInt())
}
@@ -152,7 +174,7 @@ class CounterViewModel @Inject constructor(
enableSubmit = false
}
fun digitClicked(digit: String) {
override fun digitClicked(digit: String) {
giveFocusToAIfNone()
activeValue += digit
@@ -160,7 +182,7 @@ class CounterViewModel @Inject constructor(
updateSubmitButton()
}
fun negateClicked() {
override fun negateClicked() {
giveFocusToAIfNone()
activeValue = if (activeValue.contains("-")) {
@@ -172,7 +194,7 @@ class CounterViewModel @Inject constructor(
updateSubmitButton()
}
fun addSub100Clicked(toAdd: Int) {
override fun addSub100Clicked(toAdd: Int) {
giveFocusToAIfNone()
activeValue = try {
@@ -188,14 +210,15 @@ class CounterViewModel @Inject constructor(
updateSubmitButton()
}
fun deleteClicked() {
override fun deleteClicked() {
if (activeValue != "") {
activeValue = activeValue.dropLast(1)
}
updateOtherScore()
updateSubmitButton()
}
fun updateNameA(value: String) {
override fun updateNameA(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameA = value
@@ -203,7 +226,7 @@ class CounterViewModel @Inject constructor(
}
}
fun updateNameB(value: String) {
override fun updateNameB(value: String) {
viewModelScope.launch {
val game = gameRepository.activeGame
game.nameB = value
@@ -211,11 +234,11 @@ class CounterViewModel @Inject constructor(
}
}
fun updateFocusStateA(state: Boolean) {
override fun updateFocusStateA(state: Boolean) {
isAFocused = state
}
fun updateFocusStateB(state: Boolean) {
override fun updateFocusStateB(state: Boolean) {
isBFocused = state
}
}

View File

@@ -15,21 +15,24 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.helper.widget.MotionPlaceholder
import me.zobrist.tichucounter.R
import me.zobrist.tichucounter.ui.AppTheme
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun KeyboardView(
scoreA: String,
scoreB: String,
requestFocusA: FocusRequester,
requestFocus: FocusRequester,
enableSubmit: Boolean,
updateFocusStateA: (Boolean) -> Unit,
updateFocusStateB: (Boolean) -> Unit,
@@ -44,139 +47,156 @@ fun KeyboardView(
Column {
Row {
Column(Modifier.weight(1f)) {
CenteredTextField(
scoreA,
keyboardController,
requestFocusA
) {
updateFocusStateA(it)
}
"0",
Modifier
.focusRequester(requestFocus)
.onFocusChanged {
keyboardController?.hide()
updateFocusStateA(it.isFocused)
}
)
}
Column(Modifier.weight(1f)) {
CenteredTextField(
scoreB,
keyboardController,
null
) {
updateFocusStateB(it)
"0",
Modifier
.onFocusChanged {
keyboardController?.hide()
updateFocusStateB(it.isFocused)
}
)
}
}
Row {
Column(Modifier.weight(1f)) {
KeyboardTextButton("1") {
digitClicked("1")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("2") {
digitClicked("2")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("3") {
digitClicked("3")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("+100") {
addSub100Clicked(100)
}
}
}
Row {
Column(Modifier.weight(1f)) {
KeyboardTextButton("4") {
digitClicked("4")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("5") {
digitClicked("5")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("6") {
digitClicked("6")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("-100") {
addSub100Clicked(-100)
}
}
}
Row {
TextButton(
onClick = { digitClicked("1") },
modifier = Modifier.weight(1F)
) { Text("1") }
TextButton(
onClick = { digitClicked("2") },
modifier = Modifier.weight(1F)
) { Text("2") }
TextButton(
onClick = { digitClicked("3") },
modifier = Modifier.weight(1F)
) { Text("3") }
TextButton(
onClick = { addSub100Clicked(100) },
modifier = Modifier.weight(1F)
) { Text("+100") }
}
Row {
TextButton(
onClick = { digitClicked("4") },
modifier = Modifier.weight(1F)
) { Text("4") }
TextButton(
onClick = { digitClicked("5") },
modifier = Modifier.weight(1F)
) { Text("5") }
TextButton(
onClick = { digitClicked("6") },
modifier = Modifier.weight(1F)
) { Text("6") }
TextButton(
onClick = { addSub100Clicked(-100) },
modifier = Modifier.weight(1F)
) { Text("-100") }
}
Row {
TextButton(
onClick = { digitClicked("7") },
modifier = Modifier.weight(1F)
) { Text("7") }
TextButton(
onClick = { digitClicked("8") },
modifier = Modifier.weight(1F)
) { Text("8") }
TextButton(
onClick = { digitClicked("9") },
modifier = Modifier.weight(1F)
) { Text("9") }
IconButton(
onClick = { deleteClicked() },
modifier = Modifier.weight(1F)
) {
Icon(
Icons.Outlined.Backspace,
stringResource(R.string.back),
tint = MaterialTheme.colorScheme.primary
)
Column(Modifier.weight(1f)) {
KeyboardTextButton("7") {
digitClicked("7")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("8") {
digitClicked("8")
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("9") {
digitClicked("9")
}
}
Column(Modifier.weight(1f)) {
KeyboardIconButton(Icons.Outlined.Backspace) {
deleteClicked()
}
}
}
Row {
TextButton(
onClick = { negateClicked() },
modifier = Modifier.weight(1F)
) { Text("+/-") }
TextButton(
onClick = { digitClicked("0") },
modifier = Modifier.weight(1F)
) { Text("0") }
Spacer(modifier = Modifier.weight(1F))
IconButton(
onClick = { submitClicked() },
modifier = Modifier.weight(1F),
enabled = enableSubmit
) {
Icon(
Icons.Outlined.Check,
stringResource(R.string.submit),
tint = MaterialTheme.colorScheme.primary
)
Column(Modifier.weight(1f)) {
KeyboardTextButton("+/-") {
negateClicked()
}
}
Column(Modifier.weight(1f)) {
KeyboardTextButton("0") {
digitClicked("0")
}
}
Column(Modifier.weight(2f)) {
KeyboardIconButton(Icons.Outlined.Check, enableSubmit) {
submitClicked()
}
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@Composable
fun KeyboardTextButton(text: String, onClicked: () -> Unit) {
ElevatedButton(
modifier = Modifier.fillMaxWidth(),
onClick = { onClicked() },
) { Text(text) }
}
@Composable
fun KeyboardIconButton(icon: ImageVector, enabled: Boolean = true, onClicked: () -> Unit) {
ElevatedButton(
onClick = { onClicked() },
modifier = Modifier.fillMaxWidth(),
enabled = enabled,
) {
Icon(
icon,
contentDescription = null
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CenteredTextField(
value: String,
keyboardController: SoftwareKeyboardController?,
focusRequester: FocusRequester?,
updateFocusState: (Boolean) -> Unit
placeholder: String,
modifier: Modifier,
) {
var modifier = Modifier
.onFocusChanged {
keyboardController?.hide()
updateFocusState(it.isFocused)
}
.fillMaxWidth()
if (focusRequester != null) {
modifier.focusRequester(focusRequester)
}
TextField(
value = value,
onValueChange = { },
placeholder = {
Text(
"0",
placeholder,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
@@ -184,12 +204,11 @@ fun CenteredTextField(
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
singleLine = true,
readOnly = true,
modifier = modifier
modifier = modifier.fillMaxWidth()
)
}
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Preview(name = "Light Mode")
@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
@Composable
@@ -210,6 +229,4 @@ fun KeyboardViewPreview() {
{})
}
}
}

View File

@@ -3,6 +3,7 @@ package me.zobrist.tichucounter.ui.counter
import android.content.res.Configuration
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@@ -21,18 +22,18 @@ fun TeamScoresView(scoreA: Int, scoreB: Int) {
ElevatedCard() {
Row() {
Text(
style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.headlineSmall,
text = scoreA.toString(),
modifier = Modifier.weight(5f),
modifier = Modifier.weight(5f).padding(6.dp),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.weight(1f))
Text(
style = MaterialTheme.typography.bodyLarge,
style = MaterialTheme.typography.headlineSmall,
text = scoreB.toString(),
modifier = Modifier.weight(5f),
modifier = Modifier.weight(5f).padding(6.dp),
textAlign = TextAlign.Center
)
}