Mobile App Dev 2021W: Tutorial 2

From Soma-notes
Revision as of 14:03, 24 January 2021 by Soma (talk | contribs)
Jump to navigation Jump to search

This tutorial is still being developed.

In this tutorial you'll be playing with Convert2Cmd and Converter2. Convert2Cmd and Converter2 both make use of the unit converters defined in Converter.swift; Convert2Cmd provides a simple command line, menu-based interface to the converters, while Converter2 uses them in a simple SwiftUI-based iOS application. By studying two interfaces for the same functionality, you can see how SwiftUI-based interfaces compare with command line ones.

Key Concepts

Below are the key concepts covered in this tutorial, with links to (mostly) Apple documentation on them.

You can supplement these with other web resources. In particular, the WWDC videos related to SwiftUI are good, such as this 2020 introduction to SwiftUI. There are also videos from WWDC 2019 and before, such as this video on SwiftUI Essentials. While you do not need to consult outside material to do the assignments in this class, another perspective can be helpful.

Tasks

Code

Converter.swift

//  Conversions.swift

struct Converter {
    var convFrom = "From Type"
    var convTo = "To Type"
    var convert: (_ from: Double) -> Double?
    
    func formatConversion(_ from: Double) -> String {
        if let to = self.convert(from) {
            return "\(from) \(self.convFrom) is \(to) \(self.convTo)."
        } else {
            return "Converting \(from) \(convFrom) to \(self.convTo) failed."
        }
    }
    
    init(_ from: String, _ to: String, _ f: @escaping (_ from: Double) -> Double?) {
        self.convFrom = from
        self.convTo = to
        self.convert = f
    }
}

func InToCM(_ inch: Double) -> Double {
    let cm = 2.54 * inch
    return cm
}

let conversions: [String: Converter] =
    ["F to C": Converter("Farenheit", "Celsius",
                         {F in return ((F - 32.0)*(5/9))}),
     "C to F": Converter("Celsius", "Farenheit",
                         {C in return ((9/5)*C + 32.0)}),
     "km to mi": Converter("kilometers", "miles",
                           {k in
                            let m = k * 0.6213712
                            return m
                           }),
     "inch to cm": Converter("inches", "centimeters",
                             InToCM)
    ]

ContentView.swift (Converter2)

// ContentView.swift (Converter2)

import SwiftUI

struct ContentView: View {
    @State var convMode: String? = nil
    @State var fromS = ""
    var body: some View {
        VStack{
            ConvMenu(convMode: $convMode,
                     fromString: $fromS)
            Spacer()
            ConvOutput(convMode: $convMode,
                       fromString: $fromS)
            Spacer()
            Spacer()
        }
    }
}

struct ConvMenu: View {
    @Binding var convMode: String?
    @Binding var fromString: String
    var body: some View {
        let availConversions = [String](conversions.keys)
        Menu("Conversions menu") {
            ForEach(availConversions, id: \.self) {
                conversion in
                Button(conversion, action: {
                    convMode = conversion
                    fromString = ""
                })
            }
        }
    }
}

struct ConvOutput: View {
    @Binding var convMode: String?
    @Binding var fromString: String
    var body: some View {
        if let mode = convMode {
            let conv = conversions[mode]!
            TextField("Enter \(conv.convFrom)", text: $fromString)
            Spacer()
            if let from = Double(fromString) {
                Text(conv.formatConversion(from))
            }
        } else {
            Text("Please select a conversion")
            Text("type from the menu above.")
        }
    }
}

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

main.swift (Convert2Cmd)

//  main.swift (Convert2Cmd)

var convAvail = conversions.keys.sorted()

func getChoice() -> String? {
    print("Available Conversions:")
    for i in 0..<convAvail.count {
        print(" \(i+1). \(convAvail[i])")
    }
    
    print("Enter choice: ", terminator: "")
    if let choice = readLine() {
        if let c = Int(choice) {
            if ((c > 0) && (c <= convAvail.count)) {
                return convAvail[c-1]
            }
        }
    }
    return nil
}

let getConversion = {(_ choice: String) in
    let conv = conversions[choice]!
    print("\nEnter \(conv.convFrom): ", terminator: "")
    if let vs = readLine() {
        if let v = Double(vs) {
            let res = conv.formatConversion(v)
            print(res)
            return
        } else {
            print("You didn't enter a number!")
        }
    }
}

if let choice = getChoice() {
    getConversion(choice)
} else {
    print("You didn't make a valid choice!")
}