diff --git a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt index 8753839..221a9fb 100644 --- a/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt +++ b/app/src/main/java/me/zobrist/tichucounter/MainActivity.kt @@ -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() } diff --git a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt index 0bc781b..6d37ac4 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt @@ -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) + } } } \ No newline at end of file diff --git a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt index 647ef0f..9721bfa 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt @@ -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 = MutableLiveData() private val _historyA: MutableLiveData = MutableLiveData() private val _historyB: MutableLiveData = MutableLiveData() + private val _scrollDown: SingleLiveEvent = SingleLiveEvent() @@ -36,6 +38,11 @@ class HistoryListViewModel : ViewModel() { return _historyB } + val scrollDown: LiveData + 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() - } - - - } diff --git a/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt b/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt index 6c44be7..b40645d 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt @@ -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() diff --git a/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt b/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt index bbb3718..e5331d9 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt @@ -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 = MutableLiveData() - private val _scoreB: MutableLiveData = MutableLiveData() - private val _enableSubmitButton: MutableLiveData = MutableLiveData() - private val _submitButtonClicked: MutableLiveData = MutableLiveData() +class KeyboardViewModel : ViewModel() { + private val _scoreA: MutableLiveData = MutableLiveData() + private val _scoreB: MutableLiveData = MutableLiveData() + private val _enableSubmitButton: MutableLiveData = MutableLiveData() + private val _submitButtonClicked: SingleLiveEvent = SingleLiveEvent() val scoreA: LiveData get() { diff --git a/app/src/main/java/me/zobrist/tichucounter/framework/SingleLiveEvent.kt b/app/src/main/java/me/zobrist/tichucounter/framework/SingleLiveEvent.kt new file mode 100644 index 0000000..bff1787 --- /dev/null +++ b/app/src/main/java/me/zobrist/tichucounter/framework/SingleLiveEvent.kt @@ -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 : MutableLiveData() { + private val pending = AtomicBoolean(false) + + @MainThread + override fun observe(owner: LifecycleOwner, observer: Observer) { + 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" + } +} \ No newline at end of file diff --git a/app/src/main/java/me/zobrist/tichucounter/framework/TichuCounterApplication.kt b/app/src/main/java/me/zobrist/tichucounter/framework/TichuCounterApplication.kt deleted file mode 100644 index 786dfd8..0000000 --- a/app/src/main/java/me/zobrist/tichucounter/framework/TichuCounterApplication.kt +++ /dev/null @@ -1,7 +0,0 @@ -package me.zobrist.tichucounter.framework - -import android.app.Application -import dagger.hilt.android.HiltAndroidApp - -@HiltAndroidApp -class TichuCounterApplication : Application()