├── Demo.gif ├── LICENSE ├── NearbyPlaces ├── NearbyPlaces.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── payalgupta.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ │ └── payalgupta.xcuserdatad │ │ └── xcschemes │ │ ├── NearbyPlaces.xcscheme │ │ └── xcschememanagement.plist └── NearbyPlaces │ ├── Info.plist │ ├── NearbyPlaceEntity.swift │ └── NearbyPlaces.h ├── NearbyRestaurants.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── payalgupta.xcuserdatad │ └── xcschemes │ ├── NearbyRestaurants.xcscheme │ ├── NearbyRestaurantsTodayExtension.xcscheme │ └── xcschememanagement.plist ├── NearbyRestaurants ├── Info.plist ├── NearbyRestaurants.entitlements ├── Storyboard │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ └── Main.storyboard ├── Supporting Files │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ └── Icon-App-60x60@3x.png │ │ ├── Contents.json │ │ ├── GalleryPlaceholder.imageset │ │ │ ├── Contents.json │ │ │ └── gallery_placeholder@2x.png │ │ └── RestaurantIcon.imageset │ │ │ ├── Contents.json │ │ │ └── restaurant-icon-png-plate-1.png │ ├── Cacher.swift │ ├── LocationManager.swift │ ├── NearbyPlaceDetail.swift │ └── NearbyRestaurants-Bridging-Header.h ├── UITableViewCell │ ├── NearbyPlaceTableViewCell.swift │ ├── NearbyPlaceTableViewCell.xib │ └── NearbyRestaurantPhotoCollectionViewCell.swift └── View Controllers │ ├── NearbyRestaurantDetailViewController.swift │ └── NearbyRestaurantsViewController.swift ├── NearbyRestaurantsTodayExtension ├── Base.lproj │ └── MainInterface.storyboard ├── Cacher.swift ├── Info.plist ├── NearbyRestaurantsTodayExtension-Bridging-Header.h ├── NearbyRestaurantsTodayExtension.entitlements └── TodayViewController.swift ├── README.md └── Screenshot.PNG /Demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/Demo.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 pgpt10 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 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BDE312DA1DB6312B00BA431E /* NearbyPlaces.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE312D81DB6312B00BA431E /* NearbyPlaces.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | BDE312E51DB6316100BA431E /* NearbyPlaceEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDE312E41DB6316100BA431E /* NearbyPlaceEntity.swift */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXFileReference section */ 15 | BDE312D51DB6312B00BA431E /* NearbyPlaces.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NearbyPlaces.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 16 | BDE312D81DB6312B00BA431E /* NearbyPlaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NearbyPlaces.h; sourceTree = ""; }; 17 | BDE312D91DB6312B00BA431E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 18 | BDE312E41DB6316100BA431E /* NearbyPlaceEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyPlaceEntity.swift; sourceTree = ""; }; 19 | /* End PBXFileReference section */ 20 | 21 | /* Begin PBXFrameworksBuildPhase section */ 22 | BDE312D11DB6312B00BA431E /* Frameworks */ = { 23 | isa = PBXFrameworksBuildPhase; 24 | buildActionMask = 2147483647; 25 | files = ( 26 | ); 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXFrameworksBuildPhase section */ 30 | 31 | /* Begin PBXGroup section */ 32 | BDE312CB1DB6312B00BA431E = { 33 | isa = PBXGroup; 34 | children = ( 35 | BDE312D71DB6312B00BA431E /* NearbyPlaces */, 36 | BDE312D61DB6312B00BA431E /* Products */, 37 | ); 38 | sourceTree = ""; 39 | }; 40 | BDE312D61DB6312B00BA431E /* Products */ = { 41 | isa = PBXGroup; 42 | children = ( 43 | BDE312D51DB6312B00BA431E /* NearbyPlaces.framework */, 44 | ); 45 | name = Products; 46 | sourceTree = ""; 47 | }; 48 | BDE312D71DB6312B00BA431E /* NearbyPlaces */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | BDE312E41DB6316100BA431E /* NearbyPlaceEntity.swift */, 52 | BDE312D81DB6312B00BA431E /* NearbyPlaces.h */, 53 | BDE312D91DB6312B00BA431E /* Info.plist */, 54 | ); 55 | path = NearbyPlaces; 56 | sourceTree = ""; 57 | }; 58 | /* End PBXGroup section */ 59 | 60 | /* Begin PBXHeadersBuildPhase section */ 61 | BDE312D21DB6312B00BA431E /* Headers */ = { 62 | isa = PBXHeadersBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | BDE312DA1DB6312B00BA431E /* NearbyPlaces.h in Headers */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXHeadersBuildPhase section */ 70 | 71 | /* Begin PBXNativeTarget section */ 72 | BDE312D41DB6312B00BA431E /* NearbyPlaces */ = { 73 | isa = PBXNativeTarget; 74 | buildConfigurationList = BDE312DD1DB6312B00BA431E /* Build configuration list for PBXNativeTarget "NearbyPlaces" */; 75 | buildPhases = ( 76 | BDE312D01DB6312B00BA431E /* Sources */, 77 | BDE312D11DB6312B00BA431E /* Frameworks */, 78 | BDE312D21DB6312B00BA431E /* Headers */, 79 | BDE312D31DB6312B00BA431E /* Resources */, 80 | ); 81 | buildRules = ( 82 | ); 83 | dependencies = ( 84 | ); 85 | name = NearbyPlaces; 86 | productName = NearbyPlaces; 87 | productReference = BDE312D51DB6312B00BA431E /* NearbyPlaces.framework */; 88 | productType = "com.apple.product-type.framework"; 89 | }; 90 | /* End PBXNativeTarget section */ 91 | 92 | /* Begin PBXProject section */ 93 | BDE312CC1DB6312B00BA431E /* Project object */ = { 94 | isa = PBXProject; 95 | attributes = { 96 | LastUpgradeCheck = 0800; 97 | ORGANIZATIONNAME = "Infoedge Pvt. Ltd."; 98 | TargetAttributes = { 99 | BDE312D41DB6312B00BA431E = { 100 | CreatedOnToolsVersion = 8.0; 101 | DevelopmentTeam = Z3QQ492P6Z; 102 | LastSwiftMigration = 0820; 103 | ProvisioningStyle = Manual; 104 | }; 105 | }; 106 | }; 107 | buildConfigurationList = BDE312CF1DB6312B00BA431E /* Build configuration list for PBXProject "NearbyPlaces" */; 108 | compatibilityVersion = "Xcode 3.2"; 109 | developmentRegion = English; 110 | hasScannedForEncodings = 0; 111 | knownRegions = ( 112 | en, 113 | ); 114 | mainGroup = BDE312CB1DB6312B00BA431E; 115 | productRefGroup = BDE312D61DB6312B00BA431E /* Products */; 116 | projectDirPath = ""; 117 | projectRoot = ""; 118 | targets = ( 119 | BDE312D41DB6312B00BA431E /* NearbyPlaces */, 120 | ); 121 | }; 122 | /* End PBXProject section */ 123 | 124 | /* Begin PBXResourcesBuildPhase section */ 125 | BDE312D31DB6312B00BA431E /* Resources */ = { 126 | isa = PBXResourcesBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | ); 130 | runOnlyForDeploymentPostprocessing = 0; 131 | }; 132 | /* End PBXResourcesBuildPhase section */ 133 | 134 | /* Begin PBXSourcesBuildPhase section */ 135 | BDE312D01DB6312B00BA431E /* Sources */ = { 136 | isa = PBXSourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | BDE312E51DB6316100BA431E /* NearbyPlaceEntity.swift in Sources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXSourcesBuildPhase section */ 144 | 145 | /* Begin XCBuildConfiguration section */ 146 | BDE312DB1DB6312B00BA431E /* Debug */ = { 147 | isa = XCBuildConfiguration; 148 | buildSettings = { 149 | ALWAYS_SEARCH_USER_PATHS = NO; 150 | CLANG_ANALYZER_NONNULL = YES; 151 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 152 | CLANG_CXX_LIBRARY = "libc++"; 153 | CLANG_ENABLE_MODULES = YES; 154 | CLANG_ENABLE_OBJC_ARC = YES; 155 | CLANG_WARN_BOOL_CONVERSION = YES; 156 | CLANG_WARN_CONSTANT_CONVERSION = YES; 157 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 158 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 159 | CLANG_WARN_EMPTY_BODY = YES; 160 | CLANG_WARN_ENUM_CONVERSION = YES; 161 | CLANG_WARN_INFINITE_RECURSION = YES; 162 | CLANG_WARN_INT_CONVERSION = YES; 163 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 164 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 165 | CLANG_WARN_UNREACHABLE_CODE = YES; 166 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 167 | COPY_PHASE_STRIP = NO; 168 | CURRENT_PROJECT_VERSION = 1; 169 | DEBUG_INFORMATION_FORMAT = dwarf; 170 | ENABLE_STRICT_OBJC_MSGSEND = YES; 171 | ENABLE_TESTABILITY = YES; 172 | GCC_C_LANGUAGE_STANDARD = gnu99; 173 | GCC_DYNAMIC_NO_PIC = NO; 174 | GCC_NO_COMMON_BLOCKS = YES; 175 | GCC_OPTIMIZATION_LEVEL = 0; 176 | GCC_PREPROCESSOR_DEFINITIONS = ( 177 | "DEBUG=1", 178 | "$(inherited)", 179 | ); 180 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 181 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 182 | GCC_WARN_UNDECLARED_SELECTOR = YES; 183 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 184 | GCC_WARN_UNUSED_FUNCTION = YES; 185 | GCC_WARN_UNUSED_VARIABLE = YES; 186 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 187 | MTL_ENABLE_DEBUG_INFO = YES; 188 | ONLY_ACTIVE_ARCH = YES; 189 | SDKROOT = iphoneos; 190 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 191 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 192 | TARGETED_DEVICE_FAMILY = "1,2"; 193 | VERSIONING_SYSTEM = "apple-generic"; 194 | VERSION_INFO_PREFIX = ""; 195 | }; 196 | name = Debug; 197 | }; 198 | BDE312DC1DB6312B00BA431E /* Release */ = { 199 | isa = XCBuildConfiguration; 200 | buildSettings = { 201 | ALWAYS_SEARCH_USER_PATHS = NO; 202 | CLANG_ANALYZER_NONNULL = YES; 203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 204 | CLANG_CXX_LIBRARY = "libc++"; 205 | CLANG_ENABLE_MODULES = YES; 206 | CLANG_ENABLE_OBJC_ARC = YES; 207 | CLANG_WARN_BOOL_CONVERSION = YES; 208 | CLANG_WARN_CONSTANT_CONVERSION = YES; 209 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 210 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INFINITE_RECURSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 216 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 217 | CLANG_WARN_UNREACHABLE_CODE = YES; 218 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 219 | COPY_PHASE_STRIP = NO; 220 | CURRENT_PROJECT_VERSION = 1; 221 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 222 | ENABLE_NS_ASSERTIONS = NO; 223 | ENABLE_STRICT_OBJC_MSGSEND = YES; 224 | GCC_C_LANGUAGE_STANDARD = gnu99; 225 | GCC_NO_COMMON_BLOCKS = YES; 226 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 227 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 228 | GCC_WARN_UNDECLARED_SELECTOR = YES; 229 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 230 | GCC_WARN_UNUSED_FUNCTION = YES; 231 | GCC_WARN_UNUSED_VARIABLE = YES; 232 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 233 | MTL_ENABLE_DEBUG_INFO = NO; 234 | SDKROOT = iphoneos; 235 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 236 | TARGETED_DEVICE_FAMILY = "1,2"; 237 | VALIDATE_PRODUCT = YES; 238 | VERSIONING_SYSTEM = "apple-generic"; 239 | VERSION_INFO_PREFIX = ""; 240 | }; 241 | name = Release; 242 | }; 243 | BDE312DE1DB6312B00BA431E /* Debug */ = { 244 | isa = XCBuildConfiguration; 245 | buildSettings = { 246 | CLANG_ENABLE_MODULES = YES; 247 | CODE_SIGN_IDENTITY = "iPhone Developer: Dinesh Kumar (J3LPPA9AA4)"; 248 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 249 | DEFINES_MODULE = YES; 250 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 251 | DYLIB_COMPATIBILITY_VERSION = 1; 252 | DYLIB_CURRENT_VERSION = 1; 253 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 254 | INFOPLIST_FILE = NearbyPlaces/Info.plist; 255 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 256 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 257 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 258 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyPlaces; 259 | PRODUCT_NAME = "$(TARGET_NAME)"; 260 | SKIP_INSTALL = YES; 261 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 262 | SWIFT_VERSION = 3.0; 263 | }; 264 | name = Debug; 265 | }; 266 | BDE312DF1DB6312B00BA431E /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | CLANG_ENABLE_MODULES = YES; 270 | CODE_SIGN_IDENTITY = "iPhone Developer: Dinesh Kumar (J3LPPA9AA4)"; 271 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 272 | DEFINES_MODULE = YES; 273 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 274 | DYLIB_COMPATIBILITY_VERSION = 1; 275 | DYLIB_CURRENT_VERSION = 1; 276 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 277 | INFOPLIST_FILE = NearbyPlaces/Info.plist; 278 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 279 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 280 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 281 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyPlaces; 282 | PRODUCT_NAME = "$(TARGET_NAME)"; 283 | SKIP_INSTALL = YES; 284 | SWIFT_VERSION = 3.0; 285 | }; 286 | name = Release; 287 | }; 288 | /* End XCBuildConfiguration section */ 289 | 290 | /* Begin XCConfigurationList section */ 291 | BDE312CF1DB6312B00BA431E /* Build configuration list for PBXProject "NearbyPlaces" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | BDE312DB1DB6312B00BA431E /* Debug */, 295 | BDE312DC1DB6312B00BA431E /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | BDE312DD1DB6312B00BA431E /* Build configuration list for PBXNativeTarget "NearbyPlaces" */ = { 301 | isa = XCConfigurationList; 302 | buildConfigurations = ( 303 | BDE312DE1DB6312B00BA431E /* Debug */, 304 | BDE312DF1DB6312B00BA431E /* Release */, 305 | ); 306 | defaultConfigurationIsVisible = 0; 307 | defaultConfigurationName = Release; 308 | }; 309 | /* End XCConfigurationList section */ 310 | }; 311 | rootObject = BDE312CC1DB6312B00BA431E /* Project object */; 312 | } 313 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces.xcodeproj/project.xcworkspace/xcuserdata/payalgupta.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyPlaces/NearbyPlaces.xcodeproj/project.xcworkspace/xcuserdata/payalgupta.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces.xcodeproj/xcuserdata/payalgupta.xcuserdatad/xcschemes/NearbyPlaces.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces.xcodeproj/xcuserdata/payalgupta.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | NearbyPlaces.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | BDE312D41DB6312B00BA431E 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces/NearbyPlaceEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyPlaceDetail.swift 3 | // NearbyPlaces 4 | // 5 | // Created by Payal Gupta on 10/18/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public let kGoogleAPIKey : String = "AIzaSyA-80bYgdT6jJdi-K7SQQ4gqkHms3t4jP4" 12 | 13 | open class NearbyPlaceEntity : NSObject, NSCoding 14 | { 15 | //MARK: Internal Properties 16 | open let name : String 17 | open let address : String 18 | open let placeID : String 19 | open var icon : String? 20 | 21 | //MARK: Initializer 22 | public init?(jsonDictionary : [String : AnyObject]) 23 | { 24 | guard let name = jsonDictionary["name"] as? String, let placeID = jsonDictionary["place_id"] as? String, let address = jsonDictionary["vicinity"] as? String else 25 | { 26 | return nil 27 | } 28 | self.name = name 29 | self.placeID = placeID 30 | self.address = address 31 | self.icon = jsonDictionary["icon"] as? String 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) 35 | { 36 | self.name = aDecoder.decodeObject(forKey: "name") as! String 37 | self.address = aDecoder.decodeObject(forKey: "address") as! String 38 | self.placeID = aDecoder.decodeObject(forKey: "placeID") as! String 39 | self.icon = aDecoder.decodeObject(forKey: "icon") as? String 40 | } 41 | 42 | public func encode(with aCoder: NSCoder) 43 | { 44 | aCoder.encode(self.name, forKey: "name") 45 | aCoder.encode(self.address, forKey: "address") 46 | aCoder.encode(self.placeID, forKey: "placeID") 47 | aCoder.encode(self.icon, forKey: "icon") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /NearbyPlaces/NearbyPlaces/NearbyPlaces.h: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyPlaces.h 3 | // NearbyPlaces 4 | // 5 | // Created by Payal Gupta on 10/18/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for NearbyPlaces. 12 | FOUNDATION_EXPORT double NearbyPlacesVersionNumber; 13 | 14 | //! Project version string for NearbyPlaces. 15 | FOUNDATION_EXPORT const unsigned char NearbyPlacesVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /NearbyRestaurants.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BD21F0891DBBC28E00ECA962 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BD21F0881DBBC28E00ECA962 /* Info.plist */; }; 11 | BDB1C4661DB8A71200253E7A /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDB1C4651DB8A71200253E7A /* NotificationCenter.framework */; }; 12 | BDB1C4691DB8A71200253E7A /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDB1C4681DB8A71200253E7A /* TodayViewController.swift */; }; 13 | BDB1C46C1DB8A71300253E7A /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDB1C46A1DB8A71300253E7A /* MainInterface.storyboard */; }; 14 | BDB1C4701DB8A71300253E7A /* NearbyRestaurantsTodayExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BDB1C4641DB8A71200253E7A /* NearbyRestaurantsTodayExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 15 | BDB85D191DB62A42008F0E1E /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDB85D181DB62A42008F0E1E /* CoreLocation.framework */; }; 16 | BDC421401E0BE28100F006E3 /* NearbyPlaceDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC4213F1E0BE28100F006E3 /* NearbyPlaceDetail.swift */; }; 17 | BDC421471E0BE3DE00F006E3 /* NearbyPlaces.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDE2D98D1DC9C30E00CD5AAD /* NearbyPlaces.framework */; }; 18 | BDC421481E0BE3DE00F006E3 /* NearbyPlaces.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BDE2D98D1DC9C30E00CD5AAD /* NearbyPlaces.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | BDC4214C1E0BE3E500F006E3 /* NearbyPlaces.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDE2D98D1DC9C30E00CD5AAD /* NearbyPlaces.framework */; }; 20 | BDC421501E0BFDE500F006E3 /* Cacher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC4214F1E0BFDE500F006E3 /* Cacher.swift */; }; 21 | BDC421561E0C000600F006E3 /* Cacher.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC421551E0C000600F006E3 /* Cacher.swift */; }; 22 | BDC4215D1E0C06AE00F006E3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BDFD33DB1DBBC16900104198 /* Assets.xcassets */; }; 23 | BDFD33E41DBBC16900104198 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDFD33D71DBBC16900104198 /* LaunchScreen.storyboard */; }; 24 | BDFD33E51DBBC16900104198 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BDFD33D91DBBC16900104198 /* Main.storyboard */; }; 25 | BDFD33E61DBBC16900104198 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BDFD33DB1DBBC16900104198 /* Assets.xcassets */; }; 26 | BDFD33E81DBBC16900104198 /* NearbyPlaceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33DE1DBBC16900104198 /* NearbyPlaceTableViewCell.swift */; }; 27 | BDFD33E91DBBC16900104198 /* NearbyPlaceTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BDFD33DF1DBBC16900104198 /* NearbyPlaceTableViewCell.xib */; }; 28 | BDFD33EA1DBBC16900104198 /* NearbyRestaurantPhotoCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33E01DBBC16900104198 /* NearbyRestaurantPhotoCollectionViewCell.swift */; }; 29 | BDFD33EB1DBBC16900104198 /* NearbyRestaurantDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33E21DBBC16900104198 /* NearbyRestaurantDetailViewController.swift */; }; 30 | BDFD33EC1DBBC16900104198 /* NearbyRestaurantsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33E31DBBC16900104198 /* NearbyRestaurantsViewController.swift */; }; 31 | BDFD33EE1DBBC1BA00104198 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33ED1DBBC1BA00104198 /* AppDelegate.swift */; }; 32 | BDFD33F01DBBC1DB00104198 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDFD33EF1DBBC1DB00104198 /* LocationManager.swift */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | BDB1C46E1DB8A71300253E7A /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = BDB85CF11DB627A6008F0E1E /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = BDB1C4631DB8A71200253E7A; 41 | remoteInfo = NearbyRestaurantsTodayExtension; 42 | }; 43 | BDC421491E0BE3DE00F006E3 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = BDE2D9881DC9C30D00CD5AAD /* NearbyPlaces.xcodeproj */; 46 | proxyType = 1; 47 | remoteGlobalIDString = BDE312D41DB6312B00BA431E; 48 | remoteInfo = NearbyPlaces; 49 | }; 50 | BDE2D98C1DC9C30E00CD5AAD /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = BDE2D9881DC9C30D00CD5AAD /* NearbyPlaces.xcodeproj */; 53 | proxyType = 2; 54 | remoteGlobalIDString = BDE312D51DB6312B00BA431E; 55 | remoteInfo = NearbyPlaces; 56 | }; 57 | /* End PBXContainerItemProxy section */ 58 | 59 | /* Begin PBXCopyFilesBuildPhase section */ 60 | BDB1C4741DB8A71300253E7A /* Embed App Extensions */ = { 61 | isa = PBXCopyFilesBuildPhase; 62 | buildActionMask = 2147483647; 63 | dstPath = ""; 64 | dstSubfolderSpec = 13; 65 | files = ( 66 | BDB1C4701DB8A71300253E7A /* NearbyRestaurantsTodayExtension.appex in Embed App Extensions */, 67 | ); 68 | name = "Embed App Extensions"; 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | BDC4214B1E0BE3DE00F006E3 /* Embed Frameworks */ = { 72 | isa = PBXCopyFilesBuildPhase; 73 | buildActionMask = 2147483647; 74 | dstPath = ""; 75 | dstSubfolderSpec = 10; 76 | files = ( 77 | BDC421481E0BE3DE00F006E3 /* NearbyPlaces.framework in Embed Frameworks */, 78 | ); 79 | name = "Embed Frameworks"; 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXCopyFilesBuildPhase section */ 83 | 84 | /* Begin PBXFileReference section */ 85 | BD21F0881DBBC28E00ECA962 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 86 | BDB1C4641DB8A71200253E7A /* NearbyRestaurantsTodayExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NearbyRestaurantsTodayExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 87 | BDB1C4651DB8A71200253E7A /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 88 | BDB1C4681DB8A71200253E7A /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; }; 89 | BDB1C46B1DB8A71300253E7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; 90 | BDB1C46D1DB8A71300253E7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 91 | BDB85CF91DB627A6008F0E1E /* NearbyRestaurants.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NearbyRestaurants.app; sourceTree = BUILT_PRODUCTS_DIR; }; 92 | BDB85D181DB62A42008F0E1E /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 93 | BDC4213F1E0BE28100F006E3 /* NearbyPlaceDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyPlaceDetail.swift; sourceTree = ""; }; 94 | BDC4214F1E0BFDE500F006E3 /* Cacher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cacher.swift; sourceTree = ""; }; 95 | BDC421511E0BFE2A00F006E3 /* NearbyRestaurants-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NearbyRestaurants-Bridging-Header.h"; sourceTree = ""; }; 96 | BDC421551E0C000600F006E3 /* Cacher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cacher.swift; sourceTree = ""; }; 97 | BDC421571E0C008A00F006E3 /* NearbyRestaurantsTodayExtension-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NearbyRestaurantsTodayExtension-Bridging-Header.h"; sourceTree = ""; }; 98 | BDE2D9881DC9C30D00CD5AAD /* NearbyPlaces.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = NearbyPlaces.xcodeproj; path = NearbyPlaces/NearbyPlaces.xcodeproj; sourceTree = ""; }; 99 | BDFD33D81DBBC16900104198 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 100 | BDFD33D91DBBC16900104198 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 101 | BDFD33DB1DBBC16900104198 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 102 | BDFD33DE1DBBC16900104198 /* NearbyPlaceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyPlaceTableViewCell.swift; sourceTree = ""; }; 103 | BDFD33DF1DBBC16900104198 /* NearbyPlaceTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NearbyPlaceTableViewCell.xib; sourceTree = ""; }; 104 | BDFD33E01DBBC16900104198 /* NearbyRestaurantPhotoCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyRestaurantPhotoCollectionViewCell.swift; sourceTree = ""; }; 105 | BDFD33E21DBBC16900104198 /* NearbyRestaurantDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyRestaurantDetailViewController.swift; sourceTree = ""; }; 106 | BDFD33E31DBBC16900104198 /* NearbyRestaurantsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NearbyRestaurantsViewController.swift; sourceTree = ""; }; 107 | BDFD33ED1DBBC1BA00104198 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 108 | BDFD33EF1DBBC1DB00104198 /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; 109 | BDFFDA831DBDD86D00B8D417 /* NearbyRestaurantsTodayExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearbyRestaurantsTodayExtension.entitlements; sourceTree = ""; }; 110 | BDFFDA841DBDE59500B8D417 /* NearbyRestaurants.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NearbyRestaurants.entitlements; sourceTree = ""; }; 111 | /* End PBXFileReference section */ 112 | 113 | /* Begin PBXFrameworksBuildPhase section */ 114 | BDB1C4611DB8A71200253E7A /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | BDB1C4661DB8A71200253E7A /* NotificationCenter.framework in Frameworks */, 119 | BDC4214C1E0BE3E500F006E3 /* NearbyPlaces.framework in Frameworks */, 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | BDB85CF61DB627A6008F0E1E /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | BDB85D191DB62A42008F0E1E /* CoreLocation.framework in Frameworks */, 128 | BDC421471E0BE3DE00F006E3 /* NearbyPlaces.framework in Frameworks */, 129 | ); 130 | runOnlyForDeploymentPostprocessing = 0; 131 | }; 132 | /* End PBXFrameworksBuildPhase section */ 133 | 134 | /* Begin PBXGroup section */ 135 | BDB1C4671DB8A71200253E7A /* NearbyRestaurantsTodayExtension */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | BDFFDA831DBDD86D00B8D417 /* NearbyRestaurantsTodayExtension.entitlements */, 139 | BDB1C4681DB8A71200253E7A /* TodayViewController.swift */, 140 | BDB1C46A1DB8A71300253E7A /* MainInterface.storyboard */, 141 | BDB1C46D1DB8A71300253E7A /* Info.plist */, 142 | BDC421551E0C000600F006E3 /* Cacher.swift */, 143 | BDC421571E0C008A00F006E3 /* NearbyRestaurantsTodayExtension-Bridging-Header.h */, 144 | ); 145 | path = NearbyRestaurantsTodayExtension; 146 | sourceTree = ""; 147 | }; 148 | BDB85CF01DB627A6008F0E1E = { 149 | isa = PBXGroup; 150 | children = ( 151 | BDE2D9881DC9C30D00CD5AAD /* NearbyPlaces.xcodeproj */, 152 | BDB85CFB1DB627A6008F0E1E /* NearbyRestaurants */, 153 | BDB1C4671DB8A71200253E7A /* NearbyRestaurantsTodayExtension */, 154 | BDB85CFA1DB627A6008F0E1E /* Products */, 155 | BDB85D171DB62A42008F0E1E /* Frameworks */, 156 | ); 157 | sourceTree = ""; 158 | }; 159 | BDB85CFA1DB627A6008F0E1E /* Products */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | BDB85CF91DB627A6008F0E1E /* NearbyRestaurants.app */, 163 | BDB1C4641DB8A71200253E7A /* NearbyRestaurantsTodayExtension.appex */, 164 | ); 165 | name = Products; 166 | sourceTree = ""; 167 | }; 168 | BDB85CFB1DB627A6008F0E1E /* NearbyRestaurants */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | BDFFDA841DBDE59500B8D417 /* NearbyRestaurants.entitlements */, 172 | BD21F0881DBBC28E00ECA962 /* Info.plist */, 173 | BDFD33D61DBBC16900104198 /* Storyboard */, 174 | BDFD33DA1DBBC16900104198 /* Supporting Files */, 175 | BDFD33DD1DBBC16900104198 /* UITableViewCell */, 176 | BDFD33E11DBBC16900104198 /* View Controllers */, 177 | ); 178 | path = NearbyRestaurants; 179 | sourceTree = ""; 180 | }; 181 | BDB85D171DB62A42008F0E1E /* Frameworks */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | BDB85D181DB62A42008F0E1E /* CoreLocation.framework */, 185 | BDB1C4651DB8A71200253E7A /* NotificationCenter.framework */, 186 | ); 187 | name = Frameworks; 188 | sourceTree = ""; 189 | }; 190 | BDE2D9891DC9C30D00CD5AAD /* Products */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | BDE2D98D1DC9C30E00CD5AAD /* NearbyPlaces.framework */, 194 | ); 195 | name = Products; 196 | sourceTree = ""; 197 | }; 198 | BDFD33D61DBBC16900104198 /* Storyboard */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | BDFD33D71DBBC16900104198 /* LaunchScreen.storyboard */, 202 | BDFD33D91DBBC16900104198 /* Main.storyboard */, 203 | ); 204 | path = Storyboard; 205 | sourceTree = ""; 206 | }; 207 | BDFD33DA1DBBC16900104198 /* Supporting Files */ = { 208 | isa = PBXGroup; 209 | children = ( 210 | BDFD33EF1DBBC1DB00104198 /* LocationManager.swift */, 211 | BDFD33ED1DBBC1BA00104198 /* AppDelegate.swift */, 212 | BDC4213F1E0BE28100F006E3 /* NearbyPlaceDetail.swift */, 213 | BDC4214F1E0BFDE500F006E3 /* Cacher.swift */, 214 | BDC421511E0BFE2A00F006E3 /* NearbyRestaurants-Bridging-Header.h */, 215 | BDFD33DB1DBBC16900104198 /* Assets.xcassets */, 216 | ); 217 | path = "Supporting Files"; 218 | sourceTree = ""; 219 | }; 220 | BDFD33DD1DBBC16900104198 /* UITableViewCell */ = { 221 | isa = PBXGroup; 222 | children = ( 223 | BDFD33DE1DBBC16900104198 /* NearbyPlaceTableViewCell.swift */, 224 | BDFD33DF1DBBC16900104198 /* NearbyPlaceTableViewCell.xib */, 225 | BDFD33E01DBBC16900104198 /* NearbyRestaurantPhotoCollectionViewCell.swift */, 226 | ); 227 | path = UITableViewCell; 228 | sourceTree = ""; 229 | }; 230 | BDFD33E11DBBC16900104198 /* View Controllers */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | BDFD33E21DBBC16900104198 /* NearbyRestaurantDetailViewController.swift */, 234 | BDFD33E31DBBC16900104198 /* NearbyRestaurantsViewController.swift */, 235 | ); 236 | path = "View Controllers"; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXGroup section */ 240 | 241 | /* Begin PBXNativeTarget section */ 242 | BDB1C4631DB8A71200253E7A /* NearbyRestaurantsTodayExtension */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = BDB1C4731DB8A71300253E7A /* Build configuration list for PBXNativeTarget "NearbyRestaurantsTodayExtension" */; 245 | buildPhases = ( 246 | BDB1C4601DB8A71200253E7A /* Sources */, 247 | BDB1C4611DB8A71200253E7A /* Frameworks */, 248 | BDB1C4621DB8A71200253E7A /* Resources */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = NearbyRestaurantsTodayExtension; 255 | productName = NearbyRestaurantsTodayExtension; 256 | productReference = BDB1C4641DB8A71200253E7A /* NearbyRestaurantsTodayExtension.appex */; 257 | productType = "com.apple.product-type.app-extension"; 258 | }; 259 | BDB85CF81DB627A6008F0E1E /* NearbyRestaurants */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = BDB85D0B1DB627A6008F0E1E /* Build configuration list for PBXNativeTarget "NearbyRestaurants" */; 262 | buildPhases = ( 263 | BDB85CF51DB627A6008F0E1E /* Sources */, 264 | BDB85CF61DB627A6008F0E1E /* Frameworks */, 265 | BDB85CF71DB627A6008F0E1E /* Resources */, 266 | BDB1C4741DB8A71300253E7A /* Embed App Extensions */, 267 | BDC4214B1E0BE3DE00F006E3 /* Embed Frameworks */, 268 | ); 269 | buildRules = ( 270 | ); 271 | dependencies = ( 272 | BDB1C46F1DB8A71300253E7A /* PBXTargetDependency */, 273 | BDC4214A1E0BE3DE00F006E3 /* PBXTargetDependency */, 274 | ); 275 | name = NearbyRestaurants; 276 | productName = NearbyRestaurants; 277 | productReference = BDB85CF91DB627A6008F0E1E /* NearbyRestaurants.app */; 278 | productType = "com.apple.product-type.application"; 279 | }; 280 | /* End PBXNativeTarget section */ 281 | 282 | /* Begin PBXProject section */ 283 | BDB85CF11DB627A6008F0E1E /* Project object */ = { 284 | isa = PBXProject; 285 | attributes = { 286 | LastSwiftUpdateCheck = 0800; 287 | LastUpgradeCheck = 0800; 288 | ORGANIZATIONNAME = "Infoedge Pvt. Ltd."; 289 | TargetAttributes = { 290 | BDB1C4631DB8A71200253E7A = { 291 | CreatedOnToolsVersion = 8.0; 292 | DevelopmentTeam = Z3QQ492P6Z; 293 | LastSwiftMigration = 0820; 294 | ProvisioningStyle = Manual; 295 | SystemCapabilities = { 296 | com.apple.ApplicationGroups.iOS = { 297 | enabled = 1; 298 | }; 299 | }; 300 | }; 301 | BDB85CF81DB627A6008F0E1E = { 302 | CreatedOnToolsVersion = 8.0; 303 | DevelopmentTeam = Z3QQ492P6Z; 304 | LastSwiftMigration = 0820; 305 | ProvisioningStyle = Manual; 306 | SystemCapabilities = { 307 | com.apple.ApplicationGroups.iOS = { 308 | enabled = 1; 309 | }; 310 | }; 311 | }; 312 | }; 313 | }; 314 | buildConfigurationList = BDB85CF41DB627A6008F0E1E /* Build configuration list for PBXProject "NearbyRestaurants" */; 315 | compatibilityVersion = "Xcode 3.2"; 316 | developmentRegion = English; 317 | hasScannedForEncodings = 0; 318 | knownRegions = ( 319 | en, 320 | Base, 321 | ); 322 | mainGroup = BDB85CF01DB627A6008F0E1E; 323 | productRefGroup = BDB85CFA1DB627A6008F0E1E /* Products */; 324 | projectDirPath = ""; 325 | projectReferences = ( 326 | { 327 | ProductGroup = BDE2D9891DC9C30D00CD5AAD /* Products */; 328 | ProjectRef = BDE2D9881DC9C30D00CD5AAD /* NearbyPlaces.xcodeproj */; 329 | }, 330 | ); 331 | projectRoot = ""; 332 | targets = ( 333 | BDB85CF81DB627A6008F0E1E /* NearbyRestaurants */, 334 | BDB1C4631DB8A71200253E7A /* NearbyRestaurantsTodayExtension */, 335 | ); 336 | }; 337 | /* End PBXProject section */ 338 | 339 | /* Begin PBXReferenceProxy section */ 340 | BDE2D98D1DC9C30E00CD5AAD /* NearbyPlaces.framework */ = { 341 | isa = PBXReferenceProxy; 342 | fileType = wrapper.framework; 343 | path = NearbyPlaces.framework; 344 | remoteRef = BDE2D98C1DC9C30E00CD5AAD /* PBXContainerItemProxy */; 345 | sourceTree = BUILT_PRODUCTS_DIR; 346 | }; 347 | /* End PBXReferenceProxy section */ 348 | 349 | /* Begin PBXResourcesBuildPhase section */ 350 | BDB1C4621DB8A71200253E7A /* Resources */ = { 351 | isa = PBXResourcesBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | BDC4215D1E0C06AE00F006E3 /* Assets.xcassets in Resources */, 355 | BDB1C46C1DB8A71300253E7A /* MainInterface.storyboard in Resources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | BDB85CF71DB627A6008F0E1E /* Resources */ = { 360 | isa = PBXResourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | BDFD33E51DBBC16900104198 /* Main.storyboard in Resources */, 364 | BDFD33E41DBBC16900104198 /* LaunchScreen.storyboard in Resources */, 365 | BDFD33E91DBBC16900104198 /* NearbyPlaceTableViewCell.xib in Resources */, 366 | BD21F0891DBBC28E00ECA962 /* Info.plist in Resources */, 367 | BDFD33E61DBBC16900104198 /* Assets.xcassets in Resources */, 368 | ); 369 | runOnlyForDeploymentPostprocessing = 0; 370 | }; 371 | /* End PBXResourcesBuildPhase section */ 372 | 373 | /* Begin PBXSourcesBuildPhase section */ 374 | BDB1C4601DB8A71200253E7A /* Sources */ = { 375 | isa = PBXSourcesBuildPhase; 376 | buildActionMask = 2147483647; 377 | files = ( 378 | BDB1C4691DB8A71200253E7A /* TodayViewController.swift in Sources */, 379 | BDC421561E0C000600F006E3 /* Cacher.swift in Sources */, 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | }; 383 | BDB85CF51DB627A6008F0E1E /* Sources */ = { 384 | isa = PBXSourcesBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | BDFD33EE1DBBC1BA00104198 /* AppDelegate.swift in Sources */, 388 | BDC421401E0BE28100F006E3 /* NearbyPlaceDetail.swift in Sources */, 389 | BDFD33E81DBBC16900104198 /* NearbyPlaceTableViewCell.swift in Sources */, 390 | BDFD33F01DBBC1DB00104198 /* LocationManager.swift in Sources */, 391 | BDFD33EB1DBBC16900104198 /* NearbyRestaurantDetailViewController.swift in Sources */, 392 | BDC421501E0BFDE500F006E3 /* Cacher.swift in Sources */, 393 | BDFD33EC1DBBC16900104198 /* NearbyRestaurantsViewController.swift in Sources */, 394 | BDFD33EA1DBBC16900104198 /* NearbyRestaurantPhotoCollectionViewCell.swift in Sources */, 395 | ); 396 | runOnlyForDeploymentPostprocessing = 0; 397 | }; 398 | /* End PBXSourcesBuildPhase section */ 399 | 400 | /* Begin PBXTargetDependency section */ 401 | BDB1C46F1DB8A71300253E7A /* PBXTargetDependency */ = { 402 | isa = PBXTargetDependency; 403 | target = BDB1C4631DB8A71200253E7A /* NearbyRestaurantsTodayExtension */; 404 | targetProxy = BDB1C46E1DB8A71300253E7A /* PBXContainerItemProxy */; 405 | }; 406 | BDC4214A1E0BE3DE00F006E3 /* PBXTargetDependency */ = { 407 | isa = PBXTargetDependency; 408 | name = NearbyPlaces; 409 | targetProxy = BDC421491E0BE3DE00F006E3 /* PBXContainerItemProxy */; 410 | }; 411 | /* End PBXTargetDependency section */ 412 | 413 | /* Begin PBXVariantGroup section */ 414 | BDB1C46A1DB8A71300253E7A /* MainInterface.storyboard */ = { 415 | isa = PBXVariantGroup; 416 | children = ( 417 | BDB1C46B1DB8A71300253E7A /* Base */, 418 | ); 419 | name = MainInterface.storyboard; 420 | sourceTree = ""; 421 | }; 422 | BDFD33D71DBBC16900104198 /* LaunchScreen.storyboard */ = { 423 | isa = PBXVariantGroup; 424 | children = ( 425 | BDFD33D81DBBC16900104198 /* Base */, 426 | ); 427 | name = LaunchScreen.storyboard; 428 | sourceTree = ""; 429 | }; 430 | /* End PBXVariantGroup section */ 431 | 432 | /* Begin XCBuildConfiguration section */ 433 | BDB1C4711DB8A71300253E7A /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | CLANG_ENABLE_MODULES = YES; 437 | CODE_SIGN_ENTITLEMENTS = NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension.entitlements; 438 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 439 | FRAMEWORK_SEARCH_PATHS = ( 440 | "$(inherited)", 441 | "$(PROJECT_DIR)", 442 | ); 443 | INFOPLIST_FILE = NearbyRestaurantsTodayExtension/Info.plist; 444 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 445 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 446 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyRestaurantsSample.NearbyRestaurantsTodayExtension; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | PROVISIONING_PROFILE = "c7b27e9b-bd76-4a39-bc1c-ef57182f77f1"; 449 | PROVISIONING_PROFILE_SPECIFIER = NearbyRestaurantsExtensionDev; 450 | SKIP_INSTALL = YES; 451 | SWIFT_OBJC_BRIDGING_HEADER = "NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension-Bridging-Header.h"; 452 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 453 | SWIFT_VERSION = 3.0; 454 | }; 455 | name = Debug; 456 | }; 457 | BDB1C4721DB8A71300253E7A /* Release */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | CLANG_ENABLE_MODULES = YES; 461 | CODE_SIGN_ENTITLEMENTS = NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension.entitlements; 462 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 463 | FRAMEWORK_SEARCH_PATHS = ( 464 | "$(inherited)", 465 | "$(PROJECT_DIR)", 466 | ); 467 | INFOPLIST_FILE = NearbyRestaurantsTodayExtension/Info.plist; 468 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; 470 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyRestaurantsSample.NearbyRestaurantsTodayExtension; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | PROVISIONING_PROFILE = "c7b27e9b-bd76-4a39-bc1c-ef57182f77f1"; 473 | PROVISIONING_PROFILE_SPECIFIER = NearbyRestaurantsExtensionDev; 474 | SKIP_INSTALL = YES; 475 | SWIFT_OBJC_BRIDGING_HEADER = "NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension-Bridging-Header.h"; 476 | SWIFT_VERSION = 3.0; 477 | }; 478 | name = Release; 479 | }; 480 | BDB85D091DB627A6008F0E1E /* Debug */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | ALWAYS_SEARCH_USER_PATHS = NO; 484 | CLANG_ANALYZER_NONNULL = YES; 485 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 486 | CLANG_CXX_LIBRARY = "libc++"; 487 | CLANG_ENABLE_MODULES = YES; 488 | CLANG_ENABLE_OBJC_ARC = YES; 489 | CLANG_WARN_BOOL_CONVERSION = YES; 490 | CLANG_WARN_CONSTANT_CONVERSION = YES; 491 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 492 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 493 | CLANG_WARN_EMPTY_BODY = YES; 494 | CLANG_WARN_ENUM_CONVERSION = YES; 495 | CLANG_WARN_INFINITE_RECURSION = YES; 496 | CLANG_WARN_INT_CONVERSION = YES; 497 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 498 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 499 | CLANG_WARN_UNREACHABLE_CODE = YES; 500 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 501 | CODE_SIGN_IDENTITY = "iPhone Developer: Dinesh Kumar (J3LPPA9AA4)"; 502 | COPY_PHASE_STRIP = NO; 503 | DEBUG_INFORMATION_FORMAT = dwarf; 504 | ENABLE_STRICT_OBJC_MSGSEND = YES; 505 | ENABLE_TESTABILITY = YES; 506 | GCC_C_LANGUAGE_STANDARD = gnu99; 507 | GCC_DYNAMIC_NO_PIC = NO; 508 | GCC_NO_COMMON_BLOCKS = YES; 509 | GCC_OPTIMIZATION_LEVEL = 0; 510 | GCC_PREPROCESSOR_DEFINITIONS = ( 511 | "DEBUG=1", 512 | "$(inherited)", 513 | ); 514 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 515 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 516 | GCC_WARN_UNDECLARED_SELECTOR = YES; 517 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 518 | GCC_WARN_UNUSED_FUNCTION = YES; 519 | GCC_WARN_UNUSED_VARIABLE = YES; 520 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 521 | MTL_ENABLE_DEBUG_INFO = YES; 522 | ONLY_ACTIVE_ARCH = YES; 523 | PROVISIONING_PROFILE = "59e5dc26-ccc0-44a7-aa40-90a4ddc4c2b1"; 524 | SDKROOT = iphoneos; 525 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 526 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 527 | }; 528 | name = Debug; 529 | }; 530 | BDB85D0A1DB627A6008F0E1E /* Release */ = { 531 | isa = XCBuildConfiguration; 532 | buildSettings = { 533 | ALWAYS_SEARCH_USER_PATHS = NO; 534 | CLANG_ANALYZER_NONNULL = YES; 535 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 536 | CLANG_CXX_LIBRARY = "libc++"; 537 | CLANG_ENABLE_MODULES = YES; 538 | CLANG_ENABLE_OBJC_ARC = YES; 539 | CLANG_WARN_BOOL_CONVERSION = YES; 540 | CLANG_WARN_CONSTANT_CONVERSION = YES; 541 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 542 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 543 | CLANG_WARN_EMPTY_BODY = YES; 544 | CLANG_WARN_ENUM_CONVERSION = YES; 545 | CLANG_WARN_INFINITE_RECURSION = YES; 546 | CLANG_WARN_INT_CONVERSION = YES; 547 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 548 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 549 | CLANG_WARN_UNREACHABLE_CODE = YES; 550 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 551 | CODE_SIGN_IDENTITY = "iPhone Developer: Dinesh Kumar (J3LPPA9AA4)"; 552 | COPY_PHASE_STRIP = NO; 553 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 554 | ENABLE_NS_ASSERTIONS = NO; 555 | ENABLE_STRICT_OBJC_MSGSEND = YES; 556 | GCC_C_LANGUAGE_STANDARD = gnu99; 557 | GCC_NO_COMMON_BLOCKS = YES; 558 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 559 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 560 | GCC_WARN_UNDECLARED_SELECTOR = YES; 561 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 562 | GCC_WARN_UNUSED_FUNCTION = YES; 563 | GCC_WARN_UNUSED_VARIABLE = YES; 564 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 565 | MTL_ENABLE_DEBUG_INFO = NO; 566 | ONLY_ACTIVE_ARCH = YES; 567 | PROVISIONING_PROFILE = "59e5dc26-ccc0-44a7-aa40-90a4ddc4c2b1"; 568 | SDKROOT = iphoneos; 569 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 570 | VALIDATE_PRODUCT = YES; 571 | }; 572 | name = Release; 573 | }; 574 | BDB85D0C1DB627A6008F0E1E /* Debug */ = { 575 | isa = XCBuildConfiguration; 576 | buildSettings = { 577 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 578 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 579 | CLANG_ENABLE_MODULES = YES; 580 | CODE_SIGN_ENTITLEMENTS = NearbyRestaurants/NearbyRestaurants.entitlements; 581 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 582 | FRAMEWORK_SEARCH_PATHS = ( 583 | "$(inherited)", 584 | "$(PROJECT_DIR)/NearbyRestaurants", 585 | "$(PROJECT_DIR)", 586 | ); 587 | INFOPLIST_FILE = NearbyRestaurants/Info.plist; 588 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 589 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 590 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyRestaurantsSample; 591 | PRODUCT_NAME = "$(TARGET_NAME)"; 592 | PROVISIONING_PROFILE = "59e5dc26-ccc0-44a7-aa40-90a4ddc4c2b1"; 593 | PROVISIONING_PROFILE_SPECIFIER = NearbyRestaurantsDev; 594 | SWIFT_OBJC_BRIDGING_HEADER = "NearbyRestaurants/Supporting Files/NearbyRestaurants-Bridging-Header.h"; 595 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 596 | SWIFT_VERSION = 3.0; 597 | }; 598 | name = Debug; 599 | }; 600 | BDB85D0D1DB627A6008F0E1E /* Release */ = { 601 | isa = XCBuildConfiguration; 602 | buildSettings = { 603 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 604 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 605 | CLANG_ENABLE_MODULES = YES; 606 | CODE_SIGN_ENTITLEMENTS = NearbyRestaurants/NearbyRestaurants.entitlements; 607 | DEVELOPMENT_TEAM = Z3QQ492P6Z; 608 | FRAMEWORK_SEARCH_PATHS = ( 609 | "$(inherited)", 610 | "$(PROJECT_DIR)/NearbyRestaurants", 611 | "$(PROJECT_DIR)", 612 | ); 613 | INFOPLIST_FILE = NearbyRestaurants/Info.plist; 614 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 615 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 616 | PRODUCT_BUNDLE_IDENTIFIER = com.infoedge.NearbyRestaurantsSample; 617 | PRODUCT_NAME = "$(TARGET_NAME)"; 618 | PROVISIONING_PROFILE = "59e5dc26-ccc0-44a7-aa40-90a4ddc4c2b1"; 619 | PROVISIONING_PROFILE_SPECIFIER = NearbyRestaurantsDev; 620 | SWIFT_OBJC_BRIDGING_HEADER = "NearbyRestaurants/Supporting Files/NearbyRestaurants-Bridging-Header.h"; 621 | SWIFT_VERSION = 3.0; 622 | }; 623 | name = Release; 624 | }; 625 | /* End XCBuildConfiguration section */ 626 | 627 | /* Begin XCConfigurationList section */ 628 | BDB1C4731DB8A71300253E7A /* Build configuration list for PBXNativeTarget "NearbyRestaurantsTodayExtension" */ = { 629 | isa = XCConfigurationList; 630 | buildConfigurations = ( 631 | BDB1C4711DB8A71300253E7A /* Debug */, 632 | BDB1C4721DB8A71300253E7A /* Release */, 633 | ); 634 | defaultConfigurationIsVisible = 0; 635 | defaultConfigurationName = Release; 636 | }; 637 | BDB85CF41DB627A6008F0E1E /* Build configuration list for PBXProject "NearbyRestaurants" */ = { 638 | isa = XCConfigurationList; 639 | buildConfigurations = ( 640 | BDB85D091DB627A6008F0E1E /* Debug */, 641 | BDB85D0A1DB627A6008F0E1E /* Release */, 642 | ); 643 | defaultConfigurationIsVisible = 0; 644 | defaultConfigurationName = Release; 645 | }; 646 | BDB85D0B1DB627A6008F0E1E /* Build configuration list for PBXNativeTarget "NearbyRestaurants" */ = { 647 | isa = XCConfigurationList; 648 | buildConfigurations = ( 649 | BDB85D0C1DB627A6008F0E1E /* Debug */, 650 | BDB85D0D1DB627A6008F0E1E /* Release */, 651 | ); 652 | defaultConfigurationIsVisible = 0; 653 | defaultConfigurationName = Release; 654 | }; 655 | /* End XCConfigurationList section */ 656 | }; 657 | rootObject = BDB85CF11DB627A6008F0E1E /* Project object */; 658 | } 659 | -------------------------------------------------------------------------------- /NearbyRestaurants.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NearbyRestaurants.xcodeproj/xcuserdata/payalgupta.xcuserdatad/xcschemes/NearbyRestaurants.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 | -------------------------------------------------------------------------------- /NearbyRestaurants.xcodeproj/xcuserdata/payalgupta.xcuserdatad/xcschemes/NearbyRestaurantsTodayExtension.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 70 | 73 | 79 | 80 | 81 | 82 | 88 | 89 | 90 | 91 | 92 | 93 | 100 | 102 | 108 | 109 | 110 | 111 | 113 | 114 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /NearbyRestaurants.xcodeproj/xcuserdata/payalgupta.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | NearbyRestaurants.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | NearbyRestaurantsTodayExtension.xcscheme 13 | 14 | orderHint 15 | 2 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | BDB1C4631DB8A71200253E7A 21 | 22 | primary 23 | 24 | 25 | BDB85CF81DB627A6008F0E1E 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /NearbyRestaurants/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Restaurants 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 | CFBundleURLTypes 22 | 23 | 24 | CFBundleTypeRole 25 | Editor 26 | CFBundleURLSchemes 27 | 28 | NearbyRestaurantsTodayExtension 29 | 30 | 31 | 32 | CFBundleVersion 33 | 1 34 | LSRequiresIPhoneOS 35 | 36 | NSAppTransportSecurity 37 | 38 | NSAllowsArbitraryLoads 39 | 40 | 41 | NSLocationWhenInUseUsageDescription 42 | Unable to detect your current Location. Please Enable Location Services under Privacy Tab. 43 | UILaunchStoryboardName 44 | LaunchScreen 45 | UIMainStoryboardFile 46 | Main 47 | UIRequiredDeviceCapabilities 48 | 49 | armv7 50 | 51 | UISupportedInterfaceOrientations 52 | 53 | UIInterfaceOrientationPortrait 54 | UIInterfaceOrientationLandscapeLeft 55 | UIInterfaceOrientationLandscapeRight 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /NearbyRestaurants/NearbyRestaurants.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.infoedge.NearbyRestaurantsSample 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /NearbyRestaurants/Storyboard/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 | -------------------------------------------------------------------------------- /NearbyRestaurants/Storyboard/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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 78 | 84 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 10/18/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NearbyPlaces 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 19 | { 20 | LocationManager.sharedManager.startUpdatingLocation() 21 | LocationManager.sharedManager.stopUpdatingLocation() 22 | 23 | return true 24 | } 25 | 26 | func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool 27 | { 28 | if url.scheme == "NearbyRestaurantsTodayExtension" 29 | { 30 | if let placeID = url.host 31 | { 32 | let storyboard = UIStoryboard(name: "Main", bundle: nil) 33 | 34 | let detailController : NearbyRestaurantDetailViewController = storyboard.instantiateViewController(withIdentifier: "NearbyRestaurantDetailViewController") as! NearbyRestaurantDetailViewController 35 | detailController.nearbyRestaurantID = placeID 36 | (self.window?.rootViewController as! UINavigationController).pushViewController(detailController, animated: true) 37 | } 38 | } 39 | return true 40 | } 41 | 42 | 43 | func applicationWillResignActive(_ application: UIApplication) { 44 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 45 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 46 | } 47 | 48 | func applicationDidEnterBackground(_ application: UIApplication) { 49 | // 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. 50 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 51 | } 52 | 53 | func applicationWillEnterForeground(_ application: UIApplication) { 54 | // 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. 55 | } 56 | 57 | func applicationDidBecomeActive(_ application: UIApplication) { 58 | // 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. 59 | } 60 | 61 | func applicationWillTerminate(_ application: UIApplication) { 62 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 63 | } 64 | 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-57x57@1x.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "idiom" : "iphone", 53 | "size" : "57x57", 54 | "scale" : "2x" 55 | }, 56 | { 57 | "size" : "60x60", 58 | "idiom" : "iphone", 59 | "filename" : "Icon-App-60x60@2x.png", 60 | "scale" : "2x" 61 | }, 62 | { 63 | "size" : "60x60", 64 | "idiom" : "iphone", 65 | "filename" : "Icon-App-60x60@3x.png", 66 | "scale" : "3x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/GalleryPlaceholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "gallery_placeholder@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 | } -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/GalleryPlaceholder.imageset/gallery_placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/GalleryPlaceholder.imageset/gallery_placeholder@2x.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/RestaurantIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "restaurant-icon-png-plate-1.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Assets.xcassets/RestaurantIcon.imageset/restaurant-icon-png-plate-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/NearbyRestaurants/Supporting Files/Assets.xcassets/RestaurantIcon.imageset/restaurant-icon-png-plate-1.png -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/Cacher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cacher.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 12/22/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Cacher: NSObject 12 | { 13 | //MARK: - Removing all cachhed file by NNCacher 14 | static func resetCache() 15 | { 16 | do 17 | { 18 | _ = try FileManager.default.removeItem(at: URL(fileURLWithPath: self.cacheDirectory().absoluteString)) 19 | } 20 | catch let error as NSError 21 | { 22 | print(error.description) 23 | } 24 | } 25 | 26 | //MARK: Creating direcory for caching 27 | // returning URL of caching directory path 28 | static private func cacheDirectory() -> URL 29 | { 30 | var cacheURL = URL(string: NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first!) 31 | cacheURL?.appendPathComponent("Caches", isDirectory: true) 32 | let cacheDirectory: String! = cacheURL?.absoluteString 33 | var isDir : ObjCBool = false 34 | if !(FileManager.default.fileExists(atPath: cacheDirectory, isDirectory: &isDir)) 35 | { 36 | try? FileManager.default.createDirectory(atPath: cacheDirectory, withIntermediateDirectories: false, attributes: nil) 37 | } 38 | return cacheURL! 39 | } 40 | 41 | //MARK: Reading data from caching directory 42 | // returning data for Key(String) from caching directory path 43 | static func cachedDataforKey(_ key:String) -> Data? 44 | { 45 | let url = self.cacheDirectory().appendingPathComponent(self.cachedFileNameForKey(key)) 46 | let filePath = url.absoluteString 47 | let fileURL = URL(fileURLWithPath: filePath) 48 | if FileManager.default.fileExists(atPath: filePath) 49 | { 50 | return try? Data(contentsOf: fileURL) 51 | } 52 | return nil 53 | } 54 | 55 | //MARK: Caching data for key in caching directory 56 | static func cacheData(_ data: Data, forKey key:String) 57 | { 58 | let url = self.cacheDirectory().appendingPathComponent(self.cachedFileNameForKey(key)) 59 | let fileURL = URL(fileURLWithPath: url.absoluteString) 60 | do 61 | { 62 | _ = try data.write(to: fileURL, options: .atomic) 63 | } 64 | catch let error as NSError 65 | { 66 | print(error.description) 67 | } 68 | } 69 | 70 | //MARK: Generating Unique hash for key for file name 71 | static private func cachedFileNameForKey(_ key: String) -> String 72 | { 73 | guard let messageData = key.data(using:String.Encoding.utf8) else 74 | { 75 | return key 76 | } 77 | let digestLen = Int(CC_MD5_DIGEST_LENGTH) 78 | var digestData = Data(count: digestLen) 79 | _ = digestData.withUnsafeMutableBytes {digestBytes in 80 | messageData.withUnsafeBytes {messageBytes in 81 | CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes) 82 | } 83 | } 84 | let hash = NSMutableString() 85 | for i in 0.. CLLocation? 26 | { 27 | self.startUpdatingLocation() 28 | return self.locationManager.location 29 | } 30 | 31 | public func stopUpdatingLocation() 32 | { 33 | self.locationManager.stopUpdatingLocation() 34 | } 35 | 36 | public func startUpdatingLocation() 37 | { 38 | self.locationManager.startUpdatingLocation() 39 | } 40 | } 41 | 42 | // MARK: - CLLocationManagerDelegate Methods 43 | extension LocationManager : CLLocationManagerDelegate 44 | { 45 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 46 | { 47 | if CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .restricted 48 | { 49 | //Show Alert 50 | } 51 | } 52 | 53 | public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) 54 | { 55 | //Show Alert 56 | } 57 | 58 | public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) 59 | { 60 | //Show Alert 61 | self.stopUpdatingLocation() 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/NearbyPlaceDetail.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyPlaceDetail.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 12/22/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import NearbyPlaces 11 | import CoreLocation 12 | 13 | public class NearbyPlaceDetail : NearbyPlaceEntity 14 | { 15 | //MARK: Internal Properties 16 | public var completeAddress : String? 17 | public var phoneNumber : String? 18 | public var openNow : Bool 19 | public var permanentlyClosed : Bool 20 | public var weekDayText : [String]? 21 | public var photosIDs : [String]? 22 | public var googlePageURL : String? 23 | public var websiteURL : String? 24 | public var rating : Double? 25 | 26 | //MARK: Initializer 27 | override init?(jsonDictionary : [String : AnyObject]) 28 | { 29 | self.completeAddress = jsonDictionary["formatted_address"] as? String 30 | self.phoneNumber = jsonDictionary["formatted_phone_number"] as? String 31 | if let openingHours = jsonDictionary["opening_hours"] as? [String : AnyObject] 32 | { 33 | if let openNow = openingHours["open_now"] as? Bool 34 | { 35 | self.openNow = openNow 36 | } 37 | else 38 | { 39 | self.openNow = false 40 | } 41 | self.weekDayText = openingHours["weekday_text"] as? [String] 42 | } 43 | else 44 | { 45 | self.openNow = false 46 | } 47 | self.permanentlyClosed = (jsonDictionary["permanently_closed"] as? Bool) ?? false 48 | if let photosArray = jsonDictionary["photos"] as? [[String : AnyObject]], photosArray.count > 0 49 | { 50 | self.photosIDs = [String]() 51 | for photo in photosArray 52 | { 53 | self.photosIDs?.addObject(photo["photo_reference"] as? String) 54 | } 55 | } 56 | self.googlePageURL = jsonDictionary["url"] as? String 57 | self.websiteURL = jsonDictionary["website"] as? String 58 | self.rating = jsonDictionary["rating"] as? Double 59 | super.init(jsonDictionary: jsonDictionary) 60 | } 61 | 62 | required public init?(coder aDecoder: NSCoder) { 63 | fatalError("init(coder:) has not been implemented") 64 | } 65 | 66 | //MARK: Type Methods 67 | /** 68 | Google Nearby Places API hit 69 | 70 | - parameter coordinate: property coordinate for which we need to find nearby places 71 | - parameter radius: radius around property within which to find nearby places 72 | - parameter amenityType: type of nearby place - railway, atm, airport etc. 73 | - parameter completionHandler: handler after receiving response 74 | */ 75 | public static func fetchNearByGooglePlacesForCoordinate(_ coordinate : CLLocationCoordinate2D, inRadius radius : Int, forAmenityType amenityType : String, withCompletionHandler completionHandler : ((Any?,NSError?)->Void)?) 76 | { 77 | let urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(coordinate.latitude),\(coordinate.longitude)&radius=\(radius)&types=\(amenityType)&sensor=false&key=\(kGoogleAPIKey)" 78 | 79 | let task = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) in 80 | 81 | if error != nil 82 | { 83 | DispatchQueue.main.async(execute: { 84 | if let handler = completionHandler 85 | { 86 | handler(nil, error as NSError?) 87 | } 88 | }) 89 | } 90 | else 91 | { 92 | if let data = data 93 | { 94 | do 95 | { 96 | if let responseObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String : AnyObject], let resultsArray = responseObject["results"] as? [[String : AnyObject]] , resultsArray.count > 0 97 | { 98 | var nearbyPlacesArray = [NearbyPlaceEntity]() 99 | for dict in resultsArray 100 | { 101 | nearbyPlacesArray.addObject(NearbyPlaceEntity(jsonDictionary: dict)) 102 | } 103 | if nearbyPlacesArray.count > 0 104 | { 105 | DispatchQueue.main.async(execute: { 106 | if let handler = completionHandler 107 | { 108 | handler(nearbyPlacesArray, nil) 109 | } 110 | }) 111 | } 112 | else 113 | { 114 | DispatchQueue.main.async(execute: { 115 | if let handler = completionHandler 116 | { 117 | handler(nil, nil) 118 | } 119 | }) 120 | } 121 | } 122 | else 123 | { 124 | DispatchQueue.main.async(execute: { 125 | if let handler = completionHandler 126 | { 127 | handler(nil, nil) 128 | } 129 | }) 130 | } 131 | } 132 | catch 133 | { 134 | 135 | } 136 | } 137 | else 138 | { 139 | DispatchQueue.main.async(execute: { 140 | if let handler = completionHandler 141 | { 142 | handler(nil, nil) 143 | } 144 | }) 145 | } 146 | } 147 | }) 148 | task.resume() 149 | } 150 | 151 | /** 152 | Google Place Detail API hit 153 | 154 | - parameter placeID: ID of the place for which to fetch details 155 | - parameter nearbyPlaceObject: NearbyPlaceDetail type object 156 | - parameter completionHandler: handler after receiving response 157 | */ 158 | public static func fetchNearByPlaceDetailForPlaceID(_ placeID : String, withCompletionHandler completionHandler : ((Any?,NSError?)->Void)?) 159 | { 160 | let urlString = "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(placeID)&key=\(kGoogleAPIKey)" 161 | 162 | let task = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) in 163 | 164 | if error != nil 165 | { 166 | DispatchQueue.main.async(execute: { 167 | if let handler = completionHandler 168 | { 169 | handler(nil, error as NSError?) 170 | } 171 | }) 172 | } 173 | else 174 | { 175 | if let data = data 176 | { 177 | do 178 | { 179 | if let responseObject = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String : AnyObject], let resultDict = responseObject["result"] as? [String : AnyObject] 180 | { 181 | let nearbyPlaceDetailObject = NearbyPlaceDetail(jsonDictionary: resultDict) 182 | if nearbyPlaceDetailObject != nil 183 | { 184 | DispatchQueue.main.async(execute: { 185 | if let handler = completionHandler 186 | { 187 | handler(nearbyPlaceDetailObject, nil) 188 | } 189 | }) 190 | } 191 | else 192 | { 193 | DispatchQueue.main.async(execute: { 194 | if let handler = completionHandler 195 | { 196 | handler(nil, nil) 197 | } 198 | }) 199 | } 200 | } 201 | else 202 | { 203 | DispatchQueue.main.async(execute: { 204 | if let handler = completionHandler 205 | { 206 | handler(nil, nil) 207 | } 208 | }) 209 | } 210 | } 211 | catch 212 | { 213 | 214 | } 215 | } 216 | else 217 | { 218 | DispatchQueue.main.async(execute: { 219 | if let handler = completionHandler 220 | { 221 | handler(nil, nil) 222 | } 223 | }) 224 | } 225 | } 226 | }) 227 | task.resume() 228 | } 229 | } 230 | 231 | extension Array 232 | { 233 | /** 234 | Method to add elements in Array. We cannot add optionals in an Array. So to avoid "if let" checking while adding optional values in Array, this method can be used. 235 | If the optional is nil, no element added 236 | If the optional has some value, it is unwrapped and added 237 | 238 | -warning: Can only be used with Optional Values 239 | 240 | - parameter value: Optional value to be added 241 | */ 242 | mutating func addObject(_ value : Element?) 243 | { 244 | if let object = value 245 | { 246 | self.append(object) 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /NearbyRestaurants/Supporting Files/NearbyRestaurants-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /NearbyRestaurants/UITableViewCell/NearbyPlaceTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyPlaceTableViewCell.swift 3 | // NearbyPlaces 4 | // 5 | // Created by Payal Gupta on 10/18/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class NearbyPlaceTableViewCell: UITableViewCell 12 | { 13 | //MARK: Outlets 14 | @IBOutlet public weak var iconImageView: UIImageView! 15 | @IBOutlet public weak var addressLabel: UILabel! 16 | @IBOutlet public weak var nameLabel: UILabel! 17 | 18 | //MARK: View Lifecycle Methods 19 | override public func awakeFromNib() 20 | { 21 | super.awakeFromNib() 22 | self.iconImageView.image = UIImage(named: "RestaurantIcon") 23 | self.nameLabel.text = nil 24 | self.addressLabel.text = nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /NearbyRestaurants/UITableViewCell/NearbyPlaceTableViewCell.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 | 29 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /NearbyRestaurants/UITableViewCell/NearbyRestaurantPhotoCollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyRestaurantPhotoCollectionViewCell.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 10/19/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NearbyRestaurantPhotoCollectionViewCell: UICollectionViewCell 12 | { 13 | //MARK: Outlets 14 | @IBOutlet weak var photoImageView: UIImageView! 15 | 16 | //MARK: View Lifecycle Methods 17 | override func awakeFromNib() 18 | { 19 | super.awakeFromNib() 20 | self.photoImageView.image = #imageLiteral(resourceName: "GalleryPlaceholder") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /NearbyRestaurants/View Controllers/NearbyRestaurantDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyRestaurantDetailViewController.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 10/19/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NearbyPlaces 11 | 12 | class NearbyRestaurantDetailViewController: UIViewController 13 | { 14 | //MARK: Outlets 15 | @IBOutlet weak var photosCollectionView: UICollectionView! 16 | @IBOutlet weak var name: UILabel! 17 | @IBOutlet weak var address: UILabel! 18 | @IBOutlet weak var contact: UILabel! 19 | @IBOutlet weak var openOrClosed: UILabel! 20 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView! 21 | 22 | //MARK: Private Properties 23 | fileprivate let kCellSpacing : CGFloat = 5 24 | fileprivate let kCellInset : CGFloat = 15 25 | fileprivate var nearbyRestaurantDetail : NearbyPlaceDetail? 26 | 27 | 28 | //MARK: Internal Properties 29 | var nearbyRestaurantID : String? 30 | 31 | //MARK: View Lifecycle Methods 32 | override func viewDidLoad() 33 | { 34 | super.viewDidLoad() 35 | 36 | self.name.text = nil 37 | self.address.text = nil 38 | self.contact.text = nil 39 | self.openOrClosed.isHidden = true 40 | self.photosCollectionView.isHidden = true 41 | 42 | self.loadDataFromServer() 43 | } 44 | 45 | /// This Method sends the Google Place Detail API hit and the response is then saved in "self.nearbyPlaceDetailObject" and reloads the table view 46 | fileprivate func loadDataFromServer() 47 | { 48 | self.activityIndicator.startAnimating() 49 | NearbyPlaceDetail.fetchNearByPlaceDetailForPlaceID(self.nearbyRestaurantID!) { (responseObject, error) in 50 | self.activityIndicator.stopAnimating() 51 | guard let nearbyRestaurantDetail = responseObject as? NearbyPlaceDetail else 52 | { 53 | if error != nil 54 | { 55 | let alert = UIAlertView.init(title: "Alert", message: (error?.localizedDescription)!, delegate: nil, cancelButtonTitle: "OK") 56 | alert.show() 57 | } 58 | 59 | return 60 | } 61 | self.nearbyRestaurantDetail = nearbyRestaurantDetail 62 | self.photosCollectionView.isHidden = false 63 | self.openOrClosed.isHidden = false 64 | self.photosCollectionView.reloadData() 65 | self.updateRestaurantDetails() 66 | } 67 | } 68 | 69 | private func updateRestaurantDetails() 70 | { 71 | self.name.text = nearbyRestaurantDetail?.name 72 | self.address.text = nearbyRestaurantDetail?.completeAddress 73 | if let contact = nearbyRestaurantDetail?.phoneNumber 74 | { 75 | self.contact.text = "Contact : \(contact)" 76 | } 77 | if (nearbyRestaurantDetail?.permanentlyClosed)! 78 | { 79 | self.openOrClosed.text = "Permanently Closed" 80 | } 81 | else 82 | { 83 | if (nearbyRestaurantDetail?.openNow)! 84 | { 85 | self.openOrClosed.text = "Open Now" 86 | } 87 | else 88 | { 89 | self.openOrClosed.text = "Closed Now" 90 | } 91 | } 92 | } 93 | } 94 | 95 | // MARK: - UICollectionViewDataSource Methods 96 | extension NearbyRestaurantDetailViewController : UICollectionViewDataSource, UICollectionViewDelegate 97 | { 98 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 99 | { 100 | return self.nearbyRestaurantDetail?.photosIDs?.count ?? 1 101 | } 102 | 103 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 104 | { 105 | let cell = self.photosCollectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! NearbyRestaurantPhotoCollectionViewCell 106 | 107 | if let photosIDs = self.nearbyRestaurantDetail?.photosIDs 108 | { 109 | let photoID = photosIDs[indexPath.row] 110 | let urlString = "https://maps.googleapis.com/maps/api/place/photo?maxwidth=\(Int(UIScreen.main.bounds.width))&photoreference=\(photoID)&key=AIzaSyA-80bYgdT6jJdi-K7SQQ4gqkHms3t4jP4" 111 | 112 | if let url = URL(string: urlString) 113 | { 114 | let urlRequest = URLRequest(url: url) 115 | NSURLConnection.sendAsynchronousRequest(urlRequest, queue: OperationQueue.main, completionHandler: {(response, data, error) in 116 | if let data = data 117 | { 118 | let image = UIImage(data: data) 119 | cell.photoImageView.image = image 120 | } 121 | else 122 | { 123 | cell.photoImageView.image = #imageLiteral(resourceName: "GalleryPlaceholder") 124 | } 125 | }) 126 | } 127 | } 128 | else 129 | { 130 | cell.photoImageView.image = #imageLiteral(resourceName: "GalleryPlaceholder") 131 | } 132 | return cell 133 | } 134 | } 135 | 136 | // MARK: - UICollectionViewDelegateFlowLayout Methods 137 | extension NearbyRestaurantDetailViewController : UICollectionViewDelegateFlowLayout 138 | { 139 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 140 | { 141 | let cellSize = CGSize(width: self.photosCollectionView.bounds.width - (2 * kCellSpacing) - (2 * kCellInset) , height: self.photosCollectionView.bounds.height) 142 | return cellSize 143 | } 144 | 145 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 146 | { 147 | return kCellSpacing 148 | } 149 | 150 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets 151 | { 152 | let sectionInset = UIEdgeInsetsMake(0, kCellSpacing + kCellInset, 0, kCellSpacing + kCellInset) 153 | return sectionInset 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /NearbyRestaurants/View Controllers/NearbyRestaurantsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NearbyRestaurantsViewController.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 10/18/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NearbyPlaces 11 | import CoreLocation 12 | import NotificationCenter 13 | 14 | class NearbyRestaurantsViewController: UIViewController 15 | { 16 | //MARK: Private Properties 17 | fileprivate var nearbyRestaurantsArray = [NearbyPlaceEntity]() 18 | fileprivate var currentLocation : CLLocation? 19 | private let kAppGroupName = "group.com.infoedge.NearbyRestaurantsSample" 20 | private var sharedContainer : UserDefaults? 21 | fileprivate lazy var totalCountAllowed : Int = { 22 | switch UIScreen.main.bounds.height 23 | { 24 | case 480: return 3 25 | case 568 : return 4 26 | case 667 : return 5 27 | case 736 : return 5 28 | default : return 3 29 | } 30 | }() 31 | 32 | //MARK: Outlets 33 | @IBOutlet weak var tableView: UITableView! 34 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView! 35 | 36 | //MARK: View Lifecycle Methods 37 | override func viewDidLoad() 38 | { 39 | super.viewDidLoad() 40 | LocationManager.sharedManager.locationManager.delegate = self 41 | self.sharedContainer = UserDefaults(suiteName: kAppGroupName) 42 | self.tableView.register(UINib(nibName: "NearbyPlaceTableViewCell", bundle: nil), forCellReuseIdentifier: "nearbyPlace") 43 | self.tableView.estimatedRowHeight = 104 44 | self.tableView.rowHeight = UITableViewAutomaticDimension 45 | 46 | //--------------------------------------------------------------------------// 47 | ////Uncomment this if you want to hide widget when no data is available to show in the widget//////// 48 | // if self.fetchDataFromSharedContainer() == nil 49 | // { 50 | // DispatchQueue.main.async(execute: { 51 | // NCWidgetController.widgetController().setHasContent(false, forWidgetWithBundleIdentifier: "com.infoedge.NearbyRestaurantsSample.NearbyRestaurantsTodayExtension") 52 | // }) 53 | // } 54 | //--------------------------------------------------------------------------// 55 | } 56 | 57 | //MARK: Private Methods 58 | /// This Method sends the Google Places API hit and the response is then saved in "self.nearbyRestaurantsArray" and reloads the table view 59 | fileprivate func loadDataFromServer() 60 | { 61 | if let currentLocation = self.currentLocation 62 | { 63 | self.activityIndicator.startAnimating() 64 | NearbyPlaceDetail.fetchNearByGooglePlacesForCoordinate(currentLocation.coordinate, inRadius: 500, forAmenityType: "restaurant") {[weak self] (responseObject, error) in 65 | self?.activityIndicator.stopAnimating() 66 | guard let nearbyRestaurantsArray = responseObject as? [NearbyPlaceEntity] else 67 | { 68 | if error != nil 69 | { 70 | let alert = UIAlertView.init(title: "Alert", message: (error?.localizedDescription)!, delegate: nil, cancelButtonTitle: "OK") 71 | alert.show() 72 | } 73 | 74 | return 75 | } 76 | self?.nearbyRestaurantsArray = nearbyRestaurantsArray 77 | self?.tableView.reloadData() 78 | } 79 | } 80 | } 81 | 82 | /// This method fetches the data to be displayed in widget from shared container. 83 | fileprivate func fetchDataFromSharedContainer() -> [Any]? 84 | { 85 | if let sharedContainer = self.sharedContainer 86 | { 87 | let dataArray = sharedContainer.array(forKey: "NearbyRestaurantsArray") 88 | return dataArray 89 | } 90 | return nil 91 | } 92 | 93 | /// This method save the selected restaurant info "NearbyPlaceEntity" to the shared container 94 | /// 95 | /// - parameter nearbyPlaceEntity: NearbyPlaceEntity object corresponding to the selected object. 96 | fileprivate func saveDataToSharedContainer(nearbyPlaceEntity : NearbyPlaceEntity) 97 | { 98 | if let sharedContainer = self.sharedContainer 99 | { 100 | var dataArray = self.fetchDataFromSharedContainer() 101 | if dataArray == nil 102 | { 103 | dataArray = [Any]() 104 | //--------------------------------------------------------------------------// 105 | ////Uncomment this if you want to show widget when data is available to show in the widget//////// 106 | // DispatchQueue.main.async(execute: { 107 | // NCWidgetController.widgetController().setHasContent(true, forWidgetWithBundleIdentifier: "com.infoedge.NearbyRestaurantsSample.NearbyRestaurantsTodayExtension") 108 | // }) 109 | //--------------------------------------------------------------------------// 110 | } 111 | else 112 | { 113 | for data in dataArray! 114 | { 115 | let placeEntity = NSKeyedUnarchiver.unarchiveObject(with: data as! Data) as! NearbyPlaceEntity 116 | if placeEntity.placeID == nearbyPlaceEntity.placeID 117 | { 118 | return 119 | } 120 | } 121 | if dataArray!.count == self.totalCountAllowed 122 | { 123 | dataArray!.removeFirst() 124 | } 125 | } 126 | dataArray!.append(NSKeyedArchiver.archivedData(withRootObject: nearbyPlaceEntity)) 127 | sharedContainer.set(true, forKey: "UpdateRequired") 128 | sharedContainer.set(dataArray, forKey: "NearbyRestaurantsArray") 129 | sharedContainer.synchronize() 130 | } 131 | } 132 | 133 | //MARK: Button Action Methods 134 | @IBAction func refreshResults(_ sender: UIBarButtonItem?) 135 | { 136 | self.currentLocation = LocationManager.sharedManager.currentLocation() 137 | self.loadDataFromServer() 138 | } 139 | } 140 | 141 | // MARK: - UITableViewDataSource Methods 142 | extension NearbyRestaurantsViewController : UITableViewDataSource, UITableViewDelegate 143 | { 144 | ///UITableViewDataSource Methods 145 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 146 | { 147 | return self.nearbyRestaurantsArray.count 148 | } 149 | 150 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 151 | { 152 | let cell = tableView.dequeueReusableCell(withIdentifier: "nearbyPlace", for: indexPath) as! NearbyPlaceTableViewCell 153 | 154 | cell.nameLabel.text = self.nearbyRestaurantsArray[indexPath.row].name 155 | cell.addressLabel.text = self.nearbyRestaurantsArray[indexPath.row].address 156 | 157 | if let urlString = self.nearbyRestaurantsArray[indexPath.row].icon 158 | { 159 | if let cachedFileData = Cacher.cachedDataforKey(urlString) 160 | { 161 | let image = UIImage(data: cachedFileData) 162 | cell.iconImageView.image = image 163 | } 164 | else 165 | { 166 | if let url = URL(string: urlString) 167 | { 168 | let urlRequest = URLRequest(url: url) 169 | NSURLConnection.sendAsynchronousRequest(urlRequest, queue: OperationQueue.main, completionHandler: {(response, data, error) in 170 | if let imageData = data, let builderLogoImage = UIImage(data: imageData) 171 | { 172 | Cacher.cacheData(imageData, forKey: urlString) 173 | cell.iconImageView.image = builderLogoImage 174 | } 175 | else 176 | { 177 | cell.iconImageView.image = #imageLiteral(resourceName: "RestaurantIcon") 178 | } 179 | }) 180 | } 181 | else 182 | { 183 | cell.iconImageView.image = #imageLiteral(resourceName: "RestaurantIcon") 184 | } 185 | } 186 | } 187 | else 188 | { 189 | cell.iconImageView.image = #imageLiteral(resourceName: "RestaurantIcon") 190 | } 191 | return cell 192 | } 193 | 194 | ///UITableViewDelegate Methods 195 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 196 | { 197 | self.saveDataToSharedContainer(nearbyPlaceEntity: self.nearbyRestaurantsArray[indexPath.row]) 198 | let detailController : NearbyRestaurantDetailViewController = self.storyboard?.instantiateViewController(withIdentifier: "NearbyRestaurantDetailViewController") as! NearbyRestaurantDetailViewController 199 | detailController.nearbyRestaurantID = self.nearbyRestaurantsArray[indexPath.row].placeID 200 | self.navigationController?.pushViewController(detailController, animated: true) 201 | } 202 | } 203 | 204 | // MARK: - CLLocationManagerDelegate Methods 205 | extension NearbyRestaurantsViewController : CLLocationManagerDelegate 206 | { 207 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 208 | { 209 | switch status 210 | { 211 | case .authorizedWhenInUse: 212 | self.refreshResults(nil) 213 | case .denied, .restricted: 214 | print("Your app is not permitted to use location services. Change your app settings if you want to use location services.") 215 | default: 216 | break 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /NearbyRestaurantsTodayExtension/Cacher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Cacher.swift 3 | // NearbyRestaurants 4 | // 5 | // Created by Payal Gupta on 12/22/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Cacher: NSObject 12 | { 13 | //MARK: - Removing all cachhed file by NNCacher 14 | static func resetCache() 15 | { 16 | do 17 | { 18 | _ = try FileManager.default.removeItem(at: URL(fileURLWithPath: self.cacheDirectory().absoluteString)) 19 | } 20 | catch let error as NSError 21 | { 22 | print(error.description) 23 | } 24 | } 25 | 26 | //MARK: Creating direcory for caching 27 | // returning URL of caching directory path 28 | static private func cacheDirectory() -> URL 29 | { 30 | var cacheURL = URL(string: NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first!) 31 | cacheURL?.appendPathComponent("Caches", isDirectory: true) 32 | let cacheDirectory: String! = cacheURL?.absoluteString 33 | var isDir : ObjCBool = false 34 | if !(FileManager.default.fileExists(atPath: cacheDirectory, isDirectory: &isDir)) 35 | { 36 | try? FileManager.default.createDirectory(atPath: cacheDirectory, withIntermediateDirectories: false, attributes: nil) 37 | } 38 | return cacheURL! 39 | } 40 | 41 | //MARK: Reading data from caching directory 42 | // returning data for Key(String) from caching directory path 43 | static func cachedDataforKey(_ key:String) -> Data? 44 | { 45 | let url = self.cacheDirectory().appendingPathComponent(self.cachedFileNameForKey(key)) 46 | let filePath = url.absoluteString 47 | let fileURL = URL(fileURLWithPath: filePath) 48 | if FileManager.default.fileExists(atPath: filePath) 49 | { 50 | return try? Data(contentsOf: fileURL) 51 | } 52 | return nil 53 | } 54 | 55 | //MARK: Caching data for key in caching directory 56 | static func cacheData(_ data: Data, forKey key:String) 57 | { 58 | let url = self.cacheDirectory().appendingPathComponent(self.cachedFileNameForKey(key)) 59 | let fileURL = URL(fileURLWithPath: url.absoluteString) 60 | do 61 | { 62 | _ = try data.write(to: fileURL, options: .atomic) 63 | } 64 | catch let error as NSError 65 | { 66 | print(error.description) 67 | } 68 | } 69 | 70 | //MARK: Generating Unique hash for key for file name 71 | static private func cachedFileNameForKey(_ key: String) -> String 72 | { 73 | guard let messageData = key.data(using:String.Encoding.utf8) else 74 | { 75 | return key 76 | } 77 | let digestLen = Int(CC_MD5_DIGEST_LENGTH) 78 | var digestData = Data(count: digestLen) 79 | _ = digestData.withUnsafeMutableBytes {digestBytes in 80 | messageData.withUnsafeBytes {messageBytes in 81 | CC_MD5(messageBytes, CC_LONG(messageData.count), digestBytes) 82 | } 83 | } 84 | let hash = NSMutableString() 85 | for i in 0.. 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Nearby Restaurants 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionMainStoryboard 26 | MainInterface 27 | NSExtensionPointIdentifier 28 | com.apple.widget-extension 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | -------------------------------------------------------------------------------- /NearbyRestaurantsTodayExtension/NearbyRestaurantsTodayExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.com.infoedge.NearbyRestaurantsSample 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /NearbyRestaurantsTodayExtension/TodayViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TodayViewController.swift 3 | // NearbyRestaurantsTodayExtension 4 | // 5 | // Created by Payal Gupta on 10/20/16. 6 | // Copyright © 2016 Infoedge Pvt. Ltd. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NotificationCenter 11 | import NearbyPlaces 12 | 13 | class TodayViewController: UIViewController 14 | { 15 | //MARK: Outlets 16 | @IBOutlet weak var tableView: UITableView! 17 | @IBOutlet weak var showMoreButton: UIButton! //For iOS-8 and iOS-9 18 | 19 | //MARK: Private Properties 20 | fileprivate let kCellHeight : CGFloat = 90.0 21 | fileprivate var nearbyRestaurantsArray = [NearbyPlaceEntity]() 22 | private let kAppGroupName = "group.com.infoedge.NearbyRestaurantsSample" 23 | private var sharedContainer : UserDefaults? 24 | private var tableViewHeightConstraint : NSLayoutConstraint? 25 | 26 | //MARK: View Lifecycle Methods 27 | override func viewDidLoad() 28 | { 29 | super.viewDidLoad() 30 | self.sharedContainer = UserDefaults(suiteName: kAppGroupName) 31 | self.fetchDataFromSharedContainer() 32 | self.tableView.reloadData() 33 | 34 | if #available(iOSApplicationExtension 10.0, *) 35 | { 36 | //If widgetLargestAvailableDisplayMode is set to .compact, then we won't have Show More/Show Less button 37 | self.extensionContext?.widgetLargestAvailableDisplayMode = .expanded 38 | self.showMoreButton.removeFromSuperview() 39 | } 40 | else 41 | { 42 | self.tableViewHeightConstraint = NSLayoutConstraint(item: self.tableView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: kCellHeight) 43 | let refreshButtonHeightConstraint = NSLayoutConstraint(item: self.showMoreButton, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 44) 44 | NSLayoutConstraint.activate([tableViewHeightConstraint!, refreshButtonHeightConstraint]) 45 | } 46 | } 47 | 48 | //MARK: Private Methods 49 | /// This method fetches the data to be displayed in widget from shared container. 50 | fileprivate func fetchDataFromSharedContainer() 51 | { 52 | if let sharedContainer = self.sharedContainer, let dataArray = sharedContainer.array(forKey: "NearbyRestaurantsArray") 53 | { 54 | self.nearbyRestaurantsArray = [] 55 | for data in dataArray 56 | { 57 | self.nearbyRestaurantsArray.append(NSKeyedUnarchiver.unarchiveObject(with: data as! Data) as! NearbyPlaceEntity) 58 | } 59 | } 60 | } 61 | 62 | /// This method checks if the widget data updation is required. It fetches "UpdateRequired" from shared container and returns it. Also it resets "UpdateRequired" in the shared container. 63 | /// 64 | /// - returns: true, if data updation is required. false, if data updation is not required 65 | fileprivate func isUpdateRequired() -> Bool 66 | { 67 | if let sharedContainer = self.sharedContainer 68 | { 69 | let isUpdateRequired = sharedContainer.bool(forKey: "UpdateRequired") 70 | if isUpdateRequired 71 | { 72 | sharedContainer.set(false, forKey: "UpdateRequired") 73 | sharedContainer.synchronize() 74 | return true 75 | } 76 | } 77 | return false 78 | } 79 | 80 | //MARK: Button Action Methods 81 | //For iOS-8 and iOS-9 82 | @IBAction func showMoreRestaurants(_ sender: UIButton) 83 | { 84 | self.fetchDataFromSharedContainer() 85 | self.tableView.reloadData() 86 | if self.nearbyRestaurantsArray.count <= 1 87 | { 88 | return 89 | } 90 | 91 | if sender.isSelected 92 | { 93 | self.tableViewHeightConstraint?.constant = kCellHeight 94 | sender.isSelected = false 95 | } 96 | else 97 | { 98 | self.tableViewHeightConstraint?.constant = kCellHeight * CGFloat(self.nearbyRestaurantsArray.count) 99 | sender.isSelected = true 100 | } 101 | } 102 | } 103 | 104 | // MARK: - UITableViewDataSource Methods 105 | extension TodayViewController : UITableViewDataSource, UITableViewDelegate 106 | { 107 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 108 | { 109 | if self.nearbyRestaurantsArray.count == 0 110 | { 111 | return 1 112 | } 113 | return self.nearbyRestaurantsArray.count 114 | } 115 | 116 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 117 | { 118 | let cell = self.tableView.dequeueReusableCell(withIdentifier: "nearbyRestaurantCell", for: indexPath) 119 | if #available(iOS 10.0, *) 120 | { 121 | cell.textLabel?.textColor = UIColor.darkGray 122 | cell.detailTextLabel?.textColor = UIColor.darkGray 123 | } 124 | else 125 | { 126 | cell.textLabel?.textColor = UIColor.lightGray 127 | cell.detailTextLabel?.textColor = UIColor.lightGray 128 | } 129 | cell.textLabel?.text = (self.nearbyRestaurantsArray.count == 0) ? nil : self.nearbyRestaurantsArray[indexPath.row].name 130 | cell.detailTextLabel?.text = (self.nearbyRestaurantsArray.count == 0) ? "No recently viewed restaurants. Tap and open the app to view nearby restaurant." : self.nearbyRestaurantsArray[indexPath.row].address 131 | if self.nearbyRestaurantsArray.count == 0 132 | { 133 | cell.imageView?.image = nil 134 | } 135 | else 136 | { 137 | if let urlString = self.nearbyRestaurantsArray[indexPath.row].icon 138 | { 139 | if let cachedFileData = Cacher.cachedDataforKey(urlString) 140 | { 141 | let image = UIImage(data: cachedFileData) 142 | cell.imageView?.image = image 143 | } 144 | else 145 | { 146 | if let url = URL(string: urlString) 147 | { 148 | let urlRequest = URLRequest(url: url) 149 | NSURLConnection.sendAsynchronousRequest(urlRequest, queue: OperationQueue.main, completionHandler: {(response, data, error) in 150 | if let imageData = data, let builderLogoImage = UIImage(data: imageData) 151 | { 152 | Cacher.cacheData(imageData, forKey: urlString) 153 | cell.imageView?.image = builderLogoImage 154 | } 155 | else 156 | { 157 | cell.imageView?.image = #imageLiteral(resourceName: "RestaurantIcon") 158 | } 159 | }) 160 | } 161 | else 162 | { 163 | cell.imageView?.image = #imageLiteral(resourceName: "RestaurantIcon") 164 | } 165 | } 166 | } 167 | else 168 | { 169 | cell.imageView?.image = #imageLiteral(resourceName: "RestaurantIcon") 170 | } 171 | } 172 | return cell 173 | } 174 | 175 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 176 | { 177 | self.tableView.cellForRow(at: indexPath)?.isSelected = false 178 | self.extensionContext?.open(URL(string: "NearbyRestaurantsTodayExtension://\((self.nearbyRestaurantsArray.count == 0) ? "" : self.nearbyRestaurantsArray[indexPath.row].placeID)")!, completionHandler: nil) 179 | } 180 | } 181 | 182 | // MARK: - NCWidgetProviding Methods 183 | extension TodayViewController : NCWidgetProviding 184 | { 185 | //For iOS-8 and iOS-9 186 | func widgetMarginInsets(forProposedMarginInsets defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets 187 | { 188 | return UIEdgeInsets.zero 189 | } 190 | 191 | func widgetPerformUpdate(completionHandler: @escaping (NCUpdateResult) -> Swift.Void) 192 | { 193 | if self.isUpdateRequired() 194 | { 195 | self.fetchDataFromSharedContainer() 196 | self.tableView.reloadData() 197 | completionHandler(NCUpdateResult.newData) 198 | } 199 | else 200 | { 201 | completionHandler(NCUpdateResult.noData) 202 | } 203 | } 204 | 205 | @available(iOSApplicationExtension 10.0, *) 206 | //Minimum height of widget in iOS-10 is 110 i.e, for compact display mode 207 | func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) 208 | { 209 | if activeDisplayMode == .expanded 210 | { 211 | preferredContentSize = CGSize(width: 0.0, height: kCellHeight * CGFloat(self.nearbyRestaurantsArray.count)) 212 | } 213 | else 214 | { 215 | preferredContentSize = maxSize 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Today-Widget 2 | 3 | 1. Today-Widget describes how to implement Today's App Extension (Widget) in your app. 4 | 5 | 2. Some new updations are added to widget APIs in iOS 10. So, this project includes implementation details for both (iOS 10) and (iOS 8 or iOS 9). 6 | 7 | 3. Project describes: 8 | 1. Sharing code between App and Widget 9 | 2. Sharing data between App and Widget 10 | 3. Open App from Widget 11 | 4. Show More/Show Less functionality in Widget using Auto-Layout 12 | 5. Updating Widget content 13 | 6. Show/Hide widget from containing App (optional) 14 | 15 | 4. Implementation in Swift 3.0 16 | 17 | ## Preview 18 | Preview gif 19 | 20 | ## App Extension 21 | 1. Introduced in iOS 8 22 | 23 | 2. An app extension lets you extend custom functionality and content beyond your app and make it available to users while they’re interacting with other apps or the system. 24 | 25 | 3. Used for specific task 26 | 27 | 4. Not an app 28 | 29 | ## Terminology 30 | 1. Containing App - The app for which extension is created 31 | 32 | 2. Types of Extensions - Today(Widget), Share, Custom Keyboard, Photo Editing etc. 33 | 34 | 3. Extension Point - Each extension is tied to a single area of the system. Eg. Today Extension - Notification center, Share Extension - UIActivityViewController 35 | 36 | 4. Extension Container 37 | Extension is different from app 38 | Separate binary that runs independent of the containing app 39 | Can add multiple extensions to a single app 40 | To distribute app extensions to users, you submit a containing app to the App Store, when user installs the app, extension is also installed with it 41 | 42 | 5. Host App - App from which the extension is launched 43 | 44 | ## Today Extension (Widget) 45 | Here you can find the complete implementation details as well the common issues faced while implementing today extension in you app. 46 | 47 | ## Project Details 48 | 49 | This project contains 3 things: 50 | 51 | 1. Containing App : App shows the restaurants that are near to your current location. The restaurants are fetched through Google Places API - "Nearby Search" using the current location and displayed in a table. App uses the Location Services of iOS. The details of a particular restaurant are then fetched through Google Places API - "Place Detail" using placeID of the selected restaurant. Each restaurant has a unique placeID. Instead of restaurants, you can fetch any kind of place (Eg. Bank, School, Hospital etc.) according to your requirement. 52 | 53 | 2. Today Extension : Whenever the user view a restaurant's detail in containing app , its details are saved in the share container. Maximum 5 details can be saved in the container. This limit can be changed according to your requirement. Whenever the widget is loaded, these saved restaurant details are fetched from the shared container and used to update the widget's content. When a restaurant detail is tapped in the widget, containing app is opened using "openURL:" and the detail page corresponding to selected restaurant is displayed. 54 | 55 | 3. Framework : App and widget both share some of the code. So, a framework is created that contains the code common to both App and widget. 56 | 57 | ## Things to do on Apple Developer Portal 58 | 59 | 1. Create App ID for Containing App 60 | 2. Create App ID for Extension 61 | 3. Create App Group 62 | 4. Assign App Group to App ID of Containing App 63 | 5. Assign App Group to App ID of Extension 64 | 6. Create Provision Profile for App ID of Containing App 65 | 7. Create Provision Profile for App ID of Extension 66 | 67 | ## iOS 8 and iOS 9 implementaion details 68 | 69 | For iOS 8 and iOS 9, the height changes are to be handled explicitly. For this auto-layout is used. Show More/Show Less functionality need to be provided explicitly. 70 | Show More - increases the table height constraint according to the content 71 | Show Less - decreases the table height constraint to show only single row. 72 | 73 | ## iOS 10 implementation details 74 | 75 | In iOS 10, Show More/Show Less functionality is provided by the API itself. 76 | Use: 77 | 78 | 1. NCWidgetDisplayMode and 79 | 2. func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) 80 | 81 | to handle widget height changes. You don't need any explicit height constraint for this. Also explicit Show More/Show Less button is not required. 82 | 83 | ### Note: 84 | To show/hide widget from containing app - Search for "TODO" in project and follow the instructions. 85 | -------------------------------------------------------------------------------- /Screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgpt10/Today-Widget/b28df1b0a9d459f135e1ffab14438b2a51dbe02f/Screenshot.PNG --------------------------------------------------------------------------------