Mobile App Dev 2022W: Assignment 1

From Soma-notes
Revision as of 02:27, 27 January 2022 by Soma (talk | contribs)

This assignment is not yet finalized. You may begin work but you should check back once it is finalized.

Please answer all of the following questions in the supplied template. Your uploaded file should be named "comp1601-assign1-MCOname.txt" where MCOname is your MyCarletonOne username (i.e., the username you use to login to Brightspace) and it should be a UNIX text file (LF line endings).

The questions are based on textanalyzer-2, which is an enhanced version of textanalyzer-1 from Tutorial 2. There are seven questions (some of which have multiple parts) worth 20 points total.

Do not turn in modified applications. Instead, when answering code writing questions, include code snippets and explain how they should be used to modify the application. Use complete sentences when answering. Be sure to list collaborators and outside sources that you used.

Submit your answers via Brightspace by February 3, 2021 by 11:59 PM.

Questions

  1. [4] Questions about AnalysisResult View (lines 34-47):
    1. [1] What is the purpose of the Spacer() calls at the beginning and end of the AnalysisResult body?
    2. [1] What does the result area say when the app starts?
    3. [2] Can you ever make it display the the initial message after you've selected something from the analysis menu? Why or why not?
  2. [1] Why doesn't the AppTitle view use a @Binding decorator for title?
  3. [2] How often are the analysis mode functions called (at minimum)? How do you know?
  4. [2] What happens if we add a line analysisMode = "Count" between lines 13 and 14? Why?
  5. [7] Questions about ModeMenu View (lines 49-65):
    1. [1] What is the value of availModes?
    2. [2] If we replace lines 62-66 with the following for loop, Xcode will report an error. What error will it report? Why doesn't the ForEach generate the same error?
                  for mode in availModes {
                      Button(mode, action: {
                          analysis = mode
                      })
                  }
      
    3. [2] Can the value of availModes change during the execution of the program? Why or why not?
    4. [2] How could you add a menu option "Other" that set the analysisMode to "Other" without changing the analysis dictionary? What would this new menu option do?
  6. [2] How could you change the analysis dictionary so it doesn't use any more closures (anonymous functions)? Your changes should preserve the program's functionality.
  7. [2] How could you add a new analysis mode "Pets Count" that counts the total number of occurrences of the pet names Roshi, Tab, and Shift (and any other ones you want to add)? Unlike "Pets Mentioned", this one should count duplicates, e.g., "Roshi Roshi" should return a count of 2, not 1.

Code: textanalyzer-2 ContentView.swift

//
//  ContentView.swift for textanalyzer-2
//
//  Created by Anil Somayaji on 2022-01-26.
//

import SwiftUI

struct ContentView: View {
    @State private var t = ""
    @State private var analysisMode = "None"
    var body: some View {
        VStack{
            ModeMenu(analysisMode: $analysisMode)
            AppTitle(title: "Text Analyzer")
            TextField("Enter Text", text: $t).padding()
            AnalysisResult(mode: $analysisMode,
                           userInput: $t)
            Spacer()
        }
    }
}

struct AppTitle: View {
    var title: String
    
    var body: some View {
        Spacer()
        Text(title).font(.title).bold().padding()
        Spacer()
    }
}

struct AnalysisResult: View {
    @Binding var mode: String
    @Binding var userInput: String
    
    var body: some View {
        Spacer()
        if let analysisFunc = analysis[mode] {
            Text(mode + ": " + analysisFunc(userInput))
        } else {
            Text("Please Select a Mode")
        }
        Spacer()
    }
}

struct ModeMenu: View {
    @Binding var analysisMode: String

    var body: some View {
        let availModes = [String](analysis.keys)

        Menu("Analysis menu") {
            ForEach(availModes, id: \.self) {
                mode in
                Button(mode, action: {
                    analysisMode = mode
                })
            }
        }

    }
}

func countUpper(s: String) -> String {
    var count = 0
    let upperCase: Set<Character> =
    ["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)) {
            count += 1
        }
    }
    
    return String(count)
}

func countPetsMentioned(s: String) -> String {
    var count = 0
    let pets = ["Roshi", "Tab", "Shift"]
    
    for p in pets {
        if (s.contains(p)) {
            count += 1
        }
    }
    return String(count)
}

let analysis: [String: (String) -> String] = [
    "Count": {s in return String(s.count)},
    "Empty": {s in return (s == "") ? "Yes" : "No"},
    "Upper Case": countUpper,
    "Pets Mentioned": countPetsMentioned
]

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}