This commit is contained in:
@@ -13,18 +13,13 @@ import androidx.compose.material.icons.outlined.Check
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
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.geometry.Rect
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.*
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
@@ -55,50 +50,39 @@ class Keyboard : Fragment() {
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Preview
|
||||
@Composable
|
||||
fun KeyboardView(viewModel: IKeyboardViewModel = DefaultViewModel()) {
|
||||
fun KeyboardView(viewModel: KeyboardViewModel) {
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
Column {
|
||||
Row {
|
||||
CompositionLocalProvider(
|
||||
LocalTextToolbar provides EmptyTextToolbar
|
||||
) {
|
||||
TextField(
|
||||
value = viewModel.scoreA.value,
|
||||
onValueChange = { },
|
||||
placeholder = { Text("0") },
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.onFocusChanged {
|
||||
keyboardController?.hide()
|
||||
viewModel.isAFocused.value = it.isFocused
|
||||
}
|
||||
.focusRequester(viewModel.requestFocusA.value)
|
||||
.weight(1f),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
cursorColor = Color.Transparent,
|
||||
errorCursorColor = Color.Transparent
|
||||
)
|
||||
)
|
||||
TextField(
|
||||
value = viewModel.scoreB.value,
|
||||
onValueChange = { },
|
||||
placeholder = { Text("0") },
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.onFocusChanged {
|
||||
keyboardController?.hide()
|
||||
viewModel.isBFocused.value = it.isFocused
|
||||
}
|
||||
.weight(1f),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
cursorColor = Color.Transparent,
|
||||
errorCursorColor = Color.Transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
TextField(
|
||||
value = viewModel.scoreA,
|
||||
onValueChange = { },
|
||||
placeholder = { Text("0") },
|
||||
singleLine = true,
|
||||
readOnly = true,
|
||||
modifier = Modifier
|
||||
.onFocusChanged {
|
||||
keyboardController?.hide()
|
||||
viewModel.isAFocused = it.isFocused
|
||||
}
|
||||
.focusRequester(viewModel.requestFocusA)
|
||||
.weight(1f),
|
||||
)
|
||||
TextField(
|
||||
value = viewModel.scoreB,
|
||||
onValueChange = { },
|
||||
placeholder = { Text("0") },
|
||||
singleLine = true,
|
||||
readOnly = true,
|
||||
modifier = Modifier
|
||||
.onFocusChanged {
|
||||
keyboardController?.hide()
|
||||
viewModel.isBFocused = it.isFocused
|
||||
}
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -169,54 +153,9 @@ class Keyboard : Fragment() {
|
||||
IconButton(
|
||||
onClick = { viewModel.submitScore() },
|
||||
modifier = Modifier.weight(1F),
|
||||
enabled = viewModel.enableSubmit.value
|
||||
enabled = viewModel.enableSubmit
|
||||
) { 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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
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.setValue
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -11,127 +12,137 @@ import me.zobrist.tichucounter.domain.Tichu
|
||||
import me.zobrist.tichucounter.repository.GameRepository
|
||||
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
|
||||
class KeyboardViewModel @Inject constructor(private val gameRepository: GameRepository) :
|
||||
ViewModel(), IKeyboardViewModel {
|
||||
override var scoreA = mutableStateOf("")
|
||||
override var scoreB = mutableStateOf("")
|
||||
override var enableSubmit = mutableStateOf(false)
|
||||
override var isAFocused = mutableStateOf(false)
|
||||
override var isBFocused = mutableStateOf(false)
|
||||
override var requestFocusA = mutableStateOf(FocusRequester())
|
||||
ViewModel() {
|
||||
var scoreA by mutableStateOf("")
|
||||
private set
|
||||
|
||||
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 {
|
||||
gameRepository.addRoundToActiveGame(scoreA.value.toInt(), scoreB.value.toInt())
|
||||
gameRepository.addRoundToActiveGame(scoreA.toInt(), scoreB.toInt())
|
||||
}
|
||||
scoreA.value = ""
|
||||
scoreB.value = ""
|
||||
enableSubmit.value = false
|
||||
scoreA = ""
|
||||
scoreB = ""
|
||||
enableSubmit = false
|
||||
}
|
||||
|
||||
override fun appendToFocusedScore(toAppend: String) {
|
||||
val value = getActiveValue()
|
||||
value.value += toAppend
|
||||
fun appendToFocusedScore(toAppend: String) {
|
||||
activeValue += toAppend
|
||||
updateOtherScore()
|
||||
updateSubmitButton()
|
||||
}
|
||||
|
||||
override fun negateActiveInput() {
|
||||
val value = getActiveValue()
|
||||
|
||||
if (value.value.contains("-")) {
|
||||
value.value = value.value.replace("-", "")
|
||||
fun negateActiveInput() {
|
||||
activeValue = if (activeValue.contains("-")) {
|
||||
activeValue.replace("-", "")
|
||||
} else {
|
||||
value.value = "-" + value.value
|
||||
"-$activeValue"
|
||||
}
|
||||
|
||||
updateOtherScore()
|
||||
updateSubmitButton()
|
||||
}
|
||||
|
||||
override fun addToActiveInput(toAdd: Int) {
|
||||
val value = getActiveValue()
|
||||
|
||||
try {
|
||||
val temp = value.value.toInt() + toAdd
|
||||
value.value = temp.toString()
|
||||
fun addToActiveInput(toAdd: Int) {
|
||||
activeValue = try {
|
||||
val temp = activeValue.toInt() + toAdd
|
||||
temp.toString()
|
||||
} catch (e: Exception) {
|
||||
value.value = toAdd.toString()
|
||||
toAdd.toString()
|
||||
}
|
||||
if(inactiveValue == "")
|
||||
{
|
||||
updateOtherScore()
|
||||
}
|
||||
|
||||
updateSubmitButton()
|
||||
}
|
||||
|
||||
override fun removeLastCharFromActive() {
|
||||
val value = getActiveValue()
|
||||
if (value.value != "") {
|
||||
value.value = value.value.dropLast(1)
|
||||
fun removeLastCharFromActive() {
|
||||
if (activeValue != "") {
|
||||
activeValue = activeValue.dropLast(1)
|
||||
}
|
||||
updateOtherScore()
|
||||
}
|
||||
|
||||
|
||||
private fun giveFocusToAIfNone() {
|
||||
if (!isAFocused.value && !isBFocused.value) {
|
||||
requestFocusA.value.requestFocus()
|
||||
if (!isAFocused && !isBFocused) {
|
||||
requestFocusA.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateOtherScore() {
|
||||
val value = getActiveValue()
|
||||
|
||||
try {
|
||||
val tichu = Tichu()
|
||||
val myScore = value.value.toInt()
|
||||
val myScore = activeValue.toInt()
|
||||
val hisScore = tichu.calculateOtherScore(myScore)
|
||||
if (tichu.isValidRound(myScore, hisScore)) {
|
||||
updateInactiveValue(hisScore?.toString() ?: "")
|
||||
inactiveValue = hisScore?.toString() ?: ""
|
||||
} else {
|
||||
updateInactiveValue("")
|
||||
inactiveValue = ""
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
updateInactiveValue("")
|
||||
inactiveValue = ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActiveValue(): MutableState<String> {
|
||||
giveFocusToAIfNone()
|
||||
if (isBFocused.value) {
|
||||
return scoreB
|
||||
}
|
||||
return scoreA
|
||||
}
|
||||
|
||||
private fun updateInactiveValue(value: String) {
|
||||
giveFocusToAIfNone()
|
||||
if (isBFocused.value) {
|
||||
scoreA.value = value
|
||||
} else {
|
||||
scoreB.value = value
|
||||
}
|
||||
|
||||
try {
|
||||
private fun isValidTichuRound(): Boolean {
|
||||
return try {
|
||||
val tichu = Tichu()
|
||||
enableSubmit.value = tichu.isValidRound(scoreA.value.toInt(), scoreB.value.toInt())
|
||||
tichu.isValidRound(scoreA.toInt(), scoreB.toInt())
|
||||
} catch (_: java.lang.NumberFormatException) {
|
||||
enableSubmit.value = false
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSubmitButton() {
|
||||
enableSubmit = isValidTichuRound()
|
||||
}
|
||||
}
|
||||
@@ -50,15 +50,18 @@ class RoundList : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun RoundListView(viewModel: IRoundListViewModel = DefaultViewModel()) {
|
||||
fun RoundListView(viewModel: RoundListViewModel) {
|
||||
RoundListView(viewModel.scores)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RoundListView(rounds: List<Round>) {
|
||||
val lazyListState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LazyColumn(state = lazyListState) {
|
||||
itemsIndexed(viewModel.scores) { index, item ->
|
||||
itemsIndexed(rounds) { index, item ->
|
||||
RoundListItem(item, index, lazyListState)
|
||||
}
|
||||
|
||||
@@ -96,11 +99,16 @@ class RoundList : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultViewModel() : IRoundListViewModel {
|
||||
override var scores: List<Round>
|
||||
get() = TODO("Not yet implemented")
|
||||
set(value) {}
|
||||
@Composable
|
||||
@Preview
|
||||
fun RoundListViewPreview() {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -11,15 +11,10 @@ import me.zobrist.tichucounter.data.Round
|
||||
import me.zobrist.tichucounter.data.RoundDao
|
||||
import javax.inject.Inject
|
||||
|
||||
interface IRoundListViewModel {
|
||||
var scores: List<Round>
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class RoundListViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel(),
|
||||
IRoundListViewModel {
|
||||
class RoundListViewModel @Inject constructor(private val roundDao: RoundDao) : ViewModel(){
|
||||
|
||||
override var scores by mutableStateOf(emptyList<Round>())
|
||||
var scores by mutableStateOf(emptyList<Round>())
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
|
||||
@@ -15,8 +15,6 @@ import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
@@ -55,11 +53,13 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun HistoryList(viewModel: IHistoryFragmentViewModel = DefaultViewModel()) {
|
||||
val games = viewModel.gameAndHistory.value
|
||||
fun HistoryList(viewModel: HistoryFragmentViewModel) {
|
||||
HistoryList(viewModel.gameAndHistory)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HistoryList(games: List<GameAndScore>) {
|
||||
LazyColumn {
|
||||
items(games) {
|
||||
HistoryListItem(it)
|
||||
@@ -111,41 +111,16 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultViewModel : IHistoryFragmentViewModel {
|
||||
|
||||
override val gameAndHistory: State<List<GameAndScore>>
|
||||
get() {
|
||||
val tempData = mutableListOf<GameAndScore>()
|
||||
tempData.add(
|
||||
GameAndScore(
|
||||
false,
|
||||
"TeamA1sdfdsf",
|
||||
"TeamB1",
|
||||
Date(),
|
||||
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)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun HistoryListPreview() {
|
||||
val tempData = listOf<GameAndScore>(
|
||||
GameAndScore(false, "abc", "def", Date(), Date(), 1, 10, 50),
|
||||
GameAndScore(true, "ADTH", "dogfg", Date(), Date(), 2, 20, 60),
|
||||
GameAndScore(false, "TeamA3", "TeamB3", Date(), Date(), 3, 30, 70),
|
||||
GameAndScore(false, "TeamA4", "TeamB4", Date(), Date(), 4, 40, 80),
|
||||
GameAndScore(false, "TeamA5", "TeamB5", Date(), Date(), 5, 50, 90)
|
||||
)
|
||||
HistoryList(tempData)
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,29 @@
|
||||
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.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import me.zobrist.tichucounter.data.GameAndScore
|
||||
import me.zobrist.tichucounter.data.GameDao
|
||||
import me.zobrist.tichucounter.data.RoundDao
|
||||
import javax.inject.Inject
|
||||
|
||||
interface IHistoryFragmentViewModel {
|
||||
val gameAndHistory: State<List<GameAndScore>>
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class HistoryFragmentViewModel @Inject constructor(
|
||||
private val gameDao: GameDao,
|
||||
private val roundDao: RoundDao
|
||||
) : ViewModel(), IHistoryFragmentViewModel {
|
||||
private val gameDao: GameDao
|
||||
) : ViewModel() {
|
||||
|
||||
private val _gameAndHistory = mutableStateOf(emptyList<GameAndScore>())
|
||||
|
||||
override val gameAndHistory: State<List<GameAndScore>>
|
||||
get() {
|
||||
return _gameAndHistory
|
||||
}
|
||||
var gameAndHistory by mutableStateOf(emptyList<GameAndScore>())
|
||||
private set
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
gameDao.getAllWithPoints().collect { games ->
|
||||
_gameAndHistory.value = games
|
||||
gameAndHistory = games
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user