Commit af14f4aa authored by tybrandt's avatar tybrandt
Browse files

Category data is now stored and saved

parent 591f6b74
......@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
DE512D0225FB039A00EA7816 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE512D0125FB039A00EA7816 /* Category.swift */; };
DEC2565A25E887410003EFC9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2565925E887410003EFC9 /* AppDelegate.swift */; };
DEC2565C25E887410003EFC9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2565B25E887410003EFC9 /* SceneDelegate.swift */; };
DEC2565E25E887410003EFC9 /* CategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2565D25E887410003EFC9 /* CategoryViewController.swift */; };
......@@ -16,6 +17,7 @@
DEC2567125E887450003EFC9 /* Budget_TrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2567025E887450003EFC9 /* Budget_TrackerTests.swift */; };
DEC2567C25E887450003EFC9 /* Budget_TrackerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2567B25E887450003EFC9 /* Budget_TrackerUITests.swift */; };
DEC2569B25E89A400003EFC9 /* AddTransactionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEC2569A25E89A400003EFC9 /* AddTransactionViewController.swift */; };
DEEC3BC725FB1EFA00011733 /* CategoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEEC3BC625FB1EFA00011733 /* CategoryTableViewCell.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -36,6 +38,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
DE512D0125FB039A00EA7816 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = "<group>"; };
DEC2565625E887410003EFC9 /* Budget Tracker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Budget Tracker.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DEC2565925E887410003EFC9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
DEC2565B25E887410003EFC9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
......@@ -51,6 +54,7 @@
DEC2567B25E887450003EFC9 /* Budget_TrackerUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Budget_TrackerUITests.swift; sourceTree = "<group>"; };
DEC2567D25E887450003EFC9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DEC2569A25E89A400003EFC9 /* AddTransactionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddTransactionViewController.swift; sourceTree = "<group>"; };
DEEC3BC625FB1EFA00011733 /* CategoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryTableViewCell.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -104,6 +108,8 @@
DEC2565925E887410003EFC9 /* AppDelegate.swift */,
DEC2565B25E887410003EFC9 /* SceneDelegate.swift */,
DEC2565D25E887410003EFC9 /* CategoryViewController.swift */,
DEEC3BC625FB1EFA00011733 /* CategoryTableViewCell.swift */,
DE512D0125FB039A00EA7816 /* Category.swift */,
DEC2569A25E89A400003EFC9 /* AddTransactionViewController.swift */,
DEC2565F25E887410003EFC9 /* Main.storyboard */,
DEC2566225E887440003EFC9 /* Assets.xcassets */,
......@@ -262,9 +268,11 @@
buildActionMask = 2147483647;
files = (
DEC2565E25E887410003EFC9 /* CategoryViewController.swift in Sources */,
DE512D0225FB039A00EA7816 /* Category.swift in Sources */,
DEC2565A25E887410003EFC9 /* AppDelegate.swift in Sources */,
DEC2565C25E887410003EFC9 /* SceneDelegate.swift in Sources */,
DEC2569B25E89A400003EFC9 /* AddTransactionViewController.swift in Sources */,
DEEC3BC725FB1EFA00011733 /* CategoryTableViewCell.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -7,12 +7,13 @@
import UIKit
class AddTransactionViewController: UIViewController, UITextFieldDelegate {
class AddTransactionViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {
@IBOutlet weak var addButton: UIBarButtonItem!
@IBOutlet weak var categoryTextField: UITextField!
@IBOutlet weak var nameTextField: UITextField!
@IBOutlet weak var costTextField: UITextField!
var doneButton: UIBarButtonItem!
var categories = [Category]()
override func viewDidLoad() {
super.viewDidLoad()
......@@ -29,10 +30,6 @@ class AddTransactionViewController: UIViewController, UITextFieldDelegate {
name: UIResponder.keyboardWillHideNotification, object: nil)
}
@IBAction func addTransactions(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
@IBAction func cancel(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
......@@ -60,6 +57,28 @@ class AddTransactionViewController: UIViewController, UITextFieldDelegate {
return true
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
guard let button = sender as? UIBarButtonItem, button === addButton else {return}
let price = Double(costTextField.text ?? "0.0")
for category in categories {
if categoryTextField.text == category.name {
category.addToTotal(price: price ?? 0.0)
return
}
}
let category = Category(name: categoryTextField.text ?? "", price: price ?? 0.0)
var i = 0
for categoryI in categories {
if categoryI.name > categoryTextField.text! {
categories.insert(category!, at: i)
return
}
i += 1
}
categories.append(category!)
}
private func updateAddButtonStatus() {
var text = categoryTextField.text ?? ""
if text.isEmpty {
......
......@@ -47,6 +47,43 @@
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="2vd-QX-gXm">
<rect key="frame" x="20" y="88" width="374" height="691"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="CategoryTableViewCell" id="way-ii-Wwy" customClass="CategoryTableViewCell" customModule="Budget_Tracker" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="374" height="21.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="way-ii-Wwy" id="9Fx-Di-qVx">
<rect key="frame" x="0.0" y="0.0" width="374" height="21.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Price" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6fu-Bu-LnA">
<rect key="frame" x="312.5" y="0.0" width="41.5" height="22"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6pf-vN-yV5">
<rect key="frame" x="20" y="0.0" width="285" height="21.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="6fu-Bu-LnA" secondAttribute="trailing" constant="20" symbolic="YES" id="Ctv-sD-hNg"/>
<constraint firstItem="6fu-Bu-LnA" firstAttribute="leading" secondItem="6pf-vN-yV5" secondAttribute="trailing" constant="7.5" id="KOi-jR-qXp"/>
<constraint firstAttribute="bottom" secondItem="6pf-vN-yV5" secondAttribute="bottom" id="Tca-4b-CwV"/>
<constraint firstItem="6pf-vN-yV5" firstAttribute="top" secondItem="9Fx-Di-qVx" secondAttribute="top" id="V5H-KO-LRS"/>
<constraint firstAttribute="bottom" secondItem="6fu-Bu-LnA" secondAttribute="bottom" constant="-0.5" id="W6a-nc-6mI"/>
<constraint firstItem="6pf-vN-yV5" firstAttribute="leading" secondItem="9Fx-Di-qVx" secondAttribute="leading" constant="20" symbolic="YES" id="gDc-kW-U0f"/>
<constraint firstItem="6fu-Bu-LnA" firstAttribute="top" secondItem="9Fx-Di-qVx" secondAttribute="top" id="xOz-1s-Yv0"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="name" destination="6pf-vN-yV5" id="E9c-YF-2gD"/>
<outlet property="price" destination="6fu-Bu-LnA" id="z88-O1-hrQ"/>
</connections>
</tableViewCell>
</prototypes>
</tableView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sdJ-aN-yuT">
<rect key="frame" x="20" y="824" width="95" height="30"/>
......@@ -80,6 +117,7 @@
</view>
<navigationItem key="navigationItem" title="Budget Tracker" id="p8f-H0-k1k"/>
<connections>
<outlet property="categoryTable" destination="2vd-QX-gXm" id="RVa-T8-OWz"/>
<segue destination="JIR-F4-P6s" kind="presentation" identifier="addTransaction" id="4xG-2T-kn9"/>
</connections>
</viewController>
......@@ -134,6 +172,7 @@
<barButtonItem key="rightBarButtonItem" systemItem="add" id="h88-4Q-MwN">
<connections>
<action selector="addTransactions:" destination="UPP-cu-IDS" id="X9P-Aw-J4z"/>
<segue destination="ZYl-Ei-Xw9" kind="unwind" unwindAction="displayDataWithSender:" id="pTw-dw-uVJ"/>
</connections>
</barButtonItem>
</navigationItem>
......@@ -145,6 +184,7 @@
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="jOc-cA-MFX" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
<exit id="ZYl-Ei-Xw9" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="2862.3188405797105" y="164.73214285714286"/>
</scene>
......@@ -169,6 +209,7 @@
<!--Navigation Controller-->
<scene sceneID="qn1-CW-M5d">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="HJa-Mg-ThC" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="JIR-F4-P6s" sceneMemberID="viewController">
<toolbarItems/>
<navigationItem key="navigationItem" id="bC3-KK-vVK"/>
......@@ -181,9 +222,8 @@
<segue destination="UPP-cu-IDS" kind="relationship" relationship="rootViewController" id="oft-4s-nUu"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="HJa-Mg-ThC" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1948" y="165"/>
<point key="canvasLocation" x="1899" y="753"/>
</scene>
</scenes>
<resources>
......
//
// Category.swift
// Budget Tracker
//
// Created by Tyler Brandt on 3/11/21.
//
import UIKit
class Category: NSObject, NSCoding {
var name: String
var price: Double
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("categories")
struct PropertyKey {
static let name = "name"
static let price = "price"
}
init?(name: String, price: Double) {
guard !name.isEmpty else {return nil}
guard price > 0 else {return nil}
self.name = name
self.price = price
}
func addToTotal(price: Double) {
self.price += price
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: PropertyKey.name)
coder.encode(price, forKey: PropertyKey.price)
}
required convenience init?(coder: NSCoder) {
guard let name = coder.decodeObject(forKey: PropertyKey.name) as? String else {return nil}
let price = coder.decodeDouble(forKey: PropertyKey.price)
self.init(name: name, price: price)
}
}
//
// CategoryTableViewCell.swift
// Budget Tracker
//
// Created by Tyler Brandt on 3/11/21.
//
import UIKit
class CategoryTableViewCell: UITableViewCell {
@IBOutlet weak var name: UILabel!
@IBOutlet weak var price: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
......@@ -7,14 +7,82 @@
import UIKit
class CategoryViewController: UIViewController {
class CategoryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var categories = [Category]()
@IBOutlet weak var categoryTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
if let savedCategories = loadCategories() {
print("SUCCESS")
categories += savedCategories
}
categoryTable.delegate = self
categoryTable.dataSource = self
}
@IBAction func addTransaction(_ sender: UIButton) {
performSegue(withIdentifier: "addTransaction", sender: self)
}
@IBAction func displayData(sender: UIStoryboardSegue) {
if let sourceView = sender.source as? AddTransactionViewController {
categories = sourceView.categories
saveCategories()
categoryTable.reloadData()
print(categories)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch (segue.identifier ?? "") {
case "addTransaction":
guard let addViewNav = segue.destination as? UINavigationController else {return}
guard let addView = addViewNav.viewControllers.first as? AddTransactionViewController else {return}
addView.categories = categories
default:
return
}
}
func numberOfSections(in categoryTable: UITableView) -> Int {
return 1
}
func tableView(_ categoryTable: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories.count
}
func tableView(_ categoryTable: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "CategoryTableViewCell"
guard let cell = self.categoryTable.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as?
CategoryTableViewCell else {
fatalError()
}
let category = categories[indexPath.row]
cell.name.text = category.name
cell.price.text = String(category.price)
return cell
}
private func saveCategories() {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: categories,
requiringSecureCoding: false)
try data.write(to: Category.ArchiveURL)
} catch {
return
}
}
private func loadCategories() -> [Category]? {
do {
return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(
Data(contentsOf: Category.ArchiveURL)) as? [Category]
} catch {
return nil
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment