├── CODEOWNERS ├── Mooskine ├── Mooskine-complete │ ├── Mooskine │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── texture-cow.imageset │ │ │ │ ├── texture-cow.png │ │ │ │ └── Contents.json │ │ │ ├── toolbar-cow.imageset │ │ │ │ ├── 1184-cow-toolbar.png │ │ │ │ ├── 1184-cow-toolbar@2x.png │ │ │ │ ├── 1184-cow-toolbar@3x.png │ │ │ │ └── Contents.json │ │ │ ├── toolbar-bold.imageset │ │ │ │ ├── 1171-bold-toolbar.png │ │ │ │ ├── 1171-bold-toolbar@2x.png │ │ │ │ ├── 1171-bold-toolbar@3x.png │ │ │ │ └── Contents.json │ │ │ ├── toolbar-underline.imageset │ │ │ │ ├── 1173-underline-toolbar.png │ │ │ │ ├── 1173-underline-toolbar@2x.png │ │ │ │ ├── 1173-underline-toolbar@3x.png │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── OpenSans-Bold.ttf │ │ ├── OpenSans-Regular.ttf │ │ ├── OpenSans-Semibold.ttf │ │ ├── Model │ │ │ ├── Mooskine.xcdatamodeld │ │ │ │ ├── .xccurrentversion │ │ │ │ ├── Mooskine.xcdatamodel │ │ │ │ │ └── contents │ │ │ │ └── Mooskine-2017-11-10-AttributedString.xcdatamodel │ │ │ │ │ └── contents │ │ │ ├── Managed Object Extensions │ │ │ │ ├── Note+Extensions.swift │ │ │ │ └── Notebook+Extensions.swift │ │ │ ├── UpdateToAttributedStringsPolicy.swift │ │ │ ├── DataController.swift │ │ │ └── Pathifier.swift │ │ ├── Views │ │ │ ├── Cells │ │ │ │ ├── NoteCell.swift │ │ │ │ └── NotebookCell.swift │ │ │ └── Protocols │ │ │ │ └── Cell.swift │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── AppDelegate.swift │ │ └── View Controllers │ │ │ ├── NotesListViewController.swift │ │ │ ├── NotebooksListViewController.swift │ │ │ └── NoteDetailsViewController.swift │ ├── Mooskine.xcodeproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── MooskineTests │ │ ├── Info.plist │ │ └── MooskineTests.swift └── Mooskine-starter │ ├── Mooskine │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── texture-cow.imageset │ │ │ ├── texture-cow.png │ │ │ └── Contents.json │ │ ├── toolbar-cow.imageset │ │ │ ├── 1184-cow-toolbar.png │ │ │ ├── 1184-cow-toolbar@2x.png │ │ │ ├── 1184-cow-toolbar@3x.png │ │ │ └── Contents.json │ │ ├── toolbar-bold.imageset │ │ │ ├── 1171-bold-toolbar.png │ │ │ ├── 1171-bold-toolbar@2x.png │ │ │ ├── 1171-bold-toolbar@3x.png │ │ │ └── Contents.json │ │ ├── toolbar-underline.imageset │ │ │ ├── 1173-underline-toolbar.png │ │ │ ├── 1173-underline-toolbar@2x.png │ │ │ ├── 1173-underline-toolbar@3x.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── OpenSans-Bold.ttf │ ├── OpenSans-Regular.ttf │ ├── OpenSans-Semibold.ttf │ ├── Model │ │ ├── Note.swift │ │ └── Notebook.swift │ ├── Views │ │ ├── Cells │ │ │ ├── NoteCell.swift │ │ │ └── NotebookCell.swift │ │ └── Protocols │ │ │ └── Cell.swift │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── View Controllers │ │ ├── NoteDetailsViewController.swift │ │ ├── NotesListViewController.swift │ │ └── NotebooksListViewController.swift │ └── AppDelegate.swift │ ├── Mooskine.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── MooskineTests │ ├── Info.plist │ └── MooskineTests.swift ├── PickYourPitch-NoPersistence ├── PickYourPitch │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-40.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── 1024-mark-blue.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ └── Contents.json │ │ ├── play.imageset │ │ │ ├── play@2x~iphone.png │ │ │ └── Contents.json │ │ ├── stop.imageset │ │ │ ├── stop@2x~iphone.png │ │ │ └── Contents.json │ │ ├── LaunchLogo.imageset │ │ │ ├── LaunchLogo.pdf │ │ │ └── Contents.json │ │ └── microphone.imageset │ │ │ ├── microphone~iphone.png │ │ │ ├── microphone@2x~iphone.png │ │ │ └── Contents.json │ ├── RecordedAudio.swift │ ├── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── AppDelegate.swift │ ├── PlaySoundsViewController.swift │ └── RecordSoundsViewController.swift └── PickYourPitch.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── PickYourPitch.xcscmblueprint │ └── project.pbxproj ├── SandboxPlayground-Empty ├── SandboxPlayground │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-40.png │ │ │ ├── Icon-76.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-83.5@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ └── Contents.json │ │ └── LaunchLogo.imageset │ │ │ ├── LaunchLogo.pdf │ │ │ └── Contents.json │ ├── ViewController.swift │ ├── AppDelegate.swift │ ├── Info.plist │ └── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.xib └── SandboxPlayground.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── .gitignore ├── README.md ├── LICENSE └── .github └── workflows └── manual.yml /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @batmanimal 2 | 3 | * @udacity/active-public-content -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/OpenSans-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/OpenSans-Semibold.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/OpenSans-Semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/OpenSans-Semibold.ttf -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/texture-cow.imageset/texture-cow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/texture-cow.imageset/texture-cow.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/texture-cow.imageset/texture-cow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/texture-cow.imageset/texture-cow.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/play.imageset/play@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/play.imageset/play@2x~iphone.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/stop.imageset/stop@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/stop.imageset/stop@2x~iphone.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/LaunchLogo.imageset/LaunchLogo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/LaunchLogo.imageset/LaunchLogo.pdf -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.pdf -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@3x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/1024-mark-blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/1024-mark-blue.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@3x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/1184-cow-toolbar@3x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/1171-bold-toolbar@3x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/microphone.imageset/microphone~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/microphone.imageset/microphone~iphone.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/microphone.imageset/microphone@2x~iphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/microphone.imageset/microphone@2x~iphone.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@3x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@2x.png -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/ios-nd-persistence/HEAD/Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/1173-underline-toolbar@3x.png -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/LaunchLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchLogo.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/LaunchLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchLogo.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Mooskine.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | Mooskine-2017-11-10-AttributedString.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SandboxPlayground 4 | // 5 | // Created by Fernando Rodríguez Romero on 13/05/16. 6 | // Copyright © 2016 udacity.com. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - ViewController: UIViewController 12 | 13 | class ViewController: UIViewController { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/RecordedAudio.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecordedAudio.swift 3 | // Pick Your Pitch 4 | // 5 | // Created by Udacity on 1/5/15. 6 | // Copyright (c) 2014 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - RecordedAudio 12 | 13 | struct RecordedAudio { 14 | 15 | // MARK: Properties 16 | 17 | var filePathUrl: URL! 18 | var title: String! 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Managed Object Extensions/Note+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Note+Extensions.swift 3 | // Mooskine 4 | // 5 | // Created by Kathryn Rotondo on 10/21/17. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | extension Note { 13 | public override func awakeFromInsert() { 14 | super.awakeFromInsert() 15 | creationDate = Date() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/texture-cow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "texture-cow.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Managed Object Extensions/Notebook+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notebook+Extensions.swift 3 | // Mooskine 4 | // 5 | // Created by Kathryn Rotondo on 10/21/17. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | extension Notebook { 13 | public override func awakeFromInsert() { 14 | super.awakeFromInsert() 15 | creationDate = Date() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/texture-cow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "texture-cow.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/play.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "play@2x~iphone.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/stop.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "stop@2x~iphone.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Model/Note.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Note.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Note { 12 | /// The date the note was created 13 | let creationDate: Date 14 | 15 | /// The note's text 16 | var text: String 17 | 18 | init(text: String = "New note") { 19 | self.text = text 20 | creationDate = Date() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/microphone.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "microphone~iphone.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "microphone@2x~iphone.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-cow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1184-cow-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1184-cow-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1184-cow-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-cow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1184-cow-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1184-cow-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1184-cow-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-bold.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1171-bold-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1171-bold-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1171-bold-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-bold.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1171-bold-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1171-bold-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1171-bold-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Views/Cells/NoteCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteCell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal final class NoteCell: UITableViewCell, Cell { 12 | // Outlets 13 | @IBOutlet weak var textPreviewLabel: UILabel! 14 | @IBOutlet weak var dateLabel: UILabel! 15 | 16 | override func prepareForReuse() { 17 | super.prepareForReuse() 18 | textPreviewLabel.text = nil 19 | dateLabel.text = nil 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/toolbar-underline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1173-underline-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1173-underline-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1173-underline-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Views/Cells/NoteCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteCell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal final class NoteCell: UITableViewCell, Cell { 12 | // Outlets 13 | @IBOutlet weak var textPreviewLabel: UILabel! 14 | @IBOutlet weak var dateLabel: UILabel! 15 | 16 | override func prepareForReuse() { 17 | super.prepareForReuse() 18 | textPreviewLabel.text = nil 19 | dateLabel.text = nil 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/toolbar-underline.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1173-underline-toolbar.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "1173-underline-toolbar@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "1173-underline-toolbar@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Views/Cells/NotebookCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotebookCell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal final class NotebookCell: UITableViewCell, Cell { 12 | // Outlets 13 | @IBOutlet weak var nameLabel: UILabel! 14 | @IBOutlet weak var pageCountLabel: UILabel! 15 | 16 | override func prepareForReuse() { 17 | super.prepareForReuse() 18 | nameLabel.text = nil 19 | pageCountLabel.text = nil 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Views/Cells/NotebookCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotebookCell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | internal final class NotebookCell: UITableViewCell, Cell { 12 | // Outlets 13 | @IBOutlet weak var nameLabel: UILabel! 14 | @IBOutlet weak var pageCountLabel: UILabel! 15 | 16 | override func prepareForReuse() { 17 | super.prepareForReuse() 18 | nameLabel.text = nil 19 | pageCountLabel.text = nil 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Views/Protocols/Cell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol Cell: class { 12 | /// A default reuse identifier for the cell class 13 | static var defaultReuseIdentifier: String { get } 14 | } 15 | 16 | extension Cell { 17 | static var defaultReuseIdentifier: String { 18 | // Should return the class's name, without namespacing or mangling. 19 | // This works as of Swift 3.1.1, but might be fragile. 20 | return "\(self)" 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Views/Protocols/Cell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cell.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol Cell: class { 12 | /// A default reuse identifier for the cell class 13 | static var defaultReuseIdentifier: String { get } 14 | } 15 | 16 | extension Cell { 17 | static var defaultReuseIdentifier: String { 18 | // Should return the class's name, without namespacing or mangling. 19 | // This works as of Swift 3.1.1, but might be fragile. 20 | return "\(self)" 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/MooskineTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/MooskineTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SandboxPlayground 4 | // 5 | // Created by Fernando Rodríguez Romero on 13/05/16. 6 | // Copyright © 2016 udacity.com. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - AppDelegate: UIResponder, UIApplicationDelegate 12 | 13 | @UIApplicationMain 14 | class AppDelegate: UIResponder, UIApplicationDelegate { 15 | 16 | // MARK: Properties 17 | 18 | var window: UIWindow? 19 | 20 | // MARK: UIApplicationDelegate 21 | 22 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 23 | // Override point for customization after application launch. 24 | return true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | 35 | # Ignore those pesky DS_Store files! 36 | .DS_Store 37 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Model/Notebook.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notebook.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Notebook { 12 | /// The name for the notebook 13 | let name: String 14 | 15 | /// The date the notebook was created 16 | let creationDate: Date 17 | 18 | /// The notes contained by the notebook 19 | var notes: [Note] = [] 20 | 21 | init(name: String) { 22 | self.name = name 23 | creationDate = Date() 24 | notes = [] 25 | } 26 | } 27 | 28 | extension Notebook { 29 | /// Add a new note to the notebook 30 | func addNote() { 31 | notes.append(Note()) 32 | } 33 | 34 | /// Removes the note at a specific index 35 | func removeNote(at index: Int) { 36 | notes.remove(at: index) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iOS Developer Nanodegree logo 2 | 3 | # iOS Persistence and Core Data 4 | 5 | ![Platform iOS](https://img.shields.io/badge/nanodegree-iOS-blue.svg) 6 | 7 | This repository contains resources for Udacity's iOS Persistence and Core Data course. 8 | 9 | ## Overview 10 | 11 | iOS Persistence and Core Data teach common persistence techniques using Apple's frameworks for storing data locally on the device. The course includes: 12 | 13 | * PickYourPitch, which has a small user preference we'll store in UserDefaults 14 | * SandboxPlayground, which we'll use to explore saving and reading files using FileManager 15 | * Mooskine, a note-taking app which we'll convert to Core Data 16 | 17 | ## Setup 18 | 19 | Generally speaking, most projects can run without any additional setup. However, consult the iOS Persistence and Core Data course for more information. 20 | 21 | ## Maintainers 22 | 23 | @OwenLaRosa 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Udacity 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/MooskineTests/MooskineTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MooskineTests.swift 3 | // MooskineTests 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Mooskine 11 | 12 | class MooskineTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/MooskineTests/MooskineTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MooskineTests.swift 3 | // MooskineTests 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Mooskine 11 | 12 | class MooskineTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/UpdateToAttributedStringsPolicy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UpdateToAttributedStringsPolicy.swift 3 | // Mooskine 4 | // 5 | // Created by Kathryn Rotondo on 11/10/17. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import CoreData 12 | 13 | class UpdateToAttributedStringsPolicy: NSEntityMigrationPolicy { 14 | 15 | override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { 16 | // Call super 17 | try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager) 18 | 19 | // Get the (updated) destination Note instance we're modifying 20 | guard let destination = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else { return } 21 | 22 | // Use the (original) source Note instance, and instantiate a new 23 | // NSAttributedString using the original string 24 | if let text = sInstance.value(forKey: "text") as? String { 25 | destination.setValue(NSAttributedString(string: text), forKey: "attributedText") 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Mooskine.xcdatamodeld/Mooskine.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Mooskine.xcdatamodeld/Mooskine-2017-11-10-AttributedString.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIAppFonts 6 | 7 | OpenSans-Bold.ttf 8 | OpenSans-Regular.ttf 9 | OpenSans-Semibold.ttf 10 | 11 | CFBundleDevelopmentRegion 12 | en 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PRODUCT_NAME) 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleVersion 26 | 1 27 | LSRequiresIPhoneOS 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | UIInterfaceOrientationPortraitUpsideDown 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIAppFonts 6 | 7 | OpenSans-Bold.ttf 8 | OpenSans-Regular.ttf 9 | OpenSans-Semibold.ttf 10 | 11 | CFBundleDevelopmentRegion 12 | en 13 | CFBundleExecutable 14 | $(EXECUTABLE_NAME) 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | $(PRODUCT_NAME) 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleVersion 26 | 1 27 | LSRequiresIPhoneOS 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | UIInterfaceOrientationPortraitUpsideDown 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR [Assign the ND component] | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"Github PR"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/DataController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataController.swift 3 | // Mooskine 4 | // 5 | // Created by Kathryn Rotondo on 10/11/17. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | class DataController { 13 | 14 | let persistentContainer:NSPersistentContainer 15 | 16 | var viewContext:NSManagedObjectContext { 17 | return persistentContainer.viewContext 18 | } 19 | 20 | let backgroundContext:NSManagedObjectContext! 21 | 22 | init(modelName:String) { 23 | persistentContainer = NSPersistentContainer(name: modelName) 24 | 25 | backgroundContext = persistentContainer.newBackgroundContext() 26 | } 27 | 28 | func configureContexts() { 29 | viewContext.automaticallyMergesChangesFromParent = true 30 | backgroundContext.automaticallyMergesChangesFromParent = true 31 | 32 | backgroundContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump 33 | viewContext.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump 34 | } 35 | 36 | func load(completion: (() -> Void)? = nil) { 37 | persistentContainer.loadPersistentStores { storeDescription, error in 38 | guard error == nil else { 39 | fatalError(error!.localizedDescription) 40 | } 41 | self.autoSaveViewContext() 42 | self.configureContexts() 43 | completion?() 44 | } 45 | } 46 | } 47 | 48 | // MARK: - Autosaving 49 | 50 | extension DataController { 51 | func autoSaveViewContext(interval:TimeInterval = 30) { 52 | print("autosaving") 53 | 54 | guard interval > 0 else { 55 | print("cannot set negative autosave interval") 56 | return 57 | } 58 | 59 | if viewContext.hasChanges { 60 | try? viewContext.save() 61 | } 62 | 63 | DispatchQueue.main.asyncAfter(deadline: .now() + interval) { 64 | self.autoSaveViewContext(interval: interval) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/View Controllers/NoteDetailsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteDetailsViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NoteDetailsViewController: UIViewController { 12 | /// A text view that displays a note's text 13 | @IBOutlet weak var textView: UITextView! 14 | 15 | /// The note being displayed and edited 16 | var note: Note! 17 | 18 | /// A closure that is run when the user asks to delete the current note 19 | var onDelete: (() -> Void)? 20 | 21 | /// A date formatter for the view controller's title text 22 | let dateFormatter: DateFormatter = { 23 | let df = DateFormatter() 24 | df.dateStyle = .medium 25 | return df 26 | }() 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | navigationItem.title = dateFormatter.string(from: note.creationDate) 32 | textView.text = note.text 33 | } 34 | 35 | @IBAction func deleteNote(sender: Any) { 36 | presentDeleteNotebookAlert() 37 | } 38 | } 39 | 40 | // ----------------------------------------------------------------------------- 41 | // MARK: - Editing 42 | 43 | extension NoteDetailsViewController { 44 | func presentDeleteNotebookAlert() { 45 | let alert = UIAlertController(title: "Delete Note", message: "Do you want to delete this note?", preferredStyle: .alert) 46 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) 47 | alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: deleteHandler)) 48 | present(alert, animated: true, completion: nil) 49 | } 50 | 51 | func deleteHandler(alertAction: UIAlertAction) { 52 | onDelete?() 53 | } 54 | } 55 | 56 | // ----------------------------------------------------------------------------- 57 | // MARK: - UITextViewDelegate 58 | 59 | extension NoteDetailsViewController: UITextViewDelegate { 60 | func textViewDidEndEditing(_ textView: UITextView) { 61 | note.text = textView.text 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch.xcodeproj/project.xcworkspace/xcshareddata/PickYourPitch.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "110AB89DE05ABD8A5A321ADE3254A1BB5198BC51", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "CD28FA6A2CFC634512324DD7C91B7993C5276BCE" : 0, 8 | "5E32233CC4B3D004BDE8903D03F6C0AFCAF27AFC" : 0, 9 | "110AB89DE05ABD8A5A321ADE3254A1BB5198BC51" : 0 10 | }, 11 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "D4A82946-9A7F-4557-B337-2BB27D41E2A7", 12 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 13 | "CD28FA6A2CFC634512324DD7C91B7993C5276BCE" : "ios-persistence", 14 | "5E32233CC4B3D004BDE8903D03F6C0AFCAF27AFC" : "ios-persistence-2.0\/", 15 | "110AB89DE05ABD8A5A321ADE3254A1BB5198BC51" : "ios-nd-persistence\/" 16 | }, 17 | "DVTSourceControlWorkspaceBlueprintNameKey" : "PickYourPitch", 18 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 19 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "PickYourPitch\/PickYourPitch.xcodeproj", 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 21 | { 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/udacity\/ios-nd-persistence", 23 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 24 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "110AB89DE05ABD8A5A321ADE3254A1BB5198BC51" 25 | }, 26 | { 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/udacity\/ios-persistence-2.0", 28 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 29 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "5E32233CC4B3D004BDE8903D03F6C0AFCAF27AFC" 30 | }, 31 | { 32 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/udacity\/ios-persistence", 33 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 34 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "CD28FA6A2CFC634512324DD7C91B7993C5276BCE" 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small@2x.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@3x.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-40@2x.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-40@3x.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-60@2x.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "Icon-60@3x.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "1x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "20x20", 57 | "scale" : "2x" 58 | }, 59 | { 60 | "size" : "29x29", 61 | "idiom" : "ipad", 62 | "filename" : "Icon-Small.png", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "size" : "29x29", 67 | "idiom" : "ipad", 68 | "filename" : "Icon-Small@2x.png", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "size" : "40x40", 73 | "idiom" : "ipad", 74 | "filename" : "Icon-40.png", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "size" : "40x40", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-40@2x.png", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "size" : "76x76", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-76.png", 87 | "scale" : "1x" 88 | }, 89 | { 90 | "size" : "76x76", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-76@2x.png", 93 | "scale" : "2x" 94 | }, 95 | { 96 | "size" : "83.5x83.5", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-83.5@2x.png", 99 | "scale" : "2x" 100 | } 101 | ], 102 | "info" : { 103 | "version" : 1, 104 | "author" : "xcode" 105 | } 106 | } -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small@2x.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@3x.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-40@2x.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-40@3x.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-60@2x.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "Icon-60@3x.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "1x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "20x20", 57 | "scale" : "2x" 58 | }, 59 | { 60 | "size" : "29x29", 61 | "idiom" : "ipad", 62 | "filename" : "Icon-Small.png", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "size" : "29x29", 67 | "idiom" : "ipad", 68 | "filename" : "Icon-Small@2x.png", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "size" : "40x40", 73 | "idiom" : "ipad", 74 | "filename" : "Icon-40.png", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "size" : "40x40", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-40@2x.png", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "size" : "76x76", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-76.png", 87 | "scale" : "1x" 88 | }, 89 | { 90 | "size" : "76x76", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-76@2x.png", 93 | "scale" : "2x" 94 | }, 95 | { 96 | "size" : "83.5x83.5", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-83.5@2x.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "1024x1024", 103 | "idiom" : "ios-marketing", 104 | "filename" : "1024-mark-blue.png", 105 | "scale" : "1x" 106 | } 107 | ], 108 | "info" : { 109 | "version" : 1, 110 | "author" : "xcode" 111 | } 112 | } -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-29. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | let dataController = DataController(modelName: "Mooskine") 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 19 | // Override point for customization after application launch. 20 | 21 | dataController.load() 22 | 23 | let navigationController = window?.rootViewController as! UINavigationController 24 | let notebooksListViewController = navigationController.topViewController as! NotebooksListViewController 25 | notebooksListViewController.dataController = dataController 26 | 27 | return true 28 | } 29 | 30 | func applicationWillResignActive(_ application: UIApplication) { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 33 | } 34 | 35 | func applicationDidEnterBackground(_ application: UIApplication) { 36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | saveViewContext() 39 | } 40 | 41 | func applicationWillEnterForeground(_ application: UIApplication) { 42 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | func applicationDidBecomeActive(_ application: UIApplication) { 46 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 47 | } 48 | 49 | func applicationWillTerminate(_ application: UIApplication) { 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | saveViewContext() 52 | } 53 | 54 | func saveViewContext() { 55 | try? dataController.viewContext.save() 56 | } 57 | 58 | } 59 | 60 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Pick Your Pitch 4 | // 5 | // Created by Udacity on 1/5/15. 6 | // Copyright (c) 2015 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - AppDelegate: UIResponder, UIApplicationDelegate 12 | 13 | @UIApplicationMain 14 | class AppDelegate: UIResponder, UIApplicationDelegate { 15 | 16 | // MARK: Properties 17 | 18 | var window: UIWindow? 19 | 20 | // MARK: UIApplicationDelegate 21 | 22 | func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 23 | // Usually this is not overridden. Using the "did finish launching" method is more typical 24 | print("App Delegate: will finish launching") 25 | 26 | return true 27 | } 28 | 29 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 30 | // Override point for customization after application launch. 31 | 32 | print("App Delegate: did finish launching") 33 | 34 | return true 35 | } 36 | 37 | func applicationDidBecomeActive(_ application: UIApplication) { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | 40 | print("App Delegate: did become active") 41 | } 42 | 43 | func applicationWillResignActive(_ application: UIApplication) { 44 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 45 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 46 | 47 | print("App Delegate: will resign active") 48 | } 49 | 50 | func applicationDidEnterBackground(_ application: UIApplication) { 51 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 52 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 53 | 54 | print("App Delegate: did enter background") 55 | } 56 | 57 | func applicationWillEnterForeground(_ application: UIApplication) { 58 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 59 | 60 | print("App Delegate: will enter foreground") 61 | } 62 | 63 | func applicationWillTerminate(_ application: UIApplication) { 64 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 65 | 66 | print("App Delegate: will terminate") 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/PlaySoundsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaySoundsViewController.swift 3 | // Pick Your Pitch 4 | // 5 | // Created by Udacity on 1/5/15. 6 | // Copyright (c) 2014 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | // MARK: - PlaySoundsViewController: UIViewController 13 | 14 | class PlaySoundsViewController: UIViewController { 15 | 16 | // MARK: Properties 17 | 18 | let SliderValueKey = "Slider Value Key" 19 | var audioPlayer:AVAudioPlayer! 20 | var receivedAudio:RecordedAudio! 21 | var audioEngine:AVAudioEngine! 22 | var audioFile:AVAudioFile! 23 | 24 | // MARK: Outlets 25 | 26 | @IBOutlet weak var sliderView: UISlider! 27 | @IBOutlet weak var startButton: UIButton! 28 | @IBOutlet weak var stopButton: UIButton! 29 | 30 | // MARK: Life Cycle 31 | 32 | override func viewDidLoad() { 33 | super.viewDidLoad() 34 | 35 | do { 36 | audioPlayer = try AVAudioPlayer(contentsOf: receivedAudio.filePathUrl as URL) 37 | } catch _ { 38 | audioPlayer = nil 39 | } 40 | audioPlayer.enableRate = true 41 | 42 | audioEngine = AVAudioEngine() 43 | do { 44 | audioFile = try AVAudioFile(forReading: receivedAudio.filePathUrl as URL) 45 | } catch _ { 46 | audioFile = nil 47 | } 48 | 49 | setUserInterfaceToPlayMode(false) 50 | } 51 | 52 | // MARK: Set Interface 53 | 54 | func setUserInterfaceToPlayMode(_ isPlayMode: Bool) { 55 | startButton.isHidden = isPlayMode 56 | stopButton.isHidden = !isPlayMode 57 | sliderView.isEnabled = !isPlayMode 58 | } 59 | 60 | // MARK: Actions 61 | 62 | @IBAction func playAudio(_ sender: UIButton) { 63 | 64 | // Get the pitch from the slider 65 | let pitch = sliderView.value 66 | 67 | // Play the sound 68 | playAudioWithVariablePitch(pitch) 69 | 70 | // Set the UI 71 | setUserInterfaceToPlayMode(true) 72 | 73 | } 74 | 75 | @IBAction func stopAudio(_ sender: UIButton) { 76 | audioPlayer.stop() 77 | audioEngine.stop() 78 | audioEngine.reset() 79 | } 80 | 81 | @IBAction func sliderDidMove(_ sender: UISlider) { 82 | print("Slider value: \(sliderView.value)") 83 | } 84 | 85 | // MARK: Play Audio 86 | 87 | func playAudioWithVariablePitch(_ pitch: Float){ 88 | audioPlayer.stop() 89 | audioEngine.stop() 90 | audioEngine.reset() 91 | 92 | let audioPlayerNode = AVAudioPlayerNode() 93 | audioEngine.attach(audioPlayerNode) 94 | 95 | let changePitchEffect = AVAudioUnitTimePitch() 96 | changePitchEffect.pitch = pitch 97 | audioEngine.attach(changePitchEffect) 98 | 99 | audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil) 100 | audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil) 101 | 102 | audioPlayerNode.scheduleFile(audioFile, at: nil) { 103 | // When the audio completes, set the user interface on the main thread 104 | DispatchQueue.main.async {self.setUserInterfaceToPlayMode(false) } 105 | } 106 | 107 | do { 108 | try audioEngine.start() 109 | } catch _ { 110 | } 111 | 112 | audioPlayerNode.play() 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/RecordSoundsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RecordSoundsViewController.swift 3 | // Pick Your Pitch 4 | // 5 | // Created by Udacity on 1/5/15. 6 | // Copyright (c) 2014 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | // MARK: - RecordSoundsViewController: UIViewController, AVAudioRecorderDelegate 13 | 14 | class RecordSoundsViewController: UIViewController, AVAudioRecorderDelegate { 15 | 16 | // MARK: Properties 17 | 18 | var audioRecorder:AVAudioRecorder! 19 | var recordedAudio:RecordedAudio! 20 | var shouldSegueToSoundPlayer = false 21 | 22 | // MARK: Outlets 23 | 24 | @IBOutlet weak var recordingInProgress: UILabel! 25 | @IBOutlet weak var stopButton: UIButton! 26 | @IBOutlet weak var recordButton: UIButton! 27 | 28 | // MARK: Life Cycle 29 | 30 | override func viewWillAppear(_ animated: Bool) { 31 | //Hide the stop button 32 | stopButton.isHidden = true 33 | recordButton.isEnabled = true 34 | } 35 | 36 | // MARK: Actions 37 | 38 | @IBAction func recordAudio(_ sender: UIButton) { 39 | // Update the UI 40 | stopButton.isHidden = false 41 | recordingInProgress.isHidden = false 42 | recordButton.isEnabled = false 43 | 44 | // Setup audio session 45 | let session = AVAudioSession.sharedInstance() 46 | do { 47 | try session.setCategory(.playAndRecord) 48 | } catch _ { 49 | } 50 | 51 | // Create a name for the file. This is the code that you are looking for 52 | let filename = "usersVoice.wav" 53 | let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String 54 | let pathArray = [dirPath, filename] 55 | let fileURL = URL(string: pathArray.joined(separator: "/")) 56 | 57 | do { 58 | // Initialize and prepare the recorder 59 | audioRecorder = try AVAudioRecorder(url: fileURL!, settings: [String: AnyObject]()) 60 | } catch _ { 61 | } 62 | audioRecorder.delegate = self 63 | audioRecorder.isMeteringEnabled = true; 64 | audioRecorder.prepareToRecord() 65 | 66 | audioRecorder.record() 67 | } 68 | 69 | @IBAction func stopAudio(_ sender: UIButton) { 70 | recordingInProgress.isHidden = true 71 | audioRecorder.stop() 72 | let audioSession = AVAudioSession.sharedInstance(); 73 | do { 74 | try audioSession.setActive(false) 75 | } catch _ { 76 | } 77 | 78 | // This function stops the audio. We will then wait to hear back from the recorder, 79 | // through the audioRecorderDidFinishRecording method 80 | } 81 | 82 | // MARK: Audio Recorded 83 | 84 | func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { 85 | 86 | if flag { 87 | recordedAudio = RecordedAudio(filePathUrl: recorder.url, title: recorder.url.pathExtension) 88 | self.performSegue(withIdentifier: "stopRecording", sender: self) 89 | } else { 90 | print("Recording was not successful") 91 | recordButton.isEnabled = true 92 | stopButton.isHidden = true 93 | } 94 | } 95 | 96 | // MARK: Segue 97 | 98 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 99 | 100 | if segue.identifier == "stopRecording" { 101 | let playSoundsVC:PlaySoundsViewController = segue.destination as! PlaySoundsViewController 102 | let data = recordedAudio 103 | playSoundsVC.receivedAudio = data 104 | } 105 | } 106 | } 107 | 108 | 109 | // Helper function inserted by Swift 4.2 migrator. 110 | fileprivate func convertFromAVAudioSessionCategory(_ input: AVAudioSession.Category) -> String { 111 | return input.rawValue 112 | } 113 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Model/Pathifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pathifier.swift 3 | // Mooskine 4 | // 5 | // Copyright © 2017 Udacity. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | import CoreText 10 | 11 | internal struct Pathifier { 12 | /// Creates a UIBezierPath from a supplied attributed string and font (the 13 | /// font will be applied to the entire attributed string). 14 | static func makeBezierPath(for attributedString: NSAttributedString, withFont font: UIFont) -> UIBezierPath { 15 | // To generate the bezier path, we'll break the attributed string into 16 | // a series of `NSGlyph`s using TextKit, and use a CoreText function to 17 | // create individual individual paths for each glyph. 18 | 19 | // Apply the supplied font 20 | let text = NSMutableAttributedString(string: attributedString.string) 21 | text.addAttribute(NSAttributedString.Key.font, value: font, range: NSMakeRange(0, text.length)) 22 | 23 | // Create a NSLayoutManager to generate the glyphs 24 | let layoutManager = NSLayoutManager() 25 | let textContainer = NSTextContainer() 26 | let textStorage = NSTextStorage(attributedString: text) 27 | textStorage.addLayoutManager(layoutManager) 28 | layoutManager.addTextContainer(textContainer) 29 | 30 | // Use the layout manager to loop through the glyphs, adding to a bezier 31 | // path as we go 32 | let path = UIBezierPath() 33 | let font = CTFontCreateWithFontDescriptor(font.fontDescriptor, font.pointSize, nil) 34 | for glyphIndex in 0 ..< layoutManager.numberOfGlyphs { 35 | let glyph = layoutManager.cgGlyph(at: glyphIndex) 36 | let position = layoutManager.location(forGlyphAt: glyphIndex) 37 | if let glyphPath = CTFontCreatePathForGlyph(font, glyph, nil) { 38 | let glyphBezierPath = UIBezierPath(cgPath: glyphPath) 39 | glyphBezierPath.apply(CGAffineTransform(translationX: position.x, y: 0)) 40 | path.append(glyphBezierPath) 41 | } 42 | } 43 | 44 | return path 45 | } 46 | 47 | /// Generate an image for an attributed string, using `makeBezierPath(for:withFont:)` 48 | static func makeImage(for attributedString: NSAttributedString, withFont font: UIFont, withPatternImage patternImage: UIImage) -> UIImage { 49 | let path = makeBezierPath(for: attributedString, withFont: font) 50 | let bounds = path.bounds 51 | let pad = CGSize(width: 4, height: 6) // Add some padding so the wide lines don't clip - should figure out the metrics for this via Core Text. :) 52 | let size = CGSize(width: bounds.size.width + bounds.origin.x + pad.width, height: bounds.size.height + pad.height) 53 | 54 | UIGraphicsBeginImageContextWithOptions(size, false, 0) 55 | let context = UIGraphicsGetCurrentContext() 56 | 57 | // Flip the orientation vertically 58 | context?.scaleBy(x: 1, y: -1) 59 | context?.translateBy(x: 0, y: -size.height) 60 | 61 | // Adjust positioning for the padding 62 | context?.translateBy(x: -pad.width / 2, y: pad.height / 2) 63 | 64 | // Draw the path 65 | context?.setFillColor(UIColor(patternImage: patternImage).cgColor) 66 | path.fill() 67 | context?.setStrokeColor(UIColor.black.cgColor) 68 | path.stroke() 69 | let image = UIGraphicsGetImageFromCurrentImageContext() 70 | UIGraphicsEndImageContext() 71 | 72 | return image! 73 | } 74 | 75 | static func makeMutableAttributedString(for attributedString: NSAttributedString, withFont font: UIFont, withPatternImage patternImage: UIImage) -> NSMutableAttributedString { 76 | 77 | // converts text to image using patternimage 78 | let image = Pathifier.makeImage(for: attributedString, withFont: font, withPatternImage: patternImage) 79 | 80 | // creates a text attachment with the image 81 | let attachment = NSTextAttachment() 82 | attachment.image = image 83 | 84 | // converts attachment to mutable attributed string 85 | let attachmentAsText = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attachment)) 86 | return attachmentAsText 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/View Controllers/NotesListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotesListViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NotesListViewController: UIViewController, UITableViewDataSource { 12 | /// A table view that displays a list of notes for a notebook 13 | @IBOutlet weak var tableView: UITableView! 14 | 15 | /// The notebook whose notes are being displayed 16 | var notebook: Notebook! 17 | 18 | /// A date formatter for date text in note cells 19 | let dateFormatter: DateFormatter = { 20 | let df = DateFormatter() 21 | df.dateStyle = .medium 22 | return df 23 | }() 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | navigationItem.title = notebook.name 29 | navigationItem.rightBarButtonItem = editButtonItem 30 | updateEditButtonState() 31 | } 32 | 33 | override func viewWillAppear(_ animated: Bool) { 34 | super.viewWillAppear(animated) 35 | 36 | if let indexPath = tableView.indexPathForSelectedRow { 37 | tableView.deselectRow(at: indexPath, animated: false) 38 | tableView.reloadRows(at: [indexPath], with: .fade) 39 | } 40 | } 41 | 42 | // ------------------------------------------------------------------------- 43 | // MARK: - Actions 44 | 45 | @IBAction func addTapped(sender: Any) { 46 | addNote() 47 | } 48 | 49 | // ------------------------------------------------------------------------- 50 | // MARK: - Editing 51 | 52 | // Adds a new `Note` to the end of the `notebook`'s `notes` array 53 | func addNote() { 54 | notebook.addNote() 55 | tableView.insertRows(at: [IndexPath(row: numberOfNotes - 1, section: 0)], with: .fade) 56 | updateEditButtonState() 57 | } 58 | 59 | // Deletes the `Note` at the specified index path 60 | func deleteNote(at indexPath: IndexPath) { 61 | notebook.removeNote(at: indexPath.row) 62 | tableView.deleteRows(at: [indexPath], with: .fade) 63 | if numberOfNotes == 0 { 64 | setEditing(false, animated: true) 65 | } 66 | updateEditButtonState() 67 | } 68 | 69 | func updateEditButtonState() { 70 | navigationItem.rightBarButtonItem?.isEnabled = numberOfNotes > 0 71 | } 72 | 73 | override func setEditing(_ editing: Bool, animated: Bool) { 74 | super.setEditing(editing, animated: animated) 75 | tableView.setEditing(editing, animated: animated) 76 | } 77 | 78 | // ------------------------------------------------------------------------- 79 | // MARK: - Table view data source 80 | 81 | func numberOfSections(in tableView: UITableView) -> Int { 82 | return 1 83 | } 84 | 85 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 86 | return numberOfNotes 87 | } 88 | 89 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 90 | let aNote = note(at: indexPath) 91 | let cell = tableView.dequeueReusableCell(withIdentifier: NoteCell.defaultReuseIdentifier, for: indexPath) as! NoteCell 92 | 93 | // Configure cell 94 | cell.textPreviewLabel.text = aNote.text 95 | cell.dateLabel.text = dateFormatter.string(from: aNote.creationDate) 96 | 97 | return cell 98 | } 99 | 100 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 101 | switch editingStyle { 102 | case .delete: deleteNote(at: indexPath) 103 | default: () // Unsupported 104 | } 105 | } 106 | 107 | // Helpers 108 | 109 | var numberOfNotes: Int { return notebook.notes.count } 110 | 111 | func note(at indexPath: IndexPath) -> Note { 112 | return notebook.notes[indexPath.row] 113 | } 114 | 115 | // ------------------------------------------------------------------------- 116 | // MARK: - Navigation 117 | 118 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 119 | // If this is a NoteDetailsViewController, we'll configure its `Note` 120 | // and its delete action 121 | if let vc = segue.destination as? NoteDetailsViewController { 122 | if let indexPath = tableView.indexPathForSelectedRow { 123 | vc.note = note(at: indexPath) 124 | 125 | vc.onDelete = { [weak self] in 126 | if let indexPath = self?.tableView.indexPathForSelectedRow { 127 | self?.deleteNote(at: indexPath) 128 | self?.navigationController?.popViewController(animated: true) 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-starter/Mooskine/View Controllers/NotebooksListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotebooksListViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NotebooksListViewController: UIViewController, UITableViewDataSource { 12 | /// A table view that displays a list of notebooks 13 | @IBOutlet weak var tableView: UITableView! 14 | 15 | /// The `Notebook` objects being presented 16 | var notebooks: [Notebook] = [] 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | navigationItem.titleView = UIImageView(image: #imageLiteral(resourceName: "toolbar-cow")) 21 | navigationItem.rightBarButtonItem = editButtonItem 22 | updateEditButtonState() 23 | } 24 | 25 | override func viewWillAppear(_ animated: Bool) { 26 | super.viewWillAppear(animated) 27 | 28 | if let indexPath = tableView.indexPathForSelectedRow { 29 | tableView.deselectRow(at: indexPath, animated: false) 30 | tableView.reloadRows(at: [indexPath], with: .fade) 31 | } 32 | } 33 | 34 | // ------------------------------------------------------------------------- 35 | // MARK: - Actions 36 | 37 | @IBAction func addTapped(sender: Any) { 38 | presentNewNotebookAlert() 39 | } 40 | 41 | // ------------------------------------------------------------------------- 42 | // MARK: - Editing 43 | 44 | /// Display an alert prompting the user to name a new notebook. Calls 45 | /// `addNotebook(name:)`. 46 | func presentNewNotebookAlert() { 47 | let alert = UIAlertController(title: "New Notebook", message: "Enter a name for this notebook", preferredStyle: .alert) 48 | 49 | // Create actions 50 | let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 51 | let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] action in 52 | if let name = alert.textFields?.first?.text { 53 | self?.addNotebook(name: name) 54 | } 55 | } 56 | saveAction.isEnabled = false 57 | 58 | // Add a text field 59 | alert.addTextField { textField in 60 | textField.placeholder = "Name" 61 | NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: .main) { notif in 62 | if let text = textField.text, !text.isEmpty { 63 | saveAction.isEnabled = true 64 | } else { 65 | saveAction.isEnabled = false 66 | } 67 | } 68 | } 69 | 70 | alert.addAction(cancelAction) 71 | alert.addAction(saveAction) 72 | present(alert, animated: true, completion: nil) 73 | } 74 | 75 | /// Adds a new notebook to the end of the `notebooks` array 76 | func addNotebook(name: String) { 77 | let notebook = Notebook(name: name) 78 | notebooks.append(notebook) 79 | tableView.insertRows(at: [IndexPath(row: numberOfNotebooks - 1, section: 0)], with: .fade) 80 | updateEditButtonState() 81 | } 82 | 83 | /// Deletes the notebook at the specified index path 84 | func deleteNotebook(at indexPath: IndexPath) { 85 | notebooks.remove(at: indexPath.row) 86 | tableView.deleteRows(at: [indexPath], with: .fade) 87 | if numberOfNotebooks == 0 { 88 | setEditing(false, animated: true) 89 | } 90 | updateEditButtonState() 91 | } 92 | 93 | func updateEditButtonState() { 94 | navigationItem.rightBarButtonItem?.isEnabled = numberOfNotebooks > 0 95 | } 96 | 97 | override func setEditing(_ editing: Bool, animated: Bool) { 98 | super.setEditing(editing, animated: animated) 99 | tableView.setEditing(editing, animated: animated) 100 | } 101 | 102 | // ------------------------------------------------------------------------- 103 | // MARK: - Table view data source 104 | 105 | func numberOfSections(in tableView: UITableView) -> Int { 106 | return 1 107 | } 108 | 109 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 110 | return numberOfNotebooks 111 | } 112 | 113 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 114 | let aNotebook = notebook(at: indexPath) 115 | let cell = tableView.dequeueReusableCell(withIdentifier: NotebookCell.defaultReuseIdentifier, for: indexPath) as! NotebookCell 116 | 117 | // Configure cell 118 | cell.nameLabel.text = aNotebook.name 119 | let pageString = aNotebook.notes.count == 1 ? "page" : "pages" 120 | cell.pageCountLabel.text = "\(aNotebook.notes.count) \(pageString)" 121 | 122 | return cell 123 | } 124 | 125 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 126 | switch editingStyle { 127 | case .delete: deleteNotebook(at: indexPath) 128 | default: () // Unsupported 129 | } 130 | } 131 | 132 | // Helper 133 | 134 | var numberOfNotebooks: Int { return notebooks.count } 135 | 136 | func notebook(at indexPath: IndexPath) -> Notebook { 137 | return notebooks[indexPath.row] 138 | } 139 | 140 | // ------------------------------------------------------------------------- 141 | // MARK: - Navigation 142 | 143 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 144 | // If this is a NotesListViewController, we'll configure its `Notebook` 145 | if let vc = segue.destination as? NotesListViewController { 146 | if let indexPath = tableView.indexPathForSelectedRow { 147 | vc.notebook = notebook(at: indexPath) 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/View Controllers/NotesListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotesListViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | class NotesListViewController: UIViewController, UITableViewDataSource { 13 | /// A table view that displays a list of notes for a notebook 14 | @IBOutlet weak var tableView: UITableView! 15 | 16 | /// The notebook whose notes are being displayed 17 | var notebook: Notebook! 18 | 19 | var dataController:DataController! 20 | 21 | var fetchedResultsController:NSFetchedResultsController! 22 | 23 | /// A date formatter for date text in note cells 24 | let dateFormatter: DateFormatter = { 25 | let df = DateFormatter() 26 | df.dateStyle = .medium 27 | return df 28 | }() 29 | 30 | fileprivate func setupFetchedResultsController() { 31 | let fetchRequest:NSFetchRequest = Note.fetchRequest() 32 | let predicate = NSPredicate(format: "notebook == %@", notebook) 33 | fetchRequest.predicate = predicate 34 | let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: true) 35 | fetchRequest.sortDescriptors = [sortDescriptor] 36 | 37 | fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: dataController.viewContext, sectionNameKeyPath: nil, cacheName: "\(notebook)-notes") 38 | fetchedResultsController.delegate = self 39 | 40 | do { 41 | try fetchedResultsController.performFetch() 42 | } catch { 43 | fatalError("The fetch could not be performed: \(error.localizedDescription)") 44 | } 45 | } 46 | 47 | override func viewDidLoad() { 48 | super.viewDidLoad() 49 | 50 | navigationItem.title = notebook.name 51 | navigationItem.rightBarButtonItem = editButtonItem 52 | 53 | setupFetchedResultsController() 54 | 55 | updateEditButtonState() 56 | } 57 | 58 | override func viewWillAppear(_ animated: Bool) { 59 | super.viewWillAppear(animated) 60 | setupFetchedResultsController() 61 | if let indexPath = tableView.indexPathForSelectedRow { 62 | tableView.deselectRow(at: indexPath, animated: false) 63 | tableView.reloadRows(at: [indexPath], with: .fade) 64 | } 65 | } 66 | 67 | override func viewDidDisappear(_ animated: Bool) { 68 | super.viewDidDisappear(animated) 69 | fetchedResultsController = nil 70 | } 71 | 72 | // ------------------------------------------------------------------------- 73 | // MARK: - Actions 74 | 75 | @IBAction func addTapped(sender: Any) { 76 | addNote() 77 | } 78 | 79 | // ------------------------------------------------------------------------- 80 | // MARK: - Editing 81 | 82 | // Adds a new `Note` to the end of the `notebook`'s `notes` array 83 | func addNote() { 84 | let note = Note(context: dataController.viewContext) 85 | note.creationDate = Date() 86 | note.notebook = notebook 87 | try? dataController.viewContext.save() 88 | } 89 | 90 | // Deletes the `Note` at the specified index path 91 | func deleteNote(at indexPath: IndexPath) { 92 | let noteToDelete = fetchedResultsController.object(at: indexPath) 93 | dataController.viewContext.delete(noteToDelete) 94 | try? dataController.viewContext.save() 95 | } 96 | 97 | func updateEditButtonState() { 98 | navigationItem.rightBarButtonItem?.isEnabled = fetchedResultsController.sections![0].numberOfObjects > 0 99 | } 100 | 101 | override func setEditing(_ editing: Bool, animated: Bool) { 102 | super.setEditing(editing, animated: animated) 103 | tableView.setEditing(editing, animated: animated) 104 | } 105 | 106 | // ------------------------------------------------------------------------- 107 | // MARK: - Table view data source 108 | 109 | func numberOfSections(in tableView: UITableView) -> Int { 110 | return fetchedResultsController.sections?.count ?? 1 111 | } 112 | 113 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 114 | return fetchedResultsController.sections?[0].numberOfObjects ?? 0 115 | } 116 | 117 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 118 | let aNote = fetchedResultsController.object(at: indexPath) 119 | let cell = tableView.dequeueReusableCell(withIdentifier: NoteCell.defaultReuseIdentifier, for: indexPath) as! NoteCell 120 | 121 | // Configure cell 122 | cell.textPreviewLabel.attributedText = aNote.attributedText 123 | 124 | if let creationDate = aNote.creationDate { 125 | cell.dateLabel.text = dateFormatter.string(from: creationDate) 126 | } 127 | 128 | return cell 129 | } 130 | 131 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 132 | switch editingStyle { 133 | case .delete: deleteNote(at: indexPath) 134 | default: () // Unsupported 135 | } 136 | } 137 | 138 | // ------------------------------------------------------------------------- 139 | // MARK: - Navigation 140 | 141 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 142 | // If this is a NoteDetailsViewController, we'll configure its `Note` 143 | // and its delete action 144 | if let vc = segue.destination as? NoteDetailsViewController { 145 | if let indexPath = tableView.indexPathForSelectedRow { 146 | vc.note = fetchedResultsController.object(at: indexPath) 147 | vc.dataController = dataController 148 | 149 | vc.onDelete = { [weak self] in 150 | if let indexPath = self?.tableView.indexPathForSelectedRow { 151 | self?.deleteNote(at: indexPath) 152 | self?.navigationController?.popViewController(animated: true) 153 | } 154 | } 155 | } 156 | } 157 | } 158 | } 159 | 160 | extension NotesListViewController:NSFetchedResultsControllerDelegate { 161 | 162 | func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 163 | switch type { 164 | case .insert: 165 | tableView.insertRows(at: [newIndexPath!], with: .fade) 166 | break 167 | case .delete: 168 | tableView.deleteRows(at: [indexPath!], with: .fade) 169 | break 170 | case .update: 171 | tableView.reloadRows(at: [indexPath!], with: .fade) 172 | case .move: 173 | tableView.moveRow(at: indexPath!, to: newIndexPath!) 174 | } 175 | } 176 | 177 | func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { 178 | let indexSet = IndexSet(integer: sectionIndex) 179 | switch type { 180 | case .insert: tableView.insertSections(indexSet, with: .fade) 181 | case .delete: tableView.deleteSections(indexSet, with: .fade) 182 | case .update, .move: 183 | fatalError("Invalid change type in controller(_:didChange:atSectionIndex:for:). Only .insert or .delete should be possible.") 184 | } 185 | } 186 | 187 | 188 | func controllerWillChangeContent(_ controller: NSFetchedResultsController) { 189 | tableView.beginUpdates() 190 | } 191 | 192 | func controllerDidChangeContent(_ controller: NSFetchedResultsController) { 193 | tableView.endUpdates() 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/View Controllers/NotebooksListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotebooksListViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | class NotebooksListViewController: UIViewController, UITableViewDataSource { 13 | /// A table view that displays a list of notebooks 14 | @IBOutlet weak var tableView: UITableView! 15 | 16 | var dataController:DataController! 17 | 18 | var fetchedResultsController:NSFetchedResultsController! 19 | 20 | fileprivate func setupFetchedResultsController() { 21 | let fetchRequest:NSFetchRequest = Notebook.fetchRequest() 22 | let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false) 23 | fetchRequest.sortDescriptors = [sortDescriptor] 24 | 25 | fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: dataController.viewContext, sectionNameKeyPath: nil, cacheName: "notebooks") 26 | fetchedResultsController.delegate = self 27 | do { 28 | try fetchedResultsController.performFetch() 29 | } catch { 30 | fatalError("The fetch could not be performed: \(error.localizedDescription)") 31 | } 32 | } 33 | 34 | override func viewDidLoad() { 35 | super.viewDidLoad() 36 | navigationItem.titleView = UIImageView(image: #imageLiteral(resourceName: "toolbar-cow")) 37 | navigationItem.rightBarButtonItem = editButtonItem 38 | 39 | setupFetchedResultsController() 40 | } 41 | 42 | override func viewWillAppear(_ animated: Bool) { 43 | super.viewWillAppear(animated) 44 | setupFetchedResultsController() 45 | if let indexPath = tableView.indexPathForSelectedRow { 46 | tableView.deselectRow(at: indexPath, animated: false) 47 | tableView.reloadRows(at: [indexPath], with: .fade) 48 | } 49 | } 50 | 51 | override func viewDidDisappear(_ animated: Bool) { 52 | super.viewDidDisappear(animated) 53 | fetchedResultsController = nil 54 | } 55 | 56 | // ------------------------------------------------------------------------- 57 | // MARK: - Actions 58 | 59 | @IBAction func addTapped(sender: Any) { 60 | presentNewNotebookAlert() 61 | } 62 | 63 | // ------------------------------------------------------------------------- 64 | // MARK: - Editing 65 | 66 | /// Display an alert prompting the user to name a new notebook. Calls 67 | /// `addNotebook(name:)`. 68 | func presentNewNotebookAlert() { 69 | let alert = UIAlertController(title: "New Notebook", message: "Enter a name for this notebook", preferredStyle: .alert) 70 | 71 | // Create actions 72 | let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 73 | let saveAction = UIAlertAction(title: "Save", style: .default) { [weak self] action in 74 | if let name = alert.textFields?.first?.text { 75 | self?.addNotebook(name: name) 76 | } 77 | } 78 | saveAction.isEnabled = false 79 | 80 | // Add a text field 81 | alert.addTextField { textField in 82 | textField.placeholder = "Name" 83 | NotificationCenter.default.addObserver(forName: UITextField.textDidChangeNotification, object: textField, queue: .main) { notif in 84 | if let text = textField.text, !text.isEmpty { 85 | saveAction.isEnabled = true 86 | } else { 87 | saveAction.isEnabled = false 88 | } 89 | } 90 | } 91 | 92 | alert.addAction(cancelAction) 93 | alert.addAction(saveAction) 94 | present(alert, animated: true, completion: nil) 95 | } 96 | 97 | /// Adds a new notebook to the end of the `notebooks` array 98 | func addNotebook(name: String) { 99 | let notebook = Notebook(context: dataController.viewContext) 100 | notebook.name = name 101 | notebook.creationDate = Date() 102 | try? dataController.viewContext.save() 103 | } 104 | 105 | /// Deletes the notebook at the specified index path 106 | func deleteNotebook(at indexPath: IndexPath) { 107 | let notebookToDelete = fetchedResultsController.object(at: indexPath) 108 | dataController.viewContext.delete(notebookToDelete) 109 | try? dataController.viewContext.save() 110 | } 111 | 112 | func updateEditButtonState() { 113 | if let sections = fetchedResultsController.sections { 114 | navigationItem.rightBarButtonItem?.isEnabled = sections[0].numberOfObjects > 0 115 | } 116 | } 117 | 118 | override func setEditing(_ editing: Bool, animated: Bool) { 119 | super.setEditing(editing, animated: animated) 120 | tableView.setEditing(editing, animated: animated) 121 | } 122 | 123 | // ------------------------------------------------------------------------- 124 | // MARK: - Table view data source 125 | 126 | func numberOfSections(in tableView: UITableView) -> Int { 127 | return fetchedResultsController.sections?.count ?? 1 128 | } 129 | 130 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 131 | return fetchedResultsController.sections?[section].numberOfObjects ?? 0 132 | } 133 | 134 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 135 | let aNotebook = fetchedResultsController.object(at: indexPath) 136 | let cell = tableView.dequeueReusableCell(withIdentifier: NotebookCell.defaultReuseIdentifier, for: indexPath) as! NotebookCell 137 | 138 | // Configure cell 139 | cell.nameLabel.text = aNotebook.name 140 | 141 | if let count = aNotebook.notes?.count { 142 | let pageString = count == 1 ? "page" : "pages" 143 | cell.pageCountLabel.text = "\(count) \(pageString)" 144 | } 145 | 146 | return cell 147 | } 148 | 149 | func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { 150 | switch editingStyle { 151 | case .delete: deleteNotebook(at: indexPath) 152 | default: () // Unsupported 153 | } 154 | } 155 | 156 | // ------------------------------------------------------------------------- 157 | // MARK: - Navigation 158 | 159 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 160 | // If this is a NotesListViewController, we'll configure its `Notebook` 161 | if let vc = segue.destination as? NotesListViewController { 162 | if let indexPath = tableView.indexPathForSelectedRow { 163 | vc.notebook = fetchedResultsController.object(at: indexPath) 164 | vc.dataController = dataController 165 | } 166 | } 167 | } 168 | } 169 | 170 | extension NotebooksListViewController:NSFetchedResultsControllerDelegate { 171 | 172 | func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 173 | switch type { 174 | case .insert: 175 | tableView.insertRows(at: [newIndexPath!], with: .fade) 176 | break 177 | case .delete: 178 | tableView.deleteRows(at: [indexPath!], with: .fade) 179 | break 180 | case .update: 181 | tableView.reloadRows(at: [indexPath!], with: .fade) 182 | case .move: 183 | tableView.moveRow(at: indexPath!, to: newIndexPath!) 184 | } 185 | } 186 | 187 | func controller(_ controller: NSFetchedResultsController, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) { 188 | let indexSet = IndexSet(integer: sectionIndex) 189 | switch type { 190 | case .insert: tableView.insertSections(indexSet, with: .fade) 191 | case .delete: tableView.deleteSections(indexSet, with: .fade) 192 | case .update, .move: 193 | fatalError("Invalid change type in controller(_:didChange:atSectionIndex:for:). Only .insert or .delete should be possible.") 194 | } 195 | } 196 | 197 | 198 | func controllerWillChangeContent(_ controller: NSFetchedResultsController) { 199 | tableView.beginUpdates() 200 | } 201 | 202 | func controllerDidChangeContent(_ controller: NSFetchedResultsController) { 203 | tableView.endUpdates() 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/View Controllers/NoteDetailsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteDetailsViewController.swift 3 | // Mooskine 4 | // 5 | // Created by Josh Svatek on 2017-05-31. 6 | // Copyright © 2017 Udacity. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | class NoteDetailsViewController: UIViewController { 13 | /// A text view that displays a note's text 14 | @IBOutlet weak var textView: UITextView! 15 | 16 | /// The note being displayed and edited 17 | var note: Note! 18 | 19 | var dataController:DataController! 20 | 21 | var saveObserverToken: Any? 22 | 23 | /// A closure that is run when the user asks to delete the current note 24 | var onDelete: (() -> Void)? 25 | 26 | /// A date formatter for the view controller's title text 27 | let dateFormatter: DateFormatter = { 28 | let df = DateFormatter() 29 | df.dateStyle = .medium 30 | return df 31 | }() 32 | 33 | /// The accessory view used when displaying the keyboard 34 | var keyboardToolbar: UIToolbar? 35 | 36 | override func viewDidLoad() { 37 | super.viewDidLoad() 38 | 39 | if let creationDate = note.creationDate { 40 | navigationItem.title = dateFormatter.string(from: creationDate) 41 | } 42 | textView.attributedText = note.attributedText 43 | 44 | // keyboard toolbar configuration 45 | configureToolbarItems() 46 | configureTextViewInputAccessoryView() 47 | 48 | addSaveNotificationObserver() 49 | } 50 | 51 | deinit { 52 | removeSaveNotificationObserver() 53 | } 54 | 55 | @IBAction func deleteNote(sender: Any) { 56 | presentDeleteNotebookAlert() 57 | } 58 | } 59 | 60 | // ----------------------------------------------------------------------------- 61 | // MARK: - Editing 62 | 63 | extension NoteDetailsViewController { 64 | func presentDeleteNotebookAlert() { 65 | let alert = UIAlertController(title: "Delete Note", message: "Do you want to delete this note?", preferredStyle: .alert) 66 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) 67 | alert.addAction(UIAlertAction(title: "Delete", style: .destructive, handler: deleteHandler)) 68 | present(alert, animated: true, completion: nil) 69 | } 70 | 71 | func deleteHandler(alertAction: UIAlertAction) { 72 | onDelete?() 73 | } 74 | } 75 | 76 | // ----------------------------------------------------------------------------- 77 | // MARK: - UITextViewDelegate 78 | 79 | extension NoteDetailsViewController: UITextViewDelegate { 80 | func textViewDidEndEditing(_ textView: UITextView) { 81 | note.attributedText = textView.attributedText 82 | try? dataController.viewContext.save() 83 | } 84 | } 85 | 86 | // MARK: - Toolbar 87 | 88 | extension NoteDetailsViewController { 89 | /// Returns an array of toolbar items. Used to configure the view controller's 90 | /// `toolbarItems' property, and to configure an accessory view for the 91 | /// text view's keyboard that also displays these items. 92 | func makeToolbarItems() -> [UIBarButtonItem] { 93 | let trash = UIBarButtonItem(barButtonSystemItem: .trash, target: self, action: #selector(deleteTapped(sender:))) 94 | let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) 95 | let bold = UIBarButtonItem(image: #imageLiteral(resourceName: "toolbar-bold"), style: .plain, target: self, action: #selector(boldTapped(sender:))) 96 | let red = UIBarButtonItem(image: #imageLiteral(resourceName: "toolbar-underline"), style: .plain, target: self, action: #selector(redTapped(sender:))) 97 | let cow = UIBarButtonItem(image: #imageLiteral(resourceName: "toolbar-cow"), style: .plain, target: self, action: #selector(cowTapped(sender:))) 98 | 99 | return [space, trash, space, bold, space, red, space, cow, space] 100 | } 101 | 102 | /// Configure the current toolbar 103 | func configureToolbarItems() { 104 | toolbarItems = makeToolbarItems() 105 | navigationController?.setToolbarHidden(false, animated: false) 106 | } 107 | 108 | /// Configure the text view's input accessory view -- this is the view that 109 | /// appears above the keyboard. We'll return a toolbar populated with our 110 | /// view controller's toolbar items, so that the toolbar functionality isn't 111 | /// hidden when the keyboard appears 112 | func configureTextViewInputAccessoryView() { 113 | let toolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 44)) 114 | toolbar.items = makeToolbarItems() 115 | textView.inputAccessoryView = toolbar 116 | } 117 | 118 | @IBAction func deleteTapped(sender: Any) { 119 | showDeleteAlert() 120 | } 121 | 122 | @IBAction func boldTapped(sender: Any) { 123 | let newText = textView.attributedText.mutableCopy() as! NSMutableAttributedString 124 | newText.addAttribute(.font, value: UIFont(name: "OpenSans-Bold", size: 22) as Any, range: textView.selectedRange) 125 | 126 | let selectedTextRange = textView.selectedTextRange 127 | 128 | textView.attributedText = newText 129 | textView.selectedTextRange = selectedTextRange 130 | note.attributedText = textView.attributedText 131 | ((try? dataController?.viewContext.save()) as ()??) 132 | } 133 | 134 | @IBAction func redTapped(sender: Any) { 135 | let newText = textView.attributedText.mutableCopy() as! NSMutableAttributedString 136 | let attributes: [NSAttributedString.Key: Any] = [ 137 | .foregroundColor: UIColor.red, 138 | .underlineStyle: 1, 139 | .underlineColor: UIColor.red 140 | ] 141 | newText.addAttributes(attributes, range: textView.selectedRange) 142 | 143 | let selectedTextRange = textView.selectedTextRange 144 | 145 | textView.attributedText = newText 146 | textView.selectedTextRange = selectedTextRange 147 | note.attributedText = textView.attributedText 148 | try? dataController?.viewContext.save() 149 | } 150 | 151 | @IBAction func cowTapped(sender: Any) { 152 | let backgroundContext:NSManagedObjectContext! = dataController?.backgroundContext 153 | 154 | let newText = textView.attributedText.mutableCopy() as! NSMutableAttributedString 155 | 156 | let selectedRange = textView.selectedRange 157 | let selectedText = textView.attributedText.attributedSubstring(from: selectedRange) 158 | 159 | let noteID = note.objectID 160 | 161 | dataController?.backgroundContext.perform { 162 | let backgroundNote = backgroundContext.object(with: noteID) as! Note 163 | 164 | let cowText = Pathifier.makeMutableAttributedString(for: selectedText, withFont: UIFont(name: "AvenirNext-Heavy", size: 56)!, withPatternImage: #imageLiteral(resourceName: "texture-cow")) 165 | 166 | sleep(5) 167 | 168 | newText.replaceCharacters(in: selectedRange, with: cowText) 169 | 170 | backgroundNote.attributedText = newText 171 | try? backgroundContext.save() 172 | } 173 | } 174 | 175 | // MARK: Helper methods for actions 176 | private func showDeleteAlert() { 177 | let alert = UIAlertController(title: "Delete Note?", message: "Are you sure you want to delete the current note?", preferredStyle: .alert) 178 | 179 | let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) 180 | let deleteAction = UIAlertAction(title: "Delete", style: .destructive) { [weak self] _ in 181 | guard let strongSelf = self else { return } 182 | strongSelf.onDelete?() 183 | } 184 | 185 | alert.addAction(cancelAction) 186 | alert.addAction(deleteAction) 187 | present(alert, animated: true, completion: nil) 188 | } 189 | } 190 | 191 | extension NoteDetailsViewController { 192 | 193 | func addSaveNotificationObserver() { 194 | removeSaveNotificationObserver() 195 | saveObserverToken = NotificationCenter.default.addObserver(forName: .NSManagedObjectContextObjectsDidChange, object: dataController?.viewContext, queue: nil, using: handleSaveNotification(notification:)) 196 | } 197 | 198 | func removeSaveNotificationObserver() { 199 | if let token = saveObserverToken { 200 | NotificationCenter.default.removeObserver(token) 201 | } 202 | } 203 | 204 | fileprivate func reloadText() { 205 | textView.attributedText = note.attributedText 206 | } 207 | 208 | func handleSaveNotification(notification:Notification) { 209 | DispatchQueue.main.async { 210 | self.reloadText() 211 | } 212 | } 213 | } 214 | 215 | -------------------------------------------------------------------------------- /SandboxPlayground-Empty/SandboxPlayground.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A9CCAFD51D37C53C00E00DAF /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9CCAFD31D37C53C00E00DAF /* LaunchScreen.xib */; }; 11 | EDA163371CE69ECA009671EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA163361CE69ECA009671EE /* AppDelegate.swift */; }; 12 | EDA163391CE69ECA009671EE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDA163381CE69ECA009671EE /* ViewController.swift */; }; 13 | EDA1633C1CE69ECA009671EE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EDA1633A1CE69ECA009671EE /* Main.storyboard */; }; 14 | EDA1633E1CE69ECA009671EE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EDA1633D1CE69ECA009671EE /* Assets.xcassets */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | A9CCAFD41D37C53C00E00DAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 19 | EDA163331CE69ECA009671EE /* SandboxPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SandboxPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | EDA163361CE69ECA009671EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | EDA163381CE69ECA009671EE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | EDA1633B1CE69ECA009671EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | EDA1633D1CE69ECA009671EE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | EDA163421CE69ECB009671EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | /* End PBXFileReference section */ 26 | 27 | /* Begin PBXFrameworksBuildPhase section */ 28 | EDA163301CE69ECA009671EE /* Frameworks */ = { 29 | isa = PBXFrameworksBuildPhase; 30 | buildActionMask = 2147483647; 31 | files = ( 32 | ); 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXFrameworksBuildPhase section */ 36 | 37 | /* Begin PBXGroup section */ 38 | A9CCAFD61D37C54100E00DAF /* Assets */ = { 39 | isa = PBXGroup; 40 | children = ( 41 | EDA1633A1CE69ECA009671EE /* Main.storyboard */, 42 | A9CCAFD31D37C53C00E00DAF /* LaunchScreen.xib */, 43 | EDA1633D1CE69ECA009671EE /* Assets.xcassets */, 44 | ); 45 | name = Assets; 46 | sourceTree = ""; 47 | }; 48 | A9CCAFD71D37C54500E00DAF /* Supporting Files */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | EDA163421CE69ECB009671EE /* Info.plist */, 52 | ); 53 | name = "Supporting Files"; 54 | sourceTree = ""; 55 | }; 56 | EDA1632A1CE69ECA009671EE = { 57 | isa = PBXGroup; 58 | children = ( 59 | EDA163351CE69ECA009671EE /* SandboxPlayground */, 60 | EDA163341CE69ECA009671EE /* Products */, 61 | ); 62 | sourceTree = ""; 63 | }; 64 | EDA163341CE69ECA009671EE /* Products */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | EDA163331CE69ECA009671EE /* SandboxPlayground.app */, 68 | ); 69 | name = Products; 70 | sourceTree = ""; 71 | }; 72 | EDA163351CE69ECA009671EE /* SandboxPlayground */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | EDA163361CE69ECA009671EE /* AppDelegate.swift */, 76 | EDA163381CE69ECA009671EE /* ViewController.swift */, 77 | A9CCAFD61D37C54100E00DAF /* Assets */, 78 | A9CCAFD71D37C54500E00DAF /* Supporting Files */, 79 | ); 80 | path = SandboxPlayground; 81 | sourceTree = ""; 82 | }; 83 | /* End PBXGroup section */ 84 | 85 | /* Begin PBXNativeTarget section */ 86 | EDA163321CE69ECA009671EE /* SandboxPlayground */ = { 87 | isa = PBXNativeTarget; 88 | buildConfigurationList = EDA163501CE69ECB009671EE /* Build configuration list for PBXNativeTarget "SandboxPlayground" */; 89 | buildPhases = ( 90 | EDA1632F1CE69ECA009671EE /* Sources */, 91 | EDA163301CE69ECA009671EE /* Frameworks */, 92 | EDA163311CE69ECA009671EE /* Resources */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = SandboxPlayground; 99 | productName = SandboxPlayground; 100 | productReference = EDA163331CE69ECA009671EE /* SandboxPlayground.app */; 101 | productType = "com.apple.product-type.application"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | EDA1632B1CE69ECA009671EE /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastSwiftUpdateCheck = 0730; 110 | LastUpgradeCheck = 1020; 111 | ORGANIZATIONNAME = udacity.com; 112 | TargetAttributes = { 113 | EDA163321CE69ECA009671EE = { 114 | CreatedOnToolsVersion = 7.3; 115 | LastSwiftMigration = 0800; 116 | }; 117 | }; 118 | }; 119 | buildConfigurationList = EDA1632E1CE69ECA009671EE /* Build configuration list for PBXProject "SandboxPlayground" */; 120 | compatibilityVersion = "Xcode 3.2"; 121 | developmentRegion = en; 122 | hasScannedForEncodings = 0; 123 | knownRegions = ( 124 | en, 125 | Base, 126 | ); 127 | mainGroup = EDA1632A1CE69ECA009671EE; 128 | productRefGroup = EDA163341CE69ECA009671EE /* Products */; 129 | projectDirPath = ""; 130 | projectRoot = ""; 131 | targets = ( 132 | EDA163321CE69ECA009671EE /* SandboxPlayground */, 133 | ); 134 | }; 135 | /* End PBXProject section */ 136 | 137 | /* Begin PBXResourcesBuildPhase section */ 138 | EDA163311CE69ECA009671EE /* Resources */ = { 139 | isa = PBXResourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | EDA1633E1CE69ECA009671EE /* Assets.xcassets in Resources */, 143 | A9CCAFD51D37C53C00E00DAF /* LaunchScreen.xib in Resources */, 144 | EDA1633C1CE69ECA009671EE /* Main.storyboard in Resources */, 145 | ); 146 | runOnlyForDeploymentPostprocessing = 0; 147 | }; 148 | /* End PBXResourcesBuildPhase section */ 149 | 150 | /* Begin PBXSourcesBuildPhase section */ 151 | EDA1632F1CE69ECA009671EE /* Sources */ = { 152 | isa = PBXSourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | EDA163391CE69ECA009671EE /* ViewController.swift in Sources */, 156 | EDA163371CE69ECA009671EE /* AppDelegate.swift in Sources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXSourcesBuildPhase section */ 161 | 162 | /* Begin PBXVariantGroup section */ 163 | A9CCAFD31D37C53C00E00DAF /* LaunchScreen.xib */ = { 164 | isa = PBXVariantGroup; 165 | children = ( 166 | A9CCAFD41D37C53C00E00DAF /* Base */, 167 | ); 168 | name = LaunchScreen.xib; 169 | sourceTree = ""; 170 | }; 171 | EDA1633A1CE69ECA009671EE /* Main.storyboard */ = { 172 | isa = PBXVariantGroup; 173 | children = ( 174 | EDA1633B1CE69ECA009671EE /* Base */, 175 | ); 176 | name = Main.storyboard; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXVariantGroup section */ 180 | 181 | /* Begin XCBuildConfiguration section */ 182 | EDA1634E1CE69ECB009671EE /* Debug */ = { 183 | isa = XCBuildConfiguration; 184 | buildSettings = { 185 | ALWAYS_SEARCH_USER_PATHS = NO; 186 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 187 | CLANG_ANALYZER_NONNULL = YES; 188 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 189 | CLANG_CXX_LIBRARY = "libc++"; 190 | CLANG_ENABLE_MODULES = YES; 191 | CLANG_ENABLE_OBJC_ARC = YES; 192 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 193 | CLANG_WARN_BOOL_CONVERSION = YES; 194 | CLANG_WARN_COMMA = YES; 195 | CLANG_WARN_CONSTANT_CONVERSION = YES; 196 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 197 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 198 | CLANG_WARN_EMPTY_BODY = YES; 199 | CLANG_WARN_ENUM_CONVERSION = YES; 200 | CLANG_WARN_INFINITE_RECURSION = YES; 201 | CLANG_WARN_INT_CONVERSION = YES; 202 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 203 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 204 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 205 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 206 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 207 | CLANG_WARN_STRICT_PROTOTYPES = YES; 208 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 209 | CLANG_WARN_UNREACHABLE_CODE = YES; 210 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 211 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 212 | COPY_PHASE_STRIP = NO; 213 | DEBUG_INFORMATION_FORMAT = dwarf; 214 | ENABLE_STRICT_OBJC_MSGSEND = YES; 215 | ENABLE_TESTABILITY = YES; 216 | GCC_C_LANGUAGE_STANDARD = gnu99; 217 | GCC_DYNAMIC_NO_PIC = NO; 218 | GCC_NO_COMMON_BLOCKS = YES; 219 | GCC_OPTIMIZATION_LEVEL = 0; 220 | GCC_PREPROCESSOR_DEFINITIONS = ( 221 | "DEBUG=1", 222 | "$(inherited)", 223 | ); 224 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 225 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 226 | GCC_WARN_UNDECLARED_SELECTOR = YES; 227 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 228 | GCC_WARN_UNUSED_FUNCTION = YES; 229 | GCC_WARN_UNUSED_VARIABLE = YES; 230 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 231 | MTL_ENABLE_DEBUG_INFO = YES; 232 | ONLY_ACTIVE_ARCH = YES; 233 | SDKROOT = iphoneos; 234 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 235 | SWIFT_VERSION = 5.0; 236 | }; 237 | name = Debug; 238 | }; 239 | EDA1634F1CE69ECB009671EE /* Release */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 244 | CLANG_ANALYZER_NONNULL = YES; 245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 246 | CLANG_CXX_LIBRARY = "libc++"; 247 | CLANG_ENABLE_MODULES = YES; 248 | CLANG_ENABLE_OBJC_ARC = YES; 249 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 250 | CLANG_WARN_BOOL_CONVERSION = YES; 251 | CLANG_WARN_COMMA = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 254 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INFINITE_RECURSION = YES; 258 | CLANG_WARN_INT_CONVERSION = YES; 259 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 261 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 262 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 263 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 264 | CLANG_WARN_STRICT_PROTOTYPES = YES; 265 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | ENABLE_STRICT_OBJC_MSGSEND = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu99; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 276 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 277 | GCC_WARN_UNDECLARED_SELECTOR = YES; 278 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 282 | MTL_ENABLE_DEBUG_INFO = NO; 283 | SDKROOT = iphoneos; 284 | SWIFT_VERSION = 5.0; 285 | VALIDATE_PRODUCT = YES; 286 | }; 287 | name = Release; 288 | }; 289 | EDA163511CE69ECB009671EE /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 293 | INFOPLIST_FILE = SandboxPlayground/Info.plist; 294 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 295 | PRODUCT_BUNDLE_IDENTIFIER = com.udacity.SandboxPlayground; 296 | PRODUCT_NAME = "$(TARGET_NAME)"; 297 | SWIFT_VERSION = 5.0; 298 | }; 299 | name = Debug; 300 | }; 301 | EDA163521CE69ECB009671EE /* Release */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 305 | INFOPLIST_FILE = SandboxPlayground/Info.plist; 306 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 307 | PRODUCT_BUNDLE_IDENTIFIER = com.udacity.SandboxPlayground; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 310 | SWIFT_VERSION = 5.0; 311 | }; 312 | name = Release; 313 | }; 314 | /* End XCBuildConfiguration section */ 315 | 316 | /* Begin XCConfigurationList section */ 317 | EDA1632E1CE69ECA009671EE /* Build configuration list for PBXProject "SandboxPlayground" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | EDA1634E1CE69ECB009671EE /* Debug */, 321 | EDA1634F1CE69ECB009671EE /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | EDA163501CE69ECB009671EE /* Build configuration list for PBXNativeTarget "SandboxPlayground" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | EDA163511CE69ECB009671EE /* Debug */, 330 | EDA163521CE69ECB009671EE /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | defaultConfigurationName = Release; 334 | }; 335 | /* End XCConfigurationList section */ 336 | }; 337 | rootObject = EDA1632B1CE69ECA009671EE /* Project object */; 338 | } 339 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4D37A77C1A5B089600294894 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D37A77B1A5B089600294894 /* AppDelegate.swift */; }; 11 | 4D37A7811A5B089600294894 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4D37A77F1A5B089600294894 /* Main.storyboard */; }; 12 | 4D37A7831A5B089600294894 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4D37A7821A5B089600294894 /* Images.xcassets */; }; 13 | 4D37A7861A5B089600294894 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D37A7841A5B089600294894 /* LaunchScreen.xib */; }; 14 | 4D37A79E1A5B095200294894 /* PlaySoundsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D37A79B1A5B095200294894 /* PlaySoundsViewController.swift */; }; 15 | 4D37A79F1A5B095200294894 /* RecordedAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D37A79C1A5B095200294894 /* RecordedAudio.swift */; }; 16 | 4D37A7A01A5B095200294894 /* RecordSoundsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D37A79D1A5B095200294894 /* RecordSoundsViewController.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 4D37A7761A5B089600294894 /* PickYourPitch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PickYourPitch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 4D37A77A1A5B089600294894 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 22 | 4D37A77B1A5B089600294894 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | 4D37A7801A5B089600294894 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 24 | 4D37A7821A5B089600294894 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 25 | 4D37A7851A5B089600294894 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 26 | 4D37A79B1A5B095200294894 /* PlaySoundsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaySoundsViewController.swift; sourceTree = ""; }; 27 | 4D37A79C1A5B095200294894 /* RecordedAudio.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordedAudio.swift; sourceTree = ""; }; 28 | 4D37A79D1A5B095200294894 /* RecordSoundsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecordSoundsViewController.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 4D37A7731A5B089600294894 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 4D37A76D1A5B089600294894 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 4D37A7781A5B089600294894 /* PickYourPitch */, 46 | 4D37A7771A5B089600294894 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 4D37A7771A5B089600294894 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 4D37A7761A5B089600294894 /* PickYourPitch.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 4D37A7781A5B089600294894 /* PickYourPitch */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 4D37A77B1A5B089600294894 /* AppDelegate.swift */, 62 | 4D37A79C1A5B095200294894 /* RecordedAudio.swift */, 63 | 4D37A79B1A5B095200294894 /* PlaySoundsViewController.swift */, 64 | 4D37A79D1A5B095200294894 /* RecordSoundsViewController.swift */, 65 | A9CCAFD21D37C43C00E00DAF /* Assets */, 66 | 4D37A7791A5B089600294894 /* Supporting Files */, 67 | ); 68 | path = PickYourPitch; 69 | sourceTree = ""; 70 | }; 71 | 4D37A7791A5B089600294894 /* Supporting Files */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 4D37A77A1A5B089600294894 /* Info.plist */, 75 | ); 76 | name = "Supporting Files"; 77 | sourceTree = ""; 78 | }; 79 | A9CCAFD21D37C43C00E00DAF /* Assets */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 4D37A77F1A5B089600294894 /* Main.storyboard */, 83 | 4D37A7821A5B089600294894 /* Images.xcassets */, 84 | 4D37A7841A5B089600294894 /* LaunchScreen.xib */, 85 | ); 86 | name = Assets; 87 | sourceTree = ""; 88 | }; 89 | /* End PBXGroup section */ 90 | 91 | /* Begin PBXNativeTarget section */ 92 | 4D37A7751A5B089600294894 /* PickYourPitch */ = { 93 | isa = PBXNativeTarget; 94 | buildConfigurationList = 4D37A7951A5B089600294894 /* Build configuration list for PBXNativeTarget "PickYourPitch" */; 95 | buildPhases = ( 96 | 4D37A7721A5B089600294894 /* Sources */, 97 | 4D37A7731A5B089600294894 /* Frameworks */, 98 | 4D37A7741A5B089600294894 /* Resources */, 99 | ); 100 | buildRules = ( 101 | ); 102 | dependencies = ( 103 | ); 104 | name = PickYourPitch; 105 | productName = PickYourPitch; 106 | productReference = 4D37A7761A5B089600294894 /* PickYourPitch.app */; 107 | productType = "com.apple.product-type.application"; 108 | }; 109 | /* End PBXNativeTarget section */ 110 | 111 | /* Begin PBXProject section */ 112 | 4D37A76E1A5B089600294894 /* Project object */ = { 113 | isa = PBXProject; 114 | attributes = { 115 | LastSwiftUpdateCheck = 0700; 116 | LastUpgradeCheck = 1020; 117 | ORGANIZATIONNAME = Udacity; 118 | TargetAttributes = { 119 | 4D37A7751A5B089600294894 = { 120 | CreatedOnToolsVersion = 6.1.1; 121 | LastSwiftMigration = 1020; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = 4D37A7711A5B089600294894 /* Build configuration list for PBXProject "PickYourPitch" */; 126 | compatibilityVersion = "Xcode 3.2"; 127 | developmentRegion = en; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | en, 131 | Base, 132 | ); 133 | mainGroup = 4D37A76D1A5B089600294894; 134 | productRefGroup = 4D37A7771A5B089600294894 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 4D37A7751A5B089600294894 /* PickYourPitch */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | 4D37A7741A5B089600294894 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | 4D37A7811A5B089600294894 /* Main.storyboard in Resources */, 149 | 4D37A7861A5B089600294894 /* LaunchScreen.xib in Resources */, 150 | 4D37A7831A5B089600294894 /* Images.xcassets in Resources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXResourcesBuildPhase section */ 155 | 156 | /* Begin PBXSourcesBuildPhase section */ 157 | 4D37A7721A5B089600294894 /* Sources */ = { 158 | isa = PBXSourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | 4D37A79F1A5B095200294894 /* RecordedAudio.swift in Sources */, 162 | 4D37A79E1A5B095200294894 /* PlaySoundsViewController.swift in Sources */, 163 | 4D37A7A01A5B095200294894 /* RecordSoundsViewController.swift in Sources */, 164 | 4D37A77C1A5B089600294894 /* AppDelegate.swift in Sources */, 165 | ); 166 | runOnlyForDeploymentPostprocessing = 0; 167 | }; 168 | /* End PBXSourcesBuildPhase section */ 169 | 170 | /* Begin PBXVariantGroup section */ 171 | 4D37A77F1A5B089600294894 /* Main.storyboard */ = { 172 | isa = PBXVariantGroup; 173 | children = ( 174 | 4D37A7801A5B089600294894 /* Base */, 175 | ); 176 | name = Main.storyboard; 177 | sourceTree = ""; 178 | }; 179 | 4D37A7841A5B089600294894 /* LaunchScreen.xib */ = { 180 | isa = PBXVariantGroup; 181 | children = ( 182 | 4D37A7851A5B089600294894 /* Base */, 183 | ); 184 | name = LaunchScreen.xib; 185 | sourceTree = ""; 186 | }; 187 | /* End PBXVariantGroup section */ 188 | 189 | /* Begin XCBuildConfiguration section */ 190 | 4D37A7931A5B089600294894 /* Debug */ = { 191 | isa = XCBuildConfiguration; 192 | buildSettings = { 193 | ALWAYS_SEARCH_USER_PATHS = NO; 194 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 195 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 196 | CLANG_CXX_LIBRARY = "libc++"; 197 | CLANG_ENABLE_MODULES = YES; 198 | CLANG_ENABLE_OBJC_ARC = YES; 199 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 200 | CLANG_WARN_BOOL_CONVERSION = YES; 201 | CLANG_WARN_COMMA = YES; 202 | CLANG_WARN_CONSTANT_CONVERSION = YES; 203 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 204 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 205 | CLANG_WARN_EMPTY_BODY = YES; 206 | CLANG_WARN_ENUM_CONVERSION = YES; 207 | CLANG_WARN_INFINITE_RECURSION = YES; 208 | CLANG_WARN_INT_CONVERSION = YES; 209 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 210 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 211 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 212 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 213 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 214 | CLANG_WARN_STRICT_PROTOTYPES = YES; 215 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 216 | CLANG_WARN_UNREACHABLE_CODE = YES; 217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 218 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 219 | COPY_PHASE_STRIP = NO; 220 | ENABLE_STRICT_OBJC_MSGSEND = YES; 221 | ENABLE_TESTABILITY = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu99; 223 | GCC_DYNAMIC_NO_PIC = NO; 224 | GCC_NO_COMMON_BLOCKS = YES; 225 | GCC_OPTIMIZATION_LEVEL = 0; 226 | GCC_PREPROCESSOR_DEFINITIONS = ( 227 | "DEBUG=1", 228 | "$(inherited)", 229 | ); 230 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 233 | GCC_WARN_UNDECLARED_SELECTOR = YES; 234 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 235 | GCC_WARN_UNUSED_FUNCTION = YES; 236 | GCC_WARN_UNUSED_VARIABLE = YES; 237 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 238 | MTL_ENABLE_DEBUG_INFO = YES; 239 | ONLY_ACTIVE_ARCH = YES; 240 | SDKROOT = iphoneos; 241 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 242 | }; 243 | name = Debug; 244 | }; 245 | 4D37A7941A5B089600294894 /* Release */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ALWAYS_SEARCH_USER_PATHS = NO; 249 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 251 | CLANG_CXX_LIBRARY = "libc++"; 252 | CLANG_ENABLE_MODULES = YES; 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 255 | CLANG_WARN_BOOL_CONVERSION = YES; 256 | CLANG_WARN_COMMA = YES; 257 | CLANG_WARN_CONSTANT_CONVERSION = YES; 258 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 260 | CLANG_WARN_EMPTY_BODY = YES; 261 | CLANG_WARN_ENUM_CONVERSION = YES; 262 | CLANG_WARN_INFINITE_RECURSION = YES; 263 | CLANG_WARN_INT_CONVERSION = YES; 264 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 266 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 269 | CLANG_WARN_STRICT_PROTOTYPES = YES; 270 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 271 | CLANG_WARN_UNREACHABLE_CODE = YES; 272 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 273 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 274 | COPY_PHASE_STRIP = YES; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | SDKROOT = iphoneos; 288 | VALIDATE_PRODUCT = YES; 289 | }; 290 | name = Release; 291 | }; 292 | 4D37A7961A5B089600294894 /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | INFOPLIST_FILE = PickYourPitch/Info.plist; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 298 | PRODUCT_BUNDLE_IDENTIFIER = "UD.$(PRODUCT_NAME:rfc1034identifier)"; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | SWIFT_VERSION = 5.0; 301 | }; 302 | name = Debug; 303 | }; 304 | 4D37A7971A5B089600294894 /* Release */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 308 | INFOPLIST_FILE = PickYourPitch/Info.plist; 309 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 310 | PRODUCT_BUNDLE_IDENTIFIER = "UD.$(PRODUCT_NAME:rfc1034identifier)"; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 313 | SWIFT_VERSION = 5.0; 314 | }; 315 | name = Release; 316 | }; 317 | /* End XCBuildConfiguration section */ 318 | 319 | /* Begin XCConfigurationList section */ 320 | 4D37A7711A5B089600294894 /* Build configuration list for PBXProject "PickYourPitch" */ = { 321 | isa = XCConfigurationList; 322 | buildConfigurations = ( 323 | 4D37A7931A5B089600294894 /* Debug */, 324 | 4D37A7941A5B089600294894 /* Release */, 325 | ); 326 | defaultConfigurationIsVisible = 0; 327 | defaultConfigurationName = Release; 328 | }; 329 | 4D37A7951A5B089600294894 /* Build configuration list for PBXNativeTarget "PickYourPitch" */ = { 330 | isa = XCConfigurationList; 331 | buildConfigurations = ( 332 | 4D37A7961A5B089600294894 /* Debug */, 333 | 4D37A7971A5B089600294894 /* Release */, 334 | ); 335 | defaultConfigurationIsVisible = 0; 336 | defaultConfigurationName = Release; 337 | }; 338 | /* End XCConfigurationList section */ 339 | }; 340 | rootObject = 4D37A76E1A5B089600294894 /* Project object */; 341 | } 342 | -------------------------------------------------------------------------------- /PickYourPitch-NoPersistence/PickYourPitch/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 33 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 97 | 102 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /Mooskine/Mooskine-complete/Mooskine/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 146 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | --------------------------------------------------------------------------------