Mobile App Dev 2021W: Tutorial 6
This tutorial is due on March 19, 2021 via cuLearn. Please use this template for your solutions.
Tasks
- Compare the Kotlin and Swift versions of Conversions. How does the Converter class differ? How does the conversions dictionary/map differ? And, how are they the same? What does this tell you about the similarity and differences between the languages?
- What is the flow of control of MainActivity? How does this flow of control compare to that of ContentView in Converter2 from Tutorial 2?
- At the top of MainActivity (lines 15-18) four properties are declared. Are all of these used in a meaningful way? Explain how each is used.
- Add a conversion for miles to kilometers. How difficult was this compared to modifying Converter2?
- The setText on line 38 often doesn't produce visible output. What could you do so the message is displayed until something is typed?
- Add a second menu to the bottom of the screen, identical to the one at the top. How hard was this to do?
Code
Conversions.kt
package carleton.comp1601.converter_2a
// Conversions.kt
class Converter {
var convFrom = "From Type"
var convTo = "To Type"
var convert: (from: Double) -> Double?
fun formatConversion(from: Double): String {
val to = this.convert(from)
if (to != null) {
return "${from} ${this.convFrom} is ${to} ${this.convTo}."
} else {
return "Converting ${from} ${convFrom} to ${this.convTo} failed."
}
}
constructor(from: String, to: String, f: (from: Double) -> Double?) {
this.convFrom = from
this.convTo = to
this.convert = f
}
}
fun InToCM(inch: Double): Double? {
val cm = 2.54 * inch
return cm
}
val conversions = mapOf(
"F to C" to Converter("Farenheit", "Celsius",
{F -> ((F - 32.0)*(5.0/9.0))}),
"C to F" to Converter("Celsius","Farenheit",
{((9.0/5.0)*it + 32.0)}),
"km to mi" to Converter("kilometers", "miles",
fun (k: Double): Double? {
val m = k * 0.6213712
return m
}),
"inch to cm" to Converter("inches", "centimeters", ::InToCM))
MainActivity.kt
package carleton.comp1601.converter_2a
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
class MainActivity : AppCompatActivity() {
private lateinit var result: TextView
private lateinit var menuButton: Button
private lateinit var fromStringW: EditText
private var conv: Converter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
menuButton = findViewById(R.id.convMenu)
fromStringW = findViewById(R.id.fromString)
result = findViewById(R.id.result)
fromStringW.addTextChangedListener(watcher)
fromStringW.setVisibility(View.INVISIBLE);
}
fun onMenuItemClick(choice: MenuItem): Boolean {
val convName = choice.getTitle()
val c = conversions[convName]
if (c != null) {
conv = c
result.setText("You picked ${convName}")
fromStringW.setText("")
} else {
result.setText("Invalid Menu Selection")
}
fromStringW.setVisibility(View.VISIBLE);
return true
}
// https://stackoverflow.com/questions/15580111/
fun showMenu(v: View) {
val menu = PopupMenu(this, v)
for (s in conversions.keys) {
menu.menu.add(s)
}
menu.setOnMenuItemClickListener(::onMenuItemClick)
menu.show()
}
private val watcher = object : TextWatcher {
override fun afterTextChanged(s: Editable) {
val fromS = fromStringW.getText().toString()
var from = fromS.toDoubleOrNull()
if (from == null) {
result.setText("Please enter a number to convert.")
} else {
val c = conv
if (c != null) {
result.setText(c.formatConversion(from))
} else {
result.setText("No conversion selected.")
}
}
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
tools:context=".MainActivity">
<Button
android:id="@+id/convMenu"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showMenu"
android:text="Conversions Menu"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
android:textColor="@color/black"
app:backgroundTint="@color/white"
app:layout_constraintBottom_toTopOf="@+id/fromString"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/fromString"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
app:layout_constraintBottom_toTopOf="@+id/result"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/convMenu" />
<TextView
android:id="@+id/result"
android:layout_width="418dp"
android:layout_height="341dp"
android:padding="10dp"
android:text="Please select a conversion type from the menu above."
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fromString" />
</androidx.constraintlayout.widget.ConstraintLayout>