├── LICENSE
├── P1 PitchPerfect
├── .gitignore
├── Pitch Perfect.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── Pitch Perfect
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── 29.png
│ │ │ ├── Contents.json
│ │ │ ├── Icon-40.png
│ │ │ ├── Icon-40@2x-1.png
│ │ │ ├── Icon-40@2x.png
│ │ │ ├── Icon-40@3x.png
│ │ │ ├── Icon-41.png
│ │ │ ├── Icon-42.png
│ │ │ ├── Icon-43.png
│ │ │ ├── Icon-60.png
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-76.png
│ │ │ ├── Icon-76@2x.png
│ │ │ ├── Icon-83.5pt 1.51.51 PM.png
│ │ │ ├── Icon-83.5pt.png
│ │ │ ├── Icon-Small@2x-1.png
│ │ │ ├── Icon-Small@2x.png
│ │ │ └── Icon-Small@3x.png
│ │ ├── Contents.json
│ │ ├── Echo.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Echo.png
│ │ │ ├── Echo@2x.png
│ │ │ └── Echo@3x.png
│ │ ├── Fast.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Fast.png
│ │ │ ├── Fast@2x.png
│ │ │ └── Fast@3x.png
│ │ ├── HighPitch.imageset
│ │ │ ├── Contents.json
│ │ │ ├── HighPitch.png
│ │ │ ├── HighPitch@2x.png
│ │ │ └── HighPitch@3x.png
│ │ ├── Launch.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-83.5.png
│ │ │ ├── Icon-83.5@2x.png
│ │ │ └── Icon-83.5@3x.png
│ │ ├── LowPitch.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LowPitch.png
│ │ │ ├── LowPitch@2x.png
│ │ │ └── LowPitch@3x.png
│ │ ├── Pause.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Pause.png
│ │ │ ├── Pause@2x.png
│ │ │ └── Pause@3x.png
│ │ ├── Record.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Record.png
│ │ │ ├── Record@2x.png
│ │ │ └── Record@3x.png
│ │ ├── Reverb.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Reverb.png
│ │ │ ├── Reverb@2x.png
│ │ │ └── Reverb@3x.png
│ │ ├── Slow.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Slow.png
│ │ │ ├── Slow@2x.png
│ │ │ └── Slow@3x.png
│ │ └── Stop.imageset
│ │ │ ├── Contents.json
│ │ │ ├── Stop.png
│ │ │ ├── Stop@2x.png
│ │ │ └── Stop@3x.png
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── PlaySoundViewController+Audio.swift
│ ├── PlaySoundViewController.swift
│ └── RecordSoundViewController.swift
├── README.md
└── Screenshots
│ ├── HomeScreen-Idle.png
│ ├── HomeScreen-Rec.png
│ └── PlaySoundScreen.png
├── P2 MemeMe
├── .gitignore
├── MemeMe.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── MemeMe
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Meme-Me 2-1.png
│ │ │ ├── Meme-Me 2-10.png
│ │ │ ├── Meme-Me 2-11.png
│ │ │ ├── Meme-Me 2-12.png
│ │ │ ├── Meme-Me 2-13.png
│ │ │ ├── Meme-Me 2-14.png
│ │ │ ├── Meme-Me 2-15.png
│ │ │ ├── Meme-Me 2-16.png
│ │ │ ├── Meme-Me 2-2.png
│ │ │ ├── Meme-Me 2-3.png
│ │ │ ├── Meme-Me 2-4.png
│ │ │ ├── Meme-Me 2-5.png
│ │ │ ├── Meme-Me 2-6.png
│ │ │ ├── Meme-Me 2-7.png
│ │ │ ├── Meme-Me 2-8.png
│ │ │ ├── Meme-Me 2-9.png
│ │ │ ├── Meme-Me 2.png
│ │ │ └── Meme-Me.png
│ │ ├── Contents.json
│ │ ├── camera.imageset
│ │ │ ├── Contents.json
│ │ │ ├── camera@2x.png
│ │ │ └── camera@3x.png
│ │ ├── gallary.imageset
│ │ │ ├── Contents.json
│ │ │ ├── gallary@2x.png
│ │ │ └── gallary@3x.png
│ │ ├── grid.imageset
│ │ │ ├── Contents.json
│ │ │ ├── grid.png
│ │ │ ├── grid@2x.png
│ │ │ └── grid@3x.png
│ │ ├── launcher.imageset
│ │ │ ├── Contents.json
│ │ │ ├── launch-icon.png
│ │ │ ├── launch-icon@2x.png
│ │ │ └── launch-icon@3x.png
│ │ └── list.imageset
│ │ │ ├── Contents.json
│ │ │ ├── list.png
│ │ │ ├── list@2x.png
│ │ │ └── list@3x.png
│ ├── Editor
│ │ └── MemeEditorViewController.swift
│ ├── Home
│ │ ├── GridViewController.swift
│ │ ├── ListViewController.swift
│ │ ├── MemeCollectionViewCell.swift
│ │ ├── MemeTableViewCell.swift
│ │ └── MemeTableViewCell.xib
│ ├── Info.plist
│ ├── MemeDetailsViewController.swift
│ ├── Model
│ │ ├── MemeObject.swift
│ │ └── MemeStorage.swift
│ └── View
│ │ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
├── README.md
└── Screenshots
│ ├── .DS_Store
│ ├── HomeGridFilled.png
│ ├── HomeListEmpty.png
│ ├── HomeListFilled.png
│ ├── MemeEditorEmpty.png
│ └── MemeEditorFilled.png
├── P3 OnTheMap
├── .gitignore
├── On The Map.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── On The Map
│ ├── Account
│ │ └── AccountViewController.swift
│ ├── AddNew
│ │ ├── AddLocationViewController.swift
│ │ └── AddProfileViewController.swift
│ ├── Api
│ │ ├── ApiConstants.swift
│ │ ├── AuthHandler.swift
│ │ ├── BaseNetworkHandler.swift
│ │ └── ParseHandler.swift
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-40.png
│ │ │ ├── Icon-40@2x.png
│ │ │ ├── Icon-40@3x.png
│ │ │ ├── Icon-60@2x.png
│ │ │ ├── Icon-60@3x.png
│ │ │ ├── Icon-76.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
│ │ │ ├── Contents.json
│ │ │ └── LaunchLogo.pdf
│ │ ├── account.imageset
│ │ │ ├── Contents.json
│ │ │ ├── account.png
│ │ │ ├── account@2x.png
│ │ │ └── account@3x.png
│ │ ├── icon_listview-deselected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_listview-deselected.png
│ │ │ ├── icon_listview-deselected@2x.png
│ │ │ └── icon_listview-deselected@3x.png
│ │ ├── icon_listview-selected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_listview-selected.png
│ │ │ ├── icon_listview-selected@2x.png
│ │ │ └── icon_listview-selected@3x.png
│ │ ├── icon_mapview-deselected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_mapview-deselected.png
│ │ │ ├── icon_mapview-deselected@2x.png
│ │ │ └── icon_mapview-deselected@3x.png
│ │ ├── icon_mapview-selected.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_mapview-selected.png
│ │ │ ├── icon_mapview-selected@2x.png
│ │ │ └── icon_mapview-selected@3x.png
│ │ ├── icon_world.imageset
│ │ │ ├── Contents.json
│ │ │ ├── icon_world.png
│ │ │ ├── icon_world@2x.png
│ │ │ └── icon_world@3x.png
│ │ ├── loading.imageset
│ │ │ ├── Contents.json
│ │ │ ├── loading.png
│ │ │ ├── loading@2x.png
│ │ │ └── loading@3x.png
│ │ └── map-pin.imageset
│ │ │ ├── Contents.json
│ │ │ ├── map-pin.png
│ │ │ ├── map-pin@2x.png
│ │ │ └── map-pin@3x.png
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Home
│ │ ├── Map
│ │ │ ├── MapViewController+MapViewDelegate.swift
│ │ │ └── MapViewController.swift
│ │ ├── StudentLocationViewController.swift
│ │ └── Table
│ │ │ ├── TableViewController+TableViewDelegate.swift
│ │ │ └── TableViewController.swift
│ ├── Info.plist
│ ├── Login
│ │ ├── LoginViewController+Extras.swift
│ │ └── LoginViewController.swift
│ ├── Model
│ │ ├── Response
│ │ │ └── UdacityAuthResponse.swift
│ │ ├── StudentLocation.swift
│ │ └── UserInfo.swift
│ ├── Storage
│ │ ├── Cache.swift
│ │ └── Storage.swift
│ └── Utils
│ │ ├── Errors.swift
│ │ └── Extensions.swift
├── README.md
└── Screenshots
│ ├── Account.png
│ ├── AddPin.png
│ ├── AddProfile.png
│ ├── List.png
│ ├── Login.png
│ ├── Map-Pin.png
│ └── Map.png
├── P4 VirtualTourist
├── .gitignore
├── Podfile
├── Podfile.lock
├── README.md
├── Screenshots
│ ├── Album.png
│ ├── Map-DeletePin.png
│ └── Map-ViewPin.png
├── Virtual Tourist.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── Virtual Tourist.xcworkspace
│ └── contents.xcworkspacedata
└── Virtual Tourist
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── PrimaryColor.colorset
│ │ └── Contents.json
│ ├── icon_delete.imageset
│ │ ├── Contents.json
│ │ ├── icon_delete.png
│ │ ├── icon_delete@2x.png
│ │ └── icon_delete@3x.png
│ ├── icon_delete_dark.imageset
│ │ ├── Contents.json
│ │ ├── icon_delete_dark.png
│ │ ├── icon_delete_dark@2x.png
│ │ └── icon_delete_dark@3x.png
│ ├── icon_done.imageset
│ │ ├── Contents.json
│ │ ├── icon_done.png
│ │ ├── icon_done@2x.png
│ │ └── icon_done@3x.png
│ ├── icon_edit.imageset
│ │ ├── Contents.json
│ │ ├── icon_edit.png
│ │ ├── icon_edit@2x.png
│ │ └── icon_edit@3x.png
│ ├── icon_info_dark.imageset
│ │ ├── Contents.json
│ │ ├── icon_info_dark.png
│ │ ├── icon_info_dark@2x.png
│ │ └── icon_info_dark@3x.png
│ ├── icon_refresh.imageset
│ │ ├── Contents.json
│ │ ├── icon_refresh.png
│ │ ├── icon_refresh@2x.png
│ │ └── icon_refresh@3x.png
│ └── placeholder_image.imageset
│ │ ├── Contents.json
│ │ ├── placeholder_image.png
│ │ ├── placeholder_image@2x.png
│ │ └── placeholder_image@3x.png
│ ├── Data
│ ├── DataController.swift
│ ├── FlickrApiHandler.swift
│ └── MapViewDefaults.swift
│ ├── Fonts
│ ├── Raleway-Light.ttf
│ └── Raleway-Regular.ttf
│ ├── Info.plist
│ ├── Model
│ └── Virtual_Tourist.xcdatamodeld
│ │ ├── .xccurrentversion
│ │ └── Virtual_Tourist.xcdatamodel
│ │ └── contents
│ ├── Storyboard
│ └── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── UI
│ ├── Album
│ │ ├── PhotoAlbumViewController+Extras.swift
│ │ └── PhotoAlbumViewController.swift
│ ├── Map
│ │ ├── TravelMapViewController+Extras.swift
│ │ └── TravelMapViewController.swift
│ └── View
│ │ ├── PhotoViewCell.swift
│ │ └── PhotoViewCell.xib
│ └── Utils
│ ├── Errors.swift
│ └── Extensions.swift
├── P5 JSON-Feed-Reader
├── .gitignore
├── JSON Feed Reader.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
├── JSON Feed Reader.xcworkspace
│ └── contents.xcworkspacedata
├── JSON Feed Reader
│ ├── AppDelegate.swift
│ ├── Assets
│ │ └── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── json-feed.imageset
│ │ │ ├── Contents.json
│ │ │ ├── json-feed.png
│ │ │ ├── json-feed@2x.png
│ │ │ └── json-feed@3x.png
│ │ │ ├── tab_feeds.imageset
│ │ │ ├── Contents.json
│ │ │ ├── tab_feeds.png
│ │ │ ├── tab_feeds@2x.png
│ │ │ └── tab_feeds@3x.png
│ │ │ └── tab_home.imageset
│ │ │ ├── Contents.json
│ │ │ ├── tab_home.png
│ │ │ ├── tab_home@2x.png
│ │ │ └── tab_home@3x.png
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Data
│ │ ├── DataRepository.swift
│ │ ├── Local
│ │ │ ├── DataController.swift
│ │ │ ├── JSON_Feed_Reader.xcdatamodeld
│ │ │ │ ├── .xccurrentversion
│ │ │ │ └── JSON_Feed_Reader.xcdatamodel
│ │ │ │ │ └── contents
│ │ │ ├── LocalRepository.swift
│ │ │ └── PrimaryFeed.swift
│ │ ├── Remote
│ │ │ ├── ModelExtensions.swift
│ │ │ └── RemoteRepository.swift
│ │ └── RepositoryProtocol.swift
│ ├── Info.plist
│ ├── UI
│ │ ├── BaseViewController.swift
│ │ ├── HomeViewController.swift
│ │ ├── PostCell
│ │ │ ├── PostViewCell.swift
│ │ │ └── PostViewCell.xib
│ │ ├── PostContentViewController.swift
│ │ └── PostsViewController.swift
│ └── Utils
│ │ ├── Constants.swift
│ │ ├── Extensions.swift
│ │ └── Formatter.swift
├── Podfile
├── Podfile.lock
└── README.md
└── README.md
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Rajanikant Deshmukh
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 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xccheckout
19 | *.xcscmblueprint
20 |
21 | ## Obj-C/Swift specific
22 | *.hmap
23 | *.ipa
24 | *.dSYM.zip
25 | *.dSYM
26 |
27 | ## Playgrounds
28 | timeline.xctimeline
29 | playground.xcworkspace
30 |
31 | # Swift Package Manager
32 | .build/
33 |
34 | # CocoaPods
35 | Pods/
36 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Pitch Perfect
4 | //
5 | // Created by Rajanikant Deshmukh on 27/11/17.
6 | // Copyright © 2017 Rajanikant Deshmukh. 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: [UIApplicationLaunchOptionsKey: 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 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Icon-41.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Icon-60.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Icon-Small@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Icon-Small@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "Icon-40@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Icon-40@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "Icon-60@2x.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Icon-60@3x.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "Icon-43.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Icon-42.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "29.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Icon-Small@2x-1.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "Icon-40.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Icon-40@2x-1.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "Icon-76.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Icon-76@2x.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "Icon-83.5pt.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "Icon-83.5pt 1.51.51 PM.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-41.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-41.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-42.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-42.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-43.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-43.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-83.5pt 1.51.51 PM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-83.5pt 1.51.51 PM.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-83.5pt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-83.5pt.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x-1.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Echo.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Echo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Echo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Echo.imageset/Echo@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Fast.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Fast@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Fast@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Fast.imageset/Fast@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "HighPitch.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "HighPitch@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "HighPitch@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/HighPitch.imageset/HighPitch@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Icon-83.5.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Icon-83.5@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Icon-83.5@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Launch.imageset/Icon-83.5@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LowPitch.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LowPitch@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LowPitch@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/LowPitch.imageset/LowPitch@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Pause.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Pause@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Pause@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Pause.imageset/Pause@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Record.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Record@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Record@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Record.imageset/Record@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Reverb.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Reverb@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Reverb@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Reverb.imageset/Reverb@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Slow.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Slow@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Slow@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Slow.imageset/Slow@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Stop.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "Stop@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "Stop@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop@2x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Pitch Perfect/Assets.xcassets/Stop.imageset/Stop@3x.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSMicrophoneUsageDescription
6 | Pitch Perfect will need access to Microphone to record audio.
7 | CFBundleDevelopmentRegion
8 | $(DEVELOPMENT_LANGUAGE)
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
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 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/PlaySoundViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlaySoundViewController.swift
3 | // Pitch Perfect
4 | //
5 | // Created by Rajanikant Deshmukh on 01/12/17.
6 | // Copyright © 2017 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 |
12 | class PlaySoundViewController: UIViewController {
13 |
14 | // MARK: Outlets
15 |
16 | @IBOutlet weak var snailButton: UIButton!
17 | @IBOutlet weak var chipmunkButton: UIButton!
18 | @IBOutlet weak var rabbitButton: UIButton!
19 | @IBOutlet weak var vaderButton: UIButton!
20 | @IBOutlet weak var echoButton: UIButton!
21 | @IBOutlet weak var reverbButton: UIButton!
22 | @IBOutlet weak var stopButton: UIButton!
23 |
24 | var recordedAudioUrl: URL!
25 | var audioFile:AVAudioFile!
26 | var audioEngine:AVAudioEngine!
27 | var audioPlayerNode: AVAudioPlayerNode!
28 | var stopTimer: Timer!
29 |
30 | enum ButtonType: Int {case slow = 0, fast, chipmunk, vader, echo, reverb }
31 |
32 |
33 | override func viewWillAppear(_ animated: Bool) {
34 | super.viewWillAppear(animated)
35 | configureUI(.notPlaying)
36 | }
37 |
38 | override func viewDidLoad() {
39 | super.viewDidLoad()
40 | setupAudio()
41 | snailButton.imageView?.contentMode = .scaleAspectFit
42 | chipmunkButton.imageView?.contentMode = .scaleAspectFit
43 | rabbitButton.imageView?.contentMode = .scaleAspectFit
44 | vaderButton.imageView?.contentMode = .scaleAspectFit
45 | echoButton.imageView?.contentMode = .scaleAspectFit
46 | reverbButton.imageView?.contentMode = .scaleAspectFit
47 | stopButton.imageView?.contentMode = .scaleAspectFit
48 | }
49 |
50 | // MARK: Actions
51 |
52 | @IBAction func playSoundForButton(_ sender: UIButton) {
53 | switch(ButtonType(rawValue: sender.tag)!) {
54 | case .slow:
55 | playSound(rate: 0.5)
56 | case .fast:
57 | playSound(rate: 1.5)
58 | case .chipmunk:
59 | playSound(pitch: 1000)
60 | case .vader:
61 | playSound(pitch: -1000)
62 | case .echo:
63 | playSound(echo: true)
64 | case .reverb:
65 | playSound(reverb: true)
66 | }
67 |
68 | configureUI(.playing)
69 | }
70 |
71 | @IBAction func stopButtonPressed(_ sender: AnyObject) {
72 | stopAudio()
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Pitch Perfect/RecordSoundViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RecordSoundViewController.swift
3 | // Pitch Perfect
4 | //
5 | // Created by Rajanikant Deshmukh on 27/11/17.
6 | // Copyright © 2017 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AVFoundation
11 |
12 | class RecordSoundViewController: UIViewController, AVAudioRecorderDelegate {
13 |
14 | // MARK: IBOutlets
15 |
16 | @IBOutlet weak var recordLabel: UILabel!
17 | @IBOutlet weak var recordButton: UIButton!
18 | @IBOutlet weak var stopButton: UIButton!
19 |
20 | let recordingSegueId = "stopRecording"
21 | var audioRecorder: AVAudioRecorder!
22 |
23 | // MARK: UI Functions
24 |
25 | override func viewDidLoad() {
26 | super.viewDidLoad()
27 | configureUI(recording: false)
28 | }
29 |
30 | func configureUI(recording: Bool) {
31 | recordButton.isEnabled = !recording
32 | stopButton.isEnabled = recording
33 | recordLabel.text = recording ? "Recording.." : "Tap To Record"
34 | }
35 |
36 | // MARK: IBActions
37 |
38 | @IBAction func startRecording(_ sender: Any) {
39 | configureUI(recording: true)
40 |
41 | let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)[0] as String
42 | let recordingName = "recordedVoice.wav"
43 | let pathArray = [dirPath, recordingName]
44 | let filePath = URL(string: pathArray.joined(separator: "/"))
45 |
46 | let session = AVAudioSession.sharedInstance()
47 | try! session.setCategory(AVAudioSessionCategoryPlayAndRecord, with:AVAudioSessionCategoryOptions.defaultToSpeaker)
48 |
49 | try! audioRecorder = AVAudioRecorder(url: filePath!, settings: [:])
50 | audioRecorder.delegate = self
51 | audioRecorder.isMeteringEnabled = true
52 | audioRecorder.prepareToRecord()
53 | audioRecorder.record()
54 | }
55 |
56 | @IBAction func stopRecording(_ sender: Any) {
57 | configureUI(recording: false)
58 |
59 | audioRecorder.stop()
60 | let session = AVAudioSession.sharedInstance()
61 | try! session.setActive(false)
62 | }
63 |
64 | // MARK: AVAudioRecorderDelegate Functions
65 |
66 | func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
67 | // Called after recording and saving file is finished
68 | if flag {
69 | performSegue(withIdentifier: recordingSegueId, sender: audioRecorder.url)
70 | } else {
71 | print("Recording Audio Failed")
72 | let alert = UIAlertController(title: "Reording Failed", message: "Racording audio failed due to some unknown error.", preferredStyle: .alert)
73 | alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
74 | self.present(alert, animated: true, completion: nil)
75 | }
76 | }
77 |
78 | // MARK: Segue Functions
79 |
80 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
81 | if (segue.identifier == recordingSegueId) {
82 | let playSoundVC = segue.destination as! PlaySoundViewController
83 | let recordedAudioUrl = sender as! URL
84 | playSoundVC.recordedAudioUrl = recordedAudioUrl
85 | }
86 | }
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/README.md:
--------------------------------------------------------------------------------
1 | # Pitch Perfect
2 | Ever wondered what you’d sound like as a Chipmunk or Darth Vader? Wonder no more!
3 | Pitch Perfect is an app that records a user’s voice and then plays the modulated audio through a variety of filters.
4 |
5 | ## Screenshots
6 | | Home Screen: Idle | Home Screen: Recording | Play Sounds Screen |
7 | | ----------------- | ---------------------- | ------------------ |
8 | |  |  | 
9 |
10 | ## Frameworks Used
11 | 1. [Foundation](https://developer.apple.com/documentation/foundation)
12 | 2. [UIKit](https://developer.apple.com/documentation/uikit)
13 | 3. [AVFoundation](https://developer.apple.com/documentation/avfoundation)
14 |
15 | ## How to Build
16 | 1. Download or fork & clone project on your desktop.
17 | 2. Open `Pitch Perfect.xcodeproj` file in Xcode.
18 | 3. Now you can build and run the app.
19 |
20 | ## Licence
21 | This project is a part of Master Projects repository. For other projects and licensing information, please see [iOS Nanodegree Projects](https://github.com/rajanikantdeshmukh/iOS-Nanodegree-Projects).
22 |
--------------------------------------------------------------------------------
/P1 PitchPerfect/Screenshots/HomeScreen-Idle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Screenshots/HomeScreen-Idle.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Screenshots/HomeScreen-Rec.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Screenshots/HomeScreen-Rec.png
--------------------------------------------------------------------------------
/P1 PitchPerfect/Screenshots/PlaySoundScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P1 PitchPerfect/Screenshots/PlaySoundScreen.png
--------------------------------------------------------------------------------
/P2 MemeMe/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xccheckout
19 | *.xcscmblueprint
20 |
21 | ## Obj-C/Swift specific
22 | *.hmap
23 | *.ipa
24 | *.dSYM.zip
25 | *.dSYM
26 |
27 | ## Playgrounds
28 | timeline.xctimeline
29 | playground.xcworkspace
30 |
31 | # Swift Package Manager
32 | .build/
33 |
34 | # CocoaPods
35 | Pods/
36 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 29/12/17.
6 | // Copyright © 2017 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "Meme-Me 2-12.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "Meme-Me 2-7.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "Meme-Me 2-10.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "Meme-Me 2-5.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "Meme-Me 2-6.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "Meme-Me 2-3.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "Meme-Me 2-4.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "Meme-Me 2-1.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "Meme-Me 2-16.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "Meme-Me 2-13.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "Meme-Me 2-15.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "Meme-Me 2-11.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "Meme-Me 2-14.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "Meme-Me 2-8.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "Meme-Me 2-9.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "Meme-Me 2-2.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "Meme-Me 2.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "Meme-Me.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-1.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-10.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-11.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-12.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-13.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-14.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-15.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-16.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-2.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-3.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-4.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-5.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-6.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-7.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-8.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2-9.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me 2.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/AppIcon.appiconset/Meme-Me.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/camera.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "camera@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "camera@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/camera.imageset/camera@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/camera.imageset/camera@2x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/camera.imageset/camera@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/camera.imageset/camera@3x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/gallary.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "gallary@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "gallary@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/gallary.imageset/gallary@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/gallary.imageset/gallary@2x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/gallary.imageset/gallary@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/gallary.imageset/gallary@3x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "grid.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "grid@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "grid@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid@2x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/grid.imageset/grid@3x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "launch-icon.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "launch-icon@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "launch-icon@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon@2x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/launcher.imageset/launch-icon@3x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "list.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "list@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "list@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list@2x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/MemeMe/Assets.xcassets/list.imageset/list@3x.png
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Home/GridViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GridViewController.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 17/02/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class GridViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
12 |
13 | @IBOutlet weak var emptyTextView: UILabel!
14 | @IBOutlet weak var gridView: UICollectionView!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | gridView.delegate = self
19 | gridView.dataSource = self
20 | }
21 |
22 | override func viewWillAppear(_ animated: Bool) {
23 | super.viewWillAppear(animated)
24 | gridView.reloadData()
25 | emptyTextView.isHidden = (MemeStorage.getCount() != 0)
26 | }
27 |
28 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
29 | return MemeStorage.getCount()
30 | }
31 |
32 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
33 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MemeCellView", for: indexPath) as! MemeCollectionViewCell
34 | cell.imageView.image = MemeStorage.get(indexPath.item).memedImage
35 | return cell
36 | }
37 |
38 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
39 | // Process selection
40 | let detailViewController: MemeDetailsViewController = storyboard?.instantiateViewController(withIdentifier: "MemeDetailsViewController") as! MemeDetailsViewController
41 | detailViewController.position = indexPath.item
42 | navigationController?.pushViewController(detailViewController, animated: true)
43 | }
44 |
45 | // MARK: UICollectionViewDelegateFlowLayout Methods
46 |
47 | let itemsPerRow: CGFloat = 3
48 | let sectionInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
49 |
50 | func collectionView(_ collectionView: UICollectionView,
51 | layout collectionViewLayout: UICollectionViewLayout,
52 | sizeForItemAt indexPath: IndexPath) -> CGSize {
53 | let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
54 | let availableWidth = view.frame.width - paddingSpace
55 | let widthPerItem = availableWidth / itemsPerRow
56 |
57 | return CGSize(width: widthPerItem, height: widthPerItem)
58 | }
59 |
60 | func collectionView(_ collectionView: UICollectionView,
61 | layout collectionViewLayout: UICollectionViewLayout,
62 | insetForSectionAt section: Int) -> UIEdgeInsets {
63 | return sectionInsets
64 | }
65 |
66 | func collectionView(_ collectionView: UICollectionView,
67 | layout collectionViewLayout: UICollectionViewLayout,
68 | minimumLineSpacingForSectionAt section: Int) -> CGFloat {
69 | return sectionInsets.left
70 | }
71 |
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Home/ListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListViewController.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 17/02/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
12 |
13 | @IBOutlet weak var emptyView: UILabel!
14 | @IBOutlet weak var tableView: UITableView!
15 |
16 | override func viewWillAppear(_ animated: Bool) {
17 | super.viewWillAppear(animated)
18 | if MemeStorage.getCount() == 0 {
19 | tableView.isHidden = true
20 | emptyView.isHidden = false
21 | } else {
22 | tableView.isHidden = false
23 | emptyView.isHidden = true
24 | tableView.reloadData()
25 | }
26 | }
27 |
28 | override func viewDidLoad() {
29 | super.viewDidLoad()
30 |
31 | // Register XIB file to UITableView
32 | tableView.register(UINib(nibName: "MemeTableViewCell", bundle: nil), forCellReuseIdentifier: "MemeCellView")
33 |
34 | tableView.delegate = self
35 | tableView.dataSource = self
36 | }
37 |
38 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
39 | return MemeStorage.getCount()
40 | }
41 |
42 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
43 | let memeObject = MemeStorage.get(indexPath.row)
44 | let titleText = memeObject.topText + " " + memeObject.bottomText
45 |
46 | let cell: MemeTableViewCell = tableView.dequeueReusableCell(withIdentifier: "MemeCellView") as! MemeTableViewCell
47 |
48 | cell.memeTitleLabel.text = titleText
49 | cell.memeImageView.image = memeObject.memedImage
50 | return cell
51 | }
52 |
53 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
54 | return 128.0
55 | }
56 |
57 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
58 | let detailViewController: MemeDetailsViewController = storyboard?.instantiateViewController(withIdentifier: "MemeDetailsViewController") as! MemeDetailsViewController
59 | detailViewController.position = indexPath.item
60 | navigationController?.pushViewController(detailViewController, animated: true)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Home/MemeCollectionViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemeCollectionViewCell.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 17/02/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class MemeCollectionViewCell: UICollectionViewCell {
12 |
13 | @IBOutlet weak var imageView: UIImageView!
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Home/MemeTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemeTableViewCell.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 16/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class MemeTableViewCell: UITableViewCell {
13 |
14 | @IBOutlet weak var memeImageView: UIImageView!
15 | @IBOutlet weak var memeTitleLabel: UILabel!
16 | }
17 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSCameraUsageDescription
6 | MemeMe would like to use camera for taking pictures.
7 | NSPhotoLibraryAddUsageDescription
8 | MemeMe would like to access Photo Library for pictures.
9 | CFBundleDevelopmentRegion
10 | $(DEVELOPMENT_LANGUAGE)
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/MemeDetailsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemeDetailsViewController.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 18/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class MemeDetailsViewController: UIViewController {
13 |
14 | @IBOutlet weak var memedImageView: UIImageView!
15 |
16 | var position: Int!
17 |
18 | override func viewWillAppear(_ animated: Bool) {
19 | super.viewWillAppear(animated)
20 |
21 | if (position != nil) {
22 | let meme = MemeStorage.get(position)
23 | memedImageView.image = meme.memedImage
24 | }
25 | }
26 |
27 | override func viewDidLoad() {
28 | super.viewDidLoad()
29 | if (position == nil) {
30 | let alertController = UIAlertController(title: "No Meme Selected", message: "", preferredStyle: UIAlertControllerStyle.alert)
31 | alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"), style: .default, handler: nil))
32 |
33 | present(alertController, animated: true, completion: nil)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Model/MemeObject.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemeObject.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 14/02/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | struct MemeObject {
13 | var topText: String
14 | var bottomText: String
15 | var originalImage: UIImage
16 | var memedImage: UIImage
17 | }
18 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/Model/MemeStorage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MemeStorage.swift
3 | // MemeMe
4 | //
5 | // Created by Rajanikant Deshmukh on 16/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class MemeStorage: NSObject {
13 |
14 | private static var memes = [MemeObject]()
15 |
16 | private override init() {
17 | }
18 |
19 | static func getMemes() -> [MemeObject] {
20 | return memes
21 | }
22 |
23 | static func addMeme(_ meme: MemeObject) {
24 | memes.append(meme)
25 | }
26 |
27 | static func get(_ position: Int) -> MemeObject {
28 | return memes[position]
29 | }
30 |
31 | static func getCount() -> Int {
32 | return memes.count
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/P2 MemeMe/MemeMe/View/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/P2 MemeMe/README.md:
--------------------------------------------------------------------------------
1 | # Meme Me
2 | Meme Me is an app that creates memes from images! The Meme Editor enables the user to take a picture, and add text at the top and bottom to form a meme, and share the meme with friends. The Collection screen shows sent memes in both a table and collection view.
3 |
4 | ## Screenshots
5 |
6 | #### Meme Collection
7 | | Empty Screen | Collection | Table |
8 | | ------------ | ---------- | ----- |
9 | |  |  |  |
10 |
11 | #### Meme Editor
12 | | Empty | Editing |
13 | | ----- | ------- |
14 | |  |  |
15 |
16 | ## Frameworks Used
17 | 1. [Foundation](https://developer.apple.com/documentation/foundation)
18 | 2. [UIKit](https://developer.apple.com/documentation/uikit)
19 |
20 | ## How to Build
21 | 1. Download zip or fork & clone project on your desktop.
22 | 2. Open `MemeMe.xcodeproj` file in Xcode.
23 |
24 | ## Licence
25 | This project is a part of Master Projects repository. For other projects and licensing information, please see [iOS Nanodegree Projects](https://github.com/rajanikantdeshmukh/iOS-Nanodegree-Projects).
26 |
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/.DS_Store
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/HomeGridFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/HomeGridFilled.png
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/HomeListEmpty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/HomeListEmpty.png
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/HomeListFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/HomeListFilled.png
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/MemeEditorEmpty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/MemeEditorEmpty.png
--------------------------------------------------------------------------------
/P2 MemeMe/Screenshots/MemeEditorFilled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P2 MemeMe/Screenshots/MemeEditorFilled.png
--------------------------------------------------------------------------------
/P3 OnTheMap/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xccheckout
19 | *.xcscmblueprint
20 |
21 | ## Obj-C/Swift specific
22 | *.hmap
23 | *.ipa
24 | *.dSYM.zip
25 | *.dSYM
26 |
27 | ## Playgrounds
28 | timeline.xctimeline
29 | playground.xcworkspace
30 |
31 | # Swift Package Manager
32 | .build/
33 |
34 | # CocoaPods
35 | Pods/
36 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Account/AccountViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AccountViewController.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 23/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class AccountViewController: UIViewController {
12 |
13 | @IBOutlet weak var userImage: UIImageView!
14 | @IBOutlet weak var nicknameLabel: UILabel!
15 | @IBOutlet weak var nameLabel: UILabel!
16 | @IBOutlet weak var logoutButton: UIButton!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 |
21 | let userInfo = Cache.shared.userInfo
22 |
23 | nicknameLabel.text = userInfo?.nickName
24 | nameLabel.text = "\(userInfo?.firstName ?? "") \(userInfo?.lastName ?? "")"
25 |
26 | DispatchQueue.global(qos: .background).async {
27 | let image: UIImage
28 | do {
29 | let url = URL(string: "https:" + (userInfo?.imageUrl ?? ""))
30 | let data = try Data(contentsOf: url!)
31 | image = UIImage(data: data)!
32 | } catch {
33 | image = UIImage(named: "icon_world")!
34 | }
35 |
36 | DispatchQueue.main.async {
37 | self.userImage.image = image
38 | }
39 | }
40 | }
41 |
42 | @IBAction func onLogoutClick(_ sender: Any) {
43 | AuthHandler.shared.makeLogoutCall({error in
44 | if error != nil {
45 | self.showAlertDialog(title: "Error", message: (error?.rawValue)!, dismissHandler: nil)
46 | return
47 | }
48 |
49 | // Dismiss current view controller
50 | self.tabBarController?.dismiss(animated: true, completion: nil)
51 | })
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/AddNew/AddProfileViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AddProfileViewController.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 24/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import MapKit
11 |
12 | class AddProfileViewController: UIViewController, UITextFieldDelegate {
13 |
14 | var locationString: String?
15 | var lat: Double?
16 | var lng: Double?
17 |
18 | @IBOutlet weak var nameLabel: UILabel!
19 | @IBOutlet weak var locationLabel: UILabel!
20 | @IBOutlet weak var profileLinkInput: UITextField!
21 | @IBOutlet weak var mapView: MKMapView!
22 | @IBOutlet weak var addPinButton: UIButton!
23 |
24 | override func viewDidLoad() {
25 | super.viewDidLoad()
26 | let userInfo = Cache.shared.userInfo
27 | nameLabel.text = "\(userInfo?.firstName ?? "") \(userInfo?.lastName ?? "")"
28 | locationLabel.text = locationString
29 |
30 | profileLinkInput.delegate = self
31 |
32 | addPinButton.isEnabled = false
33 |
34 | let annotation = MKPointAnnotation()
35 | annotation.coordinate.latitude = lat!
36 | annotation.coordinate.longitude = lng!
37 | mapView.addAnnotation(annotation)
38 | mapView.centerCoordinate = annotation.coordinate
39 | mapView.region = MKCoordinateRegion(center: annotation.coordinate, span: MKCoordinateSpan(latitudeDelta: 3, longitudeDelta: 3))
40 | }
41 |
42 | @IBAction func addPinButtonClick(_ sender: Any) {
43 | let mediaUrl = profileLinkInput.text
44 | ParseHandler.shared.postStudentLocation(locationString: locationString!, mediaUrl: mediaUrl!, lat: lat!, lng: lng!, onComplete: {error in
45 | DispatchQueue.main.async {
46 | if error != nil {
47 | self.showAlertDialog(title: "Error", message: (error)!.rawValue, dismissHandler: nil)
48 | return
49 | }
50 | self.showAlertDialog(title: "Location Posted", message: "Now other students can see where you are studying.", dismissHandler: { _ in
51 | self.navigationController?.popToRootViewController(animated: true)
52 | })
53 | }
54 | })
55 | }
56 |
57 | func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
58 | addPinButton.isEnabled = ((profileLinkInput.text?.count ?? 0) > 0)
59 | return true
60 | }
61 |
62 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
63 | addPinButton.isEnabled = ((profileLinkInput.text?.count ?? 0) > 0)
64 | profileLinkInput.resignFirstResponder()
65 | return true
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Api/ApiConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ApiConstants.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 18/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | struct ApiConstants {
12 |
13 | static let PARSE_ENPOINT_URL = "https://parse.udacity.com/parse/classes"
14 | static let PARSE_APP_ID = "QrX47CA9cyuGewLdsL7o5Eb8iug6Em8ye0dnAbIr"
15 | static let REST_API_KEY = "QuWThTdiRmTux3YaDseUSEpUKo7aBYM737yKd4gY"
16 |
17 | struct Method {
18 | static let GET: String = "GET"
19 | static let POST: String = "POST"
20 | static let DELETE: String = "DELETE"
21 | }
22 |
23 | struct HeaderKey {
24 | static let CONTENT_TYPE = "Content-Type"
25 | static let ACCEPT = "Accept"
26 | }
27 |
28 | struct HeaderValue {
29 | static let MIME_TYPE_JSON = "application/json"
30 | }
31 |
32 | struct UdacityAuth {
33 | static let KEY_UDACITY = "udacity"
34 | static let KEY_USERNAME = "username"
35 | static let KEY_PASSWORD = "password"
36 |
37 | static let KEY_STATUS = "status"
38 | static let KEY_ACCOUNT = "account"
39 | static let KEY_ACC_KEY = "key"
40 | static let KEY_SESSION = "session"
41 | static let KEY_ID = "id"
42 | static let KEY_EXPIRATION = "expiration"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Api/BaseNetworkHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseNetworkHandler.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 26/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class BaseNetworkHandler: NSObject {
12 |
13 | typealias ErrorBlock = ((Errors?) -> Void)
14 |
15 | func handleError(error: Error!, onComplete: @escaping ErrorBlock) {
16 | if let urlError = error as? URLError {
17 | switch urlError.code {
18 | case .notConnectedToInternet:
19 | onComplete(Errors.NetworkError)
20 | break
21 | default:
22 | onComplete(Errors.ServerError)
23 | }
24 | }
25 | onComplete(Errors.ServerError)
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 08/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. 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: [UIApplicationLaunchOptionsKey: 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 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/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 | "idiom" : "ios-marketing",
103 | "size" : "1024x1024",
104 | "scale" : "1x"
105 | }
106 | ],
107 | "info" : {
108 | "version" : 1,
109 | "author" : "xcode"
110 | }
111 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-76.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/LaunchLogo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchLogo.pdf",
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 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/LaunchLogo.imageset/LaunchLogo.pdf
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "account.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "account@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "account@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/account.imageset/account@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_listview-deselected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_listview-deselected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_listview-deselected@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-deselected.imageset/icon_listview-deselected@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_listview-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_listview-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_listview-selected@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_listview-selected.imageset/icon_listview-selected@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_mapview-deselected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_mapview-deselected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_mapview-deselected@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-deselected.imageset/icon_mapview-deselected@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_mapview-selected.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_mapview-selected@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_mapview-selected@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_mapview-selected.imageset/icon_mapview-selected@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_world.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_world@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_world@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/icon_world.imageset/icon_world@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "loading.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "loading@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "loading@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/loading.imageset/loading@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "map-pin.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "map-pin@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "map-pin@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin@2x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/On The Map/Assets.xcassets/map-pin.imageset/map-pin@3x.png
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Home/Map/MapViewController+MapViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapViewController+MapViewDelegate.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 19/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import MapKit
11 |
12 | extension MapViewController: MKMapViewDelegate {
13 |
14 | func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
15 |
16 | let reuseId = "pin"
17 |
18 | var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
19 |
20 | if pinView == nil {
21 | pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
22 | pinView!.canShowCallout = true
23 | pinView!.pinTintColor = UIColor.red
24 | pinView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
25 | } else {
26 | pinView!.annotation = annotation
27 | }
28 |
29 | return pinView
30 | }
31 |
32 | func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
33 | if control == view.rightCalloutAccessoryView {
34 | openUrl(url: view.annotation?.subtitle!)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Home/Map/MapViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapViewController.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 18/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import MapKit
12 |
13 | class MapViewController: StudentLocationViewController {
14 |
15 | @IBOutlet weak var mapView: MKMapView!
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | mapView.delegate = self
20 | }
21 |
22 | override func studentLocationLoaded(error: Errors?) {
23 | if error != nil {
24 | showAlertDialog(title: "Error", message: (error)!.rawValue, dismissHandler: nil)
25 | return
26 | }
27 |
28 | // Set annotations on map
29 | var annotations = [MKPointAnnotation]()
30 | for studentLocation in Cache.shared.studentLocations {
31 | annotations.append(studentLocation.annotation())
32 | }
33 | self.mapView.addAnnotations(annotations)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Home/StudentLocationViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StudentLocationViewController.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 26/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class StudentLocationViewController: UIViewController {
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 |
17 | ParseHandler.shared.loadStudentLocations(limit: 100, skip: 0, onComplete: {error in
18 | DispatchQueue.main.async(execute: {
19 | self.studentLocationLoaded(error: error)
20 | })
21 | })
22 | }
23 |
24 | func studentLocationLoaded(error: Errors?) {
25 | // To be overridden
26 | }
27 |
28 | func openUrl(url: String?) {
29 | if let url = URL(string: url!) {
30 | let app = UIApplication.shared
31 | app.open(url, options: [:], completionHandler: nil)
32 | } else {
33 | showAlertDialog(title: "Ooops!", message: "The media URL provided by this student is not a valid URL", dismissHandler: nil)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Home/Table/TableViewController+TableViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController+TableViewDelegate.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 20/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension TableViewController: UITableViewDelegate, UITableViewDataSource {
13 |
14 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
15 | return Cache.shared.studentLocations.count
16 | }
17 |
18 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
19 | let studentLocation = Cache.shared.studentLocations[indexPath.row]
20 | let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellReuseIdentifier)
21 | cell?.textLabel?.text = "\(studentLocation.firstName) \(studentLocation.lastName)"
22 | cell?.detailTextLabel?.text = studentLocation.mapString
23 | return cell!
24 | }
25 |
26 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
27 | let studentLocation = Cache.shared.studentLocations[indexPath.row]
28 | openUrl(url: studentLocation.mediaURL)
29 | // Deselect the selected row
30 | tableView.deselectRow(at: indexPath, animated: true)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Home/Table/TableViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TableViewController.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 18/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class TableViewController: StudentLocationViewController {
13 |
14 | let TableViewCellReuseIdentifier = "StudentLocationCell"
15 |
16 | @IBOutlet weak var tableView: UITableView!
17 |
18 | override func viewDidLoad() {
19 | super.viewDidLoad()
20 | tableView.delegate = self
21 | tableView.dataSource = self
22 | }
23 |
24 | override func studentLocationLoaded(error: Errors?) {
25 | if error != nil {
26 | showAlertDialog(title: "Error", message: (error)!.rawValue, dismissHandler: nil)
27 | return
28 | }
29 | tableView.reloadData()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Login/LoginViewController+Extras.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoginViewController+TextFieldDelegate.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 17/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension LoginViewController : UITextFieldDelegate {
13 |
14 | // MARK: UITextFieldDelegate Methods
15 |
16 | func textFieldShouldReturn(_ textField: UITextField) -> Bool {
17 | if (textField == emailTextField) {
18 | passwordTextField.becomeFirstResponder()
19 | } else {
20 | textField.resignFirstResponder()
21 | startLogin()
22 | }
23 | return true
24 | }
25 |
26 | // MARK: Keyboard Methods
27 |
28 | func subscribeToKeyboardNotifications() {
29 | // Use UIKeyboard WillChangeFrame instead of WillShow for supporting multiple keyboards
30 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange(_:)), name: .UIKeyboardWillChangeFrame, object: nil)
31 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: nil)
32 | }
33 |
34 | func unsubscribeFromKeyboardNotifications() {
35 | // Removes all notification observers
36 | NotificationCenter.default.removeObserver(self)
37 | }
38 |
39 | @objc func keyboardWillChange(_ notification:Notification) {
40 | // Bottom Y point of the stack view
41 | let safeBottom = self.stackView.frame.maxY + 16
42 |
43 | // Top Y point of keyboard
44 | let keyboardTop = self.view.frame.height - getKeyboardHeight(notification)
45 |
46 | let offset = safeBottom - keyboardTop
47 |
48 | // If the stackview is completely visible, no need to shift view
49 | if (offset <= 0) {
50 | return
51 | }
52 |
53 | UIView.animate(withDuration: 0.3, animations: {
54 | self.view.frame.origin.y = 0
55 | self.view.frame.origin.y -= offset
56 | })
57 | }
58 |
59 | @objc func keyboardWillHide(_ notification:Notification) {
60 | // Reset the view to it's original position
61 | UIView.animate(withDuration: 0.3, animations: {
62 | self.view.frame.origin.y = 0
63 | })
64 | }
65 |
66 | func getKeyboardHeight(_ notification:Notification) -> CGFloat {
67 | let userInfo = notification.userInfo
68 | let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
69 | return keyboardSize.cgRectValue.height
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Model/Response/UdacityAuthResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UdacityAuthResponse.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 26/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UdacityAuthResponse {
12 |
13 | var sessionId: String
14 | var expiration: Date
15 | var accountKey: String
16 |
17 | init(sessionId: String, expirationString: String, accountKey: String) {
18 | self.sessionId = sessionId
19 | self.accountKey = accountKey
20 |
21 | // Create DateFormatter to format String
22 | let dateFormatter = DateFormatter()
23 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
24 | dateFormatter.timeZone = TimeZone.current
25 |
26 | // Set default session expiray to one hour after current time
27 | let defaultExpiration = Calendar.current.date(byAdding: .hour, value: 1, to: Date())
28 |
29 | // Parse session expiration date
30 | self.expiration = dateFormatter.date(from: expirationString) ?? defaultExpiration!
31 | }
32 |
33 | init(_ dictionary: NSDictionary) {
34 | let account: NSDictionary = dictionary[ApiConstants.UdacityAuth.KEY_ACCOUNT] as! NSDictionary
35 | self.accountKey = account[ApiConstants.UdacityAuth.KEY_ACC_KEY] as! String
36 |
37 | let session: NSDictionary = dictionary[ApiConstants.UdacityAuth.KEY_SESSION] as! NSDictionary
38 | self.sessionId = session[ApiConstants.UdacityAuth.KEY_ID] as! String
39 |
40 | let expirationString: String = session[ApiConstants.UdacityAuth.KEY_EXPIRATION] as! String
41 |
42 | // Create DateFormatter to format String
43 | let dateFormatter = DateFormatter()
44 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
45 | dateFormatter.timeZone = TimeZone.current
46 |
47 | // Set default session expiray to one hour after current time
48 | let defaultExpiration = Calendar.current.date(byAdding: .hour, value: 1, to: Date())
49 |
50 | // Parse session expiration date
51 | self.expiration = dateFormatter.date(from: expirationString) ?? defaultExpiration!
52 | }
53 |
54 | func dateString() -> String {
55 | let dateFormatter = DateFormatter()
56 | dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
57 | dateFormatter.timeZone = TimeZone.current
58 |
59 | return dateFormatter.string(from: self.expiration)
60 | }
61 |
62 | func isExpired() -> Bool {
63 | return Date() > self.expiration
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Model/StudentLocation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StudentLocation.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 26/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class StudentLocation {
12 |
13 | var objectId : String
14 | var uniqueKey : String
15 |
16 | var firstName : String
17 | var lastName : String
18 | var latitude : Double
19 | var longitude : Double
20 | var mapString : String
21 | var mediaURL : String
22 |
23 | var createdAt : Date
24 | var updatedAt : Date
25 |
26 | let dateFormatter = ISO8601DateFormatter()
27 |
28 | init?(_ dictionary: NSDictionary) {
29 | // These keys are compulsory for Parse and every object will have it
30 | self.objectId = (dictionary["objectId"] as! String)
31 | self.uniqueKey = (dictionary["uniqueKey"] as! String)
32 | // TODO Parse Date
33 | self.createdAt = dateFormatter.date(from: dictionary["createdAt"] as! String) ?? Date()
34 | self.updatedAt = Date()
35 |
36 | // Since the Parse data is not being validated on ServerSide
37 | // We implemement sanity checks on our side
38 |
39 | // Sanity check for name
40 | if dictionary["firstName"] == nil || dictionary["lastName"] == nil {
41 | return nil
42 | }
43 | self.firstName = dictionary["firstName"] as! String
44 | self.lastName = (dictionary["lastName"] as! String)
45 |
46 | // Sanity check for locations
47 | if dictionary["latitude"] == nil || dictionary["longitude"] == nil {
48 | return nil
49 | }
50 | self.latitude = (dictionary["latitude"] as! Double)
51 | self.longitude = (dictionary["longitude"] as! Double)
52 |
53 | // Sanity check for address and media URL
54 | if dictionary["mapString"] == nil || dictionary["mediaURL"] == nil {
55 | return nil
56 | }
57 | self.mapString = (dictionary["mapString"] as! String)
58 | self.mediaURL = (dictionary["mediaURL"] as! String)
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Model/UserInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserInfo.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 26/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UserInfo {
12 |
13 | var firstName: String
14 | var lastName: String
15 | var nickName: String
16 | var imageUrl: String
17 |
18 | init(_ dictionary: NSDictionary) {
19 | let user: NSDictionary = dictionary["user"] as! NSDictionary
20 |
21 | self.firstName = user["first_name"] as? String ?? ""
22 | self.lastName = user["last_name"] as? String ?? ""
23 | self.nickName = user["nickname"] as? String ?? ""
24 | self.imageUrl = user["_image_url"] as? String ?? ""
25 | }
26 |
27 | func isValid() -> Bool {
28 | return !self.firstName.isEmpty && !self.lastName.isEmpty
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Storage/Cache.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Cache.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 23/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class Cache {
12 |
13 | static let shared = Cache()
14 |
15 | var userInfo: UserInfo?
16 | var studentLocations: [StudentLocation]
17 |
18 | private init() {
19 | studentLocations = [StudentLocation]()
20 | }
21 |
22 | func clear() {
23 | userInfo = nil
24 | studentLocations.removeAll()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Storage/Storage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Storage.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 23/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UserAuthStorage {
12 |
13 | static let shared: UserAuthStorage = UserAuthStorage()
14 |
15 | private init() {}
16 |
17 | func getStoredUserAuth() -> UdacityAuthResponse? {
18 | // Return from UserDefaults
19 | let sessionId = UserDefaults.standard.string(forKey: "UdacityAuthResponse.sessionId")
20 | let accountKey = UserDefaults.standard.string(forKey: "UdacityAuthResponse.accountKey")
21 | let expirationString = UserDefaults.standard.string(forKey: "UdacityAuthResponse.dateString")
22 | if (sessionId != nil && accountKey != nil && expirationString != nil) {
23 | return UdacityAuthResponse(sessionId: sessionId!, expirationString: expirationString!, accountKey: accountKey!)
24 | }
25 | return nil
26 | }
27 |
28 | func storeUserAuth(_ auth: UdacityAuthResponse) {
29 | // Store in UserDefaults
30 | UserDefaults.standard.set(auth.sessionId, forKey: "UdacityAuthResponse.sessionId")
31 | UserDefaults.standard.set(auth.accountKey, forKey: "UdacityAuthResponse.accountKey")
32 | UserDefaults.standard.set(auth.dateString(), forKey: "UdacityAuthResponse.dateString")
33 | }
34 |
35 | func clearUserAuth() {
36 | // Clear UserDefaults
37 | UserDefaults.standard.removeObject(forKey: "UdacityAuthResponse.sessionId")
38 | UserDefaults.standard.removeObject(forKey: "UdacityAuthResponse.accountKey")
39 | UserDefaults.standard.removeObject(forKey: "UdacityAuthResponse.dateString")
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Utils/Errors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Errors.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 21/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Errors: String {
12 | case WrongCredentialError = "Account not found or invalid credentials."
13 | case CredentialExpiredError = "Login expired. Please login again."
14 | case NetworkError = "Please check your network and try again."
15 | case ServerError = "Server messed up. Please contact developer."
16 | case UnknownError = "The app is messed up. Please contact developer."
17 | }
18 |
--------------------------------------------------------------------------------
/P3 OnTheMap/On The Map/Utils/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // On The Map
4 | //
5 | // Created by Rajanikant Deshmukh on 19/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import MapKit
11 |
12 | extension Dictionary {
13 | func json() -> String {
14 | do {
15 | let jsonData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted)
16 | return String(bytes: jsonData, encoding: String.Encoding.utf8) ?? ""
17 | } catch {
18 | return ""
19 | }
20 | }
21 | }
22 |
23 | extension StudentLocation {
24 |
25 | func annotation() -> MKPointAnnotation {
26 | let annotation = MKPointAnnotation()
27 | annotation.coordinate.latitude = self.latitude
28 | annotation.coordinate.longitude = longitude
29 | annotation.title = "\(self.firstName) \(self.lastName)"
30 | annotation.subtitle = self.mediaURL
31 | return annotation
32 | }
33 | }
34 |
35 | extension UIViewController {
36 |
37 | func showAlertDialog(title: String, message: String, dismissHandler: ((UIAlertAction) -> Void)?) {
38 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
39 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: dismissHandler))
40 | self.present(alert, animated: true)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/P3 OnTheMap/README.md:
--------------------------------------------------------------------------------
1 | # On The Map
2 | On The Map displays information posted by other Udacity students, by interacting with Udacity's Authentication and Parse APIs. The app has a map view with pins representing student locations, and by tapping a pin, the app will display a custom URL posted by a student.
3 |
4 | # Screenshots
5 |
6 | | Login Screen | Student Pin | List |
7 | | ------------ | ----------- | ---- |
8 | |  |  | 
9 |
10 | | Account | Add Pin | Add Profile |
11 | | ------- | ------- | ----------- |
12 | |  |  |  |
13 |
14 | ## Frameworks Used
15 | 1. [Foundation](https://developer.apple.com/documentation/foundation)
16 | 2. [UIKit](https://developer.apple.com/documentation/uikit)
17 | 3. [MapKit](https://developer.apple.com/documentation/mapkit)
18 |
19 | ## How to Build
20 | 1. Download zip or fork & clone project on your desktop.
21 | 2. Open `On The Map.xcodeproj` file in Xcode.
22 | 3. Now you can build and run the app.
23 |
24 | ## Licence
25 | This project is a part of Master Projects repository. For other projects and licensing information, please see [iOS Nanodegree Projects](https://github.com/rajanikantdeshmukh/iOS-Nanodegree-Projects).
26 |
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/Account.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/Account.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/AddPin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/AddPin.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/AddProfile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/AddProfile.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/List.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/List.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/Login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/Login.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/Map-Pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/Map-Pin.png
--------------------------------------------------------------------------------
/P3 OnTheMap/Screenshots/Map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P3 OnTheMap/Screenshots/Map.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xccheckout
19 | *.xcscmblueprint
20 |
21 | ## Obj-C/Swift specific
22 | *.hmap
23 | *.ipa
24 | *.dSYM.zip
25 | *.dSYM
26 |
27 | ## Playgrounds
28 | timeline.xctimeline
29 | playground.xcworkspace
30 |
31 | # Swift Package Manager
32 | .build/
33 |
34 | # CocoaPods
35 | Pods/
36 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'Virtual Tourist' do
5 | pod 'Kingfisher', '~> 4.0'
6 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
7 | use_frameworks!
8 |
9 | # Pods for Virtual Tourist
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Kingfisher (4.6.4)
3 |
4 | DEPENDENCIES:
5 | - Kingfisher (~> 4.0)
6 |
7 | SPEC CHECKSUMS:
8 | Kingfisher: 68498a706e46c2a050b0c9572f100e5db407f6e0
9 |
10 | PODFILE CHECKSUM: 6741e6c76d9bb14d4f8b3b94d6715c292cfd7184
11 |
12 | COCOAPODS: 1.4.0
13 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/README.md:
--------------------------------------------------------------------------------
1 | # Virtual Tourist
2 | Tour the world without leaving the comforts of your couch! Virtual Tourist lets you tour the world from the comfort of your own couch. Users is able to drop pins on a map and download pictures for the location.
3 |
4 | ## Screenshots
5 |
6 | | Map | Album | Map: Delete Mode |
7 | | --- | ----- | ---------------- |
8 | |  |  | 
9 |
10 | ## Libraries and Frameworks Used
11 | **iOS Frameworks**:
12 | 1. [Foundation](https://developer.apple.com/documentation/foundation)
13 | 2. [UIKit](https://developer.apple.com/documentation/uikit)
14 | 3. [MapKit](https://developer.apple.com/documentation/mapkit)
15 | 4. [Core Data](https://developer.apple.com/documentation/coredata) to store data and images.
16 |
17 | **External Library**
18 | 6. [Kingfisher](https://github.com/onevcat/Kingfisher/) for easy image loading.
19 |
20 | ## How to Build
21 | The build system uses [CocoaPods](https://cocoapods.org) to integrate dependencies. You should be familiar with CocoaPods and API key and secret from Flickr account.
22 | 1. Download zip or fork & clone project on your desktop.
23 | 2. Open Terminal and `cd` into project folder.
24 | 3. Run `pods install` to install dependencies.
25 | 4. Open `Virtual Tourist/Virtual Tourist.xcworkspace` with Xcode.
26 | 5. Now you can build and run the app.
27 |
28 | ## Licence
29 | This project is a part of Master Projects repository. For other projects and licensing information, please see [iOS Nanodegree Projects](https://github.com/rajanikantdeshmukh/iOS-Nanodegree-Projects).
30 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Screenshots/Album.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Screenshots/Album.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Screenshots/Map-DeletePin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Screenshots/Map-DeletePin.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Screenshots/Map-ViewPin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Screenshots/Map-ViewPin.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 22/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CoreData
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 |
15 | var window: UIWindow?
16 |
17 | let dataController = DataController()
18 | var coreDataEnabled = false
19 |
20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
21 |
22 | dataController.load(completion: {
23 | print("DataController Loaded successfullys")
24 | self.coreDataEnabled = true
25 | })
26 |
27 | // Inject data controller into first ViewController
28 | let navigationController = window?.rootViewController as! UINavigationController
29 | let mapViewController = navigationController.topViewController as! TravelMapViewController
30 | mapViewController.dataController = self.dataController
31 |
32 | return true
33 | }
34 |
35 | func applicationWillTerminate(_ application: UIApplication) {
36 | self.saveContext()
37 | }
38 |
39 | func applicationDidEnterBackground(_ application: UIApplication) {
40 | self.saveContext()
41 | }
42 |
43 | // MARK: - Core Data Saving support
44 |
45 | func saveContext () {
46 | let context = dataController.viewContext
47 | if context.hasChanges {
48 | do {
49 | try context.save()
50 | } catch {
51 | let nserror = error as NSError
52 | print("Unresolved error \(nserror), \(nserror.userInfo)")
53 | }
54 | }
55 | }
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/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 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/PrimaryColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.533",
15 | "green" : "0.588"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_delete.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_delete@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_delete@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete.imageset/icon_delete@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_delete_dark.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_delete_dark@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_delete_dark@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_delete_dark.imageset/icon_delete_dark@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_done.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_done@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_done@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_done.imageset/icon_done@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_edit.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_edit@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_edit@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_edit.imageset/icon_edit@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_info_dark.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_info_dark@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_info_dark@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_info_dark.imageset/icon_info_dark@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "icon_refresh.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "icon_refresh@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "icon_refresh@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/icon_refresh.imageset/icon_refresh@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "placeholder_image.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "placeholder_image@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "placeholder_image@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image@2x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Assets.xcassets/placeholder_image.imageset/placeholder_image@3x.png
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Data/DataController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataController.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 28/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class DataController {
13 |
14 | let persistanceContainer: NSPersistentContainer
15 |
16 | init(modelName: String = "Virtual_Tourist") {
17 | self.persistanceContainer = NSPersistentContainer(name: modelName)
18 | }
19 |
20 | var viewContext: NSManagedObjectContext {
21 | return self.persistanceContainer.viewContext
22 | }
23 |
24 | func load(completion: (() -> Void)? = nil) {
25 | self.persistanceContainer.loadPersistentStores(completionHandler: {
26 | storeDescription, error in
27 | guard error == nil else {
28 | fatalError(error!.localizedDescription)
29 | }
30 |
31 | completion?()
32 | })
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Data/MapViewDefaults.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MapViewDefaults.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 27/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import MapKit
11 |
12 | class MapViewDefaults {
13 |
14 | private init() {}
15 |
16 | class func setDefaults(toSetMapView: MKMapView) {
17 | // For first time launch, the hasPreviousState will be false
18 | let hasPreviousState = UserDefaults.standard.bool(forKey: "hasPreviousState")
19 |
20 | // If the flag is set, values are saved in UserDefaults and we are free to use those
21 | if hasPreviousState {
22 | let latDouble = UserDefaults.standard.double(forKey:"lat")
23 | let lngDouble = UserDefaults.standard.double(forKey:"lng")
24 | let altInt = UserDefaults.standard.integer(forKey:"alt")
25 |
26 | toSetMapView.centerCoordinate.latitude = CLLocationDegrees(latDouble)
27 | toSetMapView.centerCoordinate.longitude = CLLocationDegrees(lngDouble)
28 | toSetMapView.camera.altitude = CLLocationDistance(altInt)
29 | }
30 | }
31 |
32 | class func saveDefaults(toSaveMapView: MKMapView) {
33 | // Get current state values from map
34 | let lat = toSaveMapView.centerCoordinate.latitude
35 | let lng = toSaveMapView.centerCoordinate.longitude
36 | let alt = toSaveMapView.camera.altitude
37 |
38 | // Save them in user defaults
39 | UserDefaults.standard.set(Double(lat), forKey: "lat")
40 | UserDefaults.standard.set(Double(lng), forKey: "lng")
41 | UserDefaults.standard.set(Int64(alt), forKey: "alt")
42 | // Set flag to show that the app have a previous state saved
43 | UserDefaults.standard.set(true, forKey: "hasPreviousState")
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Fonts/Raleway-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Fonts/Raleway-Light.ttf
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Fonts/Raleway-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P4 VirtualTourist/Virtual Tourist/Fonts/Raleway-Regular.ttf
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Model/Virtual_Tourist.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | Virtual_Tourist.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Model/Virtual_Tourist.xcdatamodeld/Virtual_Tourist.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/UI/Album/PhotoAlbumViewController+Extras.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhotoAlbumViewController+Extras.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 28/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension PhotoAlbumViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
13 |
14 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
15 | return album.count
16 | }
17 |
18 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
19 | // Load Image
20 | let photo = album[indexPath.row]
21 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoViewCell", for: indexPath) as! PhotoViewCell
22 | cell.setPhoto(photo, onComplete: {
23 | self.loadedImageCount! += 1
24 | if self.loadedImageCount == self.album.count {
25 | self.refreshButton.isEnabled = true
26 | }
27 | })
28 | return cell
29 | }
30 |
31 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
32 | // Delete photo
33 | let photo = album.remove(at: indexPath.row)
34 | dataController.viewContext.delete(photo)
35 | collectionView.reloadData()
36 | }
37 |
38 | // MARK:- UICollectionViewDelegateFlowLayout Methods
39 |
40 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
41 | let width = UIScreen.main.bounds.width
42 | let spacificWidth = (width - (2*margin + internalSpacing * CGFloat(numberOfItems - 1)))/CGFloat(numberOfItems)
43 | return CGSize(width: spacificWidth, height: spacificWidth)
44 | }
45 |
46 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
47 | return UIEdgeInsets(top: margin, left: margin, bottom: margin, right: margin)
48 | }
49 |
50 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
51 | return internalSpacing
52 | }
53 |
54 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
55 | return internalSpacing
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/UI/View/PhotoViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PhotoViewCell.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Kingfisher
11 |
12 | class PhotoViewCell: UICollectionViewCell {
13 |
14 |
15 | @IBOutlet weak var imageView: UIImageView!
16 |
17 | override func awakeFromNib() {
18 | super.awakeFromNib()
19 | }
20 |
21 | func setPhoto(_ photo: Photo, onComplete: @escaping () -> Void) {
22 | if let data = photo.image {
23 | imageView.image = UIImage(data: data)
24 | onComplete()
25 | } else {
26 | imageView.kf.setImage(
27 | with: URL(string: photo.url!),
28 | placeholder: #imageLiteral(resourceName: "placeholder_image"),
29 | options: nil,
30 | progressBlock: nil,
31 | completionHandler: { (image, error, _, _) in
32 | if let thisImage = image {
33 | photo.image = UIImagePNGRepresentation(thisImage)
34 | }
35 | onComplete()
36 | })
37 | }
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/UI/View/PhotoViewCell.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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Utils/Errors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Errors.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Errors: String {
12 | case NetworkError = "Please check your network and try again."
13 | case ServerError = "Server messed up. Please contact developer."
14 | case DatabaseError = "Database Error."
15 | case UnknownError = "The app is messed up. Please contact developer."
16 | }
17 |
--------------------------------------------------------------------------------
/P4 VirtualTourist/Virtual Tourist/Utils/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // Virtual Tourist
4 | //
5 | // Created by Rajanikant Deshmukh on 28/03/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import MapKit
12 |
13 | extension UIViewController {
14 |
15 | func showAlertDialog(title: String, message: String, dismissHandler: ((UIAlertAction) -> Void)?) {
16 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
17 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: dismissHandler))
18 | self.present(alert, animated: true)
19 | }
20 | }
21 |
22 | extension Place {
23 |
24 | func getAnnotation() -> MKAnnotation {
25 | let annotation = MKPointAnnotation()
26 | annotation.title = self.locationString
27 | annotation.coordinate = CLLocationCoordinate2DMake(self.latitude, self.longitude)
28 | return annotation
29 | }
30 | }
31 |
32 | extension Photo {
33 |
34 | convenience init?(_ dictionary: NSDictionary) {
35 | self.init()
36 | self.id = (dictionary["id"] as! String)
37 | self.title = (dictionary["title"] as! String)
38 | self.url = (dictionary["url_m"] as! String)
39 | self.width = (dictionary["width_m"] as! Int16)
40 | self.height = (dictionary["height_m"] as! Int16)
41 | }
42 |
43 | func setFrom(_ dictionary: NSDictionary) {
44 | self.id = (dictionary["id"] as! String)
45 | self.title = (dictionary["title"] as! String)
46 | self.url = (dictionary["url_m"] as? String) ?? ""
47 | self.width = Int16(dictionary["width_m"] as? String ?? "0")!
48 | self.height = Int16(dictionary["height_m"] as? String ?? "0")!
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/.gitignore:
--------------------------------------------------------------------------------
1 | ## Build generated
2 | build/
3 | DerivedData/
4 |
5 | ## Various settings
6 | *.pbxuser
7 | !default.pbxuser
8 | *.mode1v3
9 | !default.mode1v3
10 | *.mode2v3
11 | !default.mode2v3
12 | *.perspectivev3
13 | !default.perspectivev3
14 | xcuserdata/
15 |
16 | ## Other
17 | *.moved-aside
18 | *.xccheckout
19 | *.xcscmblueprint
20 |
21 | ## Obj-C/Swift specific
22 | *.hmap
23 | *.ipa
24 | *.dSYM.zip
25 | *.dSYM
26 |
27 | ## Playgrounds
28 | timeline.xctimeline
29 | playground.xcworkspace
30 |
31 | # Swift Package Manager
32 | .build/
33 |
34 | # CocoaPods
35 | Pods/
36 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/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 | }
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "json-feed.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "json-feed@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "json-feed@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed@2x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/json-feed.imageset/json-feed@3x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tab_feeds.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tab_feeds@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "tab_feeds@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds@2x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_feeds.imageset/tab_feeds@3x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "tab_home.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "tab_home@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "tab_home@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home@2x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aruke/iOS-Nanodegree-Projects/ae6711bc43d7e81c30456bf4da95d7423515491e/P5 JSON-Feed-Reader/JSON Feed Reader/Assets/Assets.xcassets/tab_home.imageset/tab_home@3x.png
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/DataRepository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataRepository.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class DataRepository: RepositoryProtocol {
12 |
13 | private let localRepository: LocalRepository
14 | private let remoteRepository: RemoteRepository
15 |
16 | init(local: LocalRepository, remote: RemoteRepository) {
17 | self.localRepository = local
18 | self.remoteRepository = remote
19 | }
20 |
21 | func loadPosts(feed: Feed, onError: @escaping ErrorCallback, onPostsLoaded: @escaping PostsCallback) {
22 | self.localRepository.loadPosts(feed: feed, onError: {
23 | error in
24 | // Load content from remote
25 | self.remoteRepository.loadPosts(feed: feed, onError: {
26 | error in
27 | DispatchQueue.main.async { onError(error) }
28 | }, onPostsLoaded: {
29 | posts in
30 | DispatchQueue.main.async { onPostsLoaded(posts) }
31 | })
32 | }, onPostsLoaded: {
33 | posts in
34 | DispatchQueue.main.async { onPostsLoaded(posts) }
35 | })
36 | }
37 |
38 | func loadContent(postId: String, onError: @escaping ErrorCallback, onContentLoaded: @escaping ContentCallback) {
39 | self.localRepository.loadContent(postId: postId, onError: {
40 | error in
41 | // Load content from remote
42 | self.remoteRepository.loadContent(postId: postId, onError: {
43 | error in
44 | DispatchQueue.main.async { onError(error) }
45 |
46 | }, onContentLoaded: {
47 | content in
48 | DispatchQueue.main.async { onContentLoaded(content) }
49 | })
50 | }, onContentLoaded: {
51 | content in
52 | DispatchQueue.main.async { onContentLoaded(content) }
53 | })
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Local/DataController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DataController.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class DataController {
13 |
14 | let persistanceContainer: NSPersistentContainer
15 | var isLoaded: Bool!
16 |
17 | init(modelName: String = "JSON_Feed_Reader") {
18 | self.persistanceContainer = NSPersistentContainer(name: modelName)
19 | isLoaded = false
20 | }
21 |
22 | var viewContext: NSManagedObjectContext {
23 | return self.persistanceContainer.viewContext
24 | }
25 |
26 | func load(completion: (() -> Void)? = nil) {
27 | self.persistanceContainer.loadPersistentStores(completionHandler: {
28 | storeDescription, error in
29 | guard error == nil else {
30 | self.isLoaded = false
31 | print("Persistenace Store not Loaded!!!")
32 | fatalError(error!.localizedDescription)
33 | }
34 |
35 | print("Persistance Store loaded successfully")
36 | self.isLoaded = true
37 | PrimaryFeed.shared.insertIfDoNotExist(dataController: self)
38 | completion?()
39 | })
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Local/JSON_Feed_Reader.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | JSON_Feed_Reader.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Local/JSON_Feed_Reader.xcdatamodeld/JSON_Feed_Reader.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Local/LocalRepository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocalRepository.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class LocalRepository: RepositoryProtocol {
13 |
14 | var dataController: DataController
15 |
16 | init(dataController: DataController) {
17 | self.dataController = dataController
18 | }
19 |
20 | func loadPosts(feed: Feed, onError: @escaping ErrorCallback, onPostsLoaded: @escaping PostsCallback) {
21 | if !dataController.isLoaded {
22 | onError(Errors.LocalDatabaseError)
23 | return
24 | }
25 |
26 | let fetchRequest: NSFetchRequest = Post.fetchRequest()
27 | do {
28 | let results = try dataController.viewContext.fetch(fetchRequest)
29 | print("Loaded posts from local db with count \(results.count)")
30 | if results.count <= 0 {
31 | throw Errors.EmptyDatabaseError
32 | }
33 | onPostsLoaded(results)
34 | } catch {
35 | print("Fetch Error")
36 | onError(Errors.LocalDatabaseError)
37 | }
38 | }
39 |
40 | func loadContent(postId: String, onError: @escaping ErrorCallback, onContentLoaded: @escaping ContentCallback) {
41 | if !dataController.isLoaded {
42 | onError(Errors.LocalDatabaseError)
43 | return
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Local/PrimaryFeed.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PrimaryFeed.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 03/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import CoreData
11 |
12 | class PrimaryFeed {
13 |
14 | static let shared = PrimaryFeed()
15 |
16 | private init() {}
17 |
18 | func insertIfDoNotExist(dataController: DataController) {
19 | let feed = Feed(context: dataController.viewContext)
20 |
21 | feed.version = "https://jsonfeed.org/version/1"
22 | feed.title = "JSON Feed"
23 | feed.author = "Brent Simmons and Manton Reece"
24 | feed.desc = "JSON Feed is a pragmatic syndication format for blogs, microblogs, and other time-based content."
25 | feed.favicon_url = "https://jsonfeed.org/graphics/icon.png"
26 | feed.feed_url = "https://jsonfeed.org/feed.json"
27 |
28 | try? dataController.viewContext.save()
29 | }
30 |
31 | func get(dataController: DataController) -> Feed? {
32 | let fetchRequest: NSFetchRequest = Feed.fetchRequest()
33 | if let feeds = try? dataController.viewContext.fetch(fetchRequest) {
34 | if feeds.count <= 0 {
35 | return nil
36 | }
37 |
38 | return feeds[0]
39 | }
40 |
41 | return nil
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Remote/ModelExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelExtensions.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 03/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import JSONFeed
11 |
12 | extension Feed {
13 |
14 | func setFrom(_ jsonFeed: JSONFeed) {
15 | self.version = String(describing: jsonFeed.version)
16 | self.title = jsonFeed.title
17 | self.author = jsonFeed.author?.name
18 | self.desc = jsonFeed.feedDescription
19 | self.feed_url = String(describing: jsonFeed.url)
20 | self.favicon_url = String(describing: jsonFeed.favicon)
21 | }
22 | }
23 |
24 | extension Post {
25 |
26 | func setFrom(_ jsonFeedItem: JSONFeedItem) {
27 | self.id = jsonFeedItem.id
28 | self.title = jsonFeedItem.title
29 | self.url = String(describing: jsonFeedItem.url)
30 | self.content_text = jsonFeedItem.contentText
31 | self.content_html = jsonFeedItem.contentHtml
32 | self.date_published = jsonFeedItem.date
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/Remote/RemoteRepository.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RemoteRepository.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import JSONFeed
11 |
12 | class RemoteRepository: RepositoryProtocol {
13 |
14 | var dataController: DataController
15 |
16 | init(dataController: DataController) {
17 | self.dataController = dataController
18 | }
19 |
20 | func loadPosts(feed: Feed, onError: @escaping ErrorCallback, onPostsLoaded: @escaping PostsCallback) {
21 | let feedUrl = URL(string: feed.feed_url!)
22 | let request = URLRequest(url: feedUrl!)
23 | let task = URLSession.shared.dataTask(with: request) {
24 | data, response, error in
25 |
26 | if error != nil {
27 | self.handleError(error, onError: onError)
28 | return
29 | }
30 |
31 | do {
32 | let jsonFeed = try JSONFeed(data: data!)
33 | var posts = [Post]()
34 | let jsonFeedItems = jsonFeed.items
35 | for jsonFeedItem in jsonFeedItems {
36 | let post = Post(context: self.dataController.viewContext)
37 | post.setFrom(jsonFeedItem)
38 | posts.append(post)
39 | }
40 | onPostsLoaded(posts)
41 | } catch {
42 | self.handleError(error, onError: onError)
43 | }
44 | }
45 | task.resume()
46 | }
47 |
48 | func loadContent(postId: String, onError: @escaping ErrorCallback, onContentLoaded: @escaping ContentCallback) {
49 | // No need to implement in Remote
50 | onError(Errors.UnknownError)
51 | }
52 |
53 | private func handleError(_ error: Error!, onError: @escaping ErrorCallback) {
54 | if let urlError = error as? URLError {
55 | switch urlError.code {
56 | case .notConnectedToInternet:
57 | onError(Errors.NetworkError)
58 | return
59 | default:
60 | onError(Errors.ServerError)
61 | return
62 | }
63 | }
64 | onError(Errors.ServerError)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Data/RepositoryProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RepositoryProtocol.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol RepositoryProtocol {
12 |
13 | typealias ErrorCallback = ((Errors) -> Void)
14 |
15 | typealias PostsCallback = (([Post]) -> Void)
16 | typealias PostCallback = ((Post) -> Void)
17 | typealias ContentCallback = ((String) -> Void)
18 |
19 | func loadPosts(feed: Feed, onError: @escaping ErrorCallback, onPostsLoaded: @escaping PostsCallback)
20 |
21 | func loadContent(postId: String, onError: @escaping ErrorCallback, onContentLoaded: @escaping ContentCallback)
22 | }
23 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/UI/BaseViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BaseViewController.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 03/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class BaseViewController: UIViewController {
13 |
14 | var dataRespository: DataRepository!
15 |
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 |
19 | // Innitialize data repository, to be accessed by other UIViewControllers
20 | let appDelegate = UIApplication.shared.delegate as! AppDelegate
21 | dataRespository = appDelegate.dataRepository
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/UI/HomeViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HomeViewController.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class HomeViewController: UIViewController {
12 |
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | }
16 |
17 | @IBAction func openWebsite(_ sender: UIButton) {
18 | openUrl(url: JsonFeedOrg.WEBSITE)
19 | }
20 |
21 | @IBAction func openSpecs(_ sender: UIButton) {
22 | openUrl(url: JsonFeedOrg.SPECIFICATIONS)
23 | }
24 |
25 | func openUrl(url: String?) {
26 | if let url = URL(string: url!) {
27 | let app = UIApplication.shared
28 | app.open(url, options: [:], completionHandler: nil)
29 | } else {
30 | showAlertDialog(title: "Ooops!", message: "The URL is not a valid URL", dismissHandler: nil)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/UI/PostCell/PostViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostViewCell.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 03/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PostViewCell: UITableViewCell {
12 |
13 | static let POST_VIEW_CELL = "PostViewCell"
14 |
15 | @IBOutlet weak var titleLabel: UILabel!
16 | @IBOutlet weak var dateLabel: UILabel!
17 | @IBOutlet weak var previewLabel: UILabel!
18 |
19 | override func awakeFromNib() {
20 | super.awakeFromNib()
21 | // Initialization code
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/UI/PostContentViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PostContentViewController.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class PostContentViewController: BaseViewController {
12 |
13 | static let STORYBOARD_ID = "PostContentViewController"
14 |
15 | var post: Post!
16 |
17 | @IBOutlet weak var doneButton: UIBarButtonItem!
18 | @IBOutlet weak var webView: UIWebView!
19 | @IBOutlet weak var navItem: UINavigationItem!
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 | navItem.title = post.title
24 | webView.scrollView.bounces = false
25 |
26 | // Check if THML contents are available
27 | let htmlContent = post.content_html
28 | if htmlContent == nil || (htmlContent?.isEmpty)! {
29 |
30 | // Switch to text
31 | let textContent = post.content_text
32 | if textContent == nil || (textContent?.isEmpty)! {
33 | // Show Error
34 | } else {
35 | let contents = "\(textContent!)"
36 | webView.loadHTMLString(contents, baseURL: URL(string: post.url!))
37 | }
38 |
39 |
40 | } else {
41 | webView.loadHTMLString(htmlContent!, baseURL: URL(string: post.url!))
42 | }
43 | }
44 |
45 | @IBAction func onDoneClick(_ sender: Any) {
46 | dismiss(animated: true, completion: nil)
47 | }
48 |
49 |
50 | class func instantiate(caller: UIViewController, post: Post) -> PostContentViewController {
51 | // Instantiate VC from storyboard
52 | let contentViewController: PostContentViewController = caller.storyboard?.instantiateViewController(withIdentifier: STORYBOARD_ID) as! PostContentViewController
53 | // Set required parameters and return
54 | contentViewController.post = post
55 | return contentViewController
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Utils/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class JsonFeedOrg {
12 | static let WEBSITE = "https://jsonfeed.org/"
13 | static let SPECIFICATIONS = "https://jsonfeed.org/version/1"
14 | static let FEED = "https://jsonfeed.org/feed.json"
15 | }
16 |
17 | enum Errors: Error {
18 | case NetworkError
19 | case ServerError
20 | case LocalDatabaseError
21 | case EmptyDatabaseError
22 | case UnknownError
23 | }
24 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Utils/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 02/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | extension UIViewController {
13 |
14 | func showAlertDialog(title: String, message: String, dismissHandler: ((UIAlertAction) -> Void)?) {
15 | let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
16 | alert.addAction(UIAlertAction(title: "OK", style: .default, handler: dismissHandler))
17 | self.present(alert, animated: true)
18 | }
19 |
20 | func showError(_ error: Errors) {
21 | showAlertDialog(title: "Error", message: error.localizedDescription, dismissHandler: nil)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/JSON Feed Reader/Utils/Formatter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Formatter.swift
3 | // JSON Feed Reader
4 | //
5 | // Created by Rajanikant Deshmukh on 03/04/18.
6 | // Copyright © 2018 Rajanikant Deshmukh. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | class UserFriendlyDateFormatter {
12 |
13 | private init(){}
14 |
15 | class func format(dateToFormat: Date) -> String {
16 | let dateFormatter = DateFormatter()
17 | dateFormatter.dateFormat = "dd MMM, yyyy"
18 | dateFormatter.timeZone = TimeZone.current
19 | return dateFormatter.string(from: dateToFormat)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'JSON Feed Reader' do
5 | use_frameworks!
6 |
7 | # Pods for JSON Feed Reader
8 | pod 'JSONFeed'
9 | end
10 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - JSONFeed (0.8.4)
3 |
4 | DEPENDENCIES:
5 | - JSONFeed
6 |
7 | SPEC CHECKSUMS:
8 | JSONFeed: cf6dbae6ceb7691eaf2bd17453bc533b709e2c53
9 |
10 | PODFILE CHECKSUM: 93f4ab2899f83207100ba4e2eb42e3507475f404
11 |
12 | COCOAPODS: 1.4.0
13 |
--------------------------------------------------------------------------------
/P5 JSON-Feed-Reader/README.md:
--------------------------------------------------------------------------------
1 | # JSON feed reader
2 |
3 |
4 | ## Origin
5 | This app is my Capstone project for the iOS Developer Nanodegree offered by Udacity. This Nanodegree course focuses on iOS app development using Swift, including UIKit Fundamentals, Networking, and Persistence with Code Data.
6 | The app uses JSON Feeds to get contents. I read about JSON feeds in May 2017 and instantly I fall in love with it. I decided to write a dedicated app for it and finally I made it here.
7 |
8 | ## About the App
9 | JSON fed reader in current context was s simple app that subscribed to blog feed from jsonfeed.org and let users read through it.
10 | Next releases will have subscription to multiple feeds.
11 |
12 | ## Libraries and Frameworks Used
13 | **iOS Frameworks**:
14 | 1. [Foundation](https://developer.apple.com/documentation/foundation)
15 | 2. [UIKit](https://developer.apple.com/documentation/uikit)
16 | 3. [Core Data](https://developer.apple.com/documentation/coredata) to store images.
17 |
18 | **External Library**
19 | 6. [JSONFeed](https://github.com/totocaster/JSONFeed) to parse feed data.
20 |
21 | ## How to Build
22 | The build system uses [CocoaPods](https://cocoapods.org) to integrate dependencies. You should be familiar with CocoaPods and API key and secret from Flickr account.
23 | 1. Download zip or fork & clone project on your desktop.
24 | 2. Open Terminal and `cd` into project folder. Most of the times the path will be `~/Downloads/JSON-Feed-Reader`.
25 | 3. Run `pods install` to install dependencies.
26 | 4. Open `JSON Feed Reader.xcworkspace` with Xcode.
27 | 5. Now you can build and run the app.
28 |
29 | ## Licence
30 |
31 | ```
32 | This project was submitted by Rajanikant Deshmukh as part of the iOS Developer Nanodegree At Udacity.
33 | As part of Udacity Honor code, your submissions must be your work, hence submitting this project
34 | as yours will cause you to break the Udacity Honor Code moreover, the suspension of your account.
35 | Me, the author of the project, allows you to check the code as a reference, but if you submit it,
36 | it is your responsibility if you get expelled.
37 | Besides the above notice, the following license applies, and this license notice must be included
38 | in all works derived from this project.
39 |
40 | MIT License
41 |
42 | Copyright (c) 2018 Rajanikant Deshmukh
43 |
44 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software
45 | and associated documentation files (the "Software"), to deal in the Software without restriction,
46 | including without limitation the rights to use, copy, modify, merge, publish, distribute,
47 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
48 | furnished to do so, subject to the following conditions:
49 |
50 | The above copyright notice and this permission notice shall be included in all copies or
51 | substantial portions of the Software.
52 |
53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
54 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
55 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
56 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
57 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
58 | ```
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iOS Nanodegree Projects
2 | This is master repository for my course of iOS Nanodegree with Udacity. Each project covers important aspect of iOS app development and is hosted as subdirectory. For more details on each project, check the project's directory.
3 |
4 | | # | Project | Aspect Covered | Preview | Description |
5 | | - | --------------- | -------------- | ------- | --------------- |
6 | | 1 | Pitch Perfect | Intro to iOS App Development with Swift |  | iOS app for recording voice and playing it through different voices. |
7 | | 2 | MemeMe | UIKit Fundamentals |  | Meme creator app on iOS platform. |
8 | | 3 | On the Map | iOS Networking with Swift |  | An iOS application to find Udacity Students studying across the world. |
9 | | 4 | Virtual Tourist | iOS Persistence and Core Data |  | An iOS application to download and view photos specific to selected locations. |
10 |
11 | ## Certificate
12 | You can check my Nanodegree Certificate [here](https://confirm.udacity.com/35KLMLRH).
13 |
14 | ## Licence
15 | The following notice is applicable to each project mentioned above.
16 | ```
17 | This project was submitted by Rajanikant Deshmukh as part of the iOS Developer Nanodegree At Udacity.
18 | As part of Udacity Honor code, your submissions must be your work, hence submitting this project
19 | as yours will cause you to break the Udacity Honor Code moreover, the suspension of your account.
20 | Me, the author of the project, allows you to check the code as a reference, but if you submit it,
21 | it is your responsibility if you get expelled.
22 | ```
23 |
24 | Besides the above notice, the MIT License must be included
25 | in all works derived from these projects. See [LICENCE](LICENCE) file for details.
26 |
--------------------------------------------------------------------------------