Use single live event to prevent false trigger after rotation. remove hilt (for the moment)
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2022-12-27 08:57:02 +01:00
parent 637a34efd7
commit 4e6193501b
7 changed files with 103 additions and 63 deletions

View File

@@ -22,13 +22,8 @@ import me.zobrist.tichucounter.fragments.KeyboardViewModel
import java.util.*
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private var updateOnChange: Boolean = true
@Inject
lateinit var history: History
private var currentRound: Round = Round(null, null)
private val keyboardViewModel: KeyboardViewModel by viewModels()
@@ -58,7 +53,6 @@ class MainActivity : AppCompatActivity() {
val json = this.getSharedPreferences("Settings", MODE_PRIVATE)
.getString("history", "{\"scores\":[]}")
history = Gson().fromJson(json, History::class.java)
binding.contentMain.nameTeamA.setText(
this.getSharedPreferences("Settings", MODE_PRIVATE).getString("nameTeamA", "TeamA")
)
@@ -66,7 +60,7 @@ class MainActivity : AppCompatActivity() {
this.getSharedPreferences("Settings", MODE_PRIVATE).getString("nameTeamB", "TeamB")
)
keyboardViewModel.scoreA.observe(this, androidx.lifecycle.Observer { value ->
keyboardViewModel.scoreA.observe(this) { value ->
val tichu = Tichu()
val oldValue = currentRound.scoreA
@@ -83,9 +77,9 @@ class MainActivity : AppCompatActivity() {
keyboardViewModel.setSubmitButtonEnable(tichu.isValidRound(currentRound))
}
})
}
keyboardViewModel.scoreB.observe(this, androidx.lifecycle.Observer { value ->
keyboardViewModel.scoreB.observe(this) { value ->
val tichu = Tichu()
val oldValue = currentRound.scoreB
@@ -102,28 +96,27 @@ class MainActivity : AppCompatActivity() {
keyboardViewModel.setSubmitButtonEnable(tichu.isValidRound(currentRound))
}
})
}
keyboardViewModel.submitButtonClicked.observe(this, androidx.lifecycle.Observer {
keyboardViewModel.submitButtonClicked.observe(this) {
historyListViewModel.logRound(currentRound)
keyboardViewModel.setScoreA(null)
keyboardViewModel.setScoreB(null)
})
}
historyListViewModel.totalScoreA.observe(this, androidx.lifecycle.Observer { value ->
historyListViewModel.totalScoreA.observe(this) { value ->
binding.contentMain.scoreA.text = value.toString()
})
}
historyListViewModel.totalScoreB.observe(this, androidx.lifecycle.Observer { value ->
historyListViewModel.totalScoreB.observe(this) { value ->
binding.contentMain.scoreB.text = value.toString()
})
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val prefs = this.getSharedPreferences("Settings", MODE_PRIVATE).edit()
prefs.putString("history", Gson().toJson(history))
prefs.putString("nameTeamA", binding.contentMain.nameTeamA.text.toString())
prefs.putString("nameTeamB", binding.contentMain.nameTeamB.text.toString())
prefs.apply()
@@ -177,8 +170,7 @@ class MainActivity : AppCompatActivity() {
}
private fun clearAll() {
history.clearAll()
historyListViewModel.clearAll()
}

View File

@@ -1,19 +1,12 @@
package me.zobrist.tichucounter.fragments
import android.content.Context
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import dagger.hilt.android.AndroidEntryPoint
import me.zobrist.tichucounter.databinding.FragmentHistoryListBinding
import me.zobrist.tichucounter.databinding.FragmentKeyboardBinding
class HistoryList : Fragment() {
@@ -46,13 +39,17 @@ class HistoryList : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.historyA.observe(viewLifecycleOwner, Observer { text ->
viewModel.historyA.observe(viewLifecycleOwner) { text ->
binding.historyA.text = text
})
}
viewModel.historyB.observe(viewLifecycleOwner, Observer { text ->
viewModel.historyB.observe(viewLifecycleOwner) { text ->
binding.historyB.text = text
})
}
viewModel.scrollDown.observe(viewLifecycleOwner) {
binding.scrollViewHistory.smoothScrollTo(0, binding.scrollViewHistory.height)
}
}
}

View File

@@ -1,5 +1,6 @@
package me.zobrist.tichucounter.fragments
import SingleLiveEvent
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
@@ -13,6 +14,7 @@ class HistoryListViewModel : ViewModel() {
private val _totalScoreB: MutableLiveData<Int> = MutableLiveData<Int>()
private val _historyA: MutableLiveData<String> = MutableLiveData<String>()
private val _historyB: MutableLiveData<String> = MutableLiveData<String>()
private val _scrollDown: SingleLiveEvent<Boolean> = SingleLiveEvent()
@@ -36,6 +38,11 @@ class HistoryListViewModel : ViewModel() {
return _historyB
}
val scrollDown: LiveData<Boolean>
get() {
return _scrollDown
}
private fun getScoreA() {
var tempScore = 0
scores.forEach {
@@ -47,7 +54,7 @@ class HistoryListViewModel : ViewModel() {
private fun getScoreB() {
var tempScore = 0
scores.forEach {
it.scoreB?.let {it -> tempScore += it}
it.scoreB?.let { it -> tempScore += it }
}
_totalScoreB.value = tempScore
}
@@ -68,33 +75,33 @@ class HistoryListViewModel : ViewModel() {
_historyB.value = tempHistory
}
fun logRound(round: Round) {
scores.add(round.copy())
private fun updateAll() {
getHistoryA()
getHistoryB()
getScoreA()
getScoreB()
scrollDown()
}
fun logRound(round: Round) {
scores.add(round.copy())
updateAll()
}
fun revertLastRound() {
if (scores.isNotEmpty()) {
scores.removeAt(scores.size - 1)
}
getHistoryA()
getHistoryB()
getScoreA()
getScoreB()
updateAll()
}
private fun scrollDown() {
_scrollDown.value = true
}
fun clearAll() {
scores.clear()
updateAll()
}
fun isEmpty(): Boolean {
return scores.isEmpty()
}
}

View File

@@ -11,7 +11,6 @@ import android.widget.EditText
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Observer
import dagger.hilt.android.AndroidEntryPoint
import me.zobrist.tichucounter.databinding.FragmentKeyboardBinding
class Keyboard : Fragment() {
@@ -56,13 +55,13 @@ class Keyboard : Fragment() {
if (enabled) enableSubmitButton() else disableSubmitButton()
})
viewModel.scoreA.observe(viewLifecycleOwner, Observer { value ->
viewModel.scoreA.observe(viewLifecycleOwner) { value ->
updateScore(binding.inputTeamA, value)
})
}
viewModel.scoreB.observe(viewLifecycleOwner, Observer { value ->
viewModel.scoreB.observe(viewLifecycleOwner) { value ->
updateScore(binding.inputTeamB, value)
})
}
setListeners()

View File

@@ -1,16 +1,15 @@
package me.zobrist.tichucounter.fragments
import SingleLiveEvent
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
class KeyboardViewModel: ViewModel() {
private val _scoreA: MutableLiveData<Int?> = MutableLiveData<Int?>()
private val _scoreB: MutableLiveData<Int?> = MutableLiveData<Int?>()
private val _enableSubmitButton: MutableLiveData<Boolean> = MutableLiveData<Boolean>()
private val _submitButtonClicked: MutableLiveData<Boolean> = MutableLiveData<Boolean>()
class KeyboardViewModel : ViewModel() {
private val _scoreA: MutableLiveData<Int?> = MutableLiveData()
private val _scoreB: MutableLiveData<Int?> = MutableLiveData()
private val _enableSubmitButton: MutableLiveData<Boolean> = MutableLiveData()
private val _submitButtonClicked: SingleLiveEvent<Boolean> = SingleLiveEvent()
val scoreA: LiveData<Int?>
get() {

View File

@@ -0,0 +1,53 @@
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events like
* navigation and Snackbar messages.
*
*
* This avoids a common problem with events: on configuration change (like rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
*
*
* Note that only one observer is going to be notified of changes.
*/
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner, Observer { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
})
}
@MainThread
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
fun call() {
value = null
}
companion object {
private val TAG = "SingleLiveEvent"
}
}

View File

@@ -1,7 +0,0 @@
package me.zobrist.tichucounter.framework
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class TichuCounterApplication : Application()