Simplify composables.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-01-08 18:47:08 +01:00
parent 0f4d008104
commit 823d1a6ca4
6 changed files with 163 additions and 243 deletions

View File

@@ -13,18 +13,13 @@ import androidx.compose.material.icons.outlined.Check
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.* import androidx.compose.ui.platform.*
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@@ -55,50 +50,39 @@ class Keyboard : Fragment() {
} }
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Preview
@Composable @Composable
fun KeyboardView(viewModel: IKeyboardViewModel = DefaultViewModel()) { fun KeyboardView(viewModel: KeyboardViewModel) {
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
Column { Column {
Row { Row {
CompositionLocalProvider( TextField(
LocalTextToolbar provides EmptyTextToolbar value = viewModel.scoreA,
) { onValueChange = { },
TextField( placeholder = { Text("0") },
value = viewModel.scoreA.value, singleLine = true,
onValueChange = { }, readOnly = true,
placeholder = { Text("0") }, modifier = Modifier
singleLine = true, .onFocusChanged {
modifier = Modifier keyboardController?.hide()
.onFocusChanged { viewModel.isAFocused = it.isFocused
keyboardController?.hide() }
viewModel.isAFocused.value = it.isFocused .focusRequester(viewModel.requestFocusA)
} .weight(1f),
.focusRequester(viewModel.requestFocusA.value) )
.weight(1f), TextField(
colors = TextFieldDefaults.textFieldColors( value = viewModel.scoreB,
cursorColor = Color.Transparent, onValueChange = { },
errorCursorColor = Color.Transparent placeholder = { Text("0") },
) singleLine = true,
) readOnly = true,
TextField( modifier = Modifier
value = viewModel.scoreB.value, .onFocusChanged {
onValueChange = { }, keyboardController?.hide()
placeholder = { Text("0") }, viewModel.isBFocused = it.isFocused
singleLine = true, }
modifier = Modifier .weight(1f)
.onFocusChanged { )
keyboardController?.hide()
viewModel.isBFocused.value = it.isFocused
}
.weight(1f),
colors = TextFieldDefaults.textFieldColors(
cursorColor = Color.Transparent,
errorCursorColor = Color.Transparent
)
)
}
} }
Row { Row {
@@ -169,54 +153,9 @@ class Keyboard : Fragment() {
IconButton( IconButton(
onClick = { viewModel.submitScore() }, onClick = { viewModel.submitScore() },
modifier = Modifier.weight(1F), modifier = Modifier.weight(1F),
enabled = viewModel.enableSubmit.value enabled = viewModel.enableSubmit
) { Icon(Icons.Outlined.Check, stringResource(R.string.submit)) } ) { Icon(Icons.Outlined.Check, stringResource(R.string.submit)) }
} }
} }
} }
object EmptyTextToolbar : TextToolbar {
override val status: TextToolbarStatus = TextToolbarStatus.Hidden
override fun hide() {}
override fun showMenu(
rect: Rect,
onCopyRequested: (() -> Unit)?,
onPasteRequested: (() -> Unit)?,
onCutRequested: (() -> Unit)?,
onSelectAllRequested: (() -> Unit)?,
) {
}
}
internal class DefaultViewModel : IKeyboardViewModel {
override var scoreA: MutableState<String> = mutableStateOf("")
override var scoreB: MutableState<String> = mutableStateOf("")
override var enableSubmit = mutableStateOf(false)
override var isAFocused = mutableStateOf(false)
override var isBFocused = mutableStateOf(false)
override var requestFocusA = mutableStateOf(FocusRequester())
override fun appendToFocusedScore(toAppend: String) {
TODO("Not yet implemented")
}
override fun negateActiveInput() {
TODO("Not yet implemented")
}
override fun addToActiveInput(toAdd: Int) {
TODO("Not yet implemented")
}
override fun removeLastCharFromActive() {
TODO("Not yet implemented")
}
override fun submitScore() {
TODO("Not yet implemented")
}
}
} }

View File

@@ -1,7 +1,8 @@
package me.zobrist.tichucounter.ui.counter package me.zobrist.tichucounter.ui.counter
import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
@@ -11,127 +12,137 @@ import me.zobrist.tichucounter.domain.Tichu
import me.zobrist.tichucounter.repository.GameRepository import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject import javax.inject.Inject
interface IKeyboardViewModel {
var scoreA: MutableState<String>
var scoreB: MutableState<String>
var enableSubmit: MutableState<Boolean>
var isAFocused: MutableState<Boolean>
var isBFocused: MutableState<Boolean>
var requestFocusA: MutableState<FocusRequester>
fun appendToFocusedScore(toAppend: String)
fun negateActiveInput()
fun addToActiveInput(toAdd: Int)
fun removeLastCharFromActive()
fun submitScore()
}
@HiltViewModel @HiltViewModel
class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepository) : class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepository) :
ViewModel(), IKeyboardViewModel { ViewModel() {
override var scoreA = mutableStateOf("") var scoreA by mutableStateOf("")
override var scoreB = mutableStateOf("") private set
override var enableSubmit = mutableStateOf(false)
override var isAFocused = mutableStateOf(false)
override var isBFocused = mutableStateOf(false)
override var requestFocusA = mutableStateOf(FocusRequester())
override fun submitScore() { var scoreB by mutableStateOf("")
private set
var enableSubmit by mutableStateOf(false)
private set
var isAFocused by mutableStateOf(false)
var isBFocused by mutableStateOf(false)
var requestFocusA by mutableStateOf(FocusRequester())
private set
private var activeValue: String
get() {
return if (isBFocused) {
scoreB
} else {
scoreA
}
}
set(value) {
if (isBFocused) {
scoreB = value
} else {
scoreA = value
}
}
private var inactiveValue: String
get() {
return if (isAFocused) {
scoreB
} else {
scoreA
}
}
set(value) {
if (isAFocused) {
scoreB = value
} else {
scoreA = value
}
}
fun submitScore() {
viewModelScope.launch { viewModelScope.launch {
gameRepository.addRoundToActiveGame(scoreA.value.toInt(), scoreB.value.toInt()) gameRepository.addRoundToActiveGame(scoreA.toInt(), scoreB.toInt())
} }
scoreA.value = "" scoreA = ""
scoreB.value = "" scoreB = ""
enableSubmit.value = false enableSubmit = false
} }
override fun appendToFocusedScore(toAppend: String) { fun appendToFocusedScore(toAppend: String) {
val value = getActiveValue() activeValue += toAppend
value.value += toAppend
updateOtherScore() updateOtherScore()
updateSubmitButton()
} }
override fun negateActiveInput() { fun negateActiveInput() {
val value = getActiveValue() activeValue = if (activeValue.contains("-")) {
activeValue.replace("-", "")
if (value.value.contains("-")) {
value.value = value.value.replace("-", "")
} else { } else {
value.value = "-" + value.value "-$activeValue"
} }
updateOtherScore() updateOtherScore()
updateSubmitButton()
} }
override fun addToActiveInput(toAdd: Int) { fun addToActiveInput(toAdd: Int) {
val value = getActiveValue() activeValue = try {
val temp = activeValue.toInt() + toAdd
try { temp.toString()
val temp = value.value.toInt() + toAdd
value.value = temp.toString()
} catch (e: Exception) { } catch (e: Exception) {
value.value = toAdd.toString() toAdd.toString()
} }
if(inactiveValue == "")
{
updateOtherScore()
}
updateSubmitButton()
} }
override fun removeLastCharFromActive() { fun removeLastCharFromActive() {
val value = getActiveValue() if (activeValue != "") {
if (value.value != "") { activeValue = activeValue.dropLast(1)
value.value = value.value.dropLast(1)
} }
updateOtherScore() updateOtherScore()
} }
private fun giveFocusToAIfNone() { private fun giveFocusToAIfNone() {
if (!isAFocused.value && !isBFocused.value) { if (!isAFocused && !isBFocused) {
requestFocusA.value.requestFocus() requestFocusA.requestFocus()
} }
} }
private fun updateOtherScore() { private fun updateOtherScore() {
val value = getActiveValue()
try { try {
val tichu = Tichu() val tichu = Tichu()
val myScore = value.value.toInt() val myScore = activeValue.toInt()
val hisScore = tichu.calculateOtherScore(myScore) val hisScore = tichu.calculateOtherScore(myScore)
if (tichu.isValidRound(myScore, hisScore)) { if (tichu.isValidRound(myScore, hisScore)) {
updateInactiveValue(hisScore?.toString() ?: "") inactiveValue = hisScore?.toString() ?: ""
} else { } else {
updateInactiveValue("") inactiveValue = ""
} }
} catch (_: Exception) { } catch (_: Exception) {
updateInactiveValue("") inactiveValue = ""
} }
} }
private fun getActiveValue(): MutableState<String> { private fun isValidTichuRound(): Boolean {
giveFocusToAIfNone() return try {
if (isBFocused.value) {
return scoreB
}
return scoreA
}
private fun updateInactiveValue(value: String) {
giveFocusToAIfNone()
if (isBFocused.value) {
scoreA.value = value
} else {
scoreB.value = value
}
try {
val tichu = Tichu() val tichu = Tichu()
enableSubmit.value = tichu.isValidRound(scoreA.value.toInt(), scoreB.value.toInt()) tichu.isValidRound(scoreA.toInt(), scoreB.toInt())
} catch (_: java.lang.NumberFormatException) { } catch (_: java.lang.NumberFormatException) {
enableSubmit.value = false false
} }
} }
private fun updateSubmitButton() {
enableSubmit = isValidTichuRound()
}
} }

View File

@@ -50,15 +50,18 @@ class RoundList : Fragment() {
} }
} }
@Preview
@Composable @Composable
fun RoundListView(viewModel: IRoundListViewModel = DefaultViewModel()) { fun RoundListView(viewModel: RoundListViewModel) {
RoundListView(viewModel.scores)
}
@Composable
fun RoundListView(rounds: List<Round>) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
LazyColumn(state = lazyListState) { LazyColumn(state = lazyListState) {
itemsIndexed(viewModel.scores) { index, item -> itemsIndexed(rounds) { index, item ->
RoundListItem(item, index, lazyListState) RoundListItem(item, index, lazyListState)
} }
@@ -96,11 +99,16 @@ class RoundList : Fragment() {
} }
} }
internal class DefaultViewModel() : IRoundListViewModel { @Composable
override var scores: List<Round> @Preview
get() = TODO("Not yet implemented") fun RoundListViewPreview() {
set(value) {} val rounds = listOf<Round>(
Round(1, 10, 90),
Round(1, 5, 95),
Round(1, 100, 0),
Round(1, 125, -25),
Round(1, 50, 50)
)
RoundListView(rounds)
} }
} }

View File

@@ -11,15 +11,10 @@ import me.zobrist.tichucounter.data.Round
import me.zobrist.tichucounter.data.RoundDao import me.zobrist.tichucounter.data.RoundDao
import javax.inject.Inject import javax.inject.Inject
interface IRoundListViewModel {
var scores: List<Round>
}
@HiltViewModel @HiltViewModel
class RoundListViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel(), class RoundListViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel(){
IRoundListViewModel {
override var scores by mutableStateOf(emptyList<Round>()) var scores by mutableStateOf(emptyList<Round>())
init { init {
viewModelScope.launch { viewModelScope.launch {

View File

@@ -15,8 +15,6 @@ import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.platform.ViewCompositionStrategy
@@ -55,11 +53,13 @@ class HistoryFragment : Fragment() {
} }
} }
@Preview
@Composable @Composable
fun HistoryList(viewModel: IHistoryFragmentViewModel = DefaultViewModel()) { fun HistoryList(viewModel: HistoryFragmentViewModel) {
val games = viewModel.gameAndHistory.value HistoryList(viewModel.gameAndHistory)
}
@Composable
fun HistoryList(games: List<GameAndScore>) {
LazyColumn { LazyColumn {
items(games) { items(games) {
HistoryListItem(it) HistoryListItem(it)
@@ -111,41 +111,16 @@ class HistoryFragment : Fragment() {
} }
} }
internal class DefaultViewModel : IHistoryFragmentViewModel { @Preview
@Composable
override val gameAndHistory: State<List<GameAndScore>> private fun HistoryListPreview() {
get() { val tempData = listOf<GameAndScore>(
val tempData = mutableListOf<GameAndScore>() GameAndScore(false, "abc", "def", Date(), Date(), 1, 10, 50),
tempData.add( GameAndScore(true, "ADTH", "dogfg", Date(), Date(), 2, 20, 60),
GameAndScore( GameAndScore(false, "TeamA3", "TeamB3", Date(), Date(), 3, 30, 70),
false, GameAndScore(false, "TeamA4", "TeamB4", Date(), Date(), 4, 40, 80),
"TeamA1sdfdsf", GameAndScore(false, "TeamA5", "TeamB5", Date(), Date(), 5, 50, 90)
"TeamB1", )
Date(), HistoryList(tempData)
Date(),
1,
10,
50
)
)
tempData.add(
GameAndScore(
true,
"TeamA2",
"TeamB2sdfsdf",
Date(),
Date(),
2,
20,
60
)
)
tempData.add(GameAndScore(false, "TeamA3", "TeamB3", Date(), Date(), 3, 30, 70))
tempData.add(GameAndScore(false, "TeamA4", "TeamB4", Date(), Date(), 4, 40, 80))
tempData.add(GameAndScore(false, "TeamA5", "TeamB5", Date(), Date(), 5, 50, 90))
return mutableStateOf(tempData)
}
} }
} }

View File

@@ -1,37 +1,29 @@
package me.zobrist.tichucounter.ui.history package me.zobrist.tichucounter.ui.history
import androidx.compose.runtime.State import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.GameAndScore import me.zobrist.tichucounter.data.GameAndScore
import me.zobrist.tichucounter.data.GameDao import me.zobrist.tichucounter.data.GameDao
import me.zobrist.tichucounter.data.RoundDao
import javax.inject.Inject import javax.inject.Inject
interface IHistoryFragmentViewModel {
val gameAndHistory: State<List<GameAndScore>>
}
@HiltViewModel @HiltViewModel
class HistoryFragmentViewModel @Inject constructor( class HistoryFragmentViewModel @Inject constructor(
private val gameDao: GameDao, private val gameDao: GameDao
private val roundDao: RoundDao ) : ViewModel() {
) : ViewModel(), IHistoryFragmentViewModel {
private val _gameAndHistory = mutableStateOf(emptyList<GameAndScore>()) var gameAndHistory by mutableStateOf(emptyList<GameAndScore>())
private set
override val gameAndHistory: State<List<GameAndScore>>
get() {
return _gameAndHistory
}
init { init {
viewModelScope.launch { viewModelScope.launch {
gameDao.getAllWithPoints().collect { games -> gameDao.getAllWithPoints().collect { games ->
_gameAndHistory.value = games gameAndHistory = games
} }
} }
} }