Mobile App Dev 2021W: Tutorial 6

From Soma-notes
Jump to navigation Jump to search

This tutorial is due on March 19, 2021 via cuLearn. Please use this template for your solutions.

Tasks

  1. 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?
  2. What is the flow of control of MainActivity? How does this flow of control compare to that of ContentView in Converter2 from Tutorial 2?
  3. 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.
  4. Add a conversion for miles to kilometers. How difficult was this compared to modifying Converter2?
  5. The setText on line 38 often doesn't produce visible output. What could you do so the message is displayed until something is typed?
  6. Add a second menu to the bottom of the screen, identical to the one at the top. How hard was this to do?

Code

Converter2A.zip

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>

Solutions

Tutorial 6 Solutions