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

From Soma-notes
No edit summary
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''This tutorial is still in development.'''
In this tutorial you will be playing with [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5 textanalyzer-5], which implements the same text analyzer functionality as [[Mobile App Dev 2022W: Tutorial 5|Tutorial 5's textanalyzer-3]].  This version, however, is an Android app.
In this tutorial you will be playing with [https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5 textanalyzer-5], which implements the same text analyzer functionality as [[Mobile App Dev 2022W: Tutorial 5|Tutorial 5's textanalyzer-3]].  This version, however, is an Android app.


==Getting Started==
==Getting Started==


# 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:
   <item name="windowActionBar">false</item>
   <item name="windowActionBar">false</item>
   <item name="windowNoTitle">true</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.
* 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!
* Save the project and run it!
 
 
<!---
==Key Concepts & APIs==
 
* [https://developer.apple.com/library/archive/documentation/General/Conceptual/Devpedia-CocoaApp/Storyboard.html#//apple_ref/doc/uid/TP40009071-CH99-SW1 Storyboard introduction].
* [https://developer.apple.com/tutorials/app-dev-training/creating-a-storyboard-app Creating a Storyboard App (tutorial)]
 
While there are web pages on UIKit and Storyboard in Apple's main documentation websites (as seen above), today the clear emphasis is on SwiftUI and it is much harder to find specific documentation on these older technologies.  So I mostly relied on other sources.
 
[https://www.appcoda.com Appcoda] has a lot of valuable resources on iOS UIKit.  I finally figured out how to do menus through [https://www.appcoda.com/colorpicker-datepicker/ this article by Gabriel Theodoropoulos on UIKit additions in iOS 14], and I found [https://www.appcoda.com/auto-layout-guide/ Simon Ng's introduction to Storyboard layouts] very helpful.


==Questions==
==Questions==


# Why are we using a class (on line 10) rather than a struct?
# What is the Kotlin equivalent of let?
# How are the @IBOutlet variables (lines 12-15) related to the contents of Main.storyboard?  What about the @IBAction function (line 59)?
# How does Kotlin handle variables that could be null?  How does this compare to Swift's handling of nil?
# What does updateAnalysis do?  Why are there so many calls to it?  What is the corresponding code in textanalyzer-2?
# How similar are Kotlin and Swift function definitions?  What about their declaration of dictionaries and sets?
# What does setupAnalysisMenu() do?  What is the corresponding code for this in textanalyzer-2?
# What is the :: for?  Is something similar used in Swift?
# How do the Storyboard constraints determine the app's layout?  Specifically, why is the menu at the top, the results at the bottom, and the text input in the center of the screen?
# How is the layout XML connected with Kotlin code?  Specifically, what are the two ways they are integrated in this program?  Howe do they compare with how Swift code and Storyboard layouts are connected on iOS?
# What is the role of the twatcher object?  What is the equivalent in iOS Storyboard programs?  What about SwiftUI?


==Tasks==
==Tasks==
Line 38: Line 26:
# Add the Empty and Pets Mentioned actions as they were in textanalyzer-2.
# Add the Empty and Pets Mentioned actions as they were in textanalyzer-2.
# Add a menu item "None" that sets the analysis mode to "None".  When selected, the result area should show "Please choose an analysis mode."  (This message should appear without you changing any part of the code except for the part determining the contents of the menu.)
# Add a menu item "None" that sets the analysis mode to "None".  When selected, the result area should show "Please choose an analysis mode."  (This message should appear without you changing any part of the code except for the part determining the contents of the menu.)
# Make the title of the app "Text Analyzer 4" and make the text non-bold (while keeping the same font size).
# Make the title of the app "Text Analyzer 5" and make the text non-bold (while keeping the same font size).
# Put the results area in the center of the screen and the text input area just below it (thus swapping the position of the two).  Make sure your layout works with different phone sizes and when the phone is rotated.
# Put the results area in the center of the screen and the text input area just below it (thus swapping the position of the two).  Make sure your layout works with different phone sizes and when the phone is rotated.
 
# Change the button and status bar background color of the app from purple to anything else.
-->


==[https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/ textanalyzer-5 Code]==
==[https://homeostasis.scs.carleton.ca/~soma/mad-2022w/code/textanalyzer-5/ textanalyzer-5 Code]==

Latest revision as of 18:09, 16 February 2022

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!

Questions

  1. What is the Kotlin equivalent of let?
  2. How does Kotlin handle variables that could be null? How does this compare to Swift's handling of nil?
  3. How similar are Kotlin and Swift function definitions? What about their declaration of dictionaries and sets?
  4. What is the :: for? Is something similar used in Swift?
  5. How is the layout XML connected with Kotlin code? Specifically, what are the two ways they are integrated in this program? Howe do they compare with how Swift code and Storyboard layouts are connected on iOS?
  6. What is the role of the twatcher object? What is the equivalent in iOS Storyboard programs? What about SwiftUI?

Tasks

  1. Add the Empty and Pets Mentioned actions as they were in textanalyzer-2.
  2. Add a menu item "None" that sets the analysis mode to "None". When selected, the result area should show "Please choose an analysis mode." (This message should appear without you changing any part of the code except for the part determining the contents of the menu.)
  3. Make the title of the app "Text Analyzer 5" and make the text non-bold (while keeping the same font size).
  4. Put the results area in the center of the screen and the text input area just below it (thus swapping the position of the two). Make sure your layout works with different phone sizes and when the phone is rotated.
  5. Change the button and status bar background color of the app from purple to anything else.

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>