├── .gitignore ├── DribbbleApp.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── lll.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── lll.xcuserdatad │ └── xcschemes │ ├── DribbbleApp.xcscheme │ └── xcschememanagement.plist ├── DribbbleApp.xcworkspace └── contents.xcworkspacedata ├── DribbbleApp ├── AppDelegate.swift ├── BaseNavigationViewController.swift ├── BaseViewController.swift ├── CategoryViewController.swift ├── CellConfigure.swift ├── Comment.swift ├── DribbbleApp-Bridging-Header.h ├── DribbbleManager.swift ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ ├── comment.imageset │ │ ├── Contents.json │ │ ├── comment.png │ │ ├── comment@2x.png │ │ └── comment@3x.png │ ├── heart_gray.imageset │ │ ├── Contents.json │ │ ├── heart_gray.png │ │ ├── heart_gray@2x.png │ │ └── heart_gray@3x.png │ └── heart_red.imageset │ │ ├── Contents.json │ │ ├── heart_red.png │ │ ├── heart_red@2x.png │ │ └── heart_red@3x.png ├── Info.plist ├── JSONParser.swift ├── MTLShot.swift ├── Main.storyboard ├── MainViewController.swift ├── Player.swift ├── Podfile ├── Shot.swift ├── ShotAttachmentCell.swift ├── ShotCell.swift ├── ShotDetailDataSource.swift ├── ShotDetailTableHeader.swift ├── ShotDetailTableHeader.xib ├── ShotDetailViewController.swift ├── ShotInfoTableCell.swift ├── ShotLikesTableCell.swift ├── ShotListCell.swift ├── ShotTagTableCell.swift ├── Team.swift ├── TransitionManager.swift ├── UIScrollView+VGParallaxHeader.h ├── UIScrollView+VGParallaxHeader.m └── test.playground │ ├── contents.xcplayground │ ├── section-1.swift │ └── timeline.xctimeline ├── DribbbleAppTests ├── DribbbleAppTests.swift └── Info.plist ├── Podfile ├── Podfile.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | 19 | # CocoaPods 20 | # 21 | # We recommend against adding the Pods directory to your .gitignore. However 22 | # you should judge for yourself, the pros and cons are mentioned at: 23 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 24 | # 25 | Pods/ -------------------------------------------------------------------------------- /DribbbleApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0B2C63551A3E8F3E00AADF04 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0B2C63541A3E8F3E00AADF04 /* Main.storyboard */; }; 11 | 0B2C63571A3E959E00AADF04 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2C63561A3E959E00AADF04 /* MainViewController.swift */; }; 12 | 0B2E1A251A401D72009E7853 /* ShotListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2E1A241A401D72009E7853 /* ShotListCell.swift */; }; 13 | 0B2E1A281A40231B009E7853 /* ShotDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2E1A271A40231B009E7853 /* ShotDetailViewController.swift */; }; 14 | 0B2E1A2C1A403952009E7853 /* CategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2E1A2B1A403952009E7853 /* CategoryViewController.swift */; }; 15 | 0B2E1A331A4124B9009E7853 /* TransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B2E1A321A4124B9009E7853 /* TransitionManager.swift */; }; 16 | 0B3A51DA1A400BFA006FCCFD /* Player.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3A51D91A400BFA006FCCFD /* Player.swift */; }; 17 | 0B3A51DE1A400C21006FCCFD /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B3A51DD1A400C21006FCCFD /* JSONParser.swift */; }; 18 | 0B8915F91A427E770064104F /* Team.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8915F81A427E770064104F /* Team.swift */; }; 19 | 0B8915FD1A42B9930064104F /* UIScrollView+VGParallaxHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B8915FC1A42B9930064104F /* UIScrollView+VGParallaxHeader.m */; }; 20 | 0B8915FF1A42CD500064104F /* ShotDetailDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8915FE1A42CD500064104F /* ShotDetailDataSource.swift */; }; 21 | 0B8916021A43C33C0064104F /* ShotInfoTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8916011A43C33C0064104F /* ShotInfoTableCell.swift */; }; 22 | 0B8916051A43C3630064104F /* ShotLikesTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8916041A43C3630064104F /* ShotLikesTableCell.swift */; }; 23 | 0B8916071A43C3790064104F /* ShotAttachmentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8916061A43C3790064104F /* ShotAttachmentCell.swift */; }; 24 | 0B8916091A43C3D40064104F /* ShotTagTableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8916081A43C3D40064104F /* ShotTagTableCell.swift */; }; 25 | 0B89160D1A43CA900064104F /* CellConfigure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B89160C1A43CA900064104F /* CellConfigure.swift */; }; 26 | 0B8916111A43CB090064104F /* ShotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B8916101A43CB090064104F /* ShotCell.swift */; }; 27 | 0BDE4CE11A3FFADD00C8CF04 /* DribbbleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BDE4CE01A3FFADD00C8CF04 /* DribbbleManager.swift */; }; 28 | 0BF55F911A41787D0087379B /* ShotDetailTableHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF55F901A41787D0087379B /* ShotDetailTableHeader.swift */; }; 29 | 0BF55F931A41788F0087379B /* ShotDetailTableHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0BF55F921A41788F0087379B /* ShotDetailTableHeader.xib */; }; 30 | 0BF55F951A4180050087379B /* Comment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF55F941A4180050087379B /* Comment.swift */; }; 31 | 461D7322194D6AD40044B372 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D7321194D6AD40044B372 /* AppDelegate.swift */; }; 32 | 461D7324194D6AD40044B372 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 461D7323194D6AD40044B372 /* Images.xcassets */; }; 33 | 461D7330194D6AD40044B372 /* DribbbleAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D732F194D6AD40044B372 /* DribbbleAppTests.swift */; }; 34 | 461D733A194D6AF30044B372 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D7339194D6AF30044B372 /* BaseViewController.swift */; }; 35 | 461D733C194D6B130044B372 /* BaseNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461D733B194D6B130044B372 /* BaseNavigationViewController.swift */; }; 36 | 46523EB2194D7D9C00CBD927 /* Shot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46523EB1194D7D9C00CBD927 /* Shot.swift */; }; 37 | 469B864519512D1900FB55DF /* MTLShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 469B864419512D1900FB55DF /* MTLShot.swift */; }; 38 | C6D30B660CBEAAAE77096B66 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 347E1ACB80DA8E83BAFF6126 /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 39 | /* End PBXBuildFile section */ 40 | 41 | /* Begin PBXContainerItemProxy section */ 42 | 461D732A194D6AD40044B372 /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 461D7314194D6AD40044B372 /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 461D731B194D6AD40044B372; 47 | remoteInfo = DribbbleApp; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 0B3A51D41A40040A006FCCFD /* Copy Frameworks */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 10; 57 | files = ( 58 | ); 59 | name = "Copy Frameworks"; 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXCopyFilesBuildPhase section */ 63 | 64 | /* Begin PBXFileReference section */ 65 | 0B2C63541A3E8F3E00AADF04 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 66 | 0B2C63561A3E959E00AADF04 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 67 | 0B2E1A241A401D72009E7853 /* ShotListCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotListCell.swift; sourceTree = ""; }; 68 | 0B2E1A271A40231B009E7853 /* ShotDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotDetailViewController.swift; sourceTree = ""; }; 69 | 0B2E1A2B1A403952009E7853 /* CategoryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CategoryViewController.swift; sourceTree = ""; }; 70 | 0B2E1A321A4124B9009E7853 /* TransitionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionManager.swift; sourceTree = ""; }; 71 | 0B3A51D91A400BFA006FCCFD /* Player.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Player.swift; sourceTree = ""; }; 72 | 0B3A51DD1A400C21006FCCFD /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParser.swift; sourceTree = ""; }; 73 | 0B8915F81A427E770064104F /* Team.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Team.swift; sourceTree = ""; }; 74 | 0B8915FB1A42B9930064104F /* UIScrollView+VGParallaxHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+VGParallaxHeader.h"; sourceTree = ""; }; 75 | 0B8915FC1A42B9930064104F /* UIScrollView+VGParallaxHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+VGParallaxHeader.m"; sourceTree = ""; }; 76 | 0B8915FE1A42CD500064104F /* ShotDetailDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotDetailDataSource.swift; sourceTree = ""; }; 77 | 0B8916011A43C33C0064104F /* ShotInfoTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotInfoTableCell.swift; sourceTree = ""; }; 78 | 0B8916041A43C3630064104F /* ShotLikesTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotLikesTableCell.swift; sourceTree = ""; }; 79 | 0B8916061A43C3790064104F /* ShotAttachmentCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotAttachmentCell.swift; sourceTree = ""; }; 80 | 0B8916081A43C3D40064104F /* ShotTagTableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotTagTableCell.swift; sourceTree = ""; }; 81 | 0B89160C1A43CA900064104F /* CellConfigure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CellConfigure.swift; sourceTree = ""; }; 82 | 0B8916101A43CB090064104F /* ShotCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotCell.swift; sourceTree = ""; }; 83 | 0BDE4CE01A3FFADD00C8CF04 /* DribbbleManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DribbbleManager.swift; sourceTree = ""; }; 84 | 0BF55F901A41787D0087379B /* ShotDetailTableHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShotDetailTableHeader.swift; sourceTree = ""; }; 85 | 0BF55F921A41788F0087379B /* ShotDetailTableHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShotDetailTableHeader.xib; sourceTree = ""; }; 86 | 0BF55F941A4180050087379B /* Comment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Comment.swift; sourceTree = ""; }; 87 | 347E1ACB80DA8E83BAFF6126 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | 461D731C194D6AD40044B372 /* DribbbleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DribbbleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | 461D7320194D6AD40044B372 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 90 | 461D7321194D6AD40044B372 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 91 | 461D7323194D6AD40044B372 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 92 | 461D7329194D6AD40044B372 /* DribbbleAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DribbbleAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | 461D732E194D6AD40044B372 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 94 | 461D732F194D6AD40044B372 /* DribbbleAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DribbbleAppTests.swift; sourceTree = ""; }; 95 | 461D7339194D6AF30044B372 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; 96 | 461D733B194D6B130044B372 /* BaseNavigationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseNavigationViewController.swift; sourceTree = ""; }; 97 | 461D733D194D6D750044B372 /* DribbbleApp-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DribbbleApp-Bridging-Header.h"; sourceTree = ""; }; 98 | 46523EB1194D7D9C00CBD927 /* Shot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shot.swift; sourceTree = ""; }; 99 | 469B864419512D1900FB55DF /* MTLShot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTLShot.swift; sourceTree = ""; }; 100 | 46AD5954194EF86E008A2CEF /* test.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = test.playground; sourceTree = ""; }; 101 | 662A89970BF1651DE6DDD2F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 102 | F5EA75B4DB183EACF4CD6503 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 103 | /* End PBXFileReference section */ 104 | 105 | /* Begin PBXFrameworksBuildPhase section */ 106 | 461D7319194D6AD40044B372 /* Frameworks */ = { 107 | isa = PBXFrameworksBuildPhase; 108 | buildActionMask = 2147483647; 109 | files = ( 110 | C6D30B660CBEAAAE77096B66 /* Pods.framework in Frameworks */, 111 | ); 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | 461D7326194D6AD40044B372 /* Frameworks */ = { 115 | isa = PBXFrameworksBuildPhase; 116 | buildActionMask = 2147483647; 117 | files = ( 118 | ); 119 | runOnlyForDeploymentPostprocessing = 0; 120 | }; 121 | /* End PBXFrameworksBuildPhase section */ 122 | 123 | /* Begin PBXGroup section */ 124 | 0B2E1A311A41249B009E7853 /* Transition */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 0B2E1A321A4124B9009E7853 /* TransitionManager.swift */, 128 | ); 129 | name = Transition; 130 | sourceTree = ""; 131 | }; 132 | 0B3A51DC1A400C0E006FCCFD /* Protocol */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 0B3A51DD1A400C21006FCCFD /* JSONParser.swift */, 136 | 0B89160C1A43CA900064104F /* CellConfigure.swift */, 137 | ); 138 | name = Protocol; 139 | sourceTree = ""; 140 | }; 141 | 0BDE4CE21A3FFE4100C8CF04 /* Vender */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 0B8915FB1A42B9930064104F /* UIScrollView+VGParallaxHeader.h */, 145 | 0B8915FC1A42B9930064104F /* UIScrollView+VGParallaxHeader.m */, 146 | ); 147 | name = Vender; 148 | sourceTree = ""; 149 | }; 150 | 0BF55F8E1A4178560087379B /* View */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 0BF55F901A41787D0087379B /* ShotDetailTableHeader.swift */, 154 | 0BF55F921A41788F0087379B /* ShotDetailTableHeader.xib */, 155 | ); 156 | name = View; 157 | sourceTree = ""; 158 | }; 159 | 156D193553FC76EFCD14FFCE /* Pods */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | F5EA75B4DB183EACF4CD6503 /* Pods.debug.xcconfig */, 163 | 662A89970BF1651DE6DDD2F0 /* Pods.release.xcconfig */, 164 | ); 165 | name = Pods; 166 | sourceTree = ""; 167 | }; 168 | 460B953C194DBC8C0061A24B /* Cell */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 0B2E1A241A401D72009E7853 /* ShotListCell.swift */, 172 | 0B8916011A43C33C0064104F /* ShotInfoTableCell.swift */, 173 | 0B8916041A43C3630064104F /* ShotLikesTableCell.swift */, 174 | 0B8916061A43C3790064104F /* ShotAttachmentCell.swift */, 175 | 0B8916081A43C3D40064104F /* ShotTagTableCell.swift */, 176 | 0B8916101A43CB090064104F /* ShotCell.swift */, 177 | ); 178 | name = Cell; 179 | sourceTree = ""; 180 | }; 181 | 461D7313194D6AD40044B372 = { 182 | isa = PBXGroup; 183 | children = ( 184 | 461D731E194D6AD40044B372 /* DribbbleApp */, 185 | 461D732C194D6AD40044B372 /* DribbbleAppTests */, 186 | 461D731D194D6AD40044B372 /* Products */, 187 | B4E2ED7C39BF4A099C3F9EA9 /* Frameworks */, 188 | 156D193553FC76EFCD14FFCE /* Pods */, 189 | ); 190 | sourceTree = ""; 191 | }; 192 | 461D731D194D6AD40044B372 /* Products */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 461D731C194D6AD40044B372 /* DribbbleApp.app */, 196 | 461D7329194D6AD40044B372 /* DribbbleAppTests.xctest */, 197 | ); 198 | name = Products; 199 | sourceTree = ""; 200 | }; 201 | 461D731E194D6AD40044B372 /* DribbbleApp */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 0BF55F8E1A4178560087379B /* View */, 205 | 0B2E1A311A41249B009E7853 /* Transition */, 206 | 0B3A51DC1A400C0E006FCCFD /* Protocol */, 207 | 0BDE4CE21A3FFE4100C8CF04 /* Vender */, 208 | 461D7321194D6AD40044B372 /* AppDelegate.swift */, 209 | 461D7339194D6AF30044B372 /* BaseViewController.swift */, 210 | 461D733B194D6B130044B372 /* BaseNavigationViewController.swift */, 211 | 461D733D194D6D750044B372 /* DribbbleApp-Bridging-Header.h */, 212 | 0BDE4CE01A3FFADD00C8CF04 /* DribbbleManager.swift */, 213 | 460B953C194DBC8C0061A24B /* Cell */, 214 | 46523EB3194D7DB900CBD927 /* ViewControllers */, 215 | 46523EB4194D7F8D00CBD927 /* Model */, 216 | 461D7323194D6AD40044B372 /* Images.xcassets */, 217 | 0B2C63541A3E8F3E00AADF04 /* Main.storyboard */, 218 | 461D731F194D6AD40044B372 /* Supporting Files */, 219 | 0B8915FE1A42CD500064104F /* ShotDetailDataSource.swift */, 220 | ); 221 | path = DribbbleApp; 222 | sourceTree = ""; 223 | }; 224 | 461D731F194D6AD40044B372 /* Supporting Files */ = { 225 | isa = PBXGroup; 226 | children = ( 227 | 461D7320194D6AD40044B372 /* Info.plist */, 228 | ); 229 | name = "Supporting Files"; 230 | sourceTree = ""; 231 | }; 232 | 461D732C194D6AD40044B372 /* DribbbleAppTests */ = { 233 | isa = PBXGroup; 234 | children = ( 235 | 461D732F194D6AD40044B372 /* DribbbleAppTests.swift */, 236 | 461D732D194D6AD40044B372 /* Supporting Files */, 237 | ); 238 | path = DribbbleAppTests; 239 | sourceTree = ""; 240 | }; 241 | 461D732D194D6AD40044B372 /* Supporting Files */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 461D732E194D6AD40044B372 /* Info.plist */, 245 | ); 246 | name = "Supporting Files"; 247 | sourceTree = ""; 248 | }; 249 | 46523EB3194D7DB900CBD927 /* ViewControllers */ = { 250 | isa = PBXGroup; 251 | children = ( 252 | 46AD5954194EF86E008A2CEF /* test.playground */, 253 | 0B2C63561A3E959E00AADF04 /* MainViewController.swift */, 254 | 0B2E1A271A40231B009E7853 /* ShotDetailViewController.swift */, 255 | 0B2E1A2B1A403952009E7853 /* CategoryViewController.swift */, 256 | ); 257 | name = ViewControllers; 258 | sourceTree = ""; 259 | }; 260 | 46523EB4194D7F8D00CBD927 /* Model */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 46523EB1194D7D9C00CBD927 /* Shot.swift */, 264 | 0B3A51D91A400BFA006FCCFD /* Player.swift */, 265 | 0B8915F81A427E770064104F /* Team.swift */, 266 | 0BF55F941A4180050087379B /* Comment.swift */, 267 | 469B864419512D1900FB55DF /* MTLShot.swift */, 268 | ); 269 | name = Model; 270 | sourceTree = ""; 271 | }; 272 | B4E2ED7C39BF4A099C3F9EA9 /* Frameworks */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 347E1ACB80DA8E83BAFF6126 /* Pods.framework */, 276 | ); 277 | name = Frameworks; 278 | sourceTree = ""; 279 | }; 280 | /* End PBXGroup section */ 281 | 282 | /* Begin PBXNativeTarget section */ 283 | 461D731B194D6AD40044B372 /* DribbbleApp */ = { 284 | isa = PBXNativeTarget; 285 | buildConfigurationList = 461D7333194D6AD40044B372 /* Build configuration list for PBXNativeTarget "DribbbleApp" */; 286 | buildPhases = ( 287 | 1EB78E7F1E294ECAAADBFEA7 /* Check Pods Manifest.lock */, 288 | 461D7318194D6AD40044B372 /* Sources */, 289 | 461D7319194D6AD40044B372 /* Frameworks */, 290 | 461D731A194D6AD40044B372 /* Resources */, 291 | 0B3A51D41A40040A006FCCFD /* Copy Frameworks */, 292 | 97DCB7EAF34640428F15E5CD /* Copy Pods Resources */, 293 | A9E3271DC7F8DF02412D2ED0 /* Embed Pods Frameworks */, 294 | ); 295 | buildRules = ( 296 | ); 297 | dependencies = ( 298 | ); 299 | name = DribbbleApp; 300 | productName = DribbbleApp; 301 | productReference = 461D731C194D6AD40044B372 /* DribbbleApp.app */; 302 | productType = "com.apple.product-type.application"; 303 | }; 304 | 461D7328194D6AD40044B372 /* DribbbleAppTests */ = { 305 | isa = PBXNativeTarget; 306 | buildConfigurationList = 461D7336194D6AD40044B372 /* Build configuration list for PBXNativeTarget "DribbbleAppTests" */; 307 | buildPhases = ( 308 | 461D7325194D6AD40044B372 /* Sources */, 309 | 461D7326194D6AD40044B372 /* Frameworks */, 310 | 461D7327194D6AD40044B372 /* Resources */, 311 | ); 312 | buildRules = ( 313 | ); 314 | dependencies = ( 315 | 461D732B194D6AD40044B372 /* PBXTargetDependency */, 316 | ); 317 | name = DribbbleAppTests; 318 | productName = DribbbleAppTests; 319 | productReference = 461D7329194D6AD40044B372 /* DribbbleAppTests.xctest */; 320 | productType = "com.apple.product-type.bundle.unit-test"; 321 | }; 322 | /* End PBXNativeTarget section */ 323 | 324 | /* Begin PBXProject section */ 325 | 461D7314194D6AD40044B372 /* Project object */ = { 326 | isa = PBXProject; 327 | attributes = { 328 | LastUpgradeCheck = 0600; 329 | ORGANIZATIONNAME = LLL; 330 | TargetAttributes = { 331 | 461D731B194D6AD40044B372 = { 332 | CreatedOnToolsVersion = 6.0; 333 | }; 334 | 461D7328194D6AD40044B372 = { 335 | CreatedOnToolsVersion = 6.0; 336 | TestTargetID = 461D731B194D6AD40044B372; 337 | }; 338 | }; 339 | }; 340 | buildConfigurationList = 461D7317194D6AD40044B372 /* Build configuration list for PBXProject "DribbbleApp" */; 341 | compatibilityVersion = "Xcode 3.2"; 342 | developmentRegion = English; 343 | hasScannedForEncodings = 0; 344 | knownRegions = ( 345 | en, 346 | ); 347 | mainGroup = 461D7313194D6AD40044B372; 348 | productRefGroup = 461D731D194D6AD40044B372 /* Products */; 349 | projectDirPath = ""; 350 | projectRoot = ""; 351 | targets = ( 352 | 461D731B194D6AD40044B372 /* DribbbleApp */, 353 | 461D7328194D6AD40044B372 /* DribbbleAppTests */, 354 | ); 355 | }; 356 | /* End PBXProject section */ 357 | 358 | /* Begin PBXResourcesBuildPhase section */ 359 | 461D731A194D6AD40044B372 /* Resources */ = { 360 | isa = PBXResourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | 461D7324194D6AD40044B372 /* Images.xcassets in Resources */, 364 | 0B2C63551A3E8F3E00AADF04 /* Main.storyboard in Resources */, 365 | 0BF55F931A41788F0087379B /* ShotDetailTableHeader.xib in Resources */, 366 | ); 367 | runOnlyForDeploymentPostprocessing = 0; 368 | }; 369 | 461D7327194D6AD40044B372 /* Resources */ = { 370 | isa = PBXResourcesBuildPhase; 371 | buildActionMask = 2147483647; 372 | files = ( 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | /* End PBXResourcesBuildPhase section */ 377 | 378 | /* Begin PBXShellScriptBuildPhase section */ 379 | 1EB78E7F1E294ECAAADBFEA7 /* Check Pods Manifest.lock */ = { 380 | isa = PBXShellScriptBuildPhase; 381 | buildActionMask = 2147483647; 382 | files = ( 383 | ); 384 | inputPaths = ( 385 | ); 386 | name = "Check Pods Manifest.lock"; 387 | outputPaths = ( 388 | ); 389 | runOnlyForDeploymentPostprocessing = 0; 390 | shellPath = /bin/sh; 391 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 392 | showEnvVarsInLog = 0; 393 | }; 394 | 97DCB7EAF34640428F15E5CD /* Copy Pods Resources */ = { 395 | isa = PBXShellScriptBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | ); 399 | inputPaths = ( 400 | ); 401 | name = "Copy Pods Resources"; 402 | outputPaths = ( 403 | ); 404 | runOnlyForDeploymentPostprocessing = 0; 405 | shellPath = /bin/sh; 406 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 407 | showEnvVarsInLog = 0; 408 | }; 409 | A9E3271DC7F8DF02412D2ED0 /* Embed Pods Frameworks */ = { 410 | isa = PBXShellScriptBuildPhase; 411 | buildActionMask = 2147483647; 412 | files = ( 413 | ); 414 | inputPaths = ( 415 | ); 416 | name = "Embed Pods Frameworks"; 417 | outputPaths = ( 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | shellPath = /bin/sh; 421 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; 422 | showEnvVarsInLog = 0; 423 | }; 424 | /* End PBXShellScriptBuildPhase section */ 425 | 426 | /* Begin PBXSourcesBuildPhase section */ 427 | 461D7318194D6AD40044B372 /* Sources */ = { 428 | isa = PBXSourcesBuildPhase; 429 | buildActionMask = 2147483647; 430 | files = ( 431 | 0B8916091A43C3D40064104F /* ShotTagTableCell.swift in Sources */, 432 | 0B2C63571A3E959E00AADF04 /* MainViewController.swift in Sources */, 433 | 0BDE4CE11A3FFADD00C8CF04 /* DribbbleManager.swift in Sources */, 434 | 0B8915FF1A42CD500064104F /* ShotDetailDataSource.swift in Sources */, 435 | 0B2E1A331A4124B9009E7853 /* TransitionManager.swift in Sources */, 436 | 0B2E1A251A401D72009E7853 /* ShotListCell.swift in Sources */, 437 | 46523EB2194D7D9C00CBD927 /* Shot.swift in Sources */, 438 | 0B8916111A43CB090064104F /* ShotCell.swift in Sources */, 439 | 0B3A51DE1A400C21006FCCFD /* JSONParser.swift in Sources */, 440 | 0B2E1A281A40231B009E7853 /* ShotDetailViewController.swift in Sources */, 441 | 0B8916021A43C33C0064104F /* ShotInfoTableCell.swift in Sources */, 442 | 461D733C194D6B130044B372 /* BaseNavigationViewController.swift in Sources */, 443 | 0B8915F91A427E770064104F /* Team.swift in Sources */, 444 | 0B8916051A43C3630064104F /* ShotLikesTableCell.swift in Sources */, 445 | 469B864519512D1900FB55DF /* MTLShot.swift in Sources */, 446 | 0B8915FD1A42B9930064104F /* UIScrollView+VGParallaxHeader.m in Sources */, 447 | 0BF55F911A41787D0087379B /* ShotDetailTableHeader.swift in Sources */, 448 | 0B89160D1A43CA900064104F /* CellConfigure.swift in Sources */, 449 | 0B8916071A43C3790064104F /* ShotAttachmentCell.swift in Sources */, 450 | 0BF55F951A4180050087379B /* Comment.swift in Sources */, 451 | 461D7322194D6AD40044B372 /* AppDelegate.swift in Sources */, 452 | 0B2E1A2C1A403952009E7853 /* CategoryViewController.swift in Sources */, 453 | 0B3A51DA1A400BFA006FCCFD /* Player.swift in Sources */, 454 | 461D733A194D6AF30044B372 /* BaseViewController.swift in Sources */, 455 | ); 456 | runOnlyForDeploymentPostprocessing = 0; 457 | }; 458 | 461D7325194D6AD40044B372 /* Sources */ = { 459 | isa = PBXSourcesBuildPhase; 460 | buildActionMask = 2147483647; 461 | files = ( 462 | 461D7330194D6AD40044B372 /* DribbbleAppTests.swift in Sources */, 463 | ); 464 | runOnlyForDeploymentPostprocessing = 0; 465 | }; 466 | /* End PBXSourcesBuildPhase section */ 467 | 468 | /* Begin PBXTargetDependency section */ 469 | 461D732B194D6AD40044B372 /* PBXTargetDependency */ = { 470 | isa = PBXTargetDependency; 471 | target = 461D731B194D6AD40044B372 /* DribbbleApp */; 472 | targetProxy = 461D732A194D6AD40044B372 /* PBXContainerItemProxy */; 473 | }; 474 | /* End PBXTargetDependency section */ 475 | 476 | /* Begin XCBuildConfiguration section */ 477 | 461D7331194D6AD40044B372 /* Debug */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | ALWAYS_SEARCH_USER_PATHS = NO; 481 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 482 | CLANG_CXX_LIBRARY = "libc++"; 483 | CLANG_ENABLE_MODULES = YES; 484 | CLANG_ENABLE_OBJC_ARC = YES; 485 | CLANG_WARN_BOOL_CONVERSION = YES; 486 | CLANG_WARN_CONSTANT_CONVERSION = YES; 487 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 488 | CLANG_WARN_EMPTY_BODY = YES; 489 | CLANG_WARN_ENUM_CONVERSION = YES; 490 | CLANG_WARN_INT_CONVERSION = YES; 491 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 492 | CLANG_WARN_UNREACHABLE_CODE = YES; 493 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 494 | CODE_SIGN_IDENTITY = "iOS Development: han yin (6TH2V4WQ8W)"; 495 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iOS Development: han yin (6TH2V4WQ8W)"; 496 | COPY_PHASE_STRIP = NO; 497 | ENABLE_STRICT_OBJC_MSGSEND = YES; 498 | GCC_C_LANGUAGE_STANDARD = gnu99; 499 | GCC_DYNAMIC_NO_PIC = NO; 500 | GCC_OPTIMIZATION_LEVEL = 0; 501 | GCC_PREPROCESSOR_DEFINITIONS = ( 502 | "DEBUG=1", 503 | "$(inherited)", 504 | ); 505 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 506 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 507 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 508 | GCC_WARN_UNDECLARED_SELECTOR = YES; 509 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 510 | GCC_WARN_UNUSED_FUNCTION = YES; 511 | GCC_WARN_UNUSED_VARIABLE = YES; 512 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 513 | METAL_ENABLE_DEBUG_INFO = YES; 514 | ONLY_ACTIVE_ARCH = YES; 515 | PROVISIONING_PROFILE = "8f419723-3640-471d-8c54-61937bca05ba"; 516 | SDKROOT = iphoneos; 517 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 518 | }; 519 | name = Debug; 520 | }; 521 | 461D7332194D6AD40044B372 /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | ALWAYS_SEARCH_USER_PATHS = NO; 525 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 526 | CLANG_CXX_LIBRARY = "libc++"; 527 | CLANG_ENABLE_MODULES = YES; 528 | CLANG_ENABLE_OBJC_ARC = YES; 529 | CLANG_WARN_BOOL_CONVERSION = YES; 530 | CLANG_WARN_CONSTANT_CONVERSION = YES; 531 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 532 | CLANG_WARN_EMPTY_BODY = YES; 533 | CLANG_WARN_ENUM_CONVERSION = YES; 534 | CLANG_WARN_INT_CONVERSION = YES; 535 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 536 | CLANG_WARN_UNREACHABLE_CODE = YES; 537 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 538 | CODE_SIGN_IDENTITY = "iOS Development: han yin (6TH2V4WQ8W)"; 539 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iOS Development: han yin (6TH2V4WQ8W)"; 540 | COPY_PHASE_STRIP = YES; 541 | ENABLE_NS_ASSERTIONS = NO; 542 | ENABLE_STRICT_OBJC_MSGSEND = YES; 543 | GCC_C_LANGUAGE_STANDARD = gnu99; 544 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 545 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 546 | GCC_WARN_UNDECLARED_SELECTOR = YES; 547 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 548 | GCC_WARN_UNUSED_FUNCTION = YES; 549 | GCC_WARN_UNUSED_VARIABLE = YES; 550 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 551 | METAL_ENABLE_DEBUG_INFO = NO; 552 | PROVISIONING_PROFILE = "8f419723-3640-471d-8c54-61937bca05ba"; 553 | SDKROOT = iphoneos; 554 | VALIDATE_PRODUCT = YES; 555 | }; 556 | name = Release; 557 | }; 558 | 461D7334194D6AD40044B372 /* Debug */ = { 559 | isa = XCBuildConfiguration; 560 | baseConfigurationReference = F5EA75B4DB183EACF4CD6503 /* Pods.debug.xcconfig */; 561 | buildSettings = { 562 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 563 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 564 | CLANG_ENABLE_MODULES = YES; 565 | CODE_SIGN_IDENTITY = "iOS Development: han yin (6TH2V4WQ8W)"; 566 | INFOPLIST_FILE = DribbbleApp/Info.plist; 567 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 568 | PRODUCT_NAME = "$(TARGET_NAME)"; 569 | PROVISIONING_PROFILE = "8f419723-3640-471d-8c54-61937bca05ba"; 570 | SWIFT_OBJC_BRIDGING_HEADER = "DribbbleApp/DribbbleApp-Bridging-Header.h"; 571 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 572 | }; 573 | name = Debug; 574 | }; 575 | 461D7335194D6AD40044B372 /* Release */ = { 576 | isa = XCBuildConfiguration; 577 | baseConfigurationReference = 662A89970BF1651DE6DDD2F0 /* Pods.release.xcconfig */; 578 | buildSettings = { 579 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 580 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 581 | CLANG_ENABLE_MODULES = YES; 582 | CODE_SIGN_IDENTITY = "iOS Development: han yin (6TH2V4WQ8W)"; 583 | INFOPLIST_FILE = DribbbleApp/Info.plist; 584 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | PROVISIONING_PROFILE = "8f419723-3640-471d-8c54-61937bca05ba"; 587 | SWIFT_OBJC_BRIDGING_HEADER = "DribbbleApp/DribbbleApp-Bridging-Header.h"; 588 | }; 589 | name = Release; 590 | }; 591 | 461D7337194D6AD40044B372 /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DribbbleApp.app/DribbbleApp"; 595 | FRAMEWORK_SEARCH_PATHS = ( 596 | "$(SDKROOT)/Developer/Library/Frameworks", 597 | "$(inherited)", 598 | ); 599 | GCC_PREPROCESSOR_DEFINITIONS = ( 600 | "DEBUG=1", 601 | "$(inherited)", 602 | ); 603 | INFOPLIST_FILE = DribbbleAppTests/Info.plist; 604 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 605 | METAL_ENABLE_DEBUG_INFO = YES; 606 | PRODUCT_NAME = "$(TARGET_NAME)"; 607 | TEST_HOST = "$(BUNDLE_LOADER)"; 608 | }; 609 | name = Debug; 610 | }; 611 | 461D7338194D6AD40044B372 /* Release */ = { 612 | isa = XCBuildConfiguration; 613 | buildSettings = { 614 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/DribbbleApp.app/DribbbleApp"; 615 | FRAMEWORK_SEARCH_PATHS = ( 616 | "$(SDKROOT)/Developer/Library/Frameworks", 617 | "$(inherited)", 618 | ); 619 | INFOPLIST_FILE = DribbbleAppTests/Info.plist; 620 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 621 | METAL_ENABLE_DEBUG_INFO = NO; 622 | PRODUCT_NAME = "$(TARGET_NAME)"; 623 | TEST_HOST = "$(BUNDLE_LOADER)"; 624 | }; 625 | name = Release; 626 | }; 627 | /* End XCBuildConfiguration section */ 628 | 629 | /* Begin XCConfigurationList section */ 630 | 461D7317194D6AD40044B372 /* Build configuration list for PBXProject "DribbbleApp" */ = { 631 | isa = XCConfigurationList; 632 | buildConfigurations = ( 633 | 461D7331194D6AD40044B372 /* Debug */, 634 | 461D7332194D6AD40044B372 /* Release */, 635 | ); 636 | defaultConfigurationIsVisible = 0; 637 | defaultConfigurationName = Release; 638 | }; 639 | 461D7333194D6AD40044B372 /* Build configuration list for PBXNativeTarget "DribbbleApp" */ = { 640 | isa = XCConfigurationList; 641 | buildConfigurations = ( 642 | 461D7334194D6AD40044B372 /* Debug */, 643 | 461D7335194D6AD40044B372 /* Release */, 644 | ); 645 | defaultConfigurationIsVisible = 0; 646 | defaultConfigurationName = Release; 647 | }; 648 | 461D7336194D6AD40044B372 /* Build configuration list for PBXNativeTarget "DribbbleAppTests" */ = { 649 | isa = XCConfigurationList; 650 | buildConfigurations = ( 651 | 461D7337194D6AD40044B372 /* Debug */, 652 | 461D7338194D6AD40044B372 /* Release */, 653 | ); 654 | defaultConfigurationIsVisible = 0; 655 | defaultConfigurationName = Release; 656 | }; 657 | /* End XCConfigurationList section */ 658 | }; 659 | rootObject = 461D7314194D6AD40044B372 /* Project object */; 660 | } 661 | -------------------------------------------------------------------------------- /DribbbleApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DribbbleApp.xcodeproj/project.xcworkspace/xcuserdata/lll.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp.xcodeproj/project.xcworkspace/xcuserdata/lll.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /DribbbleApp.xcodeproj/xcuserdata/lll.xcuserdatad/xcschemes/DribbbleApp.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /DribbbleApp.xcodeproj/xcuserdata/lll.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DribbbleApp.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 461D731B194D6AD40044B372 16 | 17 | primary 18 | 19 | 20 | 461D7328194D6AD40044B372 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /DribbbleApp.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DribbbleApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DribbbleApp 4 | // 5 | // Created by LLL on 14-6-15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject?]?) -> Bool { 18 | return true 19 | } 20 | 21 | func applicationWillResignActive(application: UIApplication) { 22 | // 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. 23 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 24 | } 25 | 26 | func applicationDidEnterBackground(application: UIApplication) { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | func applicationWillEnterForeground(application: UIApplication) { 32 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 33 | } 34 | 35 | func applicationDidBecomeActive(application: UIApplication) { 36 | // 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. 37 | } 38 | 39 | func applicationWillTerminate(application: UIApplication) { 40 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 41 | } 42 | 43 | 44 | } 45 | 46 | -------------------------------------------------------------------------------- /DribbbleApp/BaseNavigationViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseNavigationViewController.swift 3 | // DribbbleApp 4 | // 5 | // Created by LLL on 14-6-15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseNavigationViewController: UINavigationController { 12 | 13 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 14 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 15 | // Custom initialization 16 | } 17 | 18 | override init(rootViewController: UIViewController) { 19 | super.init(rootViewController: rootViewController) 20 | } 21 | 22 | required init(coder aDecoder: NSCoder) { 23 | super.init(coder: aDecoder) 24 | } 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | } 29 | 30 | override func didReceiveMemoryWarning() { 31 | super.didReceiveMemoryWarning() 32 | // Dispose of any resources that can be recreated. 33 | } 34 | 35 | 36 | /* 37 | // #pragma mark - Navigation 38 | 39 | // In a storyboard-based application, you will often want to do a little preparation before navigation 40 | override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) { 41 | // Get the new view controller using [segue destinationViewController]. 42 | // Pass the selected object to the new view controller. 43 | } 44 | */ 45 | 46 | } 47 | -------------------------------------------------------------------------------- /DribbbleApp/BaseViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseViewController.swift 3 | // DribbbleApp 4 | // 5 | // Created by LLL on 14-6-15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BaseViewController: UIViewController { 12 | 13 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 14 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 15 | // Custom initialization 16 | } 17 | 18 | convenience init() { 19 | self.init(nibName:nil, bundle:nil) 20 | } 21 | 22 | required init(coder aDecoder: NSCoder) { 23 | super.init(coder: aDecoder) 24 | } 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | 29 | } 30 | 31 | override func didReceiveMemoryWarning() { 32 | super.didReceiveMemoryWarning() 33 | } 34 | 35 | 36 | /* 37 | // #pragma mark - Navigation 38 | 39 | // In a storyboard-based application, you will often want to do a little preparation before navigation 40 | override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) { 41 | // Get the new view controller using [segue destinationViewController]. 42 | // Pass the selected object to the new view controller. 43 | } 44 | */ 45 | 46 | } 47 | -------------------------------------------------------------------------------- /DribbbleApp/CategoryViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryViewController.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CategoryViewController: UIViewController { 12 | 13 | 14 | 15 | override func awakeFromNib() { 16 | super.awakeFromNib() 17 | } 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | // Dispose of any resources that can be recreated. 26 | } 27 | 28 | @IBAction func tapCancel(sender: AnyObject) { 29 | 30 | dismissViewControllerAnimated(true, completion: nil) 31 | } 32 | 33 | 34 | /* 35 | // MARK: - Navigation 36 | 37 | // In a storyboard-based application, you will often want to do a little preparation before navigation 38 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 39 | // Get the new view controller using segue.destinationViewController. 40 | // Pass the selected object to the new view controller. 41 | } 42 | */ 43 | 44 | } 45 | -------------------------------------------------------------------------------- /DribbbleApp/CellConfigure.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CellConfigure.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | protocol ShotCellConfigure { 12 | func configureCell(model: Shot) 13 | } -------------------------------------------------------------------------------- /DribbbleApp/Comment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Comment.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/17. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyJSON 11 | 12 | class Comment: JsonParser { 13 | 14 | var id: Int = 0 15 | var body: String = "" 16 | var likesCount: Int = 0 17 | var createdAt: String = "" 18 | var user:User = User() 19 | 20 | func parse(json: JSON) { 21 | id = json["id"].intValue 22 | body = json["body"].stringValue 23 | likesCount = json["likes_count"].intValue 24 | createdAt = json["created_at"].stringValue 25 | user.parse(json["player"]) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /DribbbleApp/DribbbleApp-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 | #import "UIScrollView+VGParallaxHeader.h" -------------------------------------------------------------------------------- /DribbbleApp/DribbbleManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DribbbleManager.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Alamofire 11 | import SwiftyJSON 12 | 13 | 14 | class DribbbleManager: NSObject { 15 | 16 | let ClientID = "27549b70c4cceebd4c222df9e98ce8ec74685382951ace45c968fbc589d0c177" 17 | let ClientSecret = "a22e5da1ea4ccb66dbafafd461b849939be983ebefad75acb8ea2f98aa0e1874" 18 | let AccessToken = "d7db2c99ce0e597d79a91b3709b066a73348bc82704105426965bb40fedc1f6b" 19 | 20 | let APIUrl = "https://api.dribbble.com/v1" 21 | 22 | typealias Complation = (JSON!, NSError!) -> Void 23 | 24 | private var complation: Complation? 25 | 26 | enum ListType: String { 27 | case Animated = "animated" 28 | case Attachments = "attachments" 29 | case Debuts = "debuts" 30 | case Playoffs = "playoffs" 31 | case Rebounds = "rebounds" 32 | case Teams = "teams" 33 | } 34 | 35 | class func getShots(list: ListType, complation: Complation) { 36 | let manager = DribbbleManager() 37 | let requestString = "\(manager.APIUrl)/shots?list=\(list.rawValue)&access_token=\(manager.AccessToken)" 38 | manager.complation = complation 39 | manager.fetch(requestString) 40 | } 41 | 42 | class func getCommentOfShot(shot: Shot, complatin: Complation) { 43 | let manager = DribbbleManager() 44 | let requestString = "\(manager.APIUrl)/shots?\(shot.id)" 45 | manager.complation = complatin 46 | manager.fetch(requestString) 47 | } 48 | 49 | func fetch(url:String) { 50 | let requestURL = NSURL(string: url) 51 | Alamofire.request(.GET, url).responseJSON { (req, resp, someJson, someError) -> Void in 52 | if let error = someError { 53 | self.complation?(nil, error) 54 | return 55 | } 56 | 57 | if let json: AnyObject = someJson { 58 | var json = JSON(json) 59 | self.complation?(json, nil) 60 | return 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/comment.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "comment.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "comment@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "comment@3x.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/comment.imageset/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/comment.imageset/comment.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/comment.imageset/comment@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/comment.imageset/comment@2x.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/comment.imageset/comment@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/comment.imageset/comment@3x.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_gray.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "heart_gray.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "heart_gray@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "heart_gray@3x.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray@2x.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_gray.imageset/heart_gray@3x.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_red.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "heart_red.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "heart_red@2x.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "heart_red@3x.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_red.imageset/heart_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_red.imageset/heart_red.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_red.imageset/heart_red@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_red.imageset/heart_red@2x.png -------------------------------------------------------------------------------- /DribbbleApp/Images.xcassets/heart_red.imageset/heart_red@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvlprliu/DribbbleApp/76107434a91675121f8cdfcd1f7d7490f68acf86/DribbbleApp/Images.xcassets/heart_red.imageset/heart_red@3x.png -------------------------------------------------------------------------------- /DribbbleApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.iyhjy.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /DribbbleApp/JSONParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSONParser.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyJSON 11 | 12 | protocol JsonParser { 13 | func parse(json: JSON) 14 | } -------------------------------------------------------------------------------- /DribbbleApp/MTLShot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MTLShot.swift 3 | // DribbbleApp 4 | // 5 | // Created by LLL on 14-6-18. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | -------------------------------------------------------------------------------- /DribbbleApp/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 | 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 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 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 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 338 | 345 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | -------------------------------------------------------------------------------- /DribbbleApp/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftyJSON 11 | 12 | class MainViewController: BaseViewController { 13 | 14 | let cellIdentifer = "ShotListCell" 15 | 16 | var refreshControl: UIRefreshControl! 17 | 18 | @IBOutlet weak var tableView: UITableView! 19 | var shots: [Shot] = [Shot]() { 20 | didSet { 21 | tableView.reloadData() 22 | } 23 | } 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | setRefreshControl() 29 | 30 | loadShots() 31 | 32 | } 33 | 34 | // MARK: - UI 35 | 36 | func setRefreshControl() { 37 | self.refreshControl = UIRefreshControl(frame: CGRectZero) 38 | refreshControl.addTarget(self, action: "reloadShots:", forControlEvents: UIControlEvents.ValueChanged) 39 | tableView.addSubview(refreshControl) 40 | } 41 | 42 | override func preferredStatusBarStyle() -> UIStatusBarStyle { 43 | return .LightContent 44 | } 45 | 46 | // MARK: - Loading data 47 | 48 | private func loadShots() { 49 | DribbbleManager.getShots(DribbbleManager.ListType.Attachments, complation: { (JSON, someError) -> Void in 50 | self.refreshControl.endRefreshing() 51 | if let error = someError { 52 | println("error : \(error)") 53 | return 54 | } 55 | 56 | if let json = JSON { 57 | 58 | var shots = [Shot]() 59 | for shotJson in json.arrayValue { 60 | var shot = Shot() 61 | shot.parse(shotJson) 62 | shots.append(shot) 63 | 64 | } 65 | self.shots = shots 66 | } 67 | }) 68 | } 69 | 70 | func reloadShots(sender: AnyObject!) { 71 | refreshControl.beginRefreshing() 72 | loadShots() 73 | } 74 | 75 | override func didReceiveMemoryWarning() { 76 | super.didReceiveMemoryWarning() 77 | // Dispose of any resources that can be recreated. 78 | } 79 | 80 | 81 | // MARK: - Navigation 82 | 83 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 84 | 85 | if segue.identifier == "ShowShotDetail" { 86 | let cell = sender as! ShotListCell 87 | let indexPath = tableView.indexPathForCell(cell) 88 | let selectedIndex = indexPath?.row 89 | if let index = selectedIndex { 90 | let selectedShot = shots[index] 91 | let desVC = segue.destinationViewController as! ShotDetailViewController 92 | desVC.shot = selectedShot 93 | } 94 | } 95 | 96 | if segue.identifier == "ShowCategory" { 97 | let desVC = segue.destinationViewController as! CategoryViewController 98 | let transitionManager = TransitionManager() 99 | desVC.transitioningDelegate = transitionManager 100 | } 101 | } 102 | } 103 | 104 | extension MainViewController: UITableViewDelegate, UITableViewDataSource { 105 | 106 | func numberOfSectionsInTableView(tableView: UITableView) -> Int { 107 | return 1 108 | } 109 | func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 110 | return shots.count 111 | } 112 | 113 | func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 114 | let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifer) as! ShotListCell 115 | let shot = shots[indexPath.row] 116 | let imageUrl = shot.normalImageURL 117 | cell.shot = shot 118 | cell.shotImageView.sd_setImageWithURL(NSURL(string: imageUrl)) 119 | 120 | 121 | return cell 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /DribbbleApp/Player.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Player.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftyJSON 11 | 12 | class User: JsonParser { 13 | 14 | var id: Int = 0 15 | var name: String = "" 16 | var username: String = "" 17 | var htmlUrl: String = "" 18 | var avatarUrl: String = "" 19 | var location: String = "" 20 | var links: [String: JSON] = [String: JSON]() 21 | var bucketsCount: Int = 0 22 | var bio: String = "" 23 | var twitterScreenName: String = "" 24 | var draftedByPlayerId: Int = 0 25 | var shotsCount: Int = 0 26 | var drafteesCount: Int = 0 27 | var followersCount: Int = 0 28 | var followingCount: Int = 0 29 | var commentsCount: Int = 0 30 | var projectCount: Int = 0 31 | var commentsReceivedCount: Int = 0 32 | var likesCount: Int = 0 33 | var likeReceivedCount: Int = 0 34 | var reboundsCount: Int = 0 35 | var reboundsReceivedCount: Int = 0 36 | var createdAt: String = "" 37 | 38 | var teamCount: Int = 0 39 | var type: String = "" 40 | var pro: Bool = false 41 | 42 | var bucketsURL: String = "" 43 | var followerURL: String = "" 44 | var followingURL: String = "" 45 | var likesURL: String = "" 46 | var projectsURL: String = "" 47 | var shotsURL: String = "" 48 | var teamsURL: String = "" 49 | var updatedAt: String = "" 50 | 51 | init() { 52 | 53 | } 54 | 55 | func parse(json: JSON) { 56 | 57 | teamCount = json["teams_count"].intValue 58 | type = json["type"].stringValue 59 | pro = json["pro"].boolValue 60 | 61 | bucketsURL = json["buckets_url"].stringValue 62 | followerURL = json["followers_url"].stringValue 63 | followingURL = json["followings_url"].stringValue 64 | likesURL = json["likes_url"].stringValue 65 | projectsURL = json["projects_url"].stringValue 66 | shotsURL = json["shots_url"].stringValue 67 | teamsURL = json["teams_url"].stringValue 68 | updatedAt = json["updated_at"].stringValue 69 | 70 | id = json["id"].intValue 71 | name = json["name"].stringValue 72 | username = json["username"].stringValue 73 | htmlUrl = json["html_url"].stringValue 74 | avatarUrl = json["avatar_url"].stringValue 75 | bio = json["bio"].stringValue 76 | links = json["links"].dictionaryValue 77 | location = json["location"].stringValue 78 | bucketsCount = json["buckets_count"].intValue 79 | projectCount = json["projects_count"].intValue 80 | twitterScreenName = json["twitter_screen_name"].stringValue 81 | draftedByPlayerId = json["drafted_by_player_id"].intValue 82 | shotsCount = json["shots_count"].intValue 83 | drafteesCount = json["draftees_count"].intValue 84 | followersCount = json["followers_count"].intValue 85 | followingCount = json["following_count"].intValue 86 | commentsCount = json["comments_count"].intValue 87 | commentsReceivedCount = json["comments_received_count"].intValue 88 | likesCount = json["likes_count"].intValue 89 | likeReceivedCount = json["likes_received_count"].intValue 90 | reboundsCount = json["rebounds_count"].intValue 91 | reboundsReceivedCount = json["rebounds_received_count"].intValue 92 | createdAt = json["created_at"].stringValue 93 | 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /DribbbleApp/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '7.0' 2 | 3 | pod 'SVProgressHUD' 4 | pod 'AFNetworking' -------------------------------------------------------------------------------- /DribbbleApp/Shot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EMShotModel.swift 3 | // DribbbleApp 4 | // 5 | // Created by LLL on 14-6-15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import SwiftyJSON 12 | 13 | class Shot: JsonParser { 14 | 15 | var id:Int = 0 16 | var title:String = "" 17 | var descriptionOfShot:String = "" 18 | var url:String = "" 19 | var shortUrl:String = "" 20 | var imageUrl:String = "" 21 | var width:Int = 0 22 | var height:Int = 0 23 | var likesCount:Int = 0 24 | var viewsCount:Int = 0 25 | var commentsCount: Int = 0 26 | var reboundsCounts: Int = 0 27 | var reboundsSourceId: Int = 0 28 | var createdAt:String = "" 29 | 30 | var attachmentsCount: Int = 0 31 | var bucketsCount: Int = 0 32 | var updatedAt: String = "" 33 | var htmlURL: String = "" 34 | var attachmentsURL: String = "" 35 | var bucketsURL: String = "" 36 | var commentsURL: String = "" 37 | var likesURL: String = "" 38 | var projectsURL: String = "" 39 | var reboundsURL: String = "" 40 | var tags: [JSON] = [JSON]() 41 | var team: Team? = nil 42 | 43 | 44 | var hidpiImageURL: String = "" 45 | var normalImageURL: String = "" 46 | var teaserImageURL: String = "" 47 | 48 | var image:UIImage? 49 | 50 | lazy var user: User = User() 51 | 52 | init() { 53 | 54 | } 55 | 56 | func parse(json: JSON){ 57 | 58 | self.id = json["id"].intValue 59 | self.title = json["title"].stringValue 60 | self.descriptionOfShot = json["description"].stringValue 61 | self.url = json["url"].stringValue 62 | self.shortUrl = json["shot_url"].stringValue 63 | self.imageUrl = json["image_url"].stringValue 64 | self.width = json["width"].intValue 65 | self.height = json["height"].intValue 66 | self.viewsCount = json["views_count"].intValue 67 | self.likesCount = json["likes_count"].intValue 68 | self.commentsCount = json["comments_count"].intValue 69 | self.reboundsCounts = json["rebounds_count"].intValue 70 | self.reboundsSourceId = json["rebounds_source_id"].intValue 71 | self.createdAt = json["created_at"].stringValue 72 | self.user.parse(json["user"]) 73 | 74 | self.attachmentsCount = json["attachments_count"].intValue 75 | self.bucketsCount = json["buckets_count"].intValue 76 | self.updatedAt = json["updated_at"].stringValue 77 | self.htmlURL = json["html_url"].stringValue 78 | self.attachmentsURL = json["attachments_url"].stringValue 79 | self.bucketsURL = json["buckets_url"].stringValue 80 | self.commentsURL = json["comments_url"].stringValue 81 | self.likesURL = json["likes_url"].stringValue 82 | self.projectsURL = json["projects_url"].stringValue 83 | self.reboundsURL = json["rebounds_url"].stringValue 84 | self.tags = json["tags"].arrayValue 85 | 86 | self.hidpiImageURL = json["images","hidpi"].stringValue 87 | self.normalImageURL = json["images","normal"].stringValue 88 | self.teaserImageURL = json["images","teaser"].stringValue 89 | 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /DribbbleApp/ShotAttachmentCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotAttachmentCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotAttachmentCell: ShotCell, ShotCellConfigure { 12 | 13 | 14 | override func configureCell(model: Shot) { 15 | println("configure cell \(self)") 16 | } 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | // Initialization code 21 | } 22 | 23 | override func setSelected(selected: Bool, animated: Bool) { 24 | super.setSelected(selected, animated: animated) 25 | 26 | // Configure the view for the selected state 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /DribbbleApp/ShotCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotCell: UITableViewCell, ShotCellConfigure { 12 | 13 | var shot: Shot? { 14 | didSet { 15 | configureCell(shot!) 16 | } 17 | } 18 | 19 | func configureCell(model: Shot) { 20 | 21 | } 22 | 23 | override func awakeFromNib() { 24 | super.awakeFromNib() 25 | // Initialization code 26 | } 27 | 28 | override func setSelected(selected: Bool, animated: Bool) { 29 | super.setSelected(selected, animated: animated) 30 | 31 | // Configure the view for the selected state 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /DribbbleApp/ShotDetailDataSource.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotDetailDataSource.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/18. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | -------------------------------------------------------------------------------- /DribbbleApp/ShotDetailTableHeader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotDetailTableHeader.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/17. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotDetailTableHeader: UIView { 12 | 13 | class func nibView() -> UIView? { 14 | 15 | return NSBundle.mainBundle().loadNibNamed("ShotDetailTableHeader", owner: nil, options: nil).first as? UIView 16 | 17 | } 18 | 19 | /* 20 | // Only override drawRect: if you perform custom drawing. 21 | // An empty implementation adversely affects performance during animation. 22 | override func drawRect(rect: CGRect) { 23 | // Drawing code 24 | } 25 | */ 26 | 27 | } 28 | -------------------------------------------------------------------------------- /DribbbleApp/ShotDetailTableHeader.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /DribbbleApp/ShotDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotDetailViewController.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotDetailViewController: UIViewController, UIScrollViewDelegate { 12 | 13 | private let AuthorCellIdentifer = "AuthorCell" 14 | private let AttetchmentCellIdentifer = "AttatchmentCell" 15 | private let TagCellIdentifer = "TagCell" 16 | private let LikeCellIdentifier = "LikeCell" 17 | 18 | var shot: Shot? = nil 19 | 20 | @IBOutlet weak var headerView: UIView! 21 | @IBOutlet weak var tableView: UITableView! 22 | 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | 27 | let headerView = ShotDetailTableHeader.nibView() 28 | 29 | tableView.setParallaxHeaderView(headerView, mode: VGParallaxHeaderMode.Fill, height: 200) 30 | tableView.rowHeight = UITableViewAutomaticDimension 31 | tableView.estimatedRowHeight = 44.0 32 | 33 | 34 | } 35 | 36 | func getComment(shot: Shot) { 37 | 38 | } 39 | 40 | override func didReceiveMemoryWarning() { 41 | super.didReceiveMemoryWarning() 42 | // Dispose of any resources that can be recreated. 43 | } 44 | 45 | func scrollViewDidScroll(scrollView: UIScrollView) { 46 | tableView.shouldPositionParallaxHeader() 47 | } 48 | 49 | /* 50 | // MARK: - Navigation 51 | 52 | // In a storyboard-based application, you will often want to do a little preparation before navigation 53 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 54 | // Get the new view controller using segue.destinationViewController. 55 | // Pass the selected object to the new view controller. 56 | } 57 | */ 58 | 59 | } 60 | 61 | extension ShotDetailViewController: UITableViewDelegate, UITableViewDataSource { 62 | 63 | 64 | 65 | func numberOfSectionsInTableView(tableView: UITableView) -> Int { 66 | return 5 67 | } 68 | 69 | func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 70 | switch section{ 71 | case 0, 1, 2: 72 | return 1 73 | case 3: 74 | if let aShot = shot { 75 | println("attachment count \(aShot.attachmentsCount)") 76 | return aShot.attachmentsCount 77 | } 78 | case 4: 79 | if let aShot = shot { 80 | println("comment count \(aShot.commentsCount)") 81 | return aShot.commentsCount 82 | } 83 | default: 84 | return 0 85 | } 86 | 87 | return 0 88 | } 89 | 90 | 91 | 92 | func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 93 | 94 | let section = indexPath.section 95 | let row = indexPath.row 96 | if section == 0 { 97 | let cell = tableView.dequeueReusableCellWithIdentifier(LikeCellIdentifier) as! ShotLikesTableCell 98 | 99 | cell.shot = shot 100 | 101 | return cell 102 | } 103 | else if section == 1 { 104 | let cell = tableView.dequeueReusableCellWithIdentifier(AuthorCellIdentifer) as! ShotInfoTableCell 105 | 106 | cell.shot = shot 107 | 108 | return cell 109 | } 110 | 111 | else if section == 2 { 112 | let tagCell = tableView.dequeueReusableCellWithIdentifier(TagCellIdentifer) as! UITableViewCell 113 | 114 | return tagCell 115 | } 116 | 117 | else if section == 3 { 118 | let attatchmentCell = tableView.dequeueReusableCellWithIdentifier(AttetchmentCellIdentifer) as! UITableViewCell 119 | 120 | return attatchmentCell 121 | } 122 | 123 | else if section == 4 { 124 | let commentCell = tableView.dequeueReusableCellWithIdentifier(AuthorCellIdentifer) as! UITableViewCell 125 | 126 | return commentCell 127 | } 128 | 129 | else { 130 | return UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "Cell") 131 | } 132 | } 133 | 134 | // func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 135 | // switch indexPath.section { 136 | // case 0: 137 | // return 86 138 | // case 1: 139 | // return 149 140 | // case 2: 141 | // return 44 142 | // case 3: 143 | // return 49 144 | // case 4: 145 | // return 120 146 | // default: 147 | // return 0 148 | // } 149 | // } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /DribbbleApp/ShotInfoTableCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotInfoTableCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotInfoTableCell: ShotCell, ShotCellConfigure { 12 | 13 | @IBOutlet weak var avatarImageView: UIImageView! 14 | @IBOutlet weak var userLabel: UILabel! 15 | @IBOutlet weak var describLabel: UILabel! 16 | @IBOutlet weak var timeLabel: UILabel! 17 | 18 | override func configureCell(model: Shot) { 19 | userLabel.text = model.user.username 20 | describLabel.text = model.descriptionOfShot 21 | } 22 | 23 | override func awakeFromNib() { 24 | super.awakeFromNib() 25 | // Initialization code 26 | } 27 | 28 | override func setSelected(selected: Bool, animated: Bool) { 29 | super.setSelected(selected, animated: animated) 30 | 31 | // Configure the view for the selected state 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /DribbbleApp/ShotLikesTableCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotLikesTableCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotLikesTableCell: ShotCell, ShotCellConfigure { 12 | 13 | @IBOutlet weak var likesCountLabel: UILabel! 14 | @IBOutlet weak var commentsCountLabel: UILabel! 15 | @IBOutlet weak var viewsCountLabel: UILabel! 16 | 17 | @IBAction func viewLikes(sender: AnyObject) { 18 | 19 | } 20 | @IBAction func viewComments(sender: AnyObject) { 21 | 22 | } 23 | 24 | override func configureCell(model: Shot) { 25 | println("configure cell \(self), \(model)") 26 | 27 | likesCountLabel.text = "\(model.likesCount)" 28 | commentsCountLabel.text = "\(model.commentsCount)" 29 | viewsCountLabel.text = "\(model.viewsCount)" 30 | 31 | } 32 | 33 | override func awakeFromNib() { 34 | super.awakeFromNib() 35 | // Initialization code 36 | } 37 | 38 | override func setSelected(selected: Bool, animated: Bool) { 39 | super.setSelected(selected, animated: animated) 40 | 41 | // Configure the view for the selected state 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /DribbbleApp/ShotListCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/16. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotListCell: ShotCell { 12 | 13 | @IBOutlet weak var shotImageView: UIImageView! 14 | @IBOutlet weak var loader: UIActivityIndicatorView! 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | loader.startAnimating() 19 | self.addObserver(self, forKeyPath: "self.shotImageView.image", options: NSKeyValueObservingOptions.New, context: nil) 20 | } 21 | 22 | override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer) { 23 | if keyPath == "self.shotImageView.image" { 24 | if let image = change["new"] as? UIImage { 25 | loader.stopAnimating() 26 | } 27 | 28 | } 29 | } 30 | 31 | deinit { 32 | println("\(__FUNCTION__)") 33 | self.removeObserver(self, forKeyPath: "self.shotImageView.image") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /DribbbleApp/ShotTagTableCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShotTagTableCell.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/19. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ShotTagTableCell: ShotCell, ShotCellConfigure { 12 | 13 | override func configureCell(model: Shot) { 14 | println("configure cell \(self)") 15 | } 16 | 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | // Initialization code 20 | } 21 | 22 | override func setSelected(selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | 25 | // Configure the view for the selected state 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /DribbbleApp/Team.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Team.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/18. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SwiftyJSON 11 | 12 | class Team: JsonParser { 13 | 14 | var id: Int = 0 15 | var name: String = "" 16 | var userName: String = "" 17 | var htmlURL: String = "" 18 | var avatarURL: String = "" 19 | var bio: String = "" 20 | var location: String = "" 21 | var links: [String: JSON] = [String: JSON]() 22 | 23 | var bucketsCount: Int = 0 24 | var followersCount: Int = 0 25 | var followingsCount: Int = 0 26 | var likesCount: Int = 0 27 | var projectsCount: Int = 0 28 | var shotsCount: Int = 0 29 | var type: String = "" 30 | var pro: Bool = false 31 | 32 | 33 | var bucketsURL: String = "" 34 | var followerURL: String = "" 35 | var followingURL: String = "" 36 | var likesURL: String = "" 37 | var projectsURL: String = "" 38 | var shotsURL: String = "" 39 | var teamsURL: String = "" 40 | var updatedAt: String = "" 41 | 42 | init() { 43 | 44 | } 45 | 46 | func parse(json: JSON) { 47 | 48 | id = json["id"].intValue 49 | name = json["name"].stringValue 50 | userName = json["user_name"].stringValue 51 | htmlURL = json["html_url"].stringValue 52 | avatarURL = json["avatar_url"].stringValue 53 | bio = json["bio"].stringValue 54 | location = json["location"].stringValue 55 | links = json["links"].dictionaryValue 56 | 57 | bucketsCount = json["buckets_count"].intValue 58 | followersCount = json["follower_count"].intValue 59 | followingsCount = json["following_count"].intValue 60 | projectsCount = json["projects_count"].intValue 61 | shotsCount = json["shots_count"].intValue 62 | 63 | type = json["type"].stringValue 64 | pro = json["pro"].boolValue 65 | 66 | bucketsURL = json["buckets_url"].stringValue 67 | followerURL = json["followers_url"].stringValue 68 | followingURL = json["followings_url"].stringValue 69 | likesURL = json["likes_url"].stringValue 70 | projectsURL = json["projects_url"].stringValue 71 | shotsURL = json["shots_url"].stringValue 72 | teamsURL = json["teams_url"].stringValue 73 | updatedAt = json["updated_at"].stringValue 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /DribbbleApp/TransitionManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransitionManager.swift 3 | // DribbbleApp 4 | // 5 | // Created by Zhuang Liu on 14/12/17. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TransitionManager: NSObject { 12 | private var presenting = false 13 | } 14 | 15 | extension TransitionManager: UIViewControllerAnimatedTransitioning { 16 | func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { 17 | return 0.25 18 | } 19 | 20 | func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 21 | 22 | let container = transitionContext.containerView() 23 | 24 | let screens: (from: UIViewController, to: UIViewController) = (transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!, transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!) 25 | 26 | container.addSubview(screens.to.view) 27 | screens.to.view.alpha = 0 28 | 29 | let duration = self.transitionDuration(transitionContext) 30 | 31 | UIView.animateWithDuration(duration, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.8, options: nil, animations: { () -> Void in 32 | screens.to.view.alpha = 1 33 | }) { (finished) -> Void in 34 | 35 | transitionContext.completeTransition(true) 36 | 37 | } 38 | } 39 | } 40 | 41 | extension TransitionManager: UIViewControllerTransitioningDelegate { 42 | func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 43 | self.presenting = true 44 | return self 45 | } 46 | 47 | func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 48 | self.presenting = false 49 | return self 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /DribbbleApp/UIScrollView+VGParallaxHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+VKParallaxHeader.m 3 | // 4 | // Created by Marek Serafin on 2014-09-18. 5 | // Copyright (c) 2013 VG. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | typedef NS_ENUM(NSInteger, VGParallaxHeaderMode) { 11 | VGParallaxHeaderModeCenter = 0, 12 | VGParallaxHeaderModeFill, 13 | VGParallaxHeaderModeTop, 14 | VGParallaxHeaderModeTopFill, 15 | }; 16 | 17 | typedef NS_ENUM(NSInteger, VGParallaxHeaderStickyViewPosition) { 18 | VGParallaxHeaderStickyViewPositionBottom = 0, 19 | VGParallaxHeaderStickyViewPositionTop, 20 | }; 21 | 22 | typedef NS_ENUM(NSInteger, VGParallaxHeaderShadowBehaviour) { 23 | VGParallaxHeaderShadowBehaviourHidden = 0, 24 | VGParallaxHeaderShadowBehaviourAppearing, 25 | VGParallaxHeaderShadowBehaviourDisappearing, 26 | VGParallaxHeaderShadowBehaviourAlways, 27 | } __deprecated; 28 | 29 | @interface VGParallaxHeader : UIView 30 | @property (nonatomic, assign, readonly) VGParallaxHeaderMode mode; 31 | 32 | @property (nonatomic, assign, readwrite) VGParallaxHeaderStickyViewPosition stickyViewPosition; 33 | @property (nonatomic, assign, readwrite) NSLayoutConstraint *stickyViewHeightConstraint; 34 | @property (nonatomic, strong, readwrite) UIView *stickyView; 35 | 36 | @property (nonatomic, assign, readonly, getter=isInsideTableView) BOOL insideTableView; 37 | @property (nonatomic, assign, readonly) CGFloat progress; 38 | 39 | @property (nonatomic, assign, readonly) VGParallaxHeaderShadowBehaviour shadowBehaviour __deprecated; 40 | 41 | - (void)setStickyView:(UIView *)stickyView 42 | withHeight:(CGFloat)height; 43 | 44 | @end 45 | 46 | @interface UIScrollView (VGParallaxHeader) 47 | 48 | @property (nonatomic, strong, readonly) VGParallaxHeader *parallaxHeader; 49 | 50 | - (void)setParallaxHeaderView:(UIView *)view 51 | mode:(VGParallaxHeaderMode)mode 52 | height:(CGFloat)height; 53 | 54 | - (void)setParallaxHeaderView:(UIView *)view 55 | mode:(VGParallaxHeaderMode)mode 56 | height:(CGFloat)height 57 | shadowBehaviour:(VGParallaxHeaderShadowBehaviour)shadowBehaviour __deprecated_msg("Use sticky view instead of shadow"); 58 | 59 | - (void)shouldPositionParallaxHeader; 60 | 61 | @end -------------------------------------------------------------------------------- /DribbbleApp/UIScrollView+VGParallaxHeader.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+VGParallaxHeader.m 3 | // 4 | // Created by Marek Serafin on 2014-09-18. 5 | // Copyright (c) 2013 VG. All rights reserved. 6 | // 7 | 8 | #import "UIScrollView+VGParallaxHeader.h" 9 | 10 | #import 11 | #import 12 | #import "PureLayout.h" 13 | 14 | static char UIScrollViewVGParallaxHeader; 15 | static void *VGParallaxHeaderObserverContext = &VGParallaxHeaderObserverContext; 16 | 17 | #pragma mark - VGParallaxHeader (Interface) 18 | @interface VGParallaxHeader () 19 | 20 | - (instancetype)initWithScrollView:(UIScrollView *)scrollView 21 | contentView:(UIView *)view 22 | mode:(VGParallaxHeaderMode)mode 23 | height:(CGFloat)height; 24 | 25 | @property (nonatomic, assign, readwrite, getter=isInsideTableView) BOOL insideTableView; 26 | 27 | @property (nonatomic, assign, readwrite) VGParallaxHeaderMode mode; 28 | 29 | @property (nonatomic, strong, readwrite) UIView *containerView; 30 | @property (nonatomic, strong, readwrite) UIView *contentView; 31 | 32 | @property (nonatomic, weak, readwrite) UIScrollView *scrollView; 33 | 34 | @property (nonatomic, readwrite) CGFloat originalTopInset; 35 | @property (nonatomic, readwrite) CGFloat originalHeight; 36 | 37 | @property (nonatomic, strong, readwrite) NSLayoutConstraint *insetAwarePositionConstraint; 38 | @property (nonatomic, strong, readwrite) NSLayoutConstraint *insetAwareSizeConstraint; 39 | 40 | @property (nonatomic, assign, readwrite) CGFloat progress; 41 | 42 | @property (nonatomic, strong, readwrite) NSArray *stickyViewContraints; 43 | 44 | @end 45 | 46 | #pragma mark - UIScrollView (Implementation) 47 | @implementation UIScrollView (VGParallaxHeader) 48 | 49 | - (void)setParallaxHeaderView:(UIView *)view 50 | mode:(VGParallaxHeaderMode)mode 51 | height:(CGFloat)height 52 | shadowBehaviour:(VGParallaxHeaderShadowBehaviour)shadowBehaviour 53 | { 54 | [self setParallaxHeaderView:view 55 | mode:mode 56 | height:height]; 57 | } 58 | 59 | - (void)setParallaxHeaderView:(UIView *)view 60 | mode:(VGParallaxHeaderMode)mode 61 | height:(CGFloat)height 62 | { 63 | // New VGParallaxHeader 64 | self.parallaxHeader = [[VGParallaxHeader alloc] initWithScrollView:self 65 | contentView:view 66 | mode:mode 67 | height:height]; 68 | // Calling this to position everything right 69 | [self shouldPositionParallaxHeader]; 70 | 71 | // If UIScrollView adjust inset 72 | if (!self.parallaxHeader.isInsideTableView) { 73 | UIEdgeInsets selfContentInset = self.contentInset; 74 | selfContentInset.top += height; 75 | 76 | self.contentInset = selfContentInset; 77 | self.contentOffset = CGPointMake(0, -selfContentInset.top); 78 | } 79 | 80 | // Watch for inset changes 81 | [self addObserver:self.parallaxHeader 82 | forKeyPath:NSStringFromSelector(@selector(contentInset)) 83 | options:NSKeyValueObservingOptionNew 84 | context:VGParallaxHeaderObserverContext]; 85 | } 86 | 87 | - (void)shouldPositionParallaxHeader 88 | { 89 | if(self.parallaxHeader.isInsideTableView) { 90 | [self positionTableViewParallaxHeader]; 91 | } 92 | else { 93 | [self positionScrollViewParallaxHeader]; 94 | } 95 | } 96 | 97 | - (void)positionTableViewParallaxHeader 98 | { 99 | CGFloat scaleProgress = fmaxf(0, (1 - ((self.contentOffset.y + self.parallaxHeader.originalTopInset) / self.parallaxHeader.originalHeight))); 100 | self.parallaxHeader.progress = scaleProgress; 101 | 102 | if (self.contentOffset.y < self.parallaxHeader.originalHeight) { 103 | // We can move height to if here because its uitableview 104 | CGFloat height = self.contentOffset.y * -1 + self.parallaxHeader.originalHeight; 105 | // Im not 100% sure if this will only speed up VGParallaxHeaderModeCenter 106 | // but on other modes it can be visible. 0.5px 107 | if (self.parallaxHeader.mode == VGParallaxHeaderModeCenter) { 108 | height = round(height); 109 | } 110 | // This is where the magic is happening 111 | self.parallaxHeader.containerView.frame = CGRectMake(0, self.contentOffset.y, CGRectGetWidth(self.frame), height); 112 | } 113 | } 114 | 115 | - (void)positionScrollViewParallaxHeader 116 | { 117 | CGFloat height = self.contentOffset.y * -1; 118 | CGFloat scaleProgress = fmaxf(0, (height / (self.parallaxHeader.originalHeight + self.parallaxHeader.originalTopInset))); 119 | self.parallaxHeader.progress = scaleProgress; 120 | 121 | if (self.contentOffset.y < 0) { 122 | // This is where the magic is happening 123 | self.parallaxHeader.frame = CGRectMake(0, self.contentOffset.y, CGRectGetWidth(self.frame), height); 124 | } 125 | } 126 | 127 | - (void)setParallaxHeader:(VGParallaxHeader *)parallaxHeader 128 | { 129 | // Remove All Subviews 130 | if([self.subviews count] > 0) { 131 | [self.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 132 | if([obj isMemberOfClass:[VGParallaxHeader class]]) { 133 | [obj removeFromSuperview]; 134 | } 135 | }]; 136 | } 137 | 138 | parallaxHeader.insideTableView = [self isKindOfClass:[UITableView class]]; 139 | 140 | // Add Parallax Header 141 | if(parallaxHeader.isInsideTableView) { 142 | [(UITableView*)self setTableHeaderView:parallaxHeader]; 143 | [parallaxHeader setNeedsLayout]; 144 | } 145 | else { 146 | [self addSubview:parallaxHeader]; 147 | } 148 | 149 | // Set Associated Object 150 | objc_setAssociatedObject(self, &UIScrollViewVGParallaxHeader, parallaxHeader, OBJC_ASSOCIATION_ASSIGN); 151 | } 152 | 153 | - (VGParallaxHeader *)parallaxHeader 154 | { 155 | return objc_getAssociatedObject(self, &UIScrollViewVGParallaxHeader); 156 | } 157 | 158 | @end 159 | 160 | #pragma mark - VGParallaxHeader (Implementation) 161 | @implementation VGParallaxHeader 162 | 163 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 164 | { 165 | self = [super initWithCoder:aDecoder]; 166 | if (!self) { 167 | return nil; 168 | } 169 | 170 | // FIXME: Init with storyboards not yet supported 171 | 172 | return self; 173 | } 174 | 175 | - (instancetype)initWithScrollView:(UIScrollView *)scrollView 176 | contentView:(UIView *)view 177 | mode:(VGParallaxHeaderMode)mode 178 | height:(CGFloat)height 179 | { 180 | self = [super initWithFrame:CGRectMake(0, 0, CGRectGetWidth(scrollView.bounds), height)]; 181 | if (!self) { 182 | return nil; 183 | } 184 | 185 | self.mode = mode; 186 | 187 | self.scrollView = scrollView; 188 | 189 | self.originalHeight = height; 190 | self.originalTopInset = scrollView.contentInset.top; 191 | 192 | self.containerView = [[UIView alloc] initWithFrame:self.bounds]; 193 | self.containerView.clipsToBounds = YES; 194 | 195 | if (!self.isInsideTableView) { 196 | self.containerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 197 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth; 198 | } 199 | 200 | [self addSubview:self.containerView]; 201 | 202 | self.contentView = view; 203 | 204 | return self; 205 | } 206 | 207 | - (void)setContentView:(UIView *)contentView 208 | { 209 | if(_contentView != nil) { 210 | [_contentView removeFromSuperview]; 211 | } 212 | 213 | _contentView = contentView; 214 | _contentView.translatesAutoresizingMaskIntoConstraints = NO; 215 | 216 | [self.containerView addSubview:_contentView]; 217 | 218 | // Constraints 219 | [self setupContentViewMode]; 220 | } 221 | 222 | - (void)setupContentViewMode 223 | { 224 | switch (self.mode) { 225 | case VGParallaxHeaderModeFill: 226 | [self addContentViewModeFillConstraints]; 227 | break; 228 | case VGParallaxHeaderModeTop: 229 | [self addContentViewModeTopConstraints]; 230 | break; 231 | case VGParallaxHeaderModeTopFill: 232 | [self addContentViewModeTopFillConstraints]; 233 | break; 234 | case VGParallaxHeaderModeCenter: 235 | default: 236 | [self addContentViewModeCenterConstraints]; 237 | break; 238 | } 239 | } 240 | 241 | - (void)observeValueForKeyPath:(NSString *)keyPath 242 | ofObject:(id)object 243 | change:(NSDictionary *)change 244 | context:(void *)context 245 | { 246 | if ([keyPath isEqualToString:NSStringFromSelector(@selector(contentInset))] && context == VGParallaxHeaderObserverContext) { 247 | UIEdgeInsets edgeInsets = [[change valueForKey:@"new"] UIEdgeInsetsValue]; 248 | 249 | // If scroll view we need to fix inset (TableView has parallax view in table view header) 250 | self.originalTopInset = edgeInsets.top - ((!self.isInsideTableView) ? self.originalHeight : 0); 251 | 252 | switch (self.mode) { 253 | case VGParallaxHeaderModeFill: 254 | self.insetAwarePositionConstraint.constant = self.originalTopInset / 2; 255 | self.insetAwareSizeConstraint.constant = -self.originalTopInset; 256 | break; 257 | case VGParallaxHeaderModeTop: 258 | self.insetAwarePositionConstraint.constant = self.originalTopInset; 259 | break; 260 | case VGParallaxHeaderModeTopFill: 261 | self.insetAwarePositionConstraint.constant = self.originalTopInset; 262 | self.insetAwareSizeConstraint.constant = -self.originalTopInset; 263 | break; 264 | case VGParallaxHeaderModeCenter: 265 | default: 266 | self.insetAwarePositionConstraint.constant = self.originalTopInset / 2; 267 | break; 268 | } 269 | 270 | if(!self.isInsideTableView) { 271 | self.scrollView.contentOffset = CGPointMake(0, -self.scrollView.contentInset.top); 272 | } 273 | 274 | // Refresh Sticky View Constraints 275 | [self updateStickyViewConstraints]; 276 | } 277 | } 278 | 279 | - (void)willMoveToSuperview:(UIView *)newSuperview 280 | { 281 | if (self.superview && newSuperview == nil) { 282 | [self.superview removeObserver:self 283 | forKeyPath:NSStringFromSelector(@selector(contentInset)) 284 | context:VGParallaxHeaderObserverContext]; 285 | } 286 | } 287 | 288 | #pragma mark - VGParallaxHeader (Auto Layout) 289 | - (void)addContentViewModeFillConstraints 290 | { 291 | [self.contentView autoPinEdgeToSuperviewEdge:ALEdgeLeft 292 | withInset:0]; 293 | [self.contentView autoPinEdgeToSuperviewEdge:ALEdgeRight 294 | withInset:0]; 295 | 296 | self.insetAwarePositionConstraint = [self.contentView autoAlignAxis:ALAxisHorizontal 297 | toSameAxisOfView:self.containerView 298 | withOffset:self.originalTopInset/2]; 299 | 300 | NSLayoutConstraint *constraint = [self.contentView autoSetDimension:ALDimensionHeight 301 | toSize:self.originalHeight 302 | relation:NSLayoutRelationGreaterThanOrEqual]; 303 | constraint.priority = UILayoutPriorityRequired; 304 | 305 | self.insetAwareSizeConstraint = [self.contentView autoMatchDimension:ALDimensionHeight 306 | toDimension:ALDimensionHeight 307 | ofView:self.containerView 308 | withOffset:-self.originalTopInset]; 309 | self.insetAwareSizeConstraint.priority = UILayoutPriorityDefaultHigh; 310 | } 311 | 312 | - (void)addContentViewModeTopConstraints 313 | { 314 | NSArray *array = [self.contentView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(self.originalTopInset, 0, 0, 0) 315 | excludingEdge:ALEdgeBottom]; 316 | self.insetAwarePositionConstraint = [array firstObject]; 317 | 318 | [self.contentView autoSetDimension:ALDimensionHeight 319 | toSize:self.originalHeight]; 320 | } 321 | 322 | - (void)addContentViewModeTopFillConstraints 323 | { 324 | NSArray *array = [self.contentView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(self.originalTopInset, 0, 0, 0) 325 | excludingEdge:ALEdgeBottom]; 326 | self.insetAwarePositionConstraint = [array firstObject]; 327 | 328 | NSLayoutConstraint *constraint = [self.contentView autoSetDimension:ALDimensionHeight 329 | toSize:self.originalHeight 330 | relation:NSLayoutRelationGreaterThanOrEqual]; 331 | constraint.priority = UILayoutPriorityRequired; 332 | 333 | self.insetAwareSizeConstraint = [self.contentView autoMatchDimension:ALDimensionHeight 334 | toDimension:ALDimensionHeight 335 | ofView:self.containerView 336 | withOffset:-self.originalTopInset]; 337 | self.insetAwareSizeConstraint.priority = UILayoutPriorityDefaultHigh; 338 | } 339 | 340 | - (void)addContentViewModeCenterConstraints 341 | { 342 | [self.contentView autoPinEdgeToSuperviewEdge:ALEdgeLeft 343 | withInset:0]; 344 | [self.contentView autoPinEdgeToSuperviewEdge:ALEdgeRight 345 | withInset:0]; 346 | [self.contentView autoSetDimension:ALDimensionHeight 347 | toSize:self.originalHeight]; 348 | 349 | self.insetAwarePositionConstraint = [self.contentView autoAlignAxis:ALAxisHorizontal 350 | toSameAxisOfView:self.containerView 351 | withOffset:round(self.originalTopInset/2)]; 352 | } 353 | 354 | #pragma mark - VGParallaxHeader (Sticky View) 355 | - (void)setStickyView:(UIView *)stickyView 356 | { 357 | // Make sure it will work with AutLayout 358 | stickyView.translatesAutoresizingMaskIntoConstraints = NO; 359 | 360 | // Add it to Parallax Header 361 | [self.containerView insertSubview:stickyView 362 | aboveSubview:self.contentView]; 363 | 364 | // Set Local Var 365 | _stickyView = stickyView; 366 | 367 | // Refresh Constraints 368 | [self updateStickyViewConstraints]; 369 | } 370 | 371 | - (void)setStickyView:(UIView *)stickyView withHeight:(CGFloat)height 372 | { 373 | // Set Sticky View 374 | [self setStickyView:stickyView]; 375 | 376 | // Add Height Constraint 377 | self.stickyViewHeightConstraint = [self.stickyView autoSetDimension:ALDimensionHeight 378 | toSize:height]; 379 | } 380 | 381 | - (void)setStickyViewPosition:(VGParallaxHeaderStickyViewPosition)stickyViewPosition 382 | { 383 | // Set Local Var 384 | _stickyViewPosition = stickyViewPosition; 385 | 386 | // Refresh Constraints 387 | [self updateStickyViewConstraints]; 388 | } 389 | 390 | - (void)setStickyViewHeightConstraint:(NSLayoutConstraint *)stickyViewHeightConstraint 391 | { 392 | // Remove Previous Height Constraint 393 | if (_stickyViewHeightConstraint != nil) { 394 | [self.stickyView removeConstraint:_stickyViewHeightConstraint]; 395 | } 396 | 397 | // Add Height Constraint 398 | if ([self.stickyView.superview isEqual:self.containerView]) { 399 | [self.stickyView addConstraint:stickyViewHeightConstraint]; 400 | } 401 | 402 | // Set Local Var 403 | _stickyViewHeightConstraint = stickyViewHeightConstraint; 404 | } 405 | 406 | - (void)updateStickyViewConstraints 407 | { 408 | // Make sure stickyView is added to Parallax Header 409 | if ([self.stickyView.superview isEqual:self.containerView]) { 410 | // Set Edges 411 | ALEdge nonStickyEdge; 412 | switch (self.stickyViewPosition) { 413 | case VGParallaxHeaderStickyViewPositionTop: 414 | nonStickyEdge = ALEdgeBottom; 415 | break; 416 | case VGParallaxHeaderStickyViewPositionBottom: 417 | default: 418 | nonStickyEdge = ALEdgeTop; 419 | break; 420 | } 421 | 422 | // Remove Previous Constraints 423 | if (self.stickyViewContraints != nil) { 424 | [self.stickyView removeConstraints:self.stickyViewContraints]; 425 | [self.containerView removeConstraints:self.stickyViewContraints]; 426 | } 427 | 428 | // Add Constraints 429 | self.stickyViewContraints = [self.stickyView autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsMake(self.originalTopInset, 0, 0, 0) 430 | excludingEdge:nonStickyEdge]; 431 | } 432 | } 433 | 434 | @end 435 | -------------------------------------------------------------------------------- /DribbbleApp/test.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DribbbleApp/test.playground/section-1.swift: -------------------------------------------------------------------------------- 1 | // Playground - noun: a place where people can play 2 | 3 | import UIKit 4 | 5 | var str = "Hello, playground" 6 | 7 | func hasAnyMatch(list:Int[], operation:(n:Int) -> Bool ) -> Bool { 8 | 9 | for item in list { 10 | if operation(n: item) { 11 | return true 12 | } 13 | } 14 | 15 | return false 16 | } 17 | 18 | hasAnyMatch([28,283,12,4], {(n:Int) -> Bool in 19 | 20 | return n < 10 21 | 22 | }) 23 | 24 | 25 | 26 | struct Stack { 27 | var stackItem = T[]() 28 | mutating func push(item:T) { 29 | stackItem.append(item) 30 | } 31 | 32 | mutating func pop() { 33 | stackItem.removeLast() 34 | } 35 | } 36 | var stackOfString = Stack() 37 | stackOfString.push("bobo") 38 | stackOfString.push("Fofo") 39 | 40 | -------------------------------------------------------------------------------- /DribbbleApp/test.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DribbbleAppTests/DribbbleAppTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DribbbleAppTests.swift 3 | // DribbbleAppTests 4 | // 5 | // Created by LLL on 14-6-15. 6 | // Copyright (c) 2014年 LLL. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class DribbbleAppTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testExample() { 24 | // This is an example of a functional test case. 25 | XCTAssert(true, "Pass") 26 | } 27 | 28 | func testPerformanceExample() { 29 | // This is an example of a performance test case. 30 | self.measureBlock() { 31 | // Put the code you want to measure the time of here. 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /DribbbleAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | comg.iyhjy.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "8.0" 2 | 3 | use_frameworks! 4 | 5 | pod "SDWebImage" 6 | pod "PureLayout" 7 | pod "SwiftyJSON" 8 | pod "Alamofire" 9 | pod "Moya" 10 | pod "ObjectMapper" 11 | pod "SVProgressHUD" 12 | 13 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (1.3.1) 3 | - Moya (2.1.0): 4 | - Moya/Core (= 2.1.0) 5 | - Moya/Core (2.1.0): 6 | - Alamofire (~> 1.3.0) 7 | - ObjectMapper (0.15) 8 | - PureLayout (2.0.4) 9 | - SDWebImage (3.7.1): 10 | - SDWebImage/Core (= 3.7.1) 11 | - SDWebImage/Core (3.7.1) 12 | - SVProgressHUD (1.1.3) 13 | - SwiftyJSON (2.2.1) 14 | 15 | DEPENDENCIES: 16 | - Alamofire 17 | - Moya 18 | - ObjectMapper 19 | - PureLayout 20 | - SDWebImage 21 | - SVProgressHUD 22 | - SwiftyJSON 23 | 24 | SPEC CHECKSUMS: 25 | Alamofire: e4ab637e3195b645c814b87a652373439e59f2a4 26 | Moya: 6ad7d6b1e12b758e46edde8a07245d633e176087 27 | ObjectMapper: 0656dc1c155825897e5acfcd25362c6b61786dcb 28 | PureLayout: 39ab7d09edec14750ba3982bf19126916861bba5 29 | SDWebImage: ed3095af2ff88b436426037444979b917f6c5575 30 | SVProgressHUD: 748080e4f36e603f6c02aec292664239df5279c1 31 | SwiftyJSON: ae2d0a3d68025d136602a33c4ee215091ced3e33 32 | 33 | COCOAPODS: 0.38.2 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DribbbleApp 2 | =========== 3 | 4 | A Dribbble client developed using swift 5 | 6 | # Used features 7 | 8 | * Swift Programming Language 9 | * Cocoapods 10 | * AFNetworking 11 | * SVProgressHub 12 | 13 | # Install 14 | 15 | 1. `pod install` 16 | 2. open DribbbleApp.xcworkspace 17 | 18 | --------------------------------------------------------------------------------