├── .gitignore ├── .travis.yml ├── InteractivePlayerView.podspec ├── InteractivePlayerView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── InteractivePlayerView.xccheckout └── xcuserdata │ └── AhmetKeskin.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── InteractivePlayerView.xcscheme │ └── xcschememanagement.plist ├── InteractivePlayerView ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── blurbg.imageset │ │ ├── Contents.json │ │ └── blurbg.png │ ├── icon_arrow_down.imageset │ │ ├── Contents.json │ │ └── icon_arrow_down.png │ ├── icon_back.imageset │ │ ├── Contents.json │ │ └── icon_back.png │ ├── icon_forward.imageset │ │ ├── Contents.json │ │ └── icon_forward.png │ ├── icon_share.imageset │ │ ├── Contents.json │ │ └── icon_share.png │ ├── imagetest.imageset │ │ ├── Contents.json │ │ └── imagetest.png │ ├── like_selected.imageset │ │ ├── Contents.json │ │ └── like_selected.png │ ├── like_unselected.imageset │ │ ├── Contents.json │ │ └── like_unselected.png │ ├── pause.imageset │ │ ├── Contents.json │ │ └── pause.png │ ├── play.imageset │ │ ├── Contents.json │ │ └── play.png │ ├── replay_selected.imageset │ │ ├── Contents.json │ │ └── replay_selected.png │ ├── replay_unselected.imageset │ │ ├── Contents.json │ │ └── replay_unselected.png │ ├── shuffle_selected.imageset │ │ ├── Contents.json │ │ └── shuffle_selected.png │ └── shuffle_unselected.imageset │ │ ├── Contents.json │ │ └── shuffle_unselected.png ├── Info.plist ├── Screen.png └── ViewController.swift ├── InteractivePlayerViewTests ├── Info.plist └── InteractivePlayerViewTests.swift ├── LICENSE.md ├── README.md └── ipv_source ├── InteractivePlayerView.swift └── InteractivePlayerView.xib /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Xcode 3 | .DS_Store 4 | */build/* 5 | *.pbxuser 6 | !default.pbxuser 7 | *.mode1v3 8 | !default.mode1v3 9 | *.mode2v3 10 | !default.mode2v3 11 | *.perspectivev3 12 | !default.perspectivev3 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | .idea/ 18 | *.hmap 19 | *.xccheckout 20 | 21 | #CocoaPods 22 | Pods -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: swift 3 | 4 | branches: 5 | only: 6 | - master 7 | 8 | xcode_project: InteractivePlayerView.xcodeproj 9 | xcode_scheme: InteractivePlayerViewTests 10 | osx_image: xcode 6.4 11 | xcode_sdk: iphonesimulator 8.4 12 | 13 | script: 14 | - xcodebuild clean build test -project InteractivePlayerView.xcodeproj -scheme InteractivePlayerViewTests -------------------------------------------------------------------------------- /InteractivePlayerView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'InteractivePlayerView' 3 | s.version = '3.0' 4 | s.license = { :type => 'MIT' } 5 | s.homepage = 'https://github.com/AhmettKeskin/InteractivePlayerView' 6 | s.authors = { 'Ahmet Keskin' => 'supreme43tr@gmail.com' } 7 | s.social_media_url = 'https://twitter.com/_Ahmettkeskin' 8 | s.summary = 'Custom music player view iOS' 9 | s.ios.deployment_target = '9.0' 10 | s.source = { :git => 'https://github.com/AhmettKeskin/InteractivePlayerView.git', :tag => s.version } 11 | s.resources = "ipv_source/*.{xib}" 12 | s.source_files = 'ipv_source/*.{swift}' 13 | s.framework = 'SystemConfiguration' 14 | s.requires_arc = true 15 | end -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 598B5DCC1BA218A20058EC5D /* Screen.png in Resources */ = {isa = PBXBuildFile; fileRef = 598B5DCB1BA218A20058EC5D /* Screen.png */; }; 11 | 59B8361D1B7DF1F6007E1290 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B8361C1B7DF1F6007E1290 /* AppDelegate.swift */; }; 12 | 59B8361F1B7DF1F6007E1290 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B8361E1B7DF1F6007E1290 /* ViewController.swift */; }; 13 | 59B836221B7DF1F6007E1290 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 59B836201B7DF1F6007E1290 /* Main.storyboard */; }; 14 | 59B836241B7DF1F6007E1290 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 59B836231B7DF1F6007E1290 /* Images.xcassets */; }; 15 | 59B836271B7DF1F6007E1290 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 59B836251B7DF1F6007E1290 /* LaunchScreen.xib */; }; 16 | 59B836331B7DF1F6007E1290 /* InteractivePlayerViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59B836321B7DF1F6007E1290 /* InteractivePlayerViewTests.swift */; }; 17 | 59D610B81BA8271200CC59A9 /* InteractivePlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59D610B61BA8271200CC59A9 /* InteractivePlayerView.swift */; }; 18 | 59D610B91BA8271200CC59A9 /* InteractivePlayerView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 59D610B71BA8271200CC59A9 /* InteractivePlayerView.xib */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 59B8362D1B7DF1F6007E1290 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 59B8360F1B7DF1F6007E1290 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 59B836161B7DF1F6007E1290; 27 | remoteInfo = InteractivePlayerView; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 598B5DCB1BA218A20058EC5D /* Screen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Screen.png; sourceTree = ""; }; 33 | 59B836171B7DF1F6007E1290 /* InteractivePlayerView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = InteractivePlayerView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 59B8361B1B7DF1F6007E1290 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 59B8361C1B7DF1F6007E1290 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 36 | 59B8361E1B7DF1F6007E1290 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 37 | 59B836211B7DF1F6007E1290 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 38 | 59B836231B7DF1F6007E1290 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 39 | 59B836261B7DF1F6007E1290 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 40 | 59B8362C1B7DF1F6007E1290 /* InteractivePlayerViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteractivePlayerViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 59B836311B7DF1F6007E1290 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 42 | 59B836321B7DF1F6007E1290 /* InteractivePlayerViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractivePlayerViewTests.swift; sourceTree = ""; }; 43 | 59D610B61BA8271200CC59A9 /* InteractivePlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractivePlayerView.swift; sourceTree = ""; }; 44 | 59D610B71BA8271200CC59A9 /* InteractivePlayerView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InteractivePlayerView.xib; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 59B836141B7DF1F6007E1290 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | 59B836291B7DF1F6007E1290 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 59B8360E1B7DF1F6007E1290 = { 66 | isa = PBXGroup; 67 | children = ( 68 | 59B836191B7DF1F6007E1290 /* InteractivePlayerView */, 69 | 59B8362F1B7DF1F6007E1290 /* InteractivePlayerViewTests */, 70 | 59B836181B7DF1F6007E1290 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 59B836181B7DF1F6007E1290 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 59B836171B7DF1F6007E1290 /* InteractivePlayerView.app */, 78 | 59B8362C1B7DF1F6007E1290 /* InteractivePlayerViewTests.xctest */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | 59B836191B7DF1F6007E1290 /* InteractivePlayerView */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 59B8361C1B7DF1F6007E1290 /* AppDelegate.swift */, 87 | 59B8361E1B7DF1F6007E1290 /* ViewController.swift */, 88 | 59B836201B7DF1F6007E1290 /* Main.storyboard */, 89 | 59B836231B7DF1F6007E1290 /* Images.xcassets */, 90 | 59B836251B7DF1F6007E1290 /* LaunchScreen.xib */, 91 | 59B8361A1B7DF1F6007E1290 /* Supporting Files */, 92 | 59B8363E1B7E1148007E1290 /* ipv_source */, 93 | ); 94 | path = InteractivePlayerView; 95 | sourceTree = ""; 96 | }; 97 | 59B8361A1B7DF1F6007E1290 /* Supporting Files */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 598B5DCB1BA218A20058EC5D /* Screen.png */, 101 | 59B8361B1B7DF1F6007E1290 /* Info.plist */, 102 | ); 103 | name = "Supporting Files"; 104 | sourceTree = ""; 105 | }; 106 | 59B8362F1B7DF1F6007E1290 /* InteractivePlayerViewTests */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 59B836321B7DF1F6007E1290 /* InteractivePlayerViewTests.swift */, 110 | 59B836301B7DF1F6007E1290 /* Supporting Files */, 111 | ); 112 | path = InteractivePlayerViewTests; 113 | sourceTree = ""; 114 | }; 115 | 59B836301B7DF1F6007E1290 /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 59B836311B7DF1F6007E1290 /* Info.plist */, 119 | ); 120 | name = "Supporting Files"; 121 | sourceTree = ""; 122 | }; 123 | 59B8363E1B7E1148007E1290 /* ipv_source */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 59D610B61BA8271200CC59A9 /* InteractivePlayerView.swift */, 127 | 59D610B71BA8271200CC59A9 /* InteractivePlayerView.xib */, 128 | ); 129 | name = ipv_source; 130 | path = ../ipv_source; 131 | sourceTree = ""; 132 | }; 133 | /* End PBXGroup section */ 134 | 135 | /* Begin PBXNativeTarget section */ 136 | 59B836161B7DF1F6007E1290 /* InteractivePlayerView */ = { 137 | isa = PBXNativeTarget; 138 | buildConfigurationList = 59B836361B7DF1F6007E1290 /* Build configuration list for PBXNativeTarget "InteractivePlayerView" */; 139 | buildPhases = ( 140 | 59B836131B7DF1F6007E1290 /* Sources */, 141 | 59B836141B7DF1F6007E1290 /* Frameworks */, 142 | 59B836151B7DF1F6007E1290 /* Resources */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = InteractivePlayerView; 149 | productName = InteractivePlayerView; 150 | productReference = 59B836171B7DF1F6007E1290 /* InteractivePlayerView.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | 59B8362B1B7DF1F6007E1290 /* InteractivePlayerViewTests */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = 59B836391B7DF1F6007E1290 /* Build configuration list for PBXNativeTarget "InteractivePlayerViewTests" */; 156 | buildPhases = ( 157 | 59B836281B7DF1F6007E1290 /* Sources */, 158 | 59B836291B7DF1F6007E1290 /* Frameworks */, 159 | 59B8362A1B7DF1F6007E1290 /* Resources */, 160 | ); 161 | buildRules = ( 162 | ); 163 | dependencies = ( 164 | 59B8362E1B7DF1F6007E1290 /* PBXTargetDependency */, 165 | ); 166 | name = InteractivePlayerViewTests; 167 | productName = InteractivePlayerViewTests; 168 | productReference = 59B8362C1B7DF1F6007E1290 /* InteractivePlayerViewTests.xctest */; 169 | productType = "com.apple.product-type.bundle.unit-test"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | 59B8360F1B7DF1F6007E1290 /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | LastSwiftMigration = 0700; 178 | LastSwiftUpdateCheck = 0700; 179 | LastUpgradeCheck = 0800; 180 | ORGANIZATIONNAME = Mobiwise; 181 | TargetAttributes = { 182 | 59B836161B7DF1F6007E1290 = { 183 | CreatedOnToolsVersion = 6.4; 184 | DevelopmentTeam = 89QENA8827; 185 | LastSwiftMigration = 0800; 186 | }; 187 | 59B8362B1B7DF1F6007E1290 = { 188 | CreatedOnToolsVersion = 6.4; 189 | DevelopmentTeam = 89QENA8827; 190 | LastSwiftMigration = 0800; 191 | TestTargetID = 59B836161B7DF1F6007E1290; 192 | }; 193 | }; 194 | }; 195 | buildConfigurationList = 59B836121B7DF1F6007E1290 /* Build configuration list for PBXProject "InteractivePlayerView" */; 196 | compatibilityVersion = "Xcode 3.2"; 197 | developmentRegion = English; 198 | hasScannedForEncodings = 0; 199 | knownRegions = ( 200 | en, 201 | Base, 202 | ); 203 | mainGroup = 59B8360E1B7DF1F6007E1290; 204 | productRefGroup = 59B836181B7DF1F6007E1290 /* Products */; 205 | projectDirPath = ""; 206 | projectRoot = ""; 207 | targets = ( 208 | 59B836161B7DF1F6007E1290 /* InteractivePlayerView */, 209 | 59B8362B1B7DF1F6007E1290 /* InteractivePlayerViewTests */, 210 | ); 211 | }; 212 | /* End PBXProject section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | 59B836151B7DF1F6007E1290 /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 59D610B91BA8271200CC59A9 /* InteractivePlayerView.xib in Resources */, 220 | 59B836221B7DF1F6007E1290 /* Main.storyboard in Resources */, 221 | 59B836271B7DF1F6007E1290 /* LaunchScreen.xib in Resources */, 222 | 598B5DCC1BA218A20058EC5D /* Screen.png in Resources */, 223 | 59B836241B7DF1F6007E1290 /* Images.xcassets in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | 59B8362A1B7DF1F6007E1290 /* Resources */ = { 228 | isa = PBXResourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXResourcesBuildPhase section */ 235 | 236 | /* Begin PBXSourcesBuildPhase section */ 237 | 59B836131B7DF1F6007E1290 /* Sources */ = { 238 | isa = PBXSourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | 59B8361F1B7DF1F6007E1290 /* ViewController.swift in Sources */, 242 | 59D610B81BA8271200CC59A9 /* InteractivePlayerView.swift in Sources */, 243 | 59B8361D1B7DF1F6007E1290 /* AppDelegate.swift in Sources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | 59B836281B7DF1F6007E1290 /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | 59B836331B7DF1F6007E1290 /* InteractivePlayerViewTests.swift in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | /* End PBXSourcesBuildPhase section */ 256 | 257 | /* Begin PBXTargetDependency section */ 258 | 59B8362E1B7DF1F6007E1290 /* PBXTargetDependency */ = { 259 | isa = PBXTargetDependency; 260 | target = 59B836161B7DF1F6007E1290 /* InteractivePlayerView */; 261 | targetProxy = 59B8362D1B7DF1F6007E1290 /* PBXContainerItemProxy */; 262 | }; 263 | /* End PBXTargetDependency section */ 264 | 265 | /* Begin PBXVariantGroup section */ 266 | 59B836201B7DF1F6007E1290 /* Main.storyboard */ = { 267 | isa = PBXVariantGroup; 268 | children = ( 269 | 59B836211B7DF1F6007E1290 /* Base */, 270 | ); 271 | name = Main.storyboard; 272 | sourceTree = ""; 273 | }; 274 | 59B836251B7DF1F6007E1290 /* LaunchScreen.xib */ = { 275 | isa = PBXVariantGroup; 276 | children = ( 277 | 59B836261B7DF1F6007E1290 /* Base */, 278 | ); 279 | name = LaunchScreen.xib; 280 | sourceTree = ""; 281 | }; 282 | /* End PBXVariantGroup section */ 283 | 284 | /* Begin XCBuildConfiguration section */ 285 | 59B836341B7DF1F6007E1290 /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 290 | CLANG_CXX_LIBRARY = "libc++"; 291 | CLANG_ENABLE_MODULES = YES; 292 | CLANG_ENABLE_OBJC_ARC = YES; 293 | CLANG_WARN_BOOL_CONVERSION = YES; 294 | CLANG_WARN_CONSTANT_CONVERSION = YES; 295 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 296 | CLANG_WARN_EMPTY_BODY = YES; 297 | CLANG_WARN_ENUM_CONVERSION = YES; 298 | CLANG_WARN_INFINITE_RECURSION = YES; 299 | CLANG_WARN_INT_CONVERSION = YES; 300 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_UNREACHABLE_CODE = YES; 303 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 304 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 307 | ENABLE_STRICT_OBJC_MSGSEND = YES; 308 | ENABLE_TESTABILITY = YES; 309 | GCC_C_LANGUAGE_STANDARD = gnu99; 310 | GCC_DYNAMIC_NO_PIC = NO; 311 | GCC_NO_COMMON_BLOCKS = YES; 312 | GCC_OPTIMIZATION_LEVEL = 0; 313 | GCC_PREPROCESSOR_DEFINITIONS = ( 314 | "DEBUG=1", 315 | "$(inherited)", 316 | ); 317 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 318 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 319 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 320 | GCC_WARN_UNDECLARED_SELECTOR = YES; 321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 322 | GCC_WARN_UNUSED_FUNCTION = YES; 323 | GCC_WARN_UNUSED_VARIABLE = YES; 324 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 325 | MTL_ENABLE_DEBUG_INFO = YES; 326 | ONLY_ACTIVE_ARCH = YES; 327 | SDKROOT = iphoneos; 328 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 329 | TARGETED_DEVICE_FAMILY = "1,2"; 330 | }; 331 | name = Debug; 332 | }; 333 | 59B836351B7DF1F6007E1290 /* Release */ = { 334 | isa = XCBuildConfiguration; 335 | buildSettings = { 336 | ALWAYS_SEARCH_USER_PATHS = NO; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BOOL_CONVERSION = YES; 342 | CLANG_WARN_CONSTANT_CONVERSION = YES; 343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 344 | CLANG_WARN_EMPTY_BODY = YES; 345 | CLANG_WARN_ENUM_CONVERSION = YES; 346 | CLANG_WARN_INFINITE_RECURSION = YES; 347 | CLANG_WARN_INT_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 353 | COPY_PHASE_STRIP = NO; 354 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 355 | ENABLE_NS_ASSERTIONS = NO; 356 | ENABLE_STRICT_OBJC_MSGSEND = YES; 357 | GCC_C_LANGUAGE_STANDARD = gnu99; 358 | GCC_NO_COMMON_BLOCKS = YES; 359 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 360 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 361 | GCC_WARN_UNDECLARED_SELECTOR = YES; 362 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 363 | GCC_WARN_UNUSED_FUNCTION = YES; 364 | GCC_WARN_UNUSED_VARIABLE = YES; 365 | IPHONEOS_DEPLOYMENT_TARGET = 8.4; 366 | MTL_ENABLE_DEBUG_INFO = NO; 367 | SDKROOT = iphoneos; 368 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 369 | TARGETED_DEVICE_FAMILY = "1,2"; 370 | VALIDATE_PRODUCT = YES; 371 | }; 372 | name = Release; 373 | }; 374 | 59B836371B7DF1F6007E1290 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 378 | CODE_SIGN_IDENTITY = "iPhone Developer"; 379 | DEVELOPMENT_TEAM = 89QENA8827; 380 | INFOPLIST_FILE = InteractivePlayerView/Info.plist; 381 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 382 | PRODUCT_BUNDLE_IDENTIFIER = "co.mobiwise.$(PRODUCT_NAME:rfc1034identifier)"; 383 | PRODUCT_NAME = "$(TARGET_NAME)"; 384 | SWIFT_VERSION = 4.0; 385 | }; 386 | name = Debug; 387 | }; 388 | 59B836381B7DF1F6007E1290 /* Release */ = { 389 | isa = XCBuildConfiguration; 390 | buildSettings = { 391 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 392 | CODE_SIGN_IDENTITY = "iPhone Developer"; 393 | DEVELOPMENT_TEAM = 89QENA8827; 394 | INFOPLIST_FILE = InteractivePlayerView/Info.plist; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 396 | PRODUCT_BUNDLE_IDENTIFIER = "co.mobiwise.$(PRODUCT_NAME:rfc1034identifier)"; 397 | PRODUCT_NAME = "$(TARGET_NAME)"; 398 | SWIFT_VERSION = 4.0; 399 | }; 400 | name = Release; 401 | }; 402 | 59B8363A1B7DF1F6007E1290 /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | BUNDLE_LOADER = "$(TEST_HOST)"; 406 | DEVELOPMENT_TEAM = 89QENA8827; 407 | FRAMEWORK_SEARCH_PATHS = ( 408 | "$(SDKROOT)/Developer/Library/Frameworks", 409 | "$(inherited)", 410 | ); 411 | GCC_PREPROCESSOR_DEFINITIONS = ( 412 | "DEBUG=1", 413 | "$(inherited)", 414 | ); 415 | INFOPLIST_FILE = InteractivePlayerViewTests/Info.plist; 416 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 417 | PRODUCT_BUNDLE_IDENTIFIER = "co.mobiwise.$(PRODUCT_NAME:rfc1034identifier)"; 418 | PRODUCT_NAME = "$(TARGET_NAME)"; 419 | SWIFT_VERSION = 3.0; 420 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/InteractivePlayerView.app/InteractivePlayerView"; 421 | }; 422 | name = Debug; 423 | }; 424 | 59B8363B1B7DF1F6007E1290 /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | BUNDLE_LOADER = "$(TEST_HOST)"; 428 | DEVELOPMENT_TEAM = 89QENA8827; 429 | FRAMEWORK_SEARCH_PATHS = ( 430 | "$(SDKROOT)/Developer/Library/Frameworks", 431 | "$(inherited)", 432 | ); 433 | INFOPLIST_FILE = InteractivePlayerViewTests/Info.plist; 434 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 435 | PRODUCT_BUNDLE_IDENTIFIER = "co.mobiwise.$(PRODUCT_NAME:rfc1034identifier)"; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | SWIFT_VERSION = 3.0; 438 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/InteractivePlayerView.app/InteractivePlayerView"; 439 | }; 440 | name = Release; 441 | }; 442 | /* End XCBuildConfiguration section */ 443 | 444 | /* Begin XCConfigurationList section */ 445 | 59B836121B7DF1F6007E1290 /* Build configuration list for PBXProject "InteractivePlayerView" */ = { 446 | isa = XCConfigurationList; 447 | buildConfigurations = ( 448 | 59B836341B7DF1F6007E1290 /* Debug */, 449 | 59B836351B7DF1F6007E1290 /* Release */, 450 | ); 451 | defaultConfigurationIsVisible = 0; 452 | defaultConfigurationName = Release; 453 | }; 454 | 59B836361B7DF1F6007E1290 /* Build configuration list for PBXNativeTarget "InteractivePlayerView" */ = { 455 | isa = XCConfigurationList; 456 | buildConfigurations = ( 457 | 59B836371B7DF1F6007E1290 /* Debug */, 458 | 59B836381B7DF1F6007E1290 /* Release */, 459 | ); 460 | defaultConfigurationIsVisible = 0; 461 | defaultConfigurationName = Release; 462 | }; 463 | 59B836391B7DF1F6007E1290 /* Build configuration list for PBXNativeTarget "InteractivePlayerViewTests" */ = { 464 | isa = XCConfigurationList; 465 | buildConfigurations = ( 466 | 59B8363A1B7DF1F6007E1290 /* Debug */, 467 | 59B8363B1B7DF1F6007E1290 /* Release */, 468 | ); 469 | defaultConfigurationIsVisible = 0; 470 | defaultConfigurationName = Release; 471 | }; 472 | /* End XCConfigurationList section */ 473 | }; 474 | rootObject = 59B8360F1B7DF1F6007E1290 /* Project object */; 475 | } 476 | -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/project.xcworkspace/xcshareddata/InteractivePlayerView.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | F4440D82-C276-423F-9BAB-EA323D4A39E5 9 | IDESourceControlProjectName 10 | InteractivePlayerView 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 8E9416140BD528BD131D28ED326E0C98471B9EEC 14 | https://github.com/AhmettKeskin/InteractivePlayerView.git 15 | 16 | IDESourceControlProjectPath 17 | InteractivePlayerView.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 8E9416140BD528BD131D28ED326E0C98471B9EEC 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/AhmettKeskin/InteractivePlayerView.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 8E9416140BD528BD131D28ED326E0C98471B9EEC 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 8E9416140BD528BD131D28ED326E0C98471B9EEC 36 | IDESourceControlWCCName 37 | InteractivePlayerView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/xcuserdata/AhmetKeskin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/xcuserdata/AhmetKeskin.xcuserdatad/xcschemes/InteractivePlayerView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /InteractivePlayerView.xcodeproj/xcuserdata/AhmetKeskin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | InteractivePlayerView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 59B836161B7DF1F6007E1290 16 | 17 | primary 18 | 19 | 20 | 59B8362B1B7DF1F6007E1290 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /InteractivePlayerView/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // InteractivePlayerView 4 | // 5 | // Created by AhmetKeskin on 02/09/15. 6 | // Copyright (c) 2015 Mobiwise. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | private func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /InteractivePlayerView/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /InteractivePlayerView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 54 | 66 | 74 | 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 | 126 | 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 | -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/blurbg.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "blurbg.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/blurbg.imageset/blurbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/blurbg.imageset/blurbg.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_arrow_down.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_arrow_down.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_arrow_down.imageset/icon_arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/icon_arrow_down.imageset/icon_arrow_down.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_back.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_back.imageset/icon_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/icon_back.imageset/icon_back.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_forward.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_forward.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_forward.imageset/icon_forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/icon_forward.imageset/icon_forward.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_share.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_share.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/icon_share.imageset/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/icon_share.imageset/icon_share.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/imagetest.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "imagetest.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/imagetest.imageset/imagetest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/imagetest.imageset/imagetest.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/like_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "like_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/like_selected.imageset/like_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/like_selected.imageset/like_selected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/like_unselected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "like_unselected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/like_unselected.imageset/like_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/like_unselected.imageset/like_unselected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/pause.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "pause.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/pause.imageset/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/pause.imageset/pause.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/play.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "play.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/play.imageset/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/play.imageset/play.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/replay_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "replay_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/replay_selected.imageset/replay_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/replay_selected.imageset/replay_selected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/replay_unselected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "replay_unselected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/replay_unselected.imageset/replay_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/replay_unselected.imageset/replay_unselected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/shuffle_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "shuffle_selected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/shuffle_selected.imageset/shuffle_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/shuffle_selected.imageset/shuffle_selected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/shuffle_unselected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "shuffle_unselected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /InteractivePlayerView/Images.xcassets/shuffle_unselected.imageset/shuffle_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Images.xcassets/shuffle_unselected.imageset/shuffle_unselected.png -------------------------------------------------------------------------------- /InteractivePlayerView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /InteractivePlayerView/Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AhmettKeskin/InteractivePlayerView/56ca51a1fd515c4c91213cae6d69cad7f478986c/InteractivePlayerView/Screen.png -------------------------------------------------------------------------------- /InteractivePlayerView/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // InteractivePlayerView 4 | // 5 | // Created by AhmetKeskin on 02/09/15. 6 | // Copyright (c) 2015 Mobiwise. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController, InteractivePlayerViewDelegate { 12 | 13 | 14 | @IBOutlet weak var blurBgImage: UIImageView! 15 | 16 | @IBOutlet weak var containerView: UIView! 17 | @IBOutlet weak var ipv: InteractivePlayerView! 18 | @IBOutlet weak var playButton: UIButton! 19 | @IBOutlet weak var pauseButton: UIButton! 20 | @IBOutlet weak var playPauseButtonView: UIView! 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | // Do any additional setup after loading the view, typically from a nib. 25 | self.view.layoutIfNeeded() 26 | self.view.backgroundColor = UIColor.clear 27 | self.makeItRounded(view: self.playPauseButtonView, newSize: self.playPauseButtonView.frame.width) 28 | 29 | self.ipv!.delegate = self 30 | 31 | // duration of music 32 | self.ipv.progress = 20.0 33 | 34 | } 35 | 36 | override func viewDidAppear(_ animated: Bool) { 37 | 38 | } 39 | 40 | override func didReceiveMemoryWarning() { 41 | super.didReceiveMemoryWarning() 42 | // Dispose of any resources that can be recreated. 43 | } 44 | 45 | override var preferredStatusBarStyle: UIStatusBarStyle { 46 | return .lightContent 47 | } 48 | 49 | @IBAction func playButtonTapped(_ sender: UIButton) { 50 | 51 | self.ipv.start() 52 | 53 | self.playButton.isHidden = true 54 | self.pauseButton.isHidden = false 55 | 56 | } 57 | 58 | @IBAction func pauseButtonTapped(_ sender: UIButton) { 59 | 60 | self.ipv.stop() 61 | 62 | self.playButton.isHidden = false 63 | self.pauseButton.isHidden = true 64 | 65 | } 66 | 67 | 68 | @IBAction func nextTapped(sender: AnyObject) { 69 | self.ipv.restartWithProgress(duration: 50) 70 | } 71 | 72 | @IBAction func previousTapped(sender: AnyObject) { 73 | self.ipv.restartWithProgress(duration: 10) 74 | } 75 | 76 | /* InteractivePlayerViewDelegate METHODS */ 77 | func actionOneButtonTapped(sender: UIButton, isSelected: Bool) { 78 | print("shuffle \(isSelected.description)") 79 | } 80 | 81 | func actionTwoButtonTapped(sender: UIButton, isSelected: Bool) { 82 | print("like \(isSelected.description)") 83 | } 84 | 85 | func actionThreeButtonTapped(sender: UIButton, isSelected: Bool) { 86 | print("replay \(isSelected.description)") 87 | 88 | } 89 | 90 | func interactivePlayerViewDidChangedDuration(playerInteractive: InteractivePlayerView, currentDuration: Double) { 91 | print("current Duration : \(currentDuration)") 92 | } 93 | 94 | func interactivePlayerViewDidStartPlaying(playerInteractive: InteractivePlayerView) { 95 | print("interactive player did started") 96 | } 97 | 98 | func interactivePlayerViewDidStopPlaying(playerInteractive: InteractivePlayerView) { 99 | print("interactive player did stop") 100 | } 101 | 102 | func makeItRounded(view : UIView!, newSize : CGFloat!){ 103 | let saveCenter : CGPoint = view.center 104 | let newFrame : CGRect = CGRect(x: view.frame.origin.x,y: view.frame.origin.y,width: newSize,height : newSize) 105 | view.frame = newFrame 106 | view.layer.cornerRadius = newSize / 2.0 107 | view.clipsToBounds = true 108 | view.center = saveCenter 109 | 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /InteractivePlayerViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /InteractivePlayerViewTests/InteractivePlayerViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InteractivePlayerViewTests.swift 3 | // InteractivePlayerViewTests 4 | // 5 | // Created by AhmetKeskin on 02/09/15. 6 | // Copyright (c) 2015 Mobiwise. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class InteractivePlayerViewTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2015 Ahmet Keskin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InteractivePlayerView 2 | 3 | Custom iOS music player view 4 | 5 | # Screen 6 | 7 | 8 | 9 | ### About 10 | InteractivePlayerView is an IBDesignableView (Custom View) which has its own progress,cover image and action buttons. 11 | 12 | 13 | ## Installation 14 | [Download](https://github.com/AhmettKeskin/InteractivePlayerView/archive/master.zip) the project and copy the InteractivePlayerView folder into your project and then simply you can use it in any file 15 | 16 | ## Requirements 17 | 18 | - iOS 9.0+ 19 | - Xcode 9.0+ 20 | - Swift 4.0+ 21 | 22 | #### Cocoapods 23 | 24 | ```swift 25 | platform :ios, '9.0' 26 | use_frameworks! 27 | 28 | pod 'InteractivePlayerView', '3.0' 29 | ``` 30 | ## Usage 31 | - Add your view in storyboard 32 | - Arrange your view's size square (It looks better this way) 33 | - Set your view's class InteractivePlayerView 34 | - Wait until it built in storyboard and set variables 35 | - Then create your property of view and set it's delegate to self to use it's delegation methods and good to go ! 36 | 37 | ``` swift 38 | @IBOutlet var ipv: InteractivePlayerView! 39 | 40 | // set delegation 41 | self.ipv!.delegate = self 42 | 43 | // duration of music 44 | self.ipv.progress = 120.0 45 | 46 | // start - stop player 47 | self.ipv.start() 48 | self.ipv.stop() 49 | 50 | // restart player with duration 51 | self.ipv.restartWithProgress(duration: 50) 52 | 53 | /* InteractivePlayerViewDelegate METHODS */ 54 | func actionOneButtonTapped(sender: UIButton, isSelected: Bool) { 55 | println("ActionOneButton tapped") 56 | } 57 | 58 | func actionTwoButtonTapped(sender: UIButton, isSelected: Bool) { 59 | println("ActionTwoButton tapped") 60 | } 61 | 62 | func actionThreeButtonTapped(sender: UIButton, isSelected: Bool) { 63 | println("ActionThreeButton tapped") 64 | 65 | } 66 | 67 | ``` 68 | 69 | ## Useful Methods 70 | 71 | ``` swift 72 | // set progress colors 73 | self.ipv.progressEmptyColor = UIColor.yellowColor() 74 | self.ipv.progressFullColor = UIColor.redColor() 75 | 76 | ``` 77 | ``` swift 78 | // get and set isSelected value of action buttons 79 | let isSelected = self.ipv.isActionOneSelected 80 | self.ipv.isActionOneSelected = true 81 | ``` 82 | ```swift 83 | // Buttons are also square and setting one value to width and height is enough. And also you can set action button's images 84 | self.ipv.buttonSizes = 30.0 85 | 86 | self.ipv.actionOne_icon_selected = UIImage(named: "shuffle_selected.png") 87 | self.ipv.actionOne_icon_unselected = UIImage(named: "shuffle_unselected.png") 88 | 89 | self.ipv.coverImage = UIImage(named: "imagetest.png") 90 | 91 | ``` 92 | 93 | 94 | ## Design 95 | 96 | [Here is original design](https://www.pinterest.com/pin/400187116866664878/) 97 | 98 | License 99 | -------- 100 | 101 | 102 | Copyright 2015 Ahmet Keskin. 103 | 104 | Licensed under the Apache License, Version 2.0 (the "License"); 105 | you may not use this file except in compliance with the License. 106 | You may obtain a copy of the License at 107 | 108 | http://www.apache.org/licenses/LICENSE-2.0 109 | 110 | Unless required by applicable law or agreed to in writing, software 111 | distributed under the License is distributed on an "AS IS" BASIS, 112 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 113 | See the License for the specific language governing permissions and 114 | limitations under the License. 115 | 116 | -------------------------------------------------------------------------------- /ipv_source/InteractivePlayerView.swift: -------------------------------------------------------------------------------- 1 | /* The MIT License 2 | 3 | Copyright 2015 Ahmet Keskin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 10 | 11 | import UIKit 12 | 13 | protocol InteractivePlayerViewDelegate { 14 | 15 | func actionOneButtonTapped(sender : UIButton, isSelected : Bool) 16 | func actionTwoButtonTapped(sender : UIButton, isSelected : Bool) 17 | func actionThreeButtonTapped(sender : UIButton, isSelected : Bool) 18 | 19 | func interactivePlayerViewDidStartPlaying(playerInteractive:InteractivePlayerView) 20 | func interactivePlayerViewDidStopPlaying(playerInteractive:InteractivePlayerView) 21 | 22 | 23 | /** 24 |   @ callbacks in every changes at the duration 25 | */ 26 | func interactivePlayerViewDidChangedDuration(playerInteractive:InteractivePlayerView , currentDuration:Double) 27 | } 28 | 29 | @IBDesignable 30 | class InteractivePlayerView : UIView { 31 | 32 | var view: UIView! 33 | var delegate: InteractivePlayerViewDelegate? 34 | 35 | @IBOutlet private var coverImageView: UIImageView! 36 | @IBOutlet private var timeLabel: UILabel! 37 | @IBOutlet private var actionOne: UIButton! 38 | @IBOutlet private var actionTwo: UIButton! 39 | @IBOutlet private var actionThree: UIButton! 40 | @IBOutlet private var actionOneButtonWidth: NSLayoutConstraint! 41 | @IBOutlet private var actionOneButtonHeight: NSLayoutConstraint! 42 | @IBOutlet private var actionTwoButtonWidth: NSLayoutConstraint! 43 | @IBOutlet private var actionTwoButtonHeight: NSLayoutConstraint! 44 | @IBOutlet private var actionThreeButtonWidth: NSLayoutConstraint! 45 | @IBOutlet private var actionThreeButtonHeight: NSLayoutConstraint! 46 | 47 | /// duration of song 48 | var progress : Double = 0.0 49 | 50 | /// is music playing 51 | var isPlaying : Bool = false 52 | 53 | /// You can set action button images with this struct 54 | var actionImages = ActionButtonImages() 55 | 56 | /// set progress colors 57 | var progressEmptyColor : UIColor = UIColor.white 58 | var progressFullColor : UIColor = UIColor.red 59 | 60 | /// used to change current time of the sound . default is true 61 | var panEnabled:Bool = true 62 | 63 | /// is ActionOne selected 64 | var isActionOneSelected : Bool = false { 65 | 66 | didSet { 67 | 68 | if isActionOneSelected { 69 | self.actionOne.isSelected = true 70 | self.actionOne.setImage(self.actionImages.actionOneSelected, for: UIControlState.selected) 71 | }else { 72 | self.actionOne.isSelected = false 73 | self.actionOne.setImage(self.actionImages.actionOneUnSelected, for: UIControlState.normal) 74 | } 75 | } 76 | } 77 | 78 | /// is ActionTwo selected 79 | var isActionTwoSelected : Bool = false { 80 | 81 | didSet { 82 | if isActionTwoSelected { 83 | self.actionTwo.isSelected = true 84 | self.actionTwo.setImage(self.actionImages.actionTwoSelected, for: UIControlState.selected) 85 | }else { 86 | self.actionTwo.isSelected = false 87 | self.actionTwo.setImage(self.actionImages.actionTwoUnSelected, for: UIControlState.normal) 88 | } 89 | } 90 | } 91 | 92 | /// is ActionThree selected 93 | var isActionThreeSelected : Bool = false { 94 | 95 | didSet { 96 | if isActionThreeSelected { 97 | self.actionThree.isSelected = true 98 | self.actionThree.setImage(self.actionImages.actionThreeSelected, for: UIControlState.selected) 99 | }else { 100 | self.actionThree.isSelected = false 101 | self.actionThree.setImage(self.actionImages.actionThreeUnSelected, for: UIControlState.normal) 102 | } 103 | } 104 | } 105 | 106 | 107 | /* Timer for update time*/ 108 | private var timer: Timer! 109 | 110 | /* Controlling progress bar animation with isAnimating */ 111 | private var isAnimating : Bool = false 112 | 113 | /* increasing duration in updateTime */ 114 | private var duration : Double{ 115 | didSet{ 116 | redrawStrokeEnd() 117 | 118 | if let theDelegate = self.delegate { 119 | theDelegate.interactivePlayerViewDidChangedDuration(playerInteractive: self, currentDuration: duration) 120 | } 121 | 122 | } 123 | } 124 | 125 | private var circleLayer: CAShapeLayer! = CAShapeLayer() 126 | 127 | /* Setting action buttons constraint width - height with buttonSizes */ 128 | @IBInspectable var buttonSizes : CGFloat = 20.0 { 129 | 130 | didSet { 131 | self.actionOneButtonHeight.constant = buttonSizes 132 | self.actionOneButtonWidth.constant = buttonSizes 133 | self.actionTwoButtonHeight.constant = buttonSizes 134 | self.actionTwoButtonWidth.constant = buttonSizes 135 | self.actionThreeButtonHeight.constant = buttonSizes 136 | self.actionThreeButtonWidth.constant = buttonSizes 137 | } 138 | } 139 | 140 | /* 141 | * 142 | * Set Images in storyBoard with IBInspectable variables 143 | * 144 | */ 145 | @IBInspectable var coverImage: UIImage? { 146 | get { 147 | return coverImageView.image 148 | } 149 | set(coverImage) { 150 | coverImageView.image = coverImage 151 | } 152 | } 153 | 154 | @IBInspectable var actionOne_icon_selected: UIImage? { 155 | 156 | get { 157 | return actionImages.actionOneSelected 158 | } 159 | set(actionOne_icon_selected) { 160 | actionOne.setImage(actionOne_icon_selected, for: UIControlState.selected) 161 | actionImages.actionOneSelected = actionOne_icon_selected 162 | } 163 | } 164 | 165 | @IBInspectable var actionOne_icon_unselected: UIImage? { 166 | 167 | get { 168 | return actionImages.actionOneUnSelected 169 | } 170 | set(actionOne_icon_unselected) { 171 | actionOne.setImage(actionOne_icon_unselected, for: UIControlState.normal) 172 | actionImages.actionOneUnSelected = actionOne_icon_unselected 173 | } 174 | } 175 | 176 | @IBInspectable var actionTwo_icon_selected: UIImage? { 177 | 178 | get { 179 | return actionImages.actionTwoSelected 180 | } 181 | set(actionTwo_icon_selected) { 182 | actionTwo.setImage(actionTwo_icon_selected, for: UIControlState.selected) 183 | actionImages.actionTwoSelected = actionTwo_icon_selected 184 | } 185 | } 186 | 187 | @IBInspectable var actionTwo_icon_unselected: UIImage? { 188 | 189 | get { 190 | return actionImages.actionTwoUnSelected 191 | } 192 | set(actionTwo_icon_unselected) { 193 | actionTwo.setImage(actionTwo_icon_unselected, for: UIControlState.normal) 194 | actionImages.actionTwoUnSelected = actionTwo_icon_unselected 195 | } 196 | } 197 | 198 | @IBInspectable var actionThree_icon_selected: UIImage? { 199 | 200 | get { 201 | return actionImages.actionThreeSelected 202 | } 203 | set(actionThree_icon_selected) { 204 | actionThree.setImage(actionThree_icon_selected, for: UIControlState.selected) 205 | actionImages.actionThreeSelected = actionThree_icon_selected 206 | } 207 | } 208 | 209 | @IBInspectable var actionThree_icon_unselected: UIImage? { 210 | 211 | get { 212 | return actionImages.actionThreeUnSelected 213 | } 214 | set(actionThree_icon_unselected) { 215 | actionThree.setImage(actionThree_icon_unselected, for: UIControlState.normal) 216 | actionImages.actionThreeUnSelected = actionThree_icon_unselected 217 | } 218 | } 219 | 220 | /* 221 | * Button images struct 222 | */ 223 | 224 | struct ActionButtonImages { 225 | 226 | var actionOneSelected : UIImage? 227 | var actionOneUnSelected : UIImage? 228 | var actionTwoSelected : UIImage? 229 | var actionTwoUnSelected : UIImage? 230 | var actionThreeSelected : UIImage? 231 | var actionThreeUnSelected : UIImage? 232 | 233 | } 234 | 235 | override init(frame: CGRect) { 236 | 237 | self.duration = 0 238 | 239 | super.init(frame: frame) 240 | self.createUI() 241 | self.addPanGesture() 242 | 243 | } 244 | 245 | required init?(coder aDecoder: NSCoder) { 246 | 247 | self.duration = 0 248 | 249 | super.init(coder: aDecoder) 250 | self.createUI() 251 | self.addPanGesture() 252 | 253 | } 254 | 255 | @IBAction private func actionOneButtonTapped(sender: UIButton) { 256 | 257 | if sender.isSelected { 258 | sender.isSelected = false 259 | }else { 260 | sender.isSelected = true 261 | } 262 | 263 | self.isActionOneSelected = sender.isSelected 264 | 265 | if let delegate = self.delegate{ 266 | delegate.actionOneButtonTapped(sender: sender, isSelected : sender.isSelected) 267 | } 268 | } 269 | 270 | @IBAction private func actionTwoButtonTapped(sender: UIButton) { 271 | 272 | if sender.isSelected { 273 | sender.isSelected = false 274 | } else { 275 | sender.isSelected = true 276 | } 277 | 278 | self.isActionTwoSelected = sender.isSelected 279 | 280 | if let delegate = self.delegate{ 281 | delegate.actionTwoButtonTapped(sender: sender, isSelected : sender.isSelected) 282 | } 283 | } 284 | 285 | @IBAction private func actionThreeButtonTapped(sender: UIButton) { 286 | 287 | if sender.isSelected { 288 | sender.isSelected = false 289 | }else { 290 | sender.isSelected = true 291 | } 292 | 293 | self.isActionThreeSelected = sender.isSelected 294 | 295 | if let delegate = self.delegate{ 296 | delegate.actionThreeButtonTapped(sender: sender, isSelected : sender.isSelected) 297 | } 298 | } 299 | 300 | override func draw(_ rect: CGRect) { 301 | 302 | self.addCirle(arcRadius: self.bounds.width + 10, capRadius: 2.0, color: self.progressEmptyColor,strokeStart: 0.0,strokeEnd: 1.0) 303 | self.createProgressCircle() 304 | 305 | } 306 | 307 | func animationDidStart(anim: CAAnimation) { 308 | 309 | circleLayer.strokeColor = self.progressFullColor.cgColor 310 | self.isAnimating = true 311 | self.duration = 0 312 | } 313 | 314 | func animationDidStop(anim: CAAnimation, finished flag: Bool) { 315 | 316 | self.isAnimating = false 317 | circleLayer.strokeColor = UIColor.clear.cgColor 318 | 319 | if(timer != nil) { 320 | timer.invalidate() 321 | timer = nil 322 | } 323 | } 324 | 325 | private func createUI() { 326 | self.layoutIfNeeded() 327 | view = loadViewFromNib() 328 | view.frame = bounds 329 | view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight] 330 | coverImageView.backgroundColor = UIColor.clear 331 | view.backgroundColor = UIColor.clear 332 | 333 | self.makeItRounded(view: view, newSize: view.bounds.width) 334 | self.backgroundColor = UIColor.clear 335 | 336 | addSubview(view) 337 | } 338 | 339 | private func loadViewFromNib() -> UIView { 340 | let bundle = Bundle(for: type(of: self)) 341 | let nib = UINib(nibName: "InteractivePlayerView", bundle: bundle) 342 | 343 | // Assumes UIView is top level and only object in CustomView.xib file 344 | let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView 345 | 346 | return view 347 | } 348 | 349 | private func makeItRounded(view : UIView!, newSize : CGFloat!){ 350 | let saveCenter : CGPoint = view.center 351 | let newFrame : CGRect = CGRect(x: view.frame.origin.x,y: view.frame.origin.y,width: newSize,height: newSize) 352 | view.frame = newFrame 353 | view.layer.cornerRadius = newSize / 2.0 354 | view.clipsToBounds = true 355 | view.center = saveCenter 356 | } 357 | 358 | private func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor, strokeStart : CGFloat, strokeEnd : CGFloat) { 359 | 360 | let centerPoint = CGPoint(x: self.bounds.midX ,y: self.bounds.midY) 361 | let startAngle = CGFloat(Double.pi/2) 362 | let endAngle = CGFloat(Double.pi * 2 + Double.pi/2) 363 | 364 | let path = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2+5, startAngle:startAngle, endAngle:endAngle, clockwise: true).cgPath 365 | 366 | let arc = CAShapeLayer() 367 | arc.lineWidth = 2 368 | arc.path = path 369 | arc.strokeStart = strokeStart 370 | arc.strokeEnd = strokeEnd 371 | arc.strokeColor = color.cgColor 372 | arc.fillColor = UIColor.clear.cgColor 373 | arc.shadowColor = UIColor.black.cgColor 374 | arc.shadowRadius = 0 375 | arc.shadowOpacity = 0 376 | arc.shadowOffset = CGSize.zero 377 | layer.addSublayer(arc) 378 | 379 | } 380 | 381 | 382 | private func createProgressCircle(){ 383 | let centerPoint = CGPoint(x: self.bounds.midX ,y: self.bounds.midY) 384 | let startAngle = CGFloat(Double.pi/2) 385 | let endAngle = CGFloat(Double.pi * 2 + Double.pi/2) 386 | 387 | // Use UIBezierPath as an easy way to create the CGPath for the layer. 388 | // The path should be the entire circle. 389 | let circlePath = UIBezierPath(arcCenter:centerPoint, radius: frame.width/2+5, startAngle:startAngle, endAngle:endAngle, clockwise: true).cgPath 390 | 391 | // Setup the CAShapeLayer with the path, colors, and line width 392 | circleLayer = CAShapeLayer() 393 | circleLayer.path = circlePath 394 | circleLayer.fillColor = UIColor.clear.cgColor 395 | circleLayer.shadowColor = UIColor.black.cgColor 396 | circleLayer.strokeColor = self.progressFullColor.cgColor 397 | circleLayer.lineWidth = 2.0; 398 | circleLayer.strokeStart = 0.0 399 | circleLayer.shadowRadius = 0 400 | circleLayer.shadowOpacity = 0 401 | circleLayer.shadowOffset = CGSize.zero 402 | 403 | // draw the colorful , nice progress circle 404 | circleLayer.strokeEnd = CGFloat(duration/progress) 405 | 406 | // Add the circleLayer to the view's layer's sublayers 407 | layer.addSublayer(circleLayer) 408 | } 409 | 410 | 411 | private func redrawStrokeEnd(){ 412 | circleLayer.strokeEnd = CGFloat(duration/progress) 413 | } 414 | 415 | private func resetAnimationCircle(){ 416 | stopTimer() 417 | duration = 0 418 | circleLayer.strokeEnd = 0 419 | } 420 | 421 | private func pauseLayer(layer : CALayer) { 422 | let pauseTime = layer.convertTime(CACurrentMediaTime(), from: nil) 423 | layer.speed = 0.0 424 | layer.timeOffset = pauseTime 425 | } 426 | 427 | private func resumeLayer(layer : CALayer) { 428 | let pausedTime = layer.timeOffset 429 | layer.speed = 1.0 430 | layer.timeOffset = 0.0 431 | layer.beginTime = 0.0 432 | let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime 433 | layer.beginTime = timeSincePause 434 | } 435 | 436 | private func startTimer(){ 437 | timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(InteractivePlayerView.updateTime), userInfo: nil, repeats: true) 438 | 439 | if let theDelegate = self.delegate { 440 | theDelegate.interactivePlayerViewDidStartPlaying(playerInteractive: self) 441 | } 442 | } 443 | 444 | private func stopTimer(){ 445 | 446 | if(timer != nil) { 447 | timer.invalidate() 448 | timer = nil 449 | 450 | if let theDelegate = self.delegate { 451 | theDelegate.interactivePlayerViewDidStopPlaying(playerInteractive: self) 452 | } 453 | 454 | } 455 | 456 | } 457 | 458 | @objc func updateTime(){ 459 | 460 | self.duration += 0.1 461 | let totalDuration = Int(self.duration) 462 | let min = totalDuration / 60 463 | let sec = totalDuration % 60 464 | 465 | timeLabel.text = NSString(format: "%i:%02i",min,sec ) as String 466 | 467 | if(self.duration >= self.progress) 468 | { 469 | stopTimer() 470 | } 471 | 472 | } 473 | 474 | /* Start timer and animation */ 475 | @objc func start(){ 476 | self.startTimer() 477 | } 478 | 479 | /* Stop timer and animation */ 480 | func stop(){ 481 | self.stopTimer() 482 | } 483 | 484 | func restartWithProgress(duration : Double){ 485 | progress = duration 486 | self.resetAnimationCircle() 487 | Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(InteractivePlayerView.start), userInfo: nil, repeats: false) 488 | } 489 | 490 | // MARK: - Gestures 491 | func addPanGesture(){ 492 | let gesture:UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(InteractivePlayerView.handlePanGesture)) 493 | gesture.maximumNumberOfTouches = 1 494 | self.addGestureRecognizer(gesture) 495 | } 496 | 497 | @objc func handlePanGesture(gesture:UIPanGestureRecognizer){ 498 | if(!self.panEnabled){ 499 | return; 500 | } 501 | 502 | let translation:CGPoint = gesture.translation(in: self) 503 | 504 | 505 | let xDirection:CGFloat = translation.x 506 | let yDirection:CGFloat = -1 * translation.y 507 | 508 | let rate:CGFloat = yDirection+xDirection // rate of forward/backwards 509 | 510 | 511 | 512 | if(gesture.state == UIGestureRecognizerState.began){ 513 | self.stopTimer() 514 | } 515 | else if(gesture.state == UIGestureRecognizerState.changed){ 516 | self.duration += Double(rate/4) 517 | 518 | if(self.duration < 0 ){ 519 | self.duration = 0 520 | } 521 | else if(self.duration >= progress){ 522 | self.duration = progress 523 | } 524 | } 525 | else if(gesture.state == UIGestureRecognizerState.ended){ 526 | self.startTimer() 527 | } 528 | 529 | 530 | gesture.setTranslation(CGPoint.zero, in: self) 531 | } 532 | 533 | } 534 | 535 | 536 | 537 | -------------------------------------------------------------------------------- /ipv_source/InteractivePlayerView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 38 | 50 | 62 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | --------------------------------------------------------------------------------