I dabble a bit in scripting so I wanted to give Android a go and went with an online beginner course for it.
The first “real” app after all the mandatory beginner stuff was a calculator and a very limited one too.
The rules are it’s going to do basic calculations on two numbers and nothing more, it will be a bit hard to maintain and there will be a couple of bugs too.
I figured fine, but the way we implemented the thing just feels like a clusterfuck. Is all of this logic necessary for basically doing one arithmetic operation on two variables? I feel like there is a more elegant solution to this.
Here is the UI (not pasting in or hard coding strings, colors and such):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvInput"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#efefef"
android:gravity="end|bottom"
android:padding="10dp"
android:text="@string/calc_text"
android:textSize="48sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btnSeven"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_7" />
<Button
android:id="@+id/btnEight"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_8" />
<Button
android:id="@+id/btnNine"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_9" />
<Button
android:id="@+id/btnDivide"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onOperator"
android:text="@string/Divide" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btnFour"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_4" />
<Button
android:id="@+id/btnFive"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_5" />
<Button
android:id="@+id/btnSix"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_6" />
<Button
android:id="@+id/btnMultiply"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onOperator"
android:text="@string/Multiply" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btnOne"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_1" />
<Button
android:id="@+id/btnTwo"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_2" />
<Button
android:id="@+id/btnThree"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="@string/_3" />
<Button
android:id="@+id/btnSubtract"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onOperator"
android:text="@string/Subtract" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/btnDot"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDecimalPoint"
android:text="." />
<Button
android:id="@+id/btnZero"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onDigit"
android:text="0" />
<Button
android:id="@+id/btnClr"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onClear"
android:text="@string/clr" />
<Button
android:id="@+id/btnAdd"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onOperator"
android:text="@string/Add" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1">
<Button
android:id="@+id/Equal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_margin="2dp"
android:layout_weight="1"
android:onClick="onEqual"
android:text="@string/Equal" />
</LinearLayout>
</LinearLayout>
and then the implementation:
package com.example.calculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import java.lang.ArithmeticException
class MainActivity : AppCompatActivity() {
private var tvInput: TextView? = null
private var lastNumeric: Boolean = false
private var lastDot: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvInput = findViewById(R.id.tvInput)
}
fun onDigit(view: View) {
tvInput?.append((view as Button).text)
lastNumeric = true
lastDot = false
}
fun onClear(view: View) {
tvInput?.text = ""
}
fun onDecimalPoint(view: View) {
if (lastNumeric && !lastDot) {
tvInput?.append(".")
lastNumeric = false
lastDot = true
}
}
fun onOperator(view: View) {
tvInput?.text?.let {
if (lastNumeric && !isOperatorAdded(it.toString())) {
tvInput?.append((view as Button).text)
lastNumeric = false
lastDot = false
}
}
}
fun onEqual(view: View) {
if (lastNumeric) {
var tvValue = tvInput?.text.toString()
var prefix = ""
try {
if (tvValue.startsWith("-")) {
prefix = "-"
tvValue = tvValue.substring(1)
}
if (tvValue.contains("-")) {
var splitValue = tvValue.split("-")
var one = splitValue[0]
var two = splitValue[1]
if (prefix.isNotEmpty())
one = prefix + one
tvInput?.text = removeZeroAfterDot((one.toDouble() - two.toDouble()).toString())
} else if (tvValue.contains("+")) {
var splitValue = tvValue.split("+")
var one = splitValue[0]
var two = splitValue[1]
if (prefix.isNotEmpty())
one = prefix + one
tvInput?.text = removeZeroAfterDot((one.toDouble() + two.toDouble()).toString())
} else if (tvValue.contains("*")) {
var splitValue = tvValue.split("*")
var one = splitValue[0]
var two = splitValue[1]
if (prefix.isNotEmpty())
one = prefix + one
tvInput?.text = removeZeroAfterDot((one.toDouble() * two.toDouble()).toString())
} else if (tvValue.contains("/")) {
var splitValue = tvValue.split("/")
var one = splitValue[0]
var two = splitValue[1]
if (prefix.isNotEmpty())
one = prefix + one
tvInput?.text = removeZeroAfterDot((one.toDouble() / two.toDouble()).toString())
}
} catch (e: ArithmeticException) {
e.printStackTrace()
}
}
}
private fun removeZeroAfterDot(result: String): String {
var value = result
if (result.contains(".0"))
value = result.substring(0, result.length - 2)
return value
}
private fun isOperatorAdded(value: String): Boolean {
return if (value.startsWith("-")) {
false
} else {
value.contains("/") || value.contains("*") || value.contains("+") || value.contains("-")
}
}
}