Mobile App Dev 2021W: Tutorial 10

From Soma-notes

Tasks/Questions

  1. Download and run Converter-SB. How similar is its execution to Converter2 from Tutorial 2? How similar to Converter2A from Tutorial 6?
  2. How are connections made between Main.storyboard and ViewController.swift? How does this compare to the connections between activity_main.xml and MainActivity.kt from Tutorial 6?
  3. How is layout specified in Main.storyboard? How similar is this to how layout was specified in Converter2 and Converter2A?
  4. How does the flow of control of Converter-SB compare to Converter2 and Converter2A?
  5. Why do you think that Converter-SB doesn't have a proper menu?
  6. Change Converter-SB so it starts with a message saying to "Choose a conversion above" in the result area and the button says "Select conversion".
  7. Using the storyboard editor, add a Label at the bottom of the screen. This label should initially be blank. It should have a center horizontal alignment, span the width of the screen, and be anchored to the bottom of the safe area.
  8. Modify ViewController.swift to make the label you added previously show a random encouragement message every time a conversion is selected. This label should go blank once the user starts typing in something. Add at least three messages, such as the following:
  • You chose wisely!
  • Keep going! Almost there!
  • Thank you for choosing.

Code

Converter-SB.zip

Conversions.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) {
            let toS = String(format: "%.3f", to)
            return "\(from) \(self.convFrom) is \(toS) \(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 =
    ["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)
    ]

let availConversions = [String] (conversions.keys)

ViewController.swift

//
//  ViewController.swift
//  Converter-SB
//
//  Created by Anil Somayaji on 2021-04-06.
//

import UIKit

class ViewController: UIViewController {
    @IBOutlet var fromField: UITextField!
    @IBOutlet weak var result: UILabel!
    @IBOutlet weak var convButton: UIButton!
    
    var convIndex = 0
    var conv = conversions[availConversions[0]]!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func updateConversion() {
        convIndex = (convIndex + 1 ) % availConversions.count
        conv = conversions[availConversions[convIndex]]!
        convButton.setTitle("Conversion: \(availConversions[convIndex])", for: .normal)
    }
    
    @IBAction func doConversion() {
        if let fromS = fromField.text {
            if let from = Double(fromS) {
                result.text =
                    conv.formatConversion(from)
            } else {
                result.text = "Please enter a number."
            }
        }
    }
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait" appearance="light"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="System colors in document resources" minToolsVersion="11.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Converter_SB" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="VJ7-bt-qir">
                                <rect key="frame" x="0.0" y="122" width="375" height="34"/>
                                <fontDescription key="fontDescription" type="system" pointSize="14"/>
                                <textInputTraits key="textInputTraits"/>
                                <connections>
                                    <action selector="doConversion" destination="BYZ-38-t0r" eventType="editingChanged" id="WEr-SS-N11"/>
                                </connections>
                            </textField>
                            <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QgR-df-1nY">
                                <rect key="frame" x="0.0" y="44" width="375" height="30"/>
                                <state key="normal" title="Button"/>
                                <connections>
                                    <action selector="updateConversion" destination="BYZ-38-t0r" eventType="touchUpInside" id="u10-i8-VVe"/>
                                </connections>
                            </button>
                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QHi-YO-lly">
                                <rect key="frame" x="0.0" y="164" width="375" height="21"/>
                                <fontDescription key="fontDescription" type="system" pointSize="17"/>
                                <nil key="textColor"/>
                                <nil key="highlightedColor"/>
                            </label>
                        </subviews>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                        <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                        <constraints>
                            <constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="VJ7-bt-qir" secondAttribute="trailing" id="1By-U1-T9I"/>
                            <constraint firstItem="QgR-df-1nY" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="3rM-HL-fub"/>
                            <constraint firstItem="QHi-YO-lly" firstAttribute="top" secondItem="VJ7-bt-qir" secondAttribute="bottom" constant="8" id="4Mw-3g-c0Y"/>
                            <constraint firstItem="VJ7-bt-qir" firstAttribute="top" secondItem="QgR-df-1nY" secondAttribute="bottom" constant="48" id="IBz-Q9-HJr"/>
                            <constraint firstAttribute="trailing" secondItem="QHi-YO-lly" secondAttribute="trailing" id="LsV-b9-Mq7"/>
                            <constraint firstItem="QHi-YO-lly" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="NS2-ki-p00"/>
                            <constraint firstItem="QHi-YO-lly" firstAttribute="top" secondItem="VJ7-bt-qir" secondAttribute="bottom" constant="8" symbolic="YES" id="NX0-K4-DfK"/>
                            <constraint firstAttribute="trailing" secondItem="QgR-df-1nY" secondAttribute="trailing" id="ckB-TL-gBc"/>
                            <constraint firstItem="QgR-df-1nY" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" constant="44" id="q2m-Gg-fyA"/>
                            <constraint firstItem="VJ7-bt-qir" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="tT6-p8-3IJ"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="convButton" destination="QgR-df-1nY" id="6Dj-hw-rOA"/>
                        <outlet property="fromField" destination="VJ7-bt-qir" id="hkS-Oj-aWr"/>
                        <outlet property="result" destination="QHi-YO-lly" id="QEU-E4-Ty3"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-215" y="40"/>
        </scene>
    </scenes>
    <resources>
        <systemColor name="systemBackgroundColor">
            <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
        </systemColor>
    </resources>
</document>