diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 227d63e..5c7aab0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,6 +11,11 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> + + + + val tichu = Tichu() + + val oldValue = currentRound.scoreA + currentRound.scoreA = value + + if (ignoreNextUpdate) { + ignoreNextUpdate = false + } else { + if (currentRound.scoreA?.let { oldValue?.getAbsoluteDifference(it) } != 100) { + ignoreNextUpdate = true + currentRound.scoreB = tichu.calculateOtherScore(value) + keyboardViewModel.setScoreB(currentRound.scoreB) + } + + keyboardViewModel.setSubmitButtonEnable(tichu.isValidRound(currentRound)) + } + }) + + keyboardViewModel.scoreB.observe(this, androidx.lifecycle.Observer { value -> + val tichu = Tichu() + + val oldValue = currentRound.scoreB + currentRound.scoreB = value + + if (ignoreNextUpdate) { + ignoreNextUpdate = false + } else { + if (currentRound.scoreB?.let { oldValue?.getAbsoluteDifference(it) } != 100) { + ignoreNextUpdate = true + currentRound.scoreA = tichu.calculateOtherScore(value) + keyboardViewModel.setScoreA(currentRound.scoreA) + } + + keyboardViewModel.setSubmitButtonEnable(tichu.isValidRound(currentRound)) + } + }) + + keyboardViewModel.submitButtonClicked.observe(this, androidx.lifecycle.Observer { + historyListViewModel.logRound(currentRound) + keyboardViewModel.setScoreA(null) + keyboardViewModel.setScoreB(null) + }) + + historyListViewModel.totalScoreA.observe(this, androidx.lifecycle.Observer { value -> + binding.contentMain.scoreA.text = value.toString() + }) + + historyListViewModel.totalScoreB.observe(this, androidx.lifecycle.Observer { value -> + binding.contentMain.scoreB.text = value.toString() + }) } override fun onSaveInstanceState(outState: Bundle) { @@ -79,264 +130,12 @@ class MainActivity : AppCompatActivity() { } - private fun setListeners() { - binding.contentMain.keyboard.inputTeamA.setOnFocusChangeListener { _, b -> - if (b) { - hideKeyboard() - } - } - - binding.contentMain.keyboard.inputTeamB.setOnFocusChangeListener { _, b -> - if (b) { - hideKeyboard() - } - } - - binding.contentMain.keyboard.inputTeamA.doOnTextChanged { text, _, _, _ -> - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - if (binding.contentMain.keyboard.inputTeamA.text.isNotEmpty()) { - if (updateOnChange) { - currentRound = try { - Round(text.toString().toInt(), true) - - } catch (e: java.lang.Exception) { - Round(1, 1) - } - binding.contentMain.keyboard.inputTeamB.setText(currentRound.scoreB.toString()) - } else { - updateOnChange = true - } - } else { - binding.contentMain.keyboard.inputTeamA.text.clear() - binding.contentMain.keyboard.inputTeamB.text.clear() - } - } - - if (currentRound.isValidRound() && binding.contentMain.keyboard.inputTeamA.text.isNotEmpty() && binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - enableSubmitButton() - } else { - disableSubmitButton() - } - } - - binding.contentMain.keyboard.inputTeamB.doOnTextChanged { text, _, _, _ -> - if (binding.contentMain.keyboard.inputTeamB.isFocused) { - if (binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - if (updateOnChange) { - currentRound = try { - Round(text.toString().toInt(), false) - - } catch (e: java.lang.Exception) { - Round(1, 1) - } - binding.contentMain.keyboard.inputTeamA.setText(currentRound.scoreA.toString()) - - } else { - updateOnChange = true - } - - } else { - binding.contentMain.keyboard.inputTeamA.text.clear() - binding.contentMain.keyboard.inputTeamB.text.clear() - } - } - - if (currentRound.isValidRound() && binding.contentMain.keyboard.inputTeamA.text.isNotEmpty() && binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - enableSubmitButton() - } else { - disableSubmitButton() - } - } - - binding.contentMain.keyboard.buttonAdd100.setOnClickListener { - giveFocusToAIfNone() - - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - - currentRound.scoreA = try { - binding.contentMain.keyboard.inputTeamA.text.toString().toInt() + 100 - } catch (e: Exception) { - currentRound.scoreB = 0 - binding.contentMain.keyboard.inputTeamB.setText(currentRound.scoreB.toString()) - 100 - } - updateOnChange = false - binding.contentMain.keyboard.inputTeamA.setText(currentRound.scoreA.toString()) - } - - if (binding.contentMain.keyboard.inputTeamB.isFocused) { - currentRound.scoreB = try { - binding.contentMain.keyboard.inputTeamB.text.toString().toInt() + 100 - } catch (e: Exception) { - currentRound.scoreA = 0 - binding.contentMain.keyboard.inputTeamA.setText(currentRound.scoreA.toString()) - 100 - - } - updateOnChange = false - binding.contentMain.keyboard.inputTeamB.setText(currentRound.scoreB.toString()) - - } - } - - binding.contentMain.keyboard.buttonSub100.setOnClickListener { - giveFocusToAIfNone() - - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - currentRound.scoreA = try { - binding.contentMain.keyboard.inputTeamA.text.toString().toInt() - 100 - } catch (e: Exception) { - currentRound.scoreB = 0 - binding.contentMain.keyboard.inputTeamB.setText(currentRound.scoreB.toString()) - -100 - } - updateOnChange = false - binding.contentMain.keyboard.inputTeamA.setText(currentRound.scoreA.toString()) - } - - if (binding.contentMain.keyboard.inputTeamB.isFocused) { - currentRound.scoreB = try { - binding.contentMain.keyboard.inputTeamB.text.toString().toInt() - 100 - } catch (e: Exception) { - currentRound.scoreA = 0 - binding.contentMain.keyboard.inputTeamA.setText(currentRound.scoreA.toString()) - -100 - } - updateOnChange = false - binding.contentMain.keyboard.inputTeamB.setText(currentRound.scoreB.toString()) - } - } - - binding.contentMain.keyboard.button0.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('0') - } - - binding.contentMain.keyboard.button1.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('1') - } - - binding.contentMain.keyboard.button2.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('2') - } - - binding.contentMain.keyboard.button3.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('3') - } - - binding.contentMain.keyboard.button4.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('4') - } - - binding.contentMain.keyboard.button5.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('5') - } - - binding.contentMain.keyboard.button6.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('6') - } - - binding.contentMain.keyboard.button7.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('7') - } - - binding.contentMain.keyboard.button8.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('8') - } - - binding.contentMain.keyboard.button9.setOnClickListener { - giveFocusToAIfNone() - appendToFocusedInput('9') - } - - binding.contentMain.keyboard.buttonInv.setOnClickListener { - val tempInt: Int - - giveFocusToAIfNone() - - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - if (binding.contentMain.keyboard.inputTeamA.text.toString() == "-") { - binding.contentMain.keyboard.inputTeamA.text.clear() - } else if (binding.contentMain.keyboard.inputTeamA.text.isNotEmpty()) { - tempInt = binding.contentMain.keyboard.inputTeamA.text.toString().toInt() * -1 - binding.contentMain.keyboard.inputTeamA.setText(tempInt.toString()) - } else { - updateOnChange = false - appendToFocusedInput('-') - currentRound = Round(1, 1) - } - - - } else if (binding.contentMain.keyboard.inputTeamB.isFocused) { - if (binding.contentMain.keyboard.inputTeamB.text.toString() == "-") { - binding.contentMain.keyboard.inputTeamB.text.clear() - } else if (binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - tempInt = binding.contentMain.keyboard.inputTeamB.text.toString().toInt() * -1 - binding.contentMain.keyboard.inputTeamB.setText(tempInt.toString()) - } else { - updateOnChange = false - appendToFocusedInput('-') - currentRound = Round(1, 1) - } - } - } - - binding.contentMain.keyboard.buttonBack.setOnClickListener { - giveFocusToAIfNone() - - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - if (binding.contentMain.keyboard.inputTeamA.text.isNotEmpty()) { - val string = binding.contentMain.keyboard.inputTeamA.text.toString() - binding.contentMain.keyboard.inputTeamA.setText(string.substring(0, string.length - 1)) - } - - } else if (binding.contentMain.keyboard.inputTeamB.isFocused) { - if (binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - val string = binding.contentMain.keyboard.inputTeamB.text.toString() - binding.contentMain.keyboard.inputTeamB.setText(string.substring(0, string.length - 1)) - } - } - } - - binding.contentMain.keyboard.submit.setOnClickListener { - giveFocusToAIfNone() - - if (binding.contentMain.keyboard.inputTeamA.text.isNotEmpty() && binding.contentMain.keyboard.inputTeamB.text.isNotEmpty()) { - - history.logRound( - Round( - binding.contentMain.keyboard.inputTeamA.text.toString().toInt(), - binding.contentMain.keyboard.inputTeamB.text.toString().toInt() - ) - ) - - updateView() - - binding.contentMain.keyboard.inputTeamA.text.clear() - binding.contentMain.keyboard.inputTeamB.text.clear() - disableSubmitButton() - - binding.contentMain.scrollHistory.scrollViewHistory.fullScroll(ScrollView.FOCUS_DOWN) - } - } - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.menu_main, menu) menu.findItem(R.id.action_screenOn).isChecked = - this.getSharedPreferences("Settings", MODE_PRIVATE) - .getBoolean("Screen_On", false) + this.getSharedPreferences("Settings", MODE_PRIVATE).getBoolean("Screen_On", false) return true } @@ -345,14 +144,11 @@ class MainActivity : AppCompatActivity() { return when (item.itemId) { R.id.action_clear -> { val builder = AlertDialog.Builder(this) - builder.setMessage(getString(R.string.confirmClear)) - .setTitle(R.string.clear) - .setCancelable(false) - .setPositiveButton(getString(R.string.yes)) { dialog, _ -> + builder.setMessage(getString(R.string.confirmClear)).setTitle(R.string.clear) + .setCancelable(false).setPositiveButton(getString(R.string.yes)) { dialog, _ -> dialog.dismiss() clearAll() - } - .setNegativeButton(getString(R.string.no)) { dialog, _ -> + }.setNegativeButton(getString(R.string.no)) { dialog, _ -> dialog.cancel() } @@ -360,7 +156,7 @@ class MainActivity : AppCompatActivity() { true } R.id.action_undo -> { - undoLastRound() + historyListViewModel.revertLastRound() true } R.id.action_theme -> { @@ -380,59 +176,11 @@ class MainActivity : AppCompatActivity() { } } - private fun hideKeyboard() { - val imm: InputMethodManager = - getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(currentFocus!!.windowToken, 0) - } - - private fun giveFocusToAIfNone() { - if (!binding.contentMain.keyboard.inputTeamA.isFocused && !binding.contentMain.keyboard.inputTeamB.isFocused) { - binding.contentMain.keyboard.inputTeamA.requestFocus() - } - } - - private fun undoLastRound() { - history.revertLastRound() - updateView() - } - - private fun updateView() { - binding.contentMain.scoreA.text = history.getScoreA().toString() - binding.contentMain.scoreB.text = history.getScoreB().toString() - - binding.contentMain.scrollHistory.historyA?.text = history.getHistoryA() - binding.contentMain.scrollHistory.historyB?.text = history.getHistoryB() - } - private fun clearAll() { - binding.contentMain.scrollHistory.historyA?.text = "" - binding.contentMain.scrollHistory.historyB?.text = "" - binding.contentMain.keyboard.inputTeamA.text.clear() - binding.contentMain.keyboard.inputTeamB.text.clear() - binding.contentMain.scoreA.text = "0" - binding.contentMain.scoreB.text = "0" history.clearAll() } - private fun appendToFocusedInput(toAppend: Char) { - if (binding.contentMain.keyboard.inputTeamA.isFocused) { - binding.contentMain.keyboard.inputTeamA.text.append(toAppend) - } else if (binding.contentMain.keyboard.inputTeamB.isFocused) { - binding.contentMain.keyboard.inputTeamB.text.append(toAppend) - } - } - - private fun enableSubmitButton() { - binding.contentMain.keyboard.submit?.imageAlpha = 255 // 0 being transparent and 255 being opaque - binding.contentMain.keyboard.submit?.isEnabled = true - } - - private fun disableSubmitButton() { - binding.contentMain.keyboard.submit?.imageAlpha = 60 // 0 being transparent and 255 being opaque - binding.contentMain.keyboard.submit?.isEnabled = false - } private fun chooseThemeDialog() { @@ -444,8 +192,7 @@ class MainActivity : AppCompatActivity() { getString(R.string.android_default_text) ) - val checkedItem = - this.getSharedPreferences("Settings", MODE_PRIVATE).getInt("Theme", 2) + val checkedItem = this.getSharedPreferences("Settings", MODE_PRIVATE).getInt("Theme", 2) val prefs = this.getSharedPreferences("Settings", MODE_PRIVATE).edit() @@ -470,8 +217,7 @@ class MainActivity : AppCompatActivity() { builder.setTitle(getString(R.string.choose_language_text)) val languagesMap = mapOf( - getString(R.string.english) to "en", - getString(R.string.german) to "de" + getString(R.string.english) to "en", getString(R.string.german) to "de" ) val languagesDisplayKeys = languagesMap.keys.toTypedArray() diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/History.kt b/app/src/main/java/me/zobrist/tichucounter/domain/History.kt index a3e3c29..4affc00 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/History.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/History.kt @@ -11,7 +11,7 @@ class History { fun getScoreA(): Int { var tempScore = 0 scores.forEach { - tempScore += it.scoreA + tempScore += it.scoreA!! } return tempScore } @@ -19,7 +19,7 @@ class History { fun getScoreB(): Int { var tempScore = 0 scores.forEach { - tempScore += it.scoreB + tempScore += it.scoreB!! } return tempScore } diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/IntExtensions.kt b/app/src/main/java/me/zobrist/tichucounter/domain/IntExtensions.kt index 92eff66..a6c3784 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/IntExtensions.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/IntExtensions.kt @@ -1,9 +1,16 @@ package me.zobrist.tichucounter.domain +import kotlin.math.abs + + fun Int.isMultipleOf5(): Boolean { return (this % 5) == 0 } fun Int.isMultipleOf100(): Boolean { return (this % 100) == 0 +} + +fun Int.getAbsoluteDifference(other: Int): Int { + return abs(this - other) } \ No newline at end of file diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/Round.kt b/app/src/main/java/me/zobrist/tichucounter/domain/Round.kt index 6ec19b1..ca59968 100644 --- a/app/src/main/java/me/zobrist/tichucounter/domain/Round.kt +++ b/app/src/main/java/me/zobrist/tichucounter/domain/Round.kt @@ -2,36 +2,5 @@ package me.zobrist.tichucounter.domain import java.io.Serializable -class Round() : Serializable { - var scoreA: Int = 0 - var scoreB: Int = 0 - - constructor(score: Int, isScoreA: Boolean) : this() { - if (isScoreA) { - scoreA = score - scoreB = calculateOtherScore(scoreA) - } else { - scoreB = score - scoreA = calculateOtherScore(scoreB) - } - } - - constructor(scoreA: Int, scoreB: Int) : this() { - this.scoreA = scoreA - this.scoreB = scoreB - } - - fun calculateOtherScore(score: Int): Int { - if (score.isMultipleOf100() && score != 0) { - return 0 - } - if (score in 101..125) { - return 0 - (score % 100) - } - return 100 - (score % 100) - } - - fun isValidRound(): Boolean { - return (scoreA.isMultipleOf5()) && scoreB.isMultipleOf5() && (scoreA + scoreB).isMultipleOf100() - } +data class Round(var scoreA: Int?, var scoreB: Int?) : Serializable { } \ No newline at end of file diff --git a/app/src/main/java/me/zobrist/tichucounter/domain/Tichu.kt b/app/src/main/java/me/zobrist/tichucounter/domain/Tichu.kt new file mode 100644 index 0000000..3561f99 --- /dev/null +++ b/app/src/main/java/me/zobrist/tichucounter/domain/Tichu.kt @@ -0,0 +1,27 @@ +package me.zobrist.tichucounter.domain + +class Tichu { + + fun calculateOtherScore(score: Int?): Int? { + if (score == null) { + return null + } + if (!score.isMultipleOf5()) { + return null + } + if (score.isMultipleOf100() && score != 0) { + return 0 + } + if (score in 101..125) { + return 0 - (score % 100) + } + return 100 - (score % 100) + } + + fun isValidRound(round: Round): Boolean { + if (round.scoreA == null || round.scoreB == null) { + return false + } + return (round.scoreA!!.isMultipleOf5()) && round.scoreB!!.isMultipleOf5() && (round.scoreA!! + round.scoreB!!).isMultipleOf100() + } +} \ No newline at end of file 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 b4f91c3..0bc781b 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryList.kt @@ -1,32 +1,58 @@ package me.zobrist.tichucounter.fragments -import androidx.lifecycle.ViewModelProvider +import android.content.Context import android.os.Bundle -import androidx.fragment.app.Fragment +import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import me.zobrist.tichucounter.R +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() { + private var _binding: FragmentHistoryListBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + companion object { fun newInstance() = HistoryList() } - private lateinit var viewModel: HistoryListViewModel + private val viewModel: HistoryListViewModel by activityViewModels() override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_history_list, container, false) + _binding = FragmentHistoryListBinding.inflate(inflater, container, false) + return binding.root } - override fun onActivityCreated(savedInstanceState: Bundle?) { + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProvider(this).get(HistoryListViewModel::class.java) - // TODO: Use the ViewModel + + viewModel.historyA.observe(viewLifecycleOwner, Observer { text -> + binding.historyA.text = text + }) + + viewModel.historyB.observe(viewLifecycleOwner, Observer { text -> + binding.historyB.text = text + }) } } \ 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 fd98b06..3f5950c 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/HistoryListViewModel.kt @@ -1,7 +1,100 @@ package me.zobrist.tichucounter.fragments +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import me.zobrist.tichucounter.domain.Round class HistoryListViewModel : ViewModel() { // TODO: Implement the ViewModel -} \ No newline at end of file + private var scores = ArrayList() + + private val _totalScoreA: MutableLiveData = MutableLiveData() + private val _totalScoreB: MutableLiveData = MutableLiveData() + private val _historyA: MutableLiveData = MutableLiveData() + private val _historyB: MutableLiveData = MutableLiveData() + + + + val totalScoreA: LiveData + get() { + return _totalScoreA + } + + val totalScoreB: LiveData + get() { + return _totalScoreB + } + + val historyA: LiveData + get() { + return _historyA + } + + val historyB: LiveData + get() { + return _historyB + } + + private fun getScoreA() { + var tempScore = 0 + scores.forEach { + tempScore += it.scoreA!! + } + _totalScoreA.value = tempScore + } + + private fun getScoreB() { + var tempScore = 0 + scores.forEach { + tempScore += it.scoreB!! + } + _totalScoreB.value = tempScore + } + + private fun getHistoryA() { + var tempHistory = String() + scores.forEach { + tempHistory += it.scoreA.toString() + "\n" + } + _historyA.value = tempHistory + } + + private fun getHistoryB() { + var tempHistory = String() + scores.forEach { + tempHistory += it.scoreB.toString() + "\n" + } + _historyB.value = tempHistory + } + + fun logRound(round: Round) { + scores.add(round.copy()) + getHistoryA() + getHistoryB() + getScoreA() + getScoreB() + } + + fun revertLastRound() { + if (scores.isNotEmpty()) { + scores.removeAt(scores.size - 1) + } + getHistoryA() + getHistoryB() + getScoreA() + getScoreB() + } + + fun clearAll() { + scores.clear() + } + + 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 8348c18..6c44be7 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/Keyboard.kt @@ -1,35 +1,265 @@ package me.zobrist.tichucounter.fragments -import androidx.lifecycle.ViewModelProvider +import android.content.Context import android.os.Bundle -import androidx.fragment.app.Fragment +import android.text.InputType import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.ScrollView -import androidx.core.widget.doOnTextChanged -import me.zobrist.tichucounter.R -import me.zobrist.tichucounter.domain.Round +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.FragmentKeyboardBinding class Keyboard : Fragment() { + private var _binding: FragmentKeyboardBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + private var unhandledNegation: Boolean = false + companion object { fun newInstance() = Keyboard() } - private lateinit var viewModel: KeyboardViewModel + private val viewModel: KeyboardViewModel by activityViewModels() override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? ): View? { - return inflater.inflate(R.layout.fragment_keyboard, container, false) + _binding = FragmentKeyboardBinding.inflate(inflater, container, false) + return binding.root } - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel = ViewModelProvider(this).get(KeyboardViewModel::class.java) - // TODO: Use the ViewModel + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + binding.inputTeamA.setRawInputType(InputType.TYPE_NULL) + binding.inputTeamB.setRawInputType(InputType.TYPE_NULL) + binding.inputTeamA.requestFocus() + + disableSubmitButton() + + viewModel.enableSubmitButton.observe(viewLifecycleOwner, Observer { enabled -> + if (enabled) enableSubmitButton() else disableSubmitButton() + }) + + viewModel.scoreA.observe(viewLifecycleOwner, Observer { value -> + updateScore(binding.inputTeamA, value) + }) + + viewModel.scoreB.observe(viewLifecycleOwner, Observer { value -> + updateScore(binding.inputTeamB, value) + }) + + setListeners() + + } + + private fun setListeners() { + binding.inputTeamA.setOnFocusChangeListener { _, b -> + if (b) { + hideKeyboard() + } + } + + binding.inputTeamB.setOnFocusChangeListener { _, b -> + if (b) { + hideKeyboard() + } + } + + binding.buttonAdd100.setOnClickListener { + var value = getActiveValue() + + value = if (value != null) { + value + 100 + } else { + 100 + } + setActiveValue(value) + } + + binding.buttonSub100.setOnClickListener { + var value = getActiveValue() + + value = if (value != null) { + value!! - 100 + } else { + -100 + } + setActiveValue(value) + } + + binding.button0.setOnClickListener { + appendToFocusedScore(0) + } + + binding.button1.setOnClickListener { + appendToFocusedScore(1) + } + + binding.button2.setOnClickListener { + appendToFocusedScore(2) + } + + binding.button3.setOnClickListener { + appendToFocusedScore(3) + } + + binding.button4.setOnClickListener { + appendToFocusedScore(4) + } + + binding.button5.setOnClickListener { + appendToFocusedScore(5) + } + + binding.button6.setOnClickListener { + appendToFocusedScore(6) + } + + binding.button7.setOnClickListener { + appendToFocusedScore(7) + } + + binding.button8.setOnClickListener { + appendToFocusedScore(8) + } + + binding.button9.setOnClickListener { + appendToFocusedScore(9) + } + + binding.buttonInv.setOnClickListener { + var value = getActiveValue() + + if (value == null) { + if (getActiveText() == "-") { + setActiveText("") + unhandledNegation = false + } else { + setActiveText("-") + unhandledNegation = true + } + } else { + value = value?.times(-1) + setActiveValue(value) + } + } + + binding.buttonBack.setOnClickListener { + var value = getActiveValue() + + if (value != null) { + value = try { + value.toString().dropLast(1).toInt() + } catch (e: Exception) { + null + } + } + setActiveValue(value) + } + + binding.submit.setOnClickListener { + viewModel.submitButtonClicked() + } + } + + private fun hideKeyboard() { + val imm = context?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? + imm?.hideSoftInputFromWindow(view?.windowToken, 0) + } + + private fun giveFocusToAIfNone() { + if (!binding.inputTeamA.isFocused && !binding.inputTeamB.isFocused) { + binding.inputTeamA.requestFocus() + } + } + + private fun updateScore(field: EditText, score: Int?) { + if (score == null) { + field.setText("") + return + } + + var text = try { + score.toString() + } catch (e: Exception) { + "" + } + field.setText(text) + } + + private fun appendToFocusedScore(toAppend: Int) { + var value = getActiveValue() + + if (value != null) { + value = value.times(10) + value = value.plus(toAppend) + } else { + value = toAppend + if (unhandledNegation) { + value = value.times(-1) + unhandledNegation = false + } + } + setActiveValue(value) + } + + private fun getActiveValue(): Int? { + giveFocusToAIfNone() + if (binding.inputTeamA.isFocused) { + return viewModel.scoreA.value + } + return viewModel.scoreB.value + } + + private fun setActiveValue(value: Int?) { + giveFocusToAIfNone() + if (binding.inputTeamA.isFocused) { + viewModel.setScoreA(value) + } else { + viewModel.setScoreB(value) + } + } + + private fun getActiveText(): String { + giveFocusToAIfNone() + if (binding.inputTeamA.isFocused) { + return binding.inputTeamA.text.toString() + } + return binding.inputTeamB.text.toString() + } + + private fun setActiveText(value: String) { + giveFocusToAIfNone() + if (binding.inputTeamA.isFocused) { + binding.inputTeamA.setText(value) + } else { + binding.inputTeamB.setText(value) + } + } + + private fun enableSubmitButton() { + binding.submit.imageAlpha = 255 // 0 being transparent and 255 being opaque + binding.submit.isEnabled = true + } + + private fun disableSubmitButton() { + binding.submit.imageAlpha = 60 // 0 being transparent and 255 being opaque + binding.submit.isEnabled = false } } \ No newline at end of file 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 debc166..bbb3718 100644 --- a/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt +++ b/app/src/main/java/me/zobrist/tichucounter/fragments/KeyboardViewModel.kt @@ -1,7 +1,50 @@ package me.zobrist.tichucounter.fragments +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() { - // TODO: Implement the ViewModel +class KeyboardViewModel: ViewModel() { + private val _scoreA: MutableLiveData = MutableLiveData() + private val _scoreB: MutableLiveData = MutableLiveData() + private val _enableSubmitButton: MutableLiveData = MutableLiveData() + private val _submitButtonClicked: MutableLiveData = MutableLiveData() + + val scoreA: LiveData + get() { + return _scoreA + } + + val scoreB: LiveData + get() { + return _scoreB + } + + val enableSubmitButton: LiveData + get() { + return _enableSubmitButton + } + + val submitButtonClicked: LiveData + get() { + return _submitButtonClicked + } + + fun setScoreA(score: Int?) { + _scoreA.value = score + } + + fun setScoreB(score: Int?) { + _scoreB.value = score + } + + fun setSubmitButtonEnable(enabled: Boolean) { + _enableSubmitButton.value = enabled + } + + fun submitButtonClicked() { + _submitButtonClicked.value = true + } } \ 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 index 9ebd198..786dfd8 100644 --- a/app/src/main/java/me/zobrist/tichucounter/framework/TichuCounterApplication.kt +++ b/app/src/main/java/me/zobrist/tichucounter/framework/TichuCounterApplication.kt @@ -4,6 +4,4 @@ import android.app.Application import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp -class TichuCounterApplication : Application() { - -} +class TichuCounterApplication : Application() diff --git a/app/src/main/res/layout-land/content_main.xml b/app/src/main/res/layout-land/content_main.xml index de2990b..9d900d7 100644 --- a/app/src/main/res/layout-land/content_main.xml +++ b/app/src/main/res/layout-land/content_main.xml @@ -1,6 +1,7 @@ - + android:clickable="false" + tools:layout="@layout/fragment_history_list" /> - + app:layout_constraintStart_toStartOf="parent" + tools:layout="@layout/fragment_keyboard" /> \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 9d33d44..17a7484 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -87,22 +87,23 @@ android:layout_height="1dp" android:layout_weight="1" android:background="?android:attr/listDivider" - app:layout_constraintTop_toBottomOf="@id/viewScore" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/viewScore" tools:layout_editor_absoluteY="50dp" /> - + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/dividerTop" + tools:layout="@layout/fragment_history_list" /> - - - + app:layout_constraintStart_toStartOf="parent" + tools:layout="@layout/fragment_keyboard" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_history_list.xml b/app/src/main/res/layout/fragment_history_list.xml index 8a1071b..4ead800 100644 --- a/app/src/main/res/layout/fragment_history_list.xml +++ b/app/src/main/res/layout/fragment_history_list.xml @@ -1,6 +1,5 @@ - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_keyboard.xml b/app/src/main/res/layout/fragment_keyboard.xml index 886ae8e..fd33032 100644 --- a/app/src/main/res/layout/fragment_keyboard.xml +++ b/app/src/main/res/layout/fragment_keyboard.xml @@ -1,9 +1,9 @@