diff --git a/Notes App.xcodeproj/project.pbxproj b/Notes App.xcodeproj/project.pbxproj index c46a84c..d8de21e 100644 --- a/Notes App.xcodeproj/project.pbxproj +++ b/Notes App.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 9F0627CF235E2E5200CC53B0 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0627CE235E2E5200CC53B0 /* Extensions.swift */; }; + 9F0627CF235E2E5200CC53B0 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0627CE235E2E5200CC53B0 /* String.swift */; }; 9F0627D2235E422E00CC53B0 /* NoteContainer.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 9F0627D0235E422E00CC53B0 /* NoteContainer.xcdatamodeld */; }; 9F0B7EEE23614621008E7C0E /* Note+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0B7EEC23614620008E7C0E /* Note+CoreDataClass.swift */; }; 9F0B7EEF23614621008E7C0E /* Note+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F0B7EED23614620008E7C0E /* Note+CoreDataProperties.swift */; }; @@ -21,6 +21,9 @@ 9FA430C1236228F900A158E7 /* Launch.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9FA430C0236228F900A158E7 /* Launch.storyboard */; }; 9FA430C42362393F00A158E7 /* HeadingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA430C32362393F00A158E7 /* HeadingLabel.swift */; }; 9FA430C723623F0900A158E7 /* NoteComposerTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA430C623623F0900A158E7 /* NoteComposerTextView.swift */; }; + 9FA430CC2362477000A158E7 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA430CB2362477000A158E7 /* Color.swift */; }; + 9FA430CE2362478700A158E7 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA430CD2362478700A158E7 /* Font.swift */; }; + 9FA430D0236247AA00A158E7 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA430CF236247AA00A158E7 /* Date.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -41,7 +44,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 9F0627CE235E2E5200CC53B0 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + 9F0627CE235E2E5200CC53B0 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 9F0627D1235E422E00CC53B0 /* NoteDataModel.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = NoteDataModel.xcdatamodel; sourceTree = ""; }; 9F0B7EEC23614620008E7C0E /* Note+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Note+CoreDataClass.swift"; sourceTree = ""; }; 9F0B7EED23614620008E7C0E /* Note+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Note+CoreDataProperties.swift"; sourceTree = ""; }; @@ -59,6 +62,9 @@ 9FA430C0236228F900A158E7 /* Launch.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Launch.storyboard; sourceTree = ""; }; 9FA430C32362393F00A158E7 /* HeadingLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingLabel.swift; sourceTree = ""; }; 9FA430C623623F0900A158E7 /* NoteComposerTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteComposerTextView.swift; sourceTree = ""; }; + 9FA430CB2362477000A158E7 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; + 9FA430CD2362478700A158E7 /* Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = ""; }; + 9FA430CF236247AA00A158E7 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,7 +119,7 @@ 9FA430C2236238CF00A158E7 /* NoteModel */, 9FA430C92362472100A158E7 /* ViewControllers */, 9FA430C52362394F00A158E7 /* Views */, - 9F0627CE235E2E5200CC53B0 /* Extensions.swift */, + 9FA430CA2362474C00A158E7 /* Extensions */, ); path = "Notes App"; sourceTree = ""; @@ -158,6 +164,17 @@ path = ViewControllers; sourceTree = ""; }; + 9FA430CA2362474C00A158E7 /* Extensions */ = { + isa = PBXGroup; + children = ( + 9F0627CE235E2E5200CC53B0 /* String.swift */, + 9FA430CF236247AA00A158E7 /* Date.swift */, + 9FA430CB2362477000A158E7 /* Color.swift */, + 9FA430CD2362478700A158E7 /* Font.swift */, + ); + path = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -289,11 +306,14 @@ buildActionMask = 2147483647; files = ( 9F0E638F235919980093FF2F /* NotesMainViewController.swift in Sources */, + 9FA430D0236247AA00A158E7 /* Date.swift in Sources */, 9F0B7EEF23614621008E7C0E /* Note+CoreDataProperties.swift in Sources */, + 9FA430CE2362478700A158E7 /* Font.swift in Sources */, 9F0E638D235919980093FF2F /* AppDelegate.swift in Sources */, 9FA430C723623F0900A158E7 /* NoteComposerTextView.swift in Sources */, + 9FA430CC2362477000A158E7 /* Color.swift in Sources */, 9F0E63C1235926740093FF2F /* NotesCell.swift in Sources */, - 9F0627CF235E2E5200CC53B0 /* Extensions.swift in Sources */, + 9F0627CF235E2E5200CC53B0 /* String.swift in Sources */, 9F0E63BF235925530093FF2F /* CircleButton.swift in Sources */, 9F0E63C323593AAF0093FF2F /* NoteComposerViewController.swift in Sources */, 9F0E63BD2359233F0093FF2F /* NotesNavigationController.swift in Sources */, diff --git a/Notes App/AppDelegate.swift b/Notes App/AppDelegate.swift index c78ede4..90b9a16 100644 --- a/Notes App/AppDelegate.swift +++ b/Notes App/AppDelegate.swift @@ -47,49 +47,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - // MARK: - Core Data stack - lazy var persistentContainer: NSPersistentContainer = { - /* - The persistent container for the application. This implementation - creates and returns a container, having loaded the store for the - application to it. This property is optional since there are legitimate - error conditions that could cause the creation of the store to fail. - */ - let container = NSPersistentContainer(name: "NoteContainer") - container.loadPersistentStores(completionHandler: { (storeDescription, error) in - if let error = error as NSError? { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - - /* - Typical reasons for an error here include: - * The parent directory does not exist, cannot be created, or disallows writing. - * The persistent store is not accessible, due to permissions or data protection when the device is locked. - * The device is out of space. - * The store could not be migrated to the current model version. - Check the error message to determine what the actual problem was. - */ - fatalError("Unresolved error \(error), \(error.userInfo)") - } - }) - return container - }() - - // MARK: - Core Data Saving support - func saveContext () { - let context = persistentContainer.viewContext - if context.hasChanges { - do { - try context.save() - } catch { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - let nserror = error as NSError - fatalError("Unresolved error \(nserror), \(nserror.userInfo)") - } - } - } - - } diff --git a/Notes App/Extensions.swift b/Notes App/Extensions.swift deleted file mode 100644 index b99981f..0000000 --- a/Notes App/Extensions.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// Extensions.swift -// Notes App -// -// Created by jason smellz on 10/21/19. -// Copyright © 2019 jacob. All rights reserved. -// - -import UIKit - -extension Date { - /// Returns a string with a formatting of date dependent on distance from now - var configureDateString: String { - let now = Date() - let formatter = DateFormatter() - formatter.timeZone = TimeZone.current - - guard let daysSinceNow = Calendar.current.dateComponents([.day], from: self, to: now).day else { return formatter.string(from: Date()) } - - // if > one week display date - formatter.dateFormat = "MM.dd.yy" - guard daysSinceNow < 7 else {return formatter.string(from: self)} - - // if > yesterday but < week ago display day of the week - guard daysSinceNow < 2 else {return formatter.weekdaySymbols[Calendar.current.component(.weekday, from: self)]} - - // if yesterday display yesterday - guard daysSinceNow < 1 else {return "Yesterday"} - - // if today display time of day - formatter.dateFormat = "h:mm a" - return formatter.string(from: self) - } -} - -extension String { - - // for use in note cell - - var truncateBody: String { - - let truncatePoint = 20 - - // if new line exists truncate body after first new line - guard self.rangeOfCharacter(from: CharacterSet.newlines) == nil else { - return self.components(separatedBy: "\n")[1] - } - - // else truncate after first 30 characters - guard self.count > truncatePoint else {return ""} - - // if there are no spaces - guard self.rangeOfCharacter(from: CharacterSet.init(charactersIn: " ")) != nil else { - return String(self.suffix(self.count - truncatePoint)) - } - - // find first space after taking suffix after thirty characters - let firstSpaceAfterSuffix = self.suffix(self.count - truncatePoint).split(separator: " " )[0] - // split components based on first occurence of word after first space found - return self.components(separatedBy: firstSpaceAfterSuffix)[1] - } - -} - -extension UIColor { - - // static constant stored properties, initialized lazily - static let notesBackground = UIColor(netHex: 0x1D1E1F) - static let notesCellBackground = UIColor(netHex: 0x242526) - static let notesCellBorder = UIColor(netHex: 0x727374) - static let notesRed = UIColor(netHex: 0xFE3B30) - static let notesBlack = UIColor(netHex: 0x141415).withAlphaComponent(0.9) - - convenience init(red: Int, green: Int, blue: Int) { - assert(red >= 0 && red <= 255, "Invalid red component") - assert(green >= 0 && green <= 255, "Invalid green component") - assert(blue >= 0 && blue <= 255, "Invalid blue component") - self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) - } - - convenience init(netHex:Int) { - self.init(red:(netHex >> 16) & 0xff, green:(netHex >> 8) & 0xff, blue:netHex & 0xff) - } -} - -extension UIFont { - - static let heading = UIFont.systemFont(ofSize: 30) - static let cellHeading = UIFont.systemFont(ofSize: 21) - static let cellBody = UIFont.systemFont(ofSize: 18, weight: .thin) - static let cellDate = UIFont.systemFont(ofSize: 15, weight: .thin) - -} - diff --git a/Notes App/Extensions/Color.swift b/Notes App/Extensions/Color.swift new file mode 100644 index 0000000..7ddb581 --- /dev/null +++ b/Notes App/Extensions/Color.swift @@ -0,0 +1,30 @@ +// +// Color.swift +// Notes App +// +// Created by jason smellz on 10/24/19. +// Copyright © 2019 jacob. All rights reserved. +// + +import UIKit + +extension UIColor { + + // static constant stored properties, initialized lazily + static let notesBackground = UIColor(netHex: 0x1D1E1F) + static let notesCellBackground = UIColor(netHex: 0x242526) + static let notesCellBorder = UIColor(netHex: 0x727374) + static let notesRed = UIColor(netHex: 0xFE3B30) + static let notesBlack = UIColor(netHex: 0x141415).withAlphaComponent(0.9) + + convenience init(red: Int, green: Int, blue: Int) { + assert(red >= 0 && red <= 255, "Invalid red component") + assert(green >= 0 && green <= 255, "Invalid green component") + assert(blue >= 0 && blue <= 255, "Invalid blue component") + self.init(red: CGFloat(red) / 255.0, green: CGFloat(green) / 255.0, blue: CGFloat(blue) / 255.0, alpha: 1.0) + } + + convenience init(netHex:Int) { + self.init(red:(netHex >> 16) & 0xff, green:(netHex >> 8) & 0xff, blue:netHex & 0xff) + } +} diff --git a/Notes App/Extensions/Date.swift b/Notes App/Extensions/Date.swift new file mode 100644 index 0000000..2e8ad0c --- /dev/null +++ b/Notes App/Extensions/Date.swift @@ -0,0 +1,34 @@ +// +// Date.swift +// Notes App +// +// Created by jason smellz on 10/24/19. +// Copyright © 2019 jacob. All rights reserved. +// + +import Foundation + +extension Date { + /// Returns a string with a formatting of date dependent on distance from now + var configureDateString: String { + let now = Date() + let formatter = DateFormatter() + formatter.timeZone = TimeZone.current + + guard let daysSinceNow = Calendar.current.dateComponents([.day], from: self, to: now).day else { return formatter.string(from: Date()) } + + // if > one week display date + formatter.dateFormat = "MM.dd.yy" + guard daysSinceNow < 7 else {return formatter.string(from: self)} + + // if > yesterday but < week ago display day of the week + guard daysSinceNow < 2 else {return formatter.weekdaySymbols[Calendar.current.component(.weekday, from: self)]} + + // if yesterday display yesterday + guard daysSinceNow < 1 else {return "Yesterday"} + + // if today display time of day + formatter.dateFormat = "h:mm a" + return formatter.string(from: self) + } +} diff --git a/Notes App/Extensions/Font.swift b/Notes App/Extensions/Font.swift new file mode 100644 index 0000000..d8c0e53 --- /dev/null +++ b/Notes App/Extensions/Font.swift @@ -0,0 +1,18 @@ +// +// Font.swift +// Notes App +// +// Created by jason smellz on 10/24/19. +// Copyright © 2019 jacob. All rights reserved. +// + +import UIKit + +extension UIFont { + + static let heading = UIFont.systemFont(ofSize: 30) + static let cellHeading = UIFont.systemFont(ofSize: 21) + static let cellBody = UIFont.systemFont(ofSize: 18, weight: .thin) + static let cellDate = UIFont.systemFont(ofSize: 15, weight: .thin) + +} diff --git a/Notes App/Extensions/String.swift b/Notes App/Extensions/String.swift new file mode 100644 index 0000000..ca63ebc --- /dev/null +++ b/Notes App/Extensions/String.swift @@ -0,0 +1,39 @@ +// +// Extensions.swift +// Notes App +// +// Created by jason smellz on 10/21/19. +// Copyright © 2019 jacob. All rights reserved. +// + +import Foundation + +extension String { + + // for use in note cell + + var truncateBody: String { + + let truncatePoint = 20 + + // if new line exists truncate body after first new line + guard self.rangeOfCharacter(from: CharacterSet.newlines) == nil else { + return self.components(separatedBy: "\n")[1] + } + + // else truncate after first 30 characters + guard self.count > truncatePoint else {return ""} + + // if there are no spaces + guard self.rangeOfCharacter(from: CharacterSet.init(charactersIn: " ")) != nil else { + return String(self.suffix(self.count - truncatePoint)) + } + + // find first space after taking suffix after thirty characters + let firstSpaceAfterSuffix = self.suffix(self.count - truncatePoint).split(separator: " " )[0] + // split components based on first occurence of word after first space found + return self.components(separatedBy: firstSpaceAfterSuffix)[1] + } + +} + diff --git a/Notes App/ViewControllers/NoteComposerViewController.swift b/Notes App/ViewControllers/NoteComposerViewController.swift index f07975f..bd6b66a 100644 --- a/Notes App/ViewControllers/NoteComposerViewController.swift +++ b/Notes App/ViewControllers/NoteComposerViewController.swift @@ -47,6 +47,7 @@ extension NoteComposerViewController { view.backgroundColor = UIColor.notesBackground view.addSubview(noteComposerTextView) + NotificationCenter.default.addObserver(self, selector: #selector(applicationWillTerminate), name: UIApplication.willTerminateNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil) @@ -150,6 +151,10 @@ extension NoteComposerViewController { hideDoneButton(true) animateBottomConstraint(0) } + + @objc fileprivate func applicationWillTerminate() { + handleDisappear() + } }