├── FacebookClone ├── Assets.xcassets │ ├── Contents.json │ ├── .DS_Store │ ├── like.imageset │ │ ├── like.png │ │ └── Contents.json │ ├── share.imageset │ │ ├── share.png │ │ └── Contents.json │ ├── comment.imageset │ │ ├── comment.png │ │ └── Contents.json │ ├── zuckdog.imageset │ │ ├── zuckdog.jpg │ │ └── Contents.json │ ├── gandhi_profile.imageset │ │ ├── gandhi.png │ │ └── Contents.json │ ├── more_icon.imageset │ │ ├── more_icon@2x.png │ │ └── Contents.json │ ├── globe_icon.imageset │ │ ├── globe_icon@2x.png │ │ └── Contents.json │ ├── globe_small.imageset │ │ ├── globe_small.png │ │ └── Contents.json │ ├── zuckprofile.imageset │ │ ├── zuckprofile.jpg │ │ └── Contents.json │ ├── gandhi_status.imageset │ │ ├── gandhi_status.jpg │ │ └── Contents.json │ ├── steve_profile.imageset │ │ ├── steve_profile.png │ │ └── Contents.json │ ├── steve_status.imageset │ │ ├── steve_status.jpg │ │ └── Contents.json │ ├── news_feed_icon.imageset │ │ ├── news_feed_icon.png │ │ └── Contents.json │ ├── messenger_icon.imageset │ │ ├── messenger_icon@2x.png │ │ └── Contents.json │ ├── requests_icon.imageset │ │ ├── requests_icon@2x.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Utility.swift ├── Extensions.swift ├── Info.plist ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── all_posts.json ├── CustomTabbarController.swift ├── AppDelegate.swift ├── OtherControllers.swift └── FeedController.swift ├── FacebookClone.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── VamshiKrishna.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcuserdata │ └── VamshiKrishna.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── FacebookClone.xcscheme └── project.pbxproj └── README.md /FacebookClone/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/like.imageset/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/like.imageset/like.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/share.imageset/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/share.imageset/share.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/comment.imageset/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/comment.imageset/comment.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/zuckdog.imageset/zuckdog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/zuckdog.imageset/zuckdog.jpg -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/gandhi_profile.imageset/gandhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/gandhi_profile.imageset/gandhi.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/more_icon.imageset/more_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/more_icon.imageset/more_icon@2x.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/globe_icon.imageset/globe_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/globe_icon.imageset/globe_icon@2x.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/globe_small.imageset/globe_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/globe_small.imageset/globe_small.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/zuckprofile.imageset/zuckprofile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/zuckprofile.imageset/zuckprofile.jpg -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/gandhi_status.imageset/gandhi_status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/gandhi_status.imageset/gandhi_status.jpg -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/steve_profile.imageset/steve_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/steve_profile.imageset/steve_profile.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/steve_status.imageset/steve_status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/steve_status.imageset/steve_status.jpg -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/news_feed_icon.imageset/news_feed_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/news_feed_icon.imageset/news_feed_icon.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/messenger_icon.imageset/messenger_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/messenger_icon.imageset/messenger_icon@2x.png -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/requests_icon.imageset/requests_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone/Assets.xcassets/requests_icon.imageset/requests_icon@2x.png -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/project.xcworkspace/xcuserdata/VamshiKrishna.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VamshiIITBHU14/FBClone/HEAD/FacebookClone.xcodeproj/project.xcworkspace/xcuserdata/VamshiKrishna.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/like.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "like.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/share.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "share.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/comment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "comment.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/zuckdog.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "zuckdog.jpg", 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 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/gandhi_profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "gandhi.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/globe_small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "globe_small.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/more_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "more_icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/zuckprofile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "zuckprofile.jpg", 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 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/gandhi_status.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "gandhi_status.jpg", 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 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/globe_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "globe_icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/steve_profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "steve_profile.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/steve_status.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "steve_status.jpg", 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 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/messenger_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "messenger_icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/news_feed_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "news_feed_icon.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /FacebookClone/Assets.xcassets/requests_icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "requests_icon@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FBClone 2 | This project is a clone of FB News Feed. Converted to Swift3 syntax (Courtesy: https://www.letsbuildthatapp.com/) 3 | It covers topics like: 4 | 1) Using a UICollectionView to make a vertical scrolling component 5 | 2) Dynamic Cell content and Loading Images 6 | 3) Load images asynchronously and caching using NSCache 7 | 4) Adding a custom UITabBar to suit to that of FB 8 | 5) Animation that zooms the image into the center of the screen 9 | 10 | All of the above with no StoryBoards used. Clean, re-usable code following MVC pattern. 11 | -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/xcuserdata/VamshiKrishna.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/xcuserdata/VamshiKrishna.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FacebookClone.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9667CBAA1ED4435F00B30B8A 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /FacebookClone/Utility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Utility.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 23/05/17. 6 | // Copyright © 2017 VamshiKrishna. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class Utility: NSObject { 12 | 13 | private override init() { } 14 | static let shared = Utility() 15 | 16 | func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect { 17 | return CGRect(x: x, y: y, width: width, height: height) 18 | } 19 | 20 | func CGSizeMake( _ width:CGFloat, _ height:CGFloat) -> CGSize{ 21 | return CGSize(width: width, height: height) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /FacebookClone/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 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /FacebookClone/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 23/05/17. 6 | // Copyright © 2017 VamshiKrishna. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIColor{ 13 | static func returnRGBColor(r:CGFloat, g:CGFloat, b:CGFloat, alpha:CGFloat) -> UIColor{ 14 | return UIColor(red: r/255, green: g/255, blue: b/255, alpha: alpha) 15 | } 16 | } 17 | 18 | extension UIView{ 19 | func addConstraintsWithFormat(format:String, views: UIView...){ 20 | 21 | var viewsDictionary = [String:UIView]() 22 | for (index, view) in views.enumerated(){ 23 | let key = "v\(index)" 24 | view.translatesAutoresizingMaskIntoConstraints = false 25 | viewsDictionary[key] = view 26 | 27 | } 28 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(), metrics: nil, views: viewsDictionary)) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /FacebookClone/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | UIViewControllerBasedStatusBarAppearance 8 | 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 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /FacebookClone/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /FacebookClone/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 | -------------------------------------------------------------------------------- /FacebookClone/all_posts.json: -------------------------------------------------------------------------------- 1 | { 2 | "posts": [ 3 | { 4 | "name": "Mark Zuckerberg", 5 | "location": { 6 | "city": "San Francisco", 7 | "state": "CA" 8 | }, 9 | "profileImageName": "zuckprofile", 10 | "statusText": "By giving people the power to share, we're making the world more transparent.", 11 | "statusImageName": "zuckdog", 12 | "numLikes": 150, 13 | "numComments": 300, 14 | "information": "some information text" 15 | }, 16 | { 17 | "name": "Steve Jobs", 18 | "location": { 19 | "city": "Cupertino", 20 | "state": "CA" 21 | }, 22 | "profileImageName": "steve_profile", 23 | "statusText": "Design is not just what it looks like and feels like. Design is how it works.\n\nBeing the richest man in the cemetery doesn't matter to me. Going to bed at night saying we've done something wonderful, that's what matters to me.\n\nSometimes when you innovate, you make mistakes. It is best to admit them quickly, and get on with improving your other innovations.", 24 | "statusImageName": "steve_status", 25 | "numLikes": 111, 26 | "numComments": 222 27 | }, 28 | { 29 | "name": "Mahatma Gandhi", 30 | "location": { 31 | "city": "Porbandar", 32 | "state": "India" 33 | }, 34 | "profileImageName": "gandhi_profile", 35 | "statusText": "Live as if you were to die tomorrow; learn as if you were to live forever.\nThe weak can never forgive. Forgiveness is the attribute of the strong.\nHappiness is when what you think, what you say, and what you do are in harmony.", 36 | "statusImageName": "gandhi_status", 37 | "numLikes": 333, 38 | "numComments": 444 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /FacebookClone/CustomTabbarController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTabbarController.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 27/05/17. 6 | // Copyright © 2017 VamshiKrishna. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class CustomTabbarController: UITabBarController { 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | let feedController = FeedController(collectionViewLayout: UICollectionViewFlowLayout()) 17 | let navigationController = UINavigationController(rootViewController: feedController) 18 | navigationController.title = "News Feed" 19 | navigationController.tabBarItem.image = UIImage(named: "news_feed_icon") 20 | 21 | let friendRequestController = FriendRequestsController() 22 | let secondNavigationController = UINavigationController(rootViewController: friendRequestController) 23 | secondNavigationController.title = "Requests" 24 | secondNavigationController.tabBarItem.image = UIImage(named: "requests_icon") 25 | 26 | let messengerVC = UIViewController() 27 | let messengerNavigationController = UINavigationController(rootViewController: messengerVC) 28 | messengerNavigationController.title = "Messenger" 29 | messengerNavigationController.tabBarItem.image = UIImage(named: "messenger_icon") 30 | 31 | let notificationsNavController = UINavigationController(rootViewController: UIViewController()) 32 | notificationsNavController.title = "Notifications" 33 | notificationsNavController.tabBarItem.image = UIImage(named: "globe_icon") 34 | 35 | let moreNavController = UINavigationController(rootViewController: UIViewController()) 36 | moreNavController.title = "More" 37 | moreNavController.tabBarItem.image = UIImage(named: "more_icon") 38 | 39 | viewControllers = [navigationController ,secondNavigationController, messengerNavigationController, notificationsNavController, moreNavController] 40 | tabBar.isTranslucent = false 41 | let topBorder = CALayer() 42 | topBorder.frame = CGRect(x: 0, y: 0, width: 1000, height: 0.5) 43 | topBorder.backgroundColor = UIColor.returnRGBColor(r: 229, g: 231, b: 235, alpha: 1).cgColor 44 | tabBar.layer.addSublayer(topBorder) 45 | tabBar.clipsToBounds = true 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FacebookClone/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 23/05/17. 6 | // Copyright © 2017 VamshiKrishna. 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 | 19 | window = UIWindow(frame: UIScreen.main.bounds) 20 | window?.makeKeyAndVisible() 21 | 22 | window?.rootViewController = CustomTabbarController() 23 | application.statusBarStyle = .lightContent 24 | 25 | UITabBar.appearance().tintColor = UIColor.returnRGBColor(r: 70, g: 146, b: 250, alpha: 1) 26 | UINavigationBar.appearance().barTintColor = UIColor(red: 51/255, green: 90/255, blue: 149/255, alpha: 1) 27 | UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white] 28 | 29 | return true 30 | } 31 | 32 | func applicationWillResignActive(_ application: UIApplication) { 33 | // 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. 34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 35 | } 36 | 37 | func applicationDidEnterBackground(_ application: UIApplication) { 38 | // 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. 39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 40 | } 41 | 42 | func applicationWillEnterForeground(_ application: UIApplication) { 43 | // 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. 44 | } 45 | 46 | func applicationDidBecomeActive(_ application: UIApplication) { 47 | // 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. 48 | } 49 | 50 | func applicationWillTerminate(_ application: UIApplication) { 51 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/xcuserdata/VamshiKrishna.xcuserdatad/xcschemes/FacebookClone.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /FacebookClone/OtherControllers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OtherControllers.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 27/05/17. 6 | // Copyright © 2017 VamshiKrishna. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class FriendRequestsController:UITableViewController{ 13 | 14 | static let cellId = "cellId" 15 | static let headerId = "headerId" 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | navigationItem.title = "Friend Requests" 20 | tableView.separatorColor = UIColor.returnRGBColor(r: 229, g: 231, b: 235, alpha: 1) 21 | tableView.sectionHeaderHeight = 26 22 | tableView.register(FriendRequestCell.self, forCellReuseIdentifier: FriendRequestsController.cellId) 23 | tableView.register(RequestHeader.self, forHeaderFooterViewReuseIdentifier: FriendRequestsController.headerId) 24 | tableView.allowsSelection = false 25 | } 26 | 27 | override func numberOfSections(in tableView: UITableView) -> Int { 28 | return 2 29 | } 30 | 31 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 32 | return 5 33 | } 34 | 35 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 36 | return 60 37 | } 38 | 39 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 40 | let cell = tableView.dequeueReusableCell(withIdentifier: FriendRequestsController.cellId, for: indexPath) as! FriendRequestCell 41 | if indexPath.row % 3 == 0 { 42 | cell.nameLabel.text = "Mark Zuckerberg" 43 | cell.requestImageView.image = UIImage(named: "zuckprofile") 44 | } else if indexPath.row % 3 == 1 { 45 | cell.nameLabel.text = "Steve Jobs" 46 | cell.requestImageView.image = UIImage(named: "steve_profile") 47 | } else { 48 | cell.nameLabel.text = "Mahatma Gandhi" 49 | cell.requestImageView.image = UIImage(named: "gandhi_profile") 50 | } 51 | 52 | cell.imageView?.backgroundColor = UIColor.black 53 | return cell 54 | } 55 | 56 | override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 57 | let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: FriendRequestsController.headerId) as! RequestHeader 58 | 59 | if section == 0 { 60 | header.nameLabel.text = "FRIEND REQUESTS" 61 | } else { 62 | header.nameLabel.text = "PEOPLE YOU MAY KNOW" 63 | } 64 | 65 | return header 66 | } 67 | } 68 | 69 | class RequestHeader: UITableViewHeaderFooterView { 70 | 71 | override init(reuseIdentifier: String?) { 72 | super.init(reuseIdentifier: reuseIdentifier) 73 | setupViews() 74 | } 75 | 76 | required init?(coder aDecoder: NSCoder) { 77 | fatalError("init(coder:) has not been implemented") 78 | } 79 | 80 | let nameLabel: UILabel = { 81 | let label = UILabel() 82 | label.text = "FRIEND REQUESTS" 83 | label.font = UIFont.systemFont(ofSize: 10) 84 | label.textColor = UIColor(white: 0.4, alpha: 1) 85 | return label 86 | }() 87 | 88 | let bottomBorderView: UIView = { 89 | let view = UIView() 90 | view.backgroundColor = UIColor.returnRGBColor(r: 229, g: 231, b: 235, alpha: 1) 91 | return view 92 | }() 93 | 94 | func setupViews(){ 95 | addSubview(nameLabel) 96 | addSubview(bottomBorderView) 97 | addConstraintsWithFormat(format: "H:|-8-[v0]-8-|", views: nameLabel) 98 | addConstraintsWithFormat(format: "H:|[v0]|", views: bottomBorderView) 99 | addConstraintsWithFormat(format: "V:|[v0][v1(0.5)]|", views: nameLabel,bottomBorderView) 100 | } 101 | 102 | } 103 | 104 | class FriendRequestCell:UITableViewCell{ 105 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) { 106 | super.init(style: style, reuseIdentifier: reuseIdentifier) 107 | setupViews() 108 | } 109 | 110 | required init?(coder aDecoder: NSCoder) { 111 | fatalError("init(coder:) has not been implemented") 112 | } 113 | 114 | let nameLabel:UILabel = { 115 | let label = UILabel() 116 | label.font = UIFont.systemFont(ofSize: 12) 117 | return label 118 | }() 119 | 120 | let requestImageView : UIImageView = { 121 | let imageView = UIImageView() 122 | imageView.contentMode = .scaleAspectFill 123 | imageView.backgroundColor = .blue 124 | imageView.layer.masksToBounds = true 125 | return imageView 126 | }() 127 | 128 | let confirmButton:UIButton = { 129 | let button = UIButton() 130 | button.setTitle("Confirm", for: .normal) 131 | button.setTitleColor(UIColor.white, for: .normal) 132 | button.backgroundColor = UIColor.returnRGBColor(r: 87, g: 143, b: 255, alpha: 1) 133 | button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 10) 134 | button.layer.cornerRadius = 2 135 | return button 136 | }() 137 | 138 | let deleteButton:UIButton = { 139 | let button = UIButton() 140 | button.setTitle("Delete", for: .normal) 141 | button.setTitleColor(UIColor(white: 0.3, alpha: 1), for: .normal) 142 | button.layer.borderColor = UIColor(white: 0.7, alpha: 1).cgColor 143 | button.layer.borderWidth = 1 144 | button.layer.cornerRadius = 2 145 | button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 10) 146 | return button 147 | }() 148 | 149 | func setupViews(){ 150 | addSubview(nameLabel) 151 | addSubview(requestImageView) 152 | addSubview(confirmButton) 153 | addSubview(deleteButton) 154 | 155 | addConstraintsWithFormat(format: "H:|-16-[v0(52)]-8-[v1]|", views: requestImageView, nameLabel) 156 | addConstraintsWithFormat(format: "V:|-4-[v0]-4-|", views: requestImageView) 157 | addConstraintsWithFormat(format: "V:|-8-[v0]-8-[v1(24)]-8-|", views: nameLabel, confirmButton) 158 | addConstraintsWithFormat(format: "H:|-76-[v0(80)]-8-[v1(80)]", views: confirmButton, deleteButton) 159 | addConstraintsWithFormat(format: "V:[v0(24)]-8-|", views: deleteButton) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /FacebookClone/FeedController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FeedController.swift 3 | // FacebookClone 4 | // 5 | // Created by Vamshi Krishna on 23/05/17. 6 | // Copyright © 2017 VamshiKrishna. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | private let reuseIdentifier = "Cell" 11 | 12 | class Post:SafeJsonObject{ 13 | var name:String? 14 | var statusText :String? 15 | var profileImageName:String? 16 | var statusImageName: String? 17 | var numLikes: NSNumber? 18 | var numComments: NSNumber? 19 | 20 | var location:Location? 21 | 22 | override func setValue(_ value: Any?, forKey key: String) { 23 | if key == "location" { 24 | location = Location() 25 | location?.setValuesForKeys(value as! [String:AnyObject]) 26 | } 27 | else{ 28 | super.setValue(value, forKey: key) 29 | } 30 | 31 | } 32 | } 33 | 34 | class Location:NSObject{ 35 | var city:String? 36 | var state:String? 37 | } 38 | class SafeJsonObject:NSObject{ 39 | override func setValue(_ value: Any?, forKey key: String) { 40 | let selectorString = "set\(key.uppercased().characters.first!)\(String(key.characters.dropFirst())):" 41 | let selector = Selector(selectorString) 42 | if responds(to: selector) { 43 | super.setValue(value, forKey: key) 44 | } 45 | } 46 | } 47 | 48 | 49 | class FeedController: UICollectionViewController, UICollectionViewDelegateFlowLayout { 50 | var posts = [Post]() 51 | 52 | override func viewDidLoad() { 53 | super.viewDidLoad() 54 | 55 | if let path = Bundle.main.path(forResource: "all_posts", ofType: "json") { 56 | do { 57 | let data = try(Data(contentsOf: URL(fileURLWithPath: path), options: NSData.ReadingOptions.mappedIfSafe)) 58 | let jsonDictionary = try(JSONSerialization.jsonObject(with: data, options: .mutableContainers)) as? [String: Any] 59 | if let postsArray = jsonDictionary?["posts"] as? [[String: AnyObject]] { 60 | self.posts = [Post]() 61 | for postDictionary in postsArray { 62 | let post = Post() 63 | post.setValuesForKeys(postDictionary) 64 | self.posts.append(post) 65 | } 66 | } 67 | } catch let err { 68 | print(err) 69 | } 70 | 71 | } 72 | 73 | navigationItem.title = "Facebook Feed" 74 | self.collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1) 75 | 76 | self.collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: reuseIdentifier) 77 | self.collectionView?.alwaysBounceVertical = true 78 | } 79 | 80 | override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 81 | return posts.count 82 | } 83 | 84 | override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 85 | let feedCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! FeedCell 86 | feedCell.post = posts[indexPath.item] 87 | feedCell.feedController = self 88 | return feedCell 89 | } 90 | 91 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 92 | if let statusText = posts[indexPath.item].statusText{ 93 | let rect = NSString(string: statusText).boundingRect(with: Utility.shared.CGSizeMake(view.frame.width, 1000), options: NSStringDrawingOptions.usesFontLeading.union(NSStringDrawingOptions.usesLineFragmentOrigin), attributes: [NSFontAttributeName:UIFont.systemFont(ofSize: 14)], context: nil) 94 | return Utility.shared.CGSizeMake(view.frame.width, rect.height+344+24) 95 | } 96 | return Utility.shared.CGSizeMake(view.frame.width, 500) 97 | } 98 | 99 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 100 | super.viewWillTransition(to: size, with: coordinator) 101 | collectionView?.collectionViewLayout.invalidateLayout() 102 | } 103 | 104 | let blackBackgroundView = UIView() 105 | var statusImageView : UIImageView? 106 | let zoomImageView = UIImageView() 107 | let navBarCoverView = UIView() 108 | let tabBarCoverView = UIView() 109 | 110 | func animateImageView(statusImageView:UIImageView){ 111 | self.statusImageView = statusImageView 112 | if let startingFrame = statusImageView.superview?.convert(statusImageView.frame, to: nil){ 113 | statusImageView.alpha = 0; 114 | 115 | blackBackgroundView.frame = self.view.frame 116 | blackBackgroundView.backgroundColor = UIColor.black 117 | blackBackgroundView.alpha = 0 118 | view.addSubview(blackBackgroundView) 119 | 120 | navBarCoverView.frame = Utility.shared.CGRectMake(0, 0, self.view.frame.width, 64) 121 | navBarCoverView.backgroundColor = .black 122 | navBarCoverView.alpha = 0 123 | 124 | if let keyWindow = UIApplication.shared.keyWindow{ 125 | keyWindow.addSubview(navBarCoverView) 126 | tabBarCoverView.frame = Utility.shared.CGRectMake(0, keyWindow.frame.height-49, self.view.frame.width, 49) 127 | tabBarCoverView.backgroundColor = .black 128 | tabBarCoverView.alpha = 0 129 | keyWindow.addSubview(tabBarCoverView) 130 | } 131 | 132 | zoomImageView.backgroundColor = UIColor.red 133 | zoomImageView.frame = startingFrame 134 | zoomImageView.isUserInteractionEnabled = true 135 | zoomImageView.image = statusImageView.image 136 | zoomImageView.contentMode = .scaleAspectFill 137 | zoomImageView.clipsToBounds = true 138 | view.addSubview(zoomImageView) 139 | 140 | zoomImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(zoomOut))) 141 | UIView.animate(withDuration: 0.75, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: .curveEaseOut, animations: { () -> Void in 142 | 143 | let height = (self.view.frame.width/startingFrame.width) * startingFrame.height 144 | let y = self.view.frame.height/2 - height/2 145 | self.zoomImageView.frame = Utility.shared.CGRectMake(0, y, self.view.frame.width, height) 146 | self.blackBackgroundView.alpha = 1 147 | self.navBarCoverView.alpha = 1 148 | self.tabBarCoverView.alpha = 1 149 | 150 | }, completion: nil) 151 | 152 | } 153 | } 154 | 155 | func zoomOut(){ 156 | if let startingFrame = statusImageView?.superview?.convert((statusImageView?.frame)!, to: nil){ 157 | UIView.animate(withDuration: 0.75, animations: { () -> Void in 158 | self.zoomImageView.frame = startingFrame 159 | self.blackBackgroundView.alpha = 0 160 | self.navBarCoverView.alpha = 0 161 | self.tabBarCoverView.alpha = 0 162 | }, completion: { (didComplete) -> Void in 163 | self.zoomImageView.removeFromSuperview() 164 | self.blackBackgroundView.removeFromSuperview() 165 | self.navBarCoverView.removeFromSuperview() 166 | self.statusImageView?.alpha = 1 167 | self.tabBarCoverView.removeFromSuperview() 168 | }) 169 | } 170 | } 171 | } 172 | 173 | class FeedCell:UICollectionViewCell{ 174 | 175 | var feedController:FeedController? 176 | func animate(){ 177 | feedController?.animateImageView(statusImageView: statusImageView) 178 | } 179 | 180 | var post:Post?{ 181 | didSet{ 182 | if let name = post?.name { 183 | 184 | let attributedText = NSMutableAttributedString(string: name, attributes: [NSFontAttributeName: UIFont.boldSystemFont(ofSize: 14)]) 185 | 186 | if let city = post?.location?.city, let state = post?.location?.state { 187 | attributedText.append(NSAttributedString(string: "\n\(city), \(state) • ", attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 12), NSForegroundColorAttributeName: 188 | UIColor.returnRGBColor(r: 155, g: 161, b: 161, alpha: 1)])) 189 | let paragraphStyle = NSMutableParagraphStyle() 190 | paragraphStyle.lineSpacing = 4 191 | attributedText.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedText.string.characters.count)) 192 | let attachment = NSTextAttachment() 193 | attachment.image = UIImage(named: "globe_small") 194 | attachment.bounds = CGRect(x: 0, y: -2, width: 12, height: 12) 195 | attributedText.append(NSAttributedString(attachment: attachment)) 196 | } 197 | 198 | nameLabel.attributedText = attributedText 199 | 200 | } 201 | 202 | if let statusText = post?.statusText{ 203 | statusTextView.text = statusText 204 | } 205 | 206 | if let profileImageName = post?.profileImageName{ 207 | profileImageView.image = UIImage(named: profileImageName) 208 | } 209 | 210 | if let statusImageName = post?.statusImageName{ 211 | statusImageView.image = UIImage(named: statusImageName) 212 | } 213 | } 214 | } 215 | override init(frame: CGRect) { 216 | super.init(frame: frame) 217 | setupViews() 218 | } 219 | 220 | required init?(coder aDecoder: NSCoder) { 221 | fatalError("init(coder:) has not been implemented") 222 | } 223 | 224 | let nameLabel:UILabel = { 225 | let label = UILabel() 226 | label.numberOfLines = 2 227 | return label 228 | }() 229 | 230 | let statusImageView : UIImageView = { 231 | let imageView = UIImageView() 232 | imageView.image = UIImage(named: "zuckdog") 233 | imageView.contentMode = .scaleAspectFill 234 | imageView.layer.masksToBounds = true 235 | imageView.isUserInteractionEnabled = true 236 | return imageView 237 | }() 238 | 239 | let statusTextView : UITextView = { 240 | let textView = UITextView() 241 | textView.font = UIFont.systemFont(ofSize: 14) 242 | textView.isScrollEnabled = false 243 | textView.isEditable = false 244 | return textView 245 | }() 246 | 247 | let profileImageView:UIImageView = { 248 | let imageView = UIImageView() 249 | imageView.image = UIImage(named: "zuckprofile") 250 | imageView.contentMode = .scaleAspectFit 251 | return imageView 252 | }() 253 | 254 | let likesCommentsLabel: UILabel = { 255 | let label = UILabel() 256 | label.text = "10000 Likes 2000 Comments" 257 | label.font = UIFont.systemFont(ofSize: 12) 258 | label.textColor = UIColor.returnRGBColor(r: 155, g: 161, b: 171, alpha: 1) 259 | return label 260 | }() 261 | 262 | let dividerLineView : UIView = { 263 | let view = UIView() 264 | view.backgroundColor = UIColor.returnRGBColor(r: 226, g: 228, b: 232, alpha: 1) 265 | return view 266 | }() 267 | 268 | static func buttonForTitleAndImage(title:String, imageName:String) -> UIButton{ 269 | let button = UIButton() 270 | button.setTitle(title, for: .normal) 271 | button.setTitleColor(UIColor.returnRGBColor(r: 142, g: 148, b: 161, alpha: 1), for: .normal) 272 | button.setImage(UIImage(named:imageName), for: .normal) 273 | button.titleEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0) 274 | button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14) 275 | return button 276 | } 277 | 278 | let likeButton = FeedCell.buttonForTitleAndImage(title: "Like", imageName: "like") 279 | let commentButton = FeedCell.buttonForTitleAndImage(title: "Comment", imageName: "comment") 280 | let shareButton = FeedCell.buttonForTitleAndImage(title: "Share", imageName: "share") 281 | 282 | func setupViews(){ 283 | backgroundColor = UIColor.white 284 | 285 | addSubview(nameLabel) 286 | addSubview(profileImageView) 287 | addSubview(statusTextView) 288 | addSubview(statusImageView) 289 | addSubview(likesCommentsLabel) 290 | addSubview(dividerLineView) 291 | addSubview(likeButton) 292 | addSubview(commentButton) 293 | addSubview(shareButton) 294 | 295 | statusImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(animate))) 296 | 297 | addConstraintsWithFormat(format: "H:|-8-[v0(44)]-8-[v1]|", views: profileImageView, nameLabel) 298 | addConstraintsWithFormat(format: "H:|-4-[v0]-4-|", views: statusTextView) 299 | addConstraintsWithFormat(format: "H:|[v0]|", views: statusImageView) 300 | addConstraintsWithFormat(format: "H:|-12-[v0]|", views: likesCommentsLabel) 301 | addConstraintsWithFormat(format: "H:|-12-[v0]-12-|", views: dividerLineView) 302 | addConstraintsWithFormat(format: "H:|[v0(v2)][v1(v2)][v2]|", views: likeButton, commentButton ,shareButton) 303 | addConstraintsWithFormat(format: "V:|-12-[v0]", views: nameLabel) 304 | addConstraintsWithFormat(format: "V:|-8-[v0(44)]-4-[v1]-4-[v2(200)]-8-[v3(24)]-8-[v4(0.4)][v5(44)]|", views: profileImageView, statusTextView, statusImageView, likesCommentsLabel, dividerLineView, likeButton) 305 | addConstraintsWithFormat(format: "V:[v0(44)]|", views: commentButton) 306 | addConstraintsWithFormat(format: "V:[v0(44)]|", views: shareButton) 307 | 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /FacebookClone.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 962DDD121ED9391200741BF6 /* CustomTabbarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962DDD111ED9391100741BF6 /* CustomTabbarController.swift */; }; 11 | 962DDD141ED941AC00741BF6 /* OtherControllers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 962DDD131ED941AC00741BF6 /* OtherControllers.swift */; }; 12 | 962DDD161ED969A900741BF6 /* all_posts.json in Resources */ = {isa = PBXBuildFile; fileRef = 962DDD151ED969A900741BF6 /* all_posts.json */; }; 13 | 9667CBAF1ED4435F00B30B8A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9667CBAE1ED4435F00B30B8A /* AppDelegate.swift */; }; 14 | 9667CBB41ED4435F00B30B8A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9667CBB21ED4435F00B30B8A /* Main.storyboard */; }; 15 | 9667CBB61ED4435F00B30B8A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9667CBB51ED4435F00B30B8A /* Assets.xcassets */; }; 16 | 9667CBB91ED4435F00B30B8A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9667CBB71ED4435F00B30B8A /* LaunchScreen.storyboard */; }; 17 | 9667CBC31ED4443D00B30B8A /* FeedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9667CBC21ED4443D00B30B8A /* FeedController.swift */; }; 18 | 9667CBC51ED445B100B30B8A /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9667CBC41ED445B100B30B8A /* Extensions.swift */; }; 19 | 9667CBC71ED45B1500B30B8A /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9667CBC61ED45B1500B30B8A /* Utility.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 962DDD111ED9391100741BF6 /* CustomTabbarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTabbarController.swift; sourceTree = ""; }; 24 | 962DDD131ED941AC00741BF6 /* OtherControllers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OtherControllers.swift; sourceTree = ""; }; 25 | 962DDD151ED969A900741BF6 /* all_posts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = all_posts.json; sourceTree = ""; }; 26 | 9667CBAB1ED4435F00B30B8A /* FacebookClone.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FacebookClone.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 9667CBAE1ED4435F00B30B8A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | 9667CBB31ED4435F00B30B8A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 9667CBB51ED4435F00B30B8A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 9667CBB81ED4435F00B30B8A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 9667CBBA1ED4435F00B30B8A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 9667CBC21ED4443D00B30B8A /* FeedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedController.swift; sourceTree = ""; }; 33 | 9667CBC41ED445B100B30B8A /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 34 | 9667CBC61ED45B1500B30B8A /* Utility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 9667CBA81ED4435F00B30B8A /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 9667CBA21ED4435F00B30B8A = { 49 | isa = PBXGroup; 50 | children = ( 51 | 9667CBAD1ED4435F00B30B8A /* FacebookClone */, 52 | 9667CBAC1ED4435F00B30B8A /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 9667CBAC1ED4435F00B30B8A /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 9667CBAB1ED4435F00B30B8A /* FacebookClone.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 9667CBAD1ED4435F00B30B8A /* FacebookClone */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 9667CBAE1ED4435F00B30B8A /* AppDelegate.swift */, 68 | 962DDD111ED9391100741BF6 /* CustomTabbarController.swift */, 69 | 962DDD131ED941AC00741BF6 /* OtherControllers.swift */, 70 | 9667CBC21ED4443D00B30B8A /* FeedController.swift */, 71 | 962DDD151ED969A900741BF6 /* all_posts.json */, 72 | 9667CBC41ED445B100B30B8A /* Extensions.swift */, 73 | 9667CBC61ED45B1500B30B8A /* Utility.swift */, 74 | 9667CBB21ED4435F00B30B8A /* Main.storyboard */, 75 | 9667CBB51ED4435F00B30B8A /* Assets.xcassets */, 76 | 9667CBB71ED4435F00B30B8A /* LaunchScreen.storyboard */, 77 | 9667CBBA1ED4435F00B30B8A /* Info.plist */, 78 | ); 79 | path = FacebookClone; 80 | sourceTree = ""; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | 9667CBAA1ED4435F00B30B8A /* FacebookClone */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = 9667CBBD1ED4435F00B30B8A /* Build configuration list for PBXNativeTarget "FacebookClone" */; 88 | buildPhases = ( 89 | 9667CBA71ED4435F00B30B8A /* Sources */, 90 | 9667CBA81ED4435F00B30B8A /* Frameworks */, 91 | 9667CBA91ED4435F00B30B8A /* Resources */, 92 | ); 93 | buildRules = ( 94 | ); 95 | dependencies = ( 96 | ); 97 | name = FacebookClone; 98 | productName = FacebookClone; 99 | productReference = 9667CBAB1ED4435F00B30B8A /* FacebookClone.app */; 100 | productType = "com.apple.product-type.application"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 9667CBA31ED4435F00B30B8A /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastSwiftUpdateCheck = 0830; 109 | LastUpgradeCheck = 0830; 110 | ORGANIZATIONNAME = VamshiKrishna; 111 | TargetAttributes = { 112 | 9667CBAA1ED4435F00B30B8A = { 113 | CreatedOnToolsVersion = 8.3.2; 114 | DevelopmentTeam = BJBC582Q56; 115 | ProvisioningStyle = Automatic; 116 | }; 117 | }; 118 | }; 119 | buildConfigurationList = 9667CBA61ED4435F00B30B8A /* Build configuration list for PBXProject "FacebookClone" */; 120 | compatibilityVersion = "Xcode 3.2"; 121 | developmentRegion = English; 122 | hasScannedForEncodings = 0; 123 | knownRegions = ( 124 | en, 125 | Base, 126 | ); 127 | mainGroup = 9667CBA21ED4435F00B30B8A; 128 | productRefGroup = 9667CBAC1ED4435F00B30B8A /* Products */; 129 | projectDirPath = ""; 130 | projectRoot = ""; 131 | targets = ( 132 | 9667CBAA1ED4435F00B30B8A /* FacebookClone */, 133 | ); 134 | }; 135 | /* End PBXProject section */ 136 | 137 | /* Begin PBXResourcesBuildPhase section */ 138 | 9667CBA91ED4435F00B30B8A /* Resources */ = { 139 | isa = PBXResourcesBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | 9667CBB91ED4435F00B30B8A /* LaunchScreen.storyboard in Resources */, 143 | 9667CBB61ED4435F00B30B8A /* Assets.xcassets in Resources */, 144 | 9667CBB41ED4435F00B30B8A /* Main.storyboard in Resources */, 145 | 962DDD161ED969A900741BF6 /* all_posts.json in Resources */, 146 | ); 147 | runOnlyForDeploymentPostprocessing = 0; 148 | }; 149 | /* End PBXResourcesBuildPhase section */ 150 | 151 | /* Begin PBXSourcesBuildPhase section */ 152 | 9667CBA71ED4435F00B30B8A /* Sources */ = { 153 | isa = PBXSourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 962DDD121ED9391200741BF6 /* CustomTabbarController.swift in Sources */, 157 | 9667CBC71ED45B1500B30B8A /* Utility.swift in Sources */, 158 | 962DDD141ED941AC00741BF6 /* OtherControllers.swift in Sources */, 159 | 9667CBAF1ED4435F00B30B8A /* AppDelegate.swift in Sources */, 160 | 9667CBC51ED445B100B30B8A /* Extensions.swift in Sources */, 161 | 9667CBC31ED4443D00B30B8A /* FeedController.swift in Sources */, 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | /* End PBXSourcesBuildPhase section */ 166 | 167 | /* Begin PBXVariantGroup section */ 168 | 9667CBB21ED4435F00B30B8A /* Main.storyboard */ = { 169 | isa = PBXVariantGroup; 170 | children = ( 171 | 9667CBB31ED4435F00B30B8A /* Base */, 172 | ); 173 | name = Main.storyboard; 174 | sourceTree = ""; 175 | }; 176 | 9667CBB71ED4435F00B30B8A /* LaunchScreen.storyboard */ = { 177 | isa = PBXVariantGroup; 178 | children = ( 179 | 9667CBB81ED4435F00B30B8A /* Base */, 180 | ); 181 | name = LaunchScreen.storyboard; 182 | sourceTree = ""; 183 | }; 184 | /* End PBXVariantGroup section */ 185 | 186 | /* Begin XCBuildConfiguration section */ 187 | 9667CBBB1ED4435F00B30B8A /* Debug */ = { 188 | isa = XCBuildConfiguration; 189 | buildSettings = { 190 | ALWAYS_SEARCH_USER_PATHS = NO; 191 | CLANG_ANALYZER_NONNULL = YES; 192 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 193 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 194 | CLANG_CXX_LIBRARY = "libc++"; 195 | CLANG_ENABLE_MODULES = YES; 196 | CLANG_ENABLE_OBJC_ARC = YES; 197 | CLANG_WARN_BOOL_CONVERSION = YES; 198 | CLANG_WARN_CONSTANT_CONVERSION = YES; 199 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 200 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 201 | CLANG_WARN_EMPTY_BODY = YES; 202 | CLANG_WARN_ENUM_CONVERSION = YES; 203 | CLANG_WARN_INFINITE_RECURSION = YES; 204 | CLANG_WARN_INT_CONVERSION = YES; 205 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 206 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 207 | CLANG_WARN_UNREACHABLE_CODE = YES; 208 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 209 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 210 | COPY_PHASE_STRIP = NO; 211 | DEBUG_INFORMATION_FORMAT = dwarf; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | ENABLE_TESTABILITY = YES; 214 | GCC_C_LANGUAGE_STANDARD = gnu99; 215 | GCC_DYNAMIC_NO_PIC = NO; 216 | GCC_NO_COMMON_BLOCKS = YES; 217 | GCC_OPTIMIZATION_LEVEL = 0; 218 | GCC_PREPROCESSOR_DEFINITIONS = ( 219 | "DEBUG=1", 220 | "$(inherited)", 221 | ); 222 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 223 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 224 | GCC_WARN_UNDECLARED_SELECTOR = YES; 225 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 226 | GCC_WARN_UNUSED_FUNCTION = YES; 227 | GCC_WARN_UNUSED_VARIABLE = YES; 228 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 229 | MTL_ENABLE_DEBUG_INFO = YES; 230 | ONLY_ACTIVE_ARCH = YES; 231 | SDKROOT = iphoneos; 232 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 233 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 234 | }; 235 | name = Debug; 236 | }; 237 | 9667CBBC1ED4435F00B30B8A /* Release */ = { 238 | isa = XCBuildConfiguration; 239 | buildSettings = { 240 | ALWAYS_SEARCH_USER_PATHS = NO; 241 | CLANG_ANALYZER_NONNULL = YES; 242 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 243 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 244 | CLANG_CXX_LIBRARY = "libc++"; 245 | CLANG_ENABLE_MODULES = YES; 246 | CLANG_ENABLE_OBJC_ARC = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 250 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 256 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 257 | CLANG_WARN_UNREACHABLE_CODE = YES; 258 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 259 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 260 | COPY_PHASE_STRIP = NO; 261 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 262 | ENABLE_NS_ASSERTIONS = NO; 263 | ENABLE_STRICT_OBJC_MSGSEND = YES; 264 | GCC_C_LANGUAGE_STANDARD = gnu99; 265 | GCC_NO_COMMON_BLOCKS = YES; 266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 268 | GCC_WARN_UNDECLARED_SELECTOR = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 270 | GCC_WARN_UNUSED_FUNCTION = YES; 271 | GCC_WARN_UNUSED_VARIABLE = YES; 272 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | SDKROOT = iphoneos; 275 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 276 | VALIDATE_PRODUCT = YES; 277 | }; 278 | name = Release; 279 | }; 280 | 9667CBBE1ED4435F00B30B8A /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 284 | DEVELOPMENT_TEAM = BJBC582Q56; 285 | INFOPLIST_FILE = FacebookClone/Info.plist; 286 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 287 | PRODUCT_BUNDLE_IDENTIFIER = VamshiKrishna.FacebookClone; 288 | PRODUCT_NAME = "$(TARGET_NAME)"; 289 | SWIFT_VERSION = 3.0; 290 | }; 291 | name = Debug; 292 | }; 293 | 9667CBBF1ED4435F00B30B8A /* Release */ = { 294 | isa = XCBuildConfiguration; 295 | buildSettings = { 296 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 297 | DEVELOPMENT_TEAM = BJBC582Q56; 298 | INFOPLIST_FILE = FacebookClone/Info.plist; 299 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 300 | PRODUCT_BUNDLE_IDENTIFIER = VamshiKrishna.FacebookClone; 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | SWIFT_VERSION = 3.0; 303 | }; 304 | name = Release; 305 | }; 306 | /* End XCBuildConfiguration section */ 307 | 308 | /* Begin XCConfigurationList section */ 309 | 9667CBA61ED4435F00B30B8A /* Build configuration list for PBXProject "FacebookClone" */ = { 310 | isa = XCConfigurationList; 311 | buildConfigurations = ( 312 | 9667CBBB1ED4435F00B30B8A /* Debug */, 313 | 9667CBBC1ED4435F00B30B8A /* Release */, 314 | ); 315 | defaultConfigurationIsVisible = 0; 316 | defaultConfigurationName = Release; 317 | }; 318 | 9667CBBD1ED4435F00B30B8A /* Build configuration list for PBXNativeTarget "FacebookClone" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | 9667CBBE1ED4435F00B30B8A /* Debug */, 322 | 9667CBBF1ED4435F00B30B8A /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | /* End XCConfigurationList section */ 328 | }; 329 | rootObject = 9667CBA31ED4435F00B30B8A /* Project object */; 330 | } 331 | --------------------------------------------------------------------------------