Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tybrandt
iOS Budget Tracker
Commits
af14f4aa
Commit
af14f4aa
authored
Mar 15, 2021
by
tybrandt
Browse files
Category data is now stored and saved
parent
591f6b74
Changes
7
Hide whitespace changes
Inline
Side-by-side
Budget Tracker.xcodeproj/project.pbxproj
View file @
af14f4aa
...
...
@@ -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
;
};
...
...
Budget Tracker.xcodeproj/project.xcworkspace/xcuserdata/tybrandt.xcuserdatad/UserInterfaceState.xcuserstate
View file @
af14f4aa
No preview for this file type
Budget Tracker/AddTransactionViewController.swift
View file @
af14f4aa
...
...
@@ -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
{
...
...
Budget Tracker/Base.lproj/Main.storyboard
View file @
af14f4aa
...
...
@@ -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=
"1
948
"
y=
"
165
"
/>
<point
key=
"canvasLocation"
x=
"1
899
"
y=
"
753
"
/>
</scene>
</scenes>
<resources>
...
...
Budget Tracker/Category.swift
0 → 100644
View file @
af14f4aa
//
// 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
)
}
}
Budget Tracker/CategoryTableViewCell.swift
0 → 100644
View file @
af14f4aa
//
// 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
)
}
}
Budget Tracker/CategoryViewController.swift
View file @
af14f4aa
...
...
@@ -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
}
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment