Difference between revisions of "Mobile App Dev 2022W: Tutorial 6"

From Soma-notes
Jump to navigation Jump to search
Line 7: Line 7:
* Install [https://developer.android.com/studio/ Android Studio].  While you can run the version for MacOS, you should probably download and run it on the fastest computer you have access to.
* Install [https://developer.android.com/studio/ Android Studio].  While you can run the version for MacOS, you should probably download and run it on the fastest computer you have access to.
* Create a new Phone & Tablet project, selecting the "Empty Activity" template.  Select "Kotlin" as the language and API 21, Android 5.0 as the minimum SDK.
* Create a new Phone & Tablet project, selecting the "Empty Activity" template.  Select "Kotlin" as the language and API 21, Android 5.0 as the minimum SDK.
* Replace the contents of [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/MainActivity.kt MainActivity.kt] (under app->java) with the version below. Be sure to copy the raw source rather than the syntax highlighted version below.
* Replace the contents of [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/MainActivity.kt MainActivity.kt] (under app->java) with the version below. Be sure to copy the raw source rather than the syntax highlighted version below. '''Preserve the first line that says "package", however, as that depends on the precise name you gave your application.'''
* Replace the contents of [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/activity_main.xml activity_main.xml] (under app->res->layout) with the version below.  Select the "Code" view (rather than "Design") so you can see the raw XML.  You may have save the file below locally as your browser may try to interpret the XML.
* Replace the contents of [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/activity_main.xml activity_main.xml] (under app->res->layout) with the version below.  Select the "Code" view (rather than "Design") so you can see the raw XML.  You may have save the file below locally as your browser may try to interpret the XML.
* Add the following lines to themes.xml (in app->res->values->themes), just below the last item:
* Add the following lines to themes.xml (in app->res->values->themes), just below the last item:

Revision as of 23:51, 15 February 2022

This tutorial is still in development.

In this tutorial you will be playing with textanalyzer-5, which implements the same text analyzer functionality as Tutorial 5's textanalyzer-3. This version, however, is an Android app.

Getting Started

  • Install Android Studio. While you can run the version for MacOS, you should probably download and run it on the fastest computer you have access to.
  • Create a new Phone & Tablet project, selecting the "Empty Activity" template. Select "Kotlin" as the language and API 21, Android 5.0 as the minimum SDK.
  • Replace the contents of MainActivity.kt (under app->java) with the version below. Be sure to copy the raw source rather than the syntax highlighted version below. Preserve the first line that says "package", however, as that depends on the precise name you gave your application.
  • Replace the contents of activity_main.xml (under app->res->layout) with the version below. Select the "Code" view (rather than "Design") so you can see the raw XML. You may have save the file below locally as your browser may try to interpret the XML.
  • Add the following lines to themes.xml (in app->res->values->themes), just below the last item:
  <item name="windowActionBar">false</item>
  <item name="windowNoTitle">true</item>
  • Create a new Android simulator using the Device Manager. We suggest a Pixel 3a running API 31, but other devices should work fine.
  • Save the project and run it!


textanalyzer-5 Code

MainActivity.kt

package carleton.comp1601.textanalyzer5

import androidx.appcompat.app.AppCompatActivity
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.widget.PopupMenu
import kotlin.reflect.KFunction1

class MainActivity : AppCompatActivity() {
    private lateinit var t: EditText
    private lateinit var analysisResult: TextView

    var analysisMode = "None"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        t = findViewById(R.id.t)
        t.addTextChangedListener(twatcher)

        analysisResult = findViewById(R.id.analysisResult)
        updateAnalysis()
    }

    fun onMenuItemClick(choice: MenuItem): Boolean {
        analysisMode = choice.getTitle() as String
        updateAnalysis()
        return true
    }

    // https://stackoverflow.com/questions/15580111/
    fun showMenu(v: View) {
        val menu = PopupMenu(this, v)

        for (s in analysis.keys) {
            menu.menu.add(s)
        }

        menu.setOnMenuItemClickListener(::onMenuItemClick)
        menu.show()
    }

    private val twatcher = object : TextWatcher {
        override fun afterTextChanged(s: Editable) {
            updateAnalysis()
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }
    }

    fun updateAnalysis() {
        val inputText: Editable? = t.text

        if (inputText != null)  {
            val analysisFunc: KFunction1<String, String>? = analysis[analysisMode]
            if (analysisFunc != null)  {
                val r = analysisFunc(inputText.toString())
                analysisResult.setText(analysisMode + ": " + r)
            } else {
                analysisResult.setText("Please choose an analysis mode.")
            }
        }
    }
}

fun countUpper(s: String): String {
    var count = 0
    val upperCase = setOf("A","B","C","D","E","F","G","H","I","J","K","L","M",
            "N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
    for (c in s) {
        if (upperCase.contains(c.toString())) {
            count += 1
        }
    }
    return count.toString()
}

fun countCharacters(s: String): String {
    val charcount = s.length
    return charcount.toString()
}

val analysis: MutableMap<String, KFunction1<String, String>> = mutableMapOf(
    "Count" to ::countCharacters,
    "Upper Case" to ::countUpper
)

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/analysisMenuButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="26dp"
        android:onClick="showMenu"
        android:text="Analysis Mode"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/appTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Text Analyzer"
        android:textAppearance="@style/TextAppearance.AppCompat.Display2"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/analysisMenuButton"
        app:layout_constraintBottom_toTopOf="@id/t"
        />

    <EditText
        android:id="@+id/t"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="20"
        android:hint="Enter Text"
        android:inputType="text"
        android:minHeight="48dp"
        android:textAppearance="@style/TextAppearance.AppCompat.Body2"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/analysisResult"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Result Area"
        android:textAppearance="@style/TextAppearance.AppCompat.Medium"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/t"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>