Commit dedcbc4f15b43b7858d08db5f58bb9892d9bde13
1 parent
48f428d0
商品管理 , 分类 , 播放器等 , 有部分bug
Showing
64 changed files
with
3445 additions
and
51 deletions
Podfile
| @@ -45,6 +45,11 @@ target 'metaCode' do | @@ -45,6 +45,11 @@ target 'metaCode' do | ||
| 45 | #轮播图 | 45 | #轮播图 |
| 46 | pod 'FSPagerView', '0.8.3' | 46 | pod 'FSPagerView', '0.8.3' |
| 47 | #pod 'SDCycleScrollView', '~> 1.82' | 47 | #pod 'SDCycleScrollView', '~> 1.82' |
| 48 | + #图片浏览器 | ||
| 49 | + pod 'SKPhotoBrowser' | ||
| 50 | + | ||
| 51 | + #视频播放器 | ||
| 52 | + pod 'PLPlayerKit' | ||
| 48 | 53 | ||
| 49 | target 'metaCodeTests' do | 54 | target 'metaCodeTests' do |
| 50 | inherit! :search_paths | 55 | inherit! :search_paths |
metaCode.xcodeproj/project.pbxproj
| @@ -29,6 +29,25 @@ | @@ -29,6 +29,25 @@ | ||
| 29 | 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */; }; | 29 | 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */; }; |
| 30 | 191733042B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */; }; | 30 | 191733042B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */; }; |
| 31 | 1917330A2B10864F007BCC04 /* Array+CNLiveExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733092B10864F007BCC04 /* Array+CNLiveExtensions.swift */; }; | 31 | 1917330A2B10864F007BCC04 /* Array+CNLiveExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733092B10864F007BCC04 /* Array+CNLiveExtensions.swift */; }; |
| 32 | + 1917330D2B1096AB007BCC04 /* CNLivePlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917330C2B1096AB007BCC04 /* CNLivePlayerViewController.swift */; }; | ||
| 33 | + 1917330F2B10989C007BCC04 /* CNLivePlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917330E2B10989C007BCC04 /* CNLivePlayerView.swift */; }; | ||
| 34 | + 191733112B109EDC007BCC04 /* CNLivePlayerControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733102B109EDC007BCC04 /* CNLivePlayerControlView.swift */; }; | ||
| 35 | + 191733132B109F7B007BCC04 /* CNLivePlayerGestureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733122B109F7B007BCC04 /* CNLivePlayerGestureView.swift */; }; | ||
| 36 | + 191733152B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733142B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift */; }; | ||
| 37 | + 191733172B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733162B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift */; }; | ||
| 38 | + 191733192B10A05D007BCC04 /* CNLivePlayerProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733182B10A05D007BCC04 /* CNLivePlayerProgressView.swift */; }; | ||
| 39 | + 1917331B2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917331A2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift */; }; | ||
| 40 | + 1917331D2B10A15A007BCC04 /* CNLivePlayerFailureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917331C2B10A15A007BCC04 /* CNLivePlayerFailureView.swift */; }; | ||
| 41 | + 1917331F2B10A1BE007BCC04 /* CNLivePlayerEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917331E2B10A1BE007BCC04 /* CNLivePlayerEnum.swift */; }; | ||
| 42 | + 191733212B143F3A007BCC04 /* CNLiveGradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733202B143F3A007BCC04 /* CNLiveGradientView.swift */; }; | ||
| 43 | + 191733232B14601A007BCC04 /* CNLivePlayerProgressSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733222B14601A007BCC04 /* CNLivePlayerProgressSlider.swift */; }; | ||
| 44 | + 191733252B146078007BCC04 /* CNLivePlayerSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733242B146078007BCC04 /* CNLivePlayerSlider.swift */; }; | ||
| 45 | + 191733272B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733262B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift */; }; | ||
| 46 | + 191733292B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733282B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift */; }; | ||
| 47 | + 1917332B2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917332A2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift */; }; | ||
| 48 | + 1917332D2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917332C2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift */; }; | ||
| 49 | + 1917332F2B16C7C9007BCC04 /* CNLiveTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1917332E2B16C7C9007BCC04 /* CNLiveTimer.swift */; }; | ||
| 50 | + 191733312B170537007BCC04 /* CNLiveCommonManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733302B170537007BCC04 /* CNLiveCommonManager.swift */; }; | ||
| 32 | 192336EB2AD9224300D47CD4 /* CNUpSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */; }; | 51 | 192336EB2AD9224300D47CD4 /* CNUpSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */; }; |
| 33 | 1926C28F2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */; }; | 52 | 1926C28F2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */; }; |
| 34 | 1926C2912AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */; }; | 53 | 1926C2912AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */; }; |
| @@ -221,6 +240,25 @@ | @@ -221,6 +240,25 @@ | ||
| 221 | 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveSelUplSingleImageView.swift; sourceTree = "<group>"; }; | 240 | 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveSelUplSingleImageView.swift; sourceTree = "<group>"; }; |
| 222 | 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDictionary+CNLiveExtensions.swift"; sourceTree = "<group>"; }; | 241 | 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDictionary+CNLiveExtensions.swift"; sourceTree = "<group>"; }; |
| 223 | 191733092B10864F007BCC04 /* Array+CNLiveExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+CNLiveExtensions.swift"; sourceTree = "<group>"; }; | 242 | 191733092B10864F007BCC04 /* Array+CNLiveExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+CNLiveExtensions.swift"; sourceTree = "<group>"; }; |
| 243 | + 1917330C2B1096AB007BCC04 /* CNLivePlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerViewController.swift; sourceTree = "<group>"; }; | ||
| 244 | + 1917330E2B10989C007BCC04 /* CNLivePlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerView.swift; sourceTree = "<group>"; }; | ||
| 245 | + 191733102B109EDC007BCC04 /* CNLivePlayerControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerControlView.swift; sourceTree = "<group>"; }; | ||
| 246 | + 191733122B109F7B007BCC04 /* CNLivePlayerGestureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerGestureView.swift; sourceTree = "<group>"; }; | ||
| 247 | + 191733142B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerTopNaviView.swift; sourceTree = "<group>"; }; | ||
| 248 | + 191733162B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerBottomNaviView.swift; sourceTree = "<group>"; }; | ||
| 249 | + 191733182B10A05D007BCC04 /* CNLivePlayerProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerProgressView.swift; sourceTree = "<group>"; }; | ||
| 250 | + 1917331A2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerLoadingView.swift; sourceTree = "<group>"; }; | ||
| 251 | + 1917331C2B10A15A007BCC04 /* CNLivePlayerFailureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerFailureView.swift; sourceTree = "<group>"; }; | ||
| 252 | + 1917331E2B10A1BE007BCC04 /* CNLivePlayerEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerEnum.swift; sourceTree = "<group>"; }; | ||
| 253 | + 191733202B143F3A007BCC04 /* CNLiveGradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveGradientView.swift; sourceTree = "<group>"; }; | ||
| 254 | + 191733222B14601A007BCC04 /* CNLivePlayerProgressSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerProgressSlider.swift; sourceTree = "<group>"; }; | ||
| 255 | + 191733242B146078007BCC04 /* CNLivePlayerSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerSlider.swift; sourceTree = "<group>"; }; | ||
| 256 | + 191733262B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerFastForwardPreviewView.swift; sourceTree = "<group>"; }; | ||
| 257 | + 191733282B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerVolumeBrightnessView.swift; sourceTree = "<group>"; }; | ||
| 258 | + 1917332A2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerLandscapeViewController.swift; sourceTree = "<group>"; }; | ||
| 259 | + 1917332C2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLivePlayerKVOModel.swift; sourceTree = "<group>"; }; | ||
| 260 | + 1917332E2B16C7C9007BCC04 /* CNLiveTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveTimer.swift; sourceTree = "<group>"; }; | ||
| 261 | + 191733302B170537007BCC04 /* CNLiveCommonManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveCommonManager.swift; sourceTree = "<group>"; }; | ||
| 224 | 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNUpSlideViewController.swift; sourceTree = "<group>"; }; | 262 | 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNUpSlideViewController.swift; sourceTree = "<group>"; }; |
| 225 | 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideViewModel.swift; sourceTree = "<group>"; }; | 263 | 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideViewModel.swift; sourceTree = "<group>"; }; |
| 226 | 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideModel.swift; sourceTree = "<group>"; }; | 264 | 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideModel.swift; sourceTree = "<group>"; }; |
| @@ -436,6 +474,31 @@ | @@ -436,6 +474,31 @@ | ||
| 436 | path = GoodsDetail; | 474 | path = GoodsDetail; |
| 437 | sourceTree = "<group>"; | 475 | sourceTree = "<group>"; |
| 438 | }; | 476 | }; |
| 477 | + 1917330B2B109691007BCC04 /* CNLivePlayer */ = { | ||
| 478 | + isa = PBXGroup; | ||
| 479 | + children = ( | ||
| 480 | + 1917330C2B1096AB007BCC04 /* CNLivePlayerViewController.swift */, | ||
| 481 | + 1917330E2B10989C007BCC04 /* CNLivePlayerView.swift */, | ||
| 482 | + 191733102B109EDC007BCC04 /* CNLivePlayerControlView.swift */, | ||
| 483 | + 191733122B109F7B007BCC04 /* CNLivePlayerGestureView.swift */, | ||
| 484 | + 191733142B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift */, | ||
| 485 | + 191733162B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift */, | ||
| 486 | + 191733182B10A05D007BCC04 /* CNLivePlayerProgressView.swift */, | ||
| 487 | + 1917331A2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift */, | ||
| 488 | + 1917331C2B10A15A007BCC04 /* CNLivePlayerFailureView.swift */, | ||
| 489 | + 1917331E2B10A1BE007BCC04 /* CNLivePlayerEnum.swift */, | ||
| 490 | + 191733202B143F3A007BCC04 /* CNLiveGradientView.swift */, | ||
| 491 | + 191733222B14601A007BCC04 /* CNLivePlayerProgressSlider.swift */, | ||
| 492 | + 191733242B146078007BCC04 /* CNLivePlayerSlider.swift */, | ||
| 493 | + 191733262B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift */, | ||
| 494 | + 191733282B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift */, | ||
| 495 | + 1917332A2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift */, | ||
| 496 | + 1917332C2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift */, | ||
| 497 | + 1917332E2B16C7C9007BCC04 /* CNLiveTimer.swift */, | ||
| 498 | + ); | ||
| 499 | + path = CNLivePlayer; | ||
| 500 | + sourceTree = "<group>"; | ||
| 501 | + }; | ||
| 439 | 19565EC32AF8ACC2007D6727 /* GoodsManager */ = { | 502 | 19565EC32AF8ACC2007D6727 /* GoodsManager */ = { |
| 440 | isa = PBXGroup; | 503 | isa = PBXGroup; |
| 441 | children = ( | 504 | children = ( |
| @@ -503,10 +566,12 @@ | @@ -503,10 +566,12 @@ | ||
| 503 | 19CC4D502ADD126D00308E2A /* Util */ = { | 566 | 19CC4D502ADD126D00308E2A /* Util */ = { |
| 504 | isa = PBXGroup; | 567 | isa = PBXGroup; |
| 505 | children = ( | 568 | children = ( |
| 569 | + 1917330B2B109691007BCC04 /* CNLivePlayer */, | ||
| 506 | 19CC4D512ADD129800308E2A /* CNUpSlideAnimationTransition.swift */, | 570 | 19CC4D512ADD129800308E2A /* CNUpSlideAnimationTransition.swift */, |
| 507 | 19FA201A2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift */, | 571 | 19FA201A2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift */, |
| 508 | 19D2CE622AE8B65D00691757 /* CNLiveDownSlideTool.swift */, | 572 | 19D2CE622AE8B65D00691757 /* CNLiveDownSlideTool.swift */, |
| 509 | 19BB202A2AF382150094D962 /* CNLiveAdaptTool.swift */, | 573 | 19BB202A2AF382150094D962 /* CNLiveAdaptTool.swift */, |
| 574 | + 191733302B170537007BCC04 /* CNLiveCommonManager.swift */, | ||
| 510 | ); | 575 | ); |
| 511 | path = Util; | 576 | path = Util; |
| 512 | sourceTree = "<group>"; | 577 | sourceTree = "<group>"; |
| @@ -1246,11 +1311,14 @@ | @@ -1246,11 +1311,14 @@ | ||
| 1246 | 191732F32B084DBC007BCC04 /* CNLiveShopClassifySwitchTableViewCell.swift in Sources */, | 1311 | 191732F32B084DBC007BCC04 /* CNLiveShopClassifySwitchTableViewCell.swift in Sources */, |
| 1247 | 191732E72B0615C1007BCC04 /* UIScrollView+CNLiveExtensions.swift in Sources */, | 1312 | 191732E72B0615C1007BCC04 /* UIScrollView+CNLiveExtensions.swift in Sources */, |
| 1248 | 1917328E2B032583007BCC04 /* CNLiveRoundedRectView.swift in Sources */, | 1313 | 1917328E2B032583007BCC04 /* CNLiveRoundedRectView.swift in Sources */, |
| 1314 | + 1917332F2B16C7C9007BCC04 /* CNLiveTimer.swift in Sources */, | ||
| 1249 | 7CD675292A270F6A008354C1 /* WJColorChange.m in Sources */, | 1315 | 7CD675292A270F6A008354C1 /* WJColorChange.m in Sources */, |
| 1250 | 79F4B11C2A33036E00993C03 /* CNLiveMineInfoAlertView.swift in Sources */, | 1316 | 79F4B11C2A33036E00993C03 /* CNLiveMineInfoAlertView.swift in Sources */, |
| 1251 | 79BB96A82AF223FB00AEA4AC /* CNLiveConfigAlertManager.swift in Sources */, | 1317 | 79BB96A82AF223FB00AEA4AC /* CNLiveConfigAlertManager.swift in Sources */, |
| 1252 | 19BB1FF02AF0E5B30094D962 /* CNLiveShopDetailModel.swift in Sources */, | 1318 | 19BB1FF02AF0E5B30094D962 /* CNLiveShopDetailModel.swift in Sources */, |
| 1253 | 796398942A260C0100D045EB /* AppDelegate.swift in Sources */, | 1319 | 796398942A260C0100D045EB /* AppDelegate.swift in Sources */, |
| 1320 | + 1917330D2B1096AB007BCC04 /* CNLivePlayerViewController.swift in Sources */, | ||
| 1321 | + 1917330F2B10989C007BCC04 /* CNLivePlayerView.swift in Sources */, | ||
| 1254 | 7989B5C72A4BDC7200A19B10 /* CNLiveMineEarnListViewController.swift in Sources */, | 1322 | 7989B5C72A4BDC7200A19B10 /* CNLiveMineEarnListViewController.swift in Sources */, |
| 1255 | 191732902B0348F6007BCC04 /* CNLiveSwitchView.swift in Sources */, | 1323 | 191732902B0348F6007BCC04 /* CNLiveSwitchView.swift in Sources */, |
| 1256 | 792B53282AFCD7640009AB49 /* CNLiveShopOrderExpressDetailViewController.swift in Sources */, | 1324 | 792B53282AFCD7640009AB49 /* CNLiveShopOrderExpressDetailViewController.swift in Sources */, |
| @@ -1268,6 +1336,7 @@ | @@ -1268,6 +1336,7 @@ | ||
| 1268 | 79282A3C2A2EDC2500B5F8CF /* NSString+CNLiveExtensions.swift in Sources */, | 1336 | 79282A3C2A2EDC2500B5F8CF /* NSString+CNLiveExtensions.swift in Sources */, |
| 1269 | 19D2CE632AE8B65D00691757 /* CNLiveDownSlideTool.swift in Sources */, | 1337 | 19D2CE632AE8B65D00691757 /* CNLiveDownSlideTool.swift in Sources */, |
| 1270 | 790B1FB82A41B6A60074CF00 /* CNLiveMineMessageViewController.swift in Sources */, | 1338 | 790B1FB82A41B6A60074CF00 /* CNLiveMineMessageViewController.swift in Sources */, |
| 1339 | + 191733252B146078007BCC04 /* CNLivePlayerSlider.swift in Sources */, | ||
| 1271 | 19BB202B2AF382150094D962 /* CNLiveAdaptTool.swift in Sources */, | 1340 | 19BB202B2AF382150094D962 /* CNLiveAdaptTool.swift in Sources */, |
| 1272 | 79E672032AFDFA9C00F2F768 /* CNLiveMineSignOutViewController.swift in Sources */, | 1341 | 79E672032AFDFA9C00F2F768 /* CNLiveMineSignOutViewController.swift in Sources */, |
| 1273 | 19565ECD2AF8D256007D6727 /* CNLiveShopGoodsListClassifyView.swift in Sources */, | 1342 | 19565ECD2AF8D256007D6727 /* CNLiveShopGoodsListClassifyView.swift in Sources */, |
| @@ -1279,6 +1348,7 @@ | @@ -1279,6 +1348,7 @@ | ||
| 1279 | 19CC4D4B2ADD086F00308E2A /* CNUpSlideDetailViewController.swift in Sources */, | 1348 | 19CC4D4B2ADD086F00308E2A /* CNUpSlideDetailViewController.swift in Sources */, |
| 1280 | 7C83B4402A52BB2B004BF4A4 /* CNGlobalEnum.swift in Sources */, | 1349 | 7C83B4402A52BB2B004BF4A4 /* CNGlobalEnum.swift in Sources */, |
| 1281 | 7C83B4442A541F36004BF4A4 /* NSDate+CNLiveExtensions.swift in Sources */, | 1350 | 7C83B4442A541F36004BF4A4 /* NSDate+CNLiveExtensions.swift in Sources */, |
| 1351 | + 1917332B2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift in Sources */, | ||
| 1282 | 798916F12B0491A400D08302 /* CNLiveShopBodyTransListView.swift in Sources */, | 1352 | 798916F12B0491A400D08302 /* CNLiveShopBodyTransListView.swift in Sources */, |
| 1283 | 7CD675482A274167008354C1 /* PGIndexBannerSubiew.m in Sources */, | 1353 | 7CD675482A274167008354C1 /* PGIndexBannerSubiew.m in Sources */, |
| 1284 | 790D019F2A2DD66E00C5978D /* CNLiveLoginViewModel.swift in Sources */, | 1354 | 790D019F2A2DD66E00C5978D /* CNLiveLoginViewModel.swift in Sources */, |
| @@ -1288,6 +1358,7 @@ | @@ -1288,6 +1358,7 @@ | ||
| 1288 | 79EABB892AB4497700F3A4E2 /* CNLiveSaveStandDB.swift in Sources */, | 1358 | 79EABB892AB4497700F3A4E2 /* CNLiveSaveStandDB.swift in Sources */, |
| 1289 | 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */, | 1359 | 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */, |
| 1290 | 19BB1FEA2AEF7B4A0094D962 /* CNLiveShopConsoleCell.swift in Sources */, | 1360 | 19BB1FEA2AEF7B4A0094D962 /* CNLiveShopConsoleCell.swift in Sources */, |
| 1361 | + 191733132B109F7B007BCC04 /* CNLivePlayerGestureView.swift in Sources */, | ||
| 1291 | 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */, | 1362 | 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */, |
| 1292 | 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */, | 1363 | 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */, |
| 1293 | 191732F82B08AB9D007BCC04 /* CNLiveShopClassilyViewModel.swift in Sources */, | 1364 | 191732F82B08AB9D007BCC04 /* CNLiveShopClassilyViewModel.swift in Sources */, |
| @@ -1305,6 +1376,7 @@ | @@ -1305,6 +1376,7 @@ | ||
| 1305 | 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */, | 1376 | 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */, |
| 1306 | 79E496E82AB9674300127BF8 /* NSMutableAttributedString+CNLiveExtensions.swift in Sources */, | 1377 | 79E496E82AB9674300127BF8 /* NSMutableAttributedString+CNLiveExtensions.swift in Sources */, |
| 1307 | 19CC4D472ADD006600308E2A /* CNDownSlideSingleCourseCell.swift in Sources */, | 1378 | 19CC4D472ADD006600308E2A /* CNDownSlideSingleCourseCell.swift in Sources */, |
| 1379 | + 191733232B14601A007BCC04 /* CNLivePlayerProgressSlider.swift in Sources */, | ||
| 1308 | 191732FE2B0B3EBF007BCC04 /* CNLiveShopGoodsDetailsViewController.swift in Sources */, | 1380 | 191732FE2B0B3EBF007BCC04 /* CNLiveShopGoodsDetailsViewController.swift in Sources */, |
| 1309 | 79E496E32AB9357000127BF8 /* UITableViewCell+CNLiveExtension.swift in Sources */, | 1381 | 79E496E32AB9357000127BF8 /* UITableViewCell+CNLiveExtension.swift in Sources */, |
| 1310 | 7C83B4422A541EBF004BF4A4 /* CALayer+CNLiveExtensions.swift in Sources */, | 1382 | 7C83B4422A541EBF004BF4A4 /* CALayer+CNLiveExtensions.swift in Sources */, |
| @@ -1312,6 +1384,7 @@ | @@ -1312,6 +1384,7 @@ | ||
| 1312 | 798A44F72A3077ED00815935 /* CNLiveHotButton.swift in Sources */, | 1384 | 798A44F72A3077ED00815935 /* CNLiveHotButton.swift in Sources */, |
| 1313 | 7CD6753D2A2740B0008354C1 /* CNMainView.swift in Sources */, | 1385 | 7CD6753D2A2740B0008354C1 /* CNMainView.swift in Sources */, |
| 1314 | 793CAF522A58FCA200882EF4 /* CNLiveMineExchangeViewController.swift in Sources */, | 1386 | 793CAF522A58FCA200882EF4 /* CNLiveMineExchangeViewController.swift in Sources */, |
| 1387 | + 191733272B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift in Sources */, | ||
| 1315 | 7CD675522A29C04B008354C1 /* CNLiveConfigstant.swift in Sources */, | 1388 | 7CD675522A29C04B008354C1 /* CNLiveConfigstant.swift in Sources */, |
| 1316 | 79282A402A2F055100B5F8CF /* CNLiveConfigUserInfo.swift in Sources */, | 1389 | 79282A402A2F055100B5F8CF /* CNLiveConfigUserInfo.swift in Sources */, |
| 1317 | 1965FA402AFB38AA00F0F435 /* CNLiveAddGoodsSelectUploadImageView.swift in Sources */, | 1390 | 1965FA402AFB38AA00F0F435 /* CNLiveAddGoodsSelectUploadImageView.swift in Sources */, |
| @@ -1325,6 +1398,7 @@ | @@ -1325,6 +1398,7 @@ | ||
| 1325 | 792E57D92A3AA2F2005834DB /* CNLiveCommonBaseModel.swift in Sources */, | 1398 | 792E57D92A3AA2F2005834DB /* CNLiveCommonBaseModel.swift in Sources */, |
| 1326 | 791C1C862AFB2EB4003E6362 /* CNLiveShopOrderExpressViewController.swift in Sources */, | 1399 | 791C1C862AFB2EB4003E6362 /* CNLiveShopOrderExpressViewController.swift in Sources */, |
| 1327 | 7CD6753E2A2740B0008354C1 /* CNUpSlideView.swift in Sources */, | 1400 | 7CD6753E2A2740B0008354C1 /* CNUpSlideView.swift in Sources */, |
| 1401 | + 191733312B170537007BCC04 /* CNLiveCommonManager.swift in Sources */, | ||
| 1328 | 7CD675402A2740B0008354C1 /* CNDownSlideView.swift in Sources */, | 1402 | 7CD675402A2740B0008354C1 /* CNDownSlideView.swift in Sources */, |
| 1329 | 191732F52B085BAE007BCC04 /* CNLiveShopClassilyIconTableViewCell.swift in Sources */, | 1403 | 191732F52B085BAE007BCC04 /* CNLiveShopClassilyIconTableViewCell.swift in Sources */, |
| 1330 | 191732E32B05F474007BCC04 /* CNLiveShopGoodsManageDetailsInputManager.swift in Sources */, | 1404 | 191732E32B05F474007BCC04 /* CNLiveShopGoodsManageDetailsInputManager.swift in Sources */, |
| @@ -1333,16 +1407,20 @@ | @@ -1333,16 +1407,20 @@ | ||
| 1333 | 798A44FD2A309EBA00815935 /* CNLiveTypeFeedBackViewController.swift in Sources */, | 1407 | 798A44FD2A309EBA00815935 /* CNLiveTypeFeedBackViewController.swift in Sources */, |
| 1334 | 79656E382AAEBA8E00119A61 /* CNLiveMineInputViewController.swift in Sources */, | 1408 | 79656E382AAEBA8E00119A61 /* CNLiveMineInputViewController.swift in Sources */, |
| 1335 | 19CC4D522ADD129800308E2A /* CNUpSlideAnimationTransition.swift in Sources */, | 1409 | 19CC4D522ADD129800308E2A /* CNUpSlideAnimationTransition.swift in Sources */, |
| 1410 | + 1917331D2B10A15A007BCC04 /* CNLivePlayerFailureView.swift in Sources */, | ||
| 1336 | 7CD6754F2A2840B9008354C1 /* CNMetaCodeHomePageController.swift in Sources */, | 1411 | 7CD6754F2A2840B9008354C1 /* CNMetaCodeHomePageController.swift in Sources */, |
| 1337 | 79D094DC2B0765DD008CB1F3 /* CNLiveShopBodyCouponGoodsListView.swift in Sources */, | 1412 | 79D094DC2B0765DD008CB1F3 /* CNLiveShopBodyCouponGoodsListView.swift in Sources */, |
| 1338 | 798916EF2B048EC800D08302 /* CNLiveShopTransListViewController.swift in Sources */, | 1413 | 798916EF2B048EC800D08302 /* CNLiveShopTransListViewController.swift in Sources */, |
| 1339 | 7989B5C52A4BDC6000A19B10 /* CNLiveMineEarnViewController.swift in Sources */, | 1414 | 7989B5C52A4BDC6000A19B10 /* CNLiveMineEarnViewController.swift in Sources */, |
| 1340 | 792E57DB2A3AE9F4005834DB /* CNLiveCommonQiniuTool.swift in Sources */, | 1415 | 792E57DB2A3AE9F4005834DB /* CNLiveCommonQiniuTool.swift in Sources */, |
| 1341 | 191732F12B084822007BCC04 /* CNLiveShopClassifyInputTableViewCell.swift in Sources */, | 1416 | 191732F12B084822007BCC04 /* CNLiveShopClassifyInputTableViewCell.swift in Sources */, |
| 1417 | + 191733212B143F3A007BCC04 /* CNLiveGradientView.swift in Sources */, | ||
| 1342 | 19BB1FE62AEB93B80094D962 /* CNLiveShopUserInfoModel.swift in Sources */, | 1418 | 19BB1FE62AEB93B80094D962 /* CNLiveShopUserInfoModel.swift in Sources */, |
| 1343 | 7CD675472A274167008354C1 /* NewPagedFlowView.m in Sources */, | 1419 | 7CD675472A274167008354C1 /* NewPagedFlowView.m in Sources */, |
| 1344 | 191732ED2B073C52007BCC04 /* CNLiveShopClassifyListModel.swift in Sources */, | 1420 | 191732ED2B073C52007BCC04 /* CNLiveShopClassifyListModel.swift in Sources */, |
| 1345 | 79F4B11A2A32F21400993C03 /* CNLiveMineNickViewController.swift in Sources */, | 1421 | 79F4B11A2A32F21400993C03 /* CNLiveMineNickViewController.swift in Sources */, |
| 1422 | + 191733112B109EDC007BCC04 /* CNLivePlayerControlView.swift in Sources */, | ||
| 1423 | + 1917331F2B10A1BE007BCC04 /* CNLivePlayerEnum.swift in Sources */, | ||
| 1346 | 798A44FF2A30A0A800815935 /* CNLiveInputFeedBackViewController.swift in Sources */, | 1424 | 798A44FF2A30A0A800815935 /* CNLiveInputFeedBackViewController.swift in Sources */, |
| 1347 | 79282A442A2F1C1E00B5F8CF /* CNLiveLoginAuthView.swift in Sources */, | 1425 | 79282A442A2F1C1E00B5F8CF /* CNLiveLoginAuthView.swift in Sources */, |
| 1348 | 79BB96A62AF21E2800AEA4AC /* CNLiveShopOrderDetailViewController.swift in Sources */, | 1426 | 79BB96A62AF21E2800AEA4AC /* CNLiveShopOrderDetailViewController.swift in Sources */, |
| @@ -1356,11 +1434,13 @@ | @@ -1356,11 +1434,13 @@ | ||
| 1356 | 7987BF3D2A497644000A1ABC /* CNLiveMineQuestViewController.swift in Sources */, | 1434 | 7987BF3D2A497644000A1ABC /* CNLiveMineQuestViewController.swift in Sources */, |
| 1357 | 798A44EA2A30135D00815935 /* CNLiveMineBodyListView.swift in Sources */, | 1435 | 798A44EA2A30135D00815935 /* CNLiveMineBodyListView.swift in Sources */, |
| 1358 | 799172322AF08D1B00DC01A8 /* CNLiveShopOrderViewController.swift in Sources */, | 1436 | 799172322AF08D1B00DC01A8 /* CNLiveShopOrderViewController.swift in Sources */, |
| 1437 | + 1917332D2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift in Sources */, | ||
| 1359 | 798A44F92A30835400815935 /* CNLiveHelpFeedBackViewController.swift in Sources */, | 1438 | 798A44F92A30835400815935 /* CNLiveHelpFeedBackViewController.swift in Sources */, |
| 1360 | 79A68C4A2A26E6CE00DC3B43 /* (null) in Sources */, | 1439 | 79A68C4A2A26E6CE00DC3B43 /* (null) in Sources */, |
| 1361 | 790D01852A2D89E100C5978D /* UIColor+CNLiveExtensions.swift in Sources */, | 1440 | 790D01852A2D89E100C5978D /* UIColor+CNLiveExtensions.swift in Sources */, |
| 1362 | 794FF1092B02131300385E85 /* CNLiveSaveSearchDB.swift in Sources */, | 1441 | 794FF1092B02131300385E85 /* CNLiveSaveSearchDB.swift in Sources */, |
| 1363 | 79396EED2A319F220053E1AF /* NSObject+CNLiveExtensions.swift in Sources */, | 1442 | 79396EED2A319F220053E1AF /* NSObject+CNLiveExtensions.swift in Sources */, |
| 1443 | + 1917331B2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift in Sources */, | ||
| 1364 | 19FA201B2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift in Sources */, | 1444 | 19FA201B2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift in Sources */, |
| 1365 | 7C4931312A2F142F000E44B4 /* CNHomePageBackgroupView.swift in Sources */, | 1445 | 7C4931312A2F142F000E44B4 /* CNHomePageBackgroupView.swift in Sources */, |
| 1366 | 19BB1FF22AF21A950094D962 /* CNLliveShopDetailBannerCell.swift in Sources */, | 1446 | 19BB1FF22AF21A950094D962 /* CNLliveShopDetailBannerCell.swift in Sources */, |
| @@ -1370,6 +1450,7 @@ | @@ -1370,6 +1450,7 @@ | ||
| 1370 | 19565EC22AF616CA007D6727 /* CNLiveShopDetailOrderAssetCell.swift in Sources */, | 1450 | 19565EC22AF616CA007D6727 /* CNLiveShopDetailOrderAssetCell.swift in Sources */, |
| 1371 | 1917330A2B10864F007BCC04 /* Array+CNLiveExtensions.swift in Sources */, | 1451 | 1917330A2B10864F007BCC04 /* Array+CNLiveExtensions.swift in Sources */, |
| 1372 | 191732FB2B0AF34A007BCC04 /* CNLiveShopGoodsDetailsModel.swift in Sources */, | 1452 | 191732FB2B0AF34A007BCC04 /* CNLiveShopGoodsDetailsModel.swift in Sources */, |
| 1453 | + 191733152B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift in Sources */, | ||
| 1373 | 794FF1052B01FC8800385E85 /* CNLiveShopOrderSearchViewController.swift in Sources */, | 1454 | 794FF1052B01FC8800385E85 /* CNLiveShopOrderSearchViewController.swift in Sources */, |
| 1374 | 798A44EC2A302DBE00815935 /* CNLiveMineAddInfoViewController.swift in Sources */, | 1455 | 798A44EC2A302DBE00815935 /* CNLiveMineAddInfoViewController.swift in Sources */, |
| 1375 | 791C1C882AFB6FD7003E6362 /* CNLiveShopOrderExpressFirmViewController.swift in Sources */, | 1456 | 791C1C882AFB6FD7003E6362 /* CNLiveShopOrderExpressFirmViewController.swift in Sources */, |
| @@ -1384,6 +1465,7 @@ | @@ -1384,6 +1465,7 @@ | ||
| 1384 | 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */, | 1465 | 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */, |
| 1385 | 798A44EE2A305AAC00815935 /* CNLiveBaseNavigationController.swift in Sources */, | 1466 | 798A44EE2A305AAC00815935 /* CNLiveBaseNavigationController.swift in Sources */, |
| 1386 | 7CD675422A2740F8008354C1 /* CNCustomIndexView.swift in Sources */, | 1467 | 7CD675422A2740F8008354C1 /* CNCustomIndexView.swift in Sources */, |
| 1468 | + 191733292B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift in Sources */, | ||
| 1387 | 7C4931292A2D8BA8000E44B4 /* CNLiveBaseTabBarViewController.swift in Sources */, | 1469 | 7C4931292A2D8BA8000E44B4 /* CNLiveBaseTabBarViewController.swift in Sources */, |
| 1388 | 79F4B1162A32B96B00993C03 /* CNLiveMineInfoViewController.swift in Sources */, | 1470 | 79F4B1162A32B96B00993C03 /* CNLiveMineInfoViewController.swift in Sources */, |
| 1389 | 791C1C8A2AFB84EE003E6362 /* CNLiveShopOrderExpressListViewController.swift in Sources */, | 1471 | 791C1C8A2AFB84EE003E6362 /* CNLiveShopOrderExpressListViewController.swift in Sources */, |
| @@ -1393,6 +1475,7 @@ | @@ -1393,6 +1475,7 @@ | ||
| 1393 | 7CD6753C2A2740B0008354C1 /* CNUpSlideViewRemindView.swift in Sources */, | 1475 | 7CD6753C2A2740B0008354C1 /* CNUpSlideViewRemindView.swift in Sources */, |
| 1394 | 79BB1C142B05C51900C5720C /* CNLiveShopCouponViewController.swift in Sources */, | 1476 | 79BB1C142B05C51900C5720C /* CNLiveShopCouponViewController.swift in Sources */, |
| 1395 | 798916ED2B048E8200D08302 /* CNLiveShopTransViewController.swift in Sources */, | 1477 | 798916ED2B048E8200D08302 /* CNLiveShopTransViewController.swift in Sources */, |
| 1478 | + 191733172B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift in Sources */, | ||
| 1396 | 19BB1FEC2AF0AB8E0094D962 /* CNLiveDownShopDetailController.swift in Sources */, | 1479 | 19BB1FEC2AF0AB8E0094D962 /* CNLiveDownShopDetailController.swift in Sources */, |
| 1397 | 794FF1072B01FC9800385E85 /* CNLiveShopOrderSearchListViewController.swift in Sources */, | 1480 | 794FF1072B01FC9800385E85 /* CNLiveShopOrderSearchListViewController.swift in Sources */, |
| 1398 | 798A44E82A30134400815935 /* CNLiveMineHeaderView.swift in Sources */, | 1481 | 798A44E82A30134400815935 /* CNLiveMineHeaderView.swift in Sources */, |
| @@ -1400,6 +1483,7 @@ | @@ -1400,6 +1483,7 @@ | ||
| 1400 | 79A267832AF8D7BC0088D9F6 /* CNLiveShopBodyCustomView.swift in Sources */, | 1483 | 79A267832AF8D7BC0088D9F6 /* CNLiveShopBodyCustomView.swift in Sources */, |
| 1401 | 791C1C8C2AFB85F8003E6362 /* CNLiveShopBodyExpressView.swift in Sources */, | 1484 | 791C1C8C2AFB85F8003E6362 /* CNLiveShopBodyExpressView.swift in Sources */, |
| 1402 | 790D019A2A2DCAE400C5978D /* CNLiveViewController.swift in Sources */, | 1485 | 790D019A2A2DCAE400C5978D /* CNLiveViewController.swift in Sources */, |
| 1486 | + 191733192B10A05D007BCC04 /* CNLivePlayerProgressView.swift in Sources */, | ||
| 1403 | 79803E272AD68D3100F05F68 /* CNLiveMineShopViewController.swift in Sources */, | 1487 | 79803E272AD68D3100F05F68 /* CNLiveMineShopViewController.swift in Sources */, |
| 1404 | 79A68C4C2A26EA6000DC3B43 /* (null) in Sources */, | 1488 | 79A68C4C2A26EA6000DC3B43 /* (null) in Sources */, |
| 1405 | 79803E292AD6991200F05F68 /* CNLiveMineInputMessageView.swift in Sources */, | 1489 | 79803E292AD6991200F05F68 /* CNLiveMineInputMessageView.swift in Sources */, |
metaCode/Classes/Common/Base/CNLiveBaseViewController.swift
| @@ -116,6 +116,11 @@ class CNLiveBaseViewController: UIViewController { | @@ -116,6 +116,11 @@ class CNLiveBaseViewController: UIViewController { | ||
| 116 | private var leftNavSpace: CGFloat = 0.0 | 116 | private var leftNavSpace: CGFloat = 0.0 |
| 117 | private var rightNavSpace: CGFloat = 0.0 | 117 | private var rightNavSpace: CGFloat = 0.0 |
| 118 | 118 | ||
| 119 | + /** | ||
| 120 | + 是否禁止右滑返回 | ||
| 121 | + */ | ||
| 122 | + var popGestureRecognizerEnable:Bool = false | ||
| 123 | + | ||
| 119 | deinit { | 124 | deinit { |
| 120 | log("主界面已销毁") | 125 | log("主界面已销毁") |
| 121 | } | 126 | } |
metaCode/Classes/Common/Util/CNLiveCommonQiniuTool.swift
| @@ -38,6 +38,7 @@ class UploadManager: NSObject { | @@ -38,6 +38,7 @@ class UploadManager: NSObject { | ||
| 38 | static func uploadImage(imageData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String { | 38 | static func uploadImage(imageData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String { |
| 39 | let key = UploadManager.createImageFileName() | 39 | let key = UploadManager.createImageFileName() |
| 40 | UploadManager.uploadData(madiaData: imageData, key: key, progress: progressBlock, success: successBlock) | 40 | UploadManager.uploadData(madiaData: imageData, key: key, progress: progressBlock, success: successBlock) |
| 41 | + return key | ||
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | /// 上传视频 | 44 | /// 上传视频 |
| @@ -48,6 +49,7 @@ class UploadManager: NSObject { | @@ -48,6 +49,7 @@ class UploadManager: NSObject { | ||
| 48 | static func uploadVideo(videoData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String { | 49 | static func uploadVideo(videoData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String { |
| 49 | let key = UploadManager.createVideoFileName() | 50 | let key = UploadManager.createVideoFileName() |
| 50 | UploadManager.uploadData(madiaData: videoData, key: key, progress: progressBlock, success: successBlock) | 51 | UploadManager.uploadData(madiaData: videoData, key: key, progress: progressBlock, success: successBlock) |
| 52 | + return key | ||
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | // MARK: - 取消上传 | 55 | // MARK: - 取消上传 |
| @@ -61,7 +63,7 @@ class UploadManager: NSObject { | @@ -61,7 +63,7 @@ class UploadManager: NSObject { | ||
| 61 | } | 63 | } |
| 62 | } | 64 | } |
| 63 | // MARK: - 删除云中图片 | 65 | // MARK: - 删除云中图片 |
| 64 | - func requestQiNiuDeleteImageUrl(imageUrl:String,resultBlock:downSlideResultBlock){ | 66 | + func requestQiNiuDeleteImageUrl(imageUrl:String,resultBlock:@escaping downSlideResultBlock){ |
| 65 | 67 | ||
| 66 | let param = NSMutableDictionary() | 68 | let param = NSMutableDictionary() |
| 67 | param.setValue(imageUrl, forKey: "img") | 69 | param.setValue(imageUrl, forKey: "img") |
metaCode/Classes/Config/CNLiveConfigstant.swift
| @@ -18,6 +18,14 @@ let KStatusBarHeight:CGFloat = UIApplication.shared.statusBarFrame.height; | @@ -18,6 +18,14 @@ let KStatusBarHeight:CGFloat = UIApplication.shared.statusBarFrame.height; | ||
| 18 | let KNavigationHeight:CGFloat = (KStatusBarHeight + 44) | 18 | let KNavigationHeight:CGFloat = (KStatusBarHeight + 44) |
| 19 | ///tabbar高度 | 19 | ///tabbar高度 |
| 20 | let KTabBarHeight:CGFloat = (KStatusBarHeight == 44 ? 83 : 49) | 20 | let KTabBarHeight:CGFloat = (KStatusBarHeight == 44 ? 83 : 49) |
| 21 | +/** | ||
| 22 | + 获取系统tabbarUI高度 | ||
| 23 | + */ | ||
| 24 | +let KTabBar_UIHeight:CGFloat = 49 | ||
| 25 | +/** | ||
| 26 | + 获取系统tabbarUI增加的高度 (因iPhoneX系列底部有安全区域增加的高度) | ||
| 27 | + */ | ||
| 28 | +let KTabBar_UI_OffsetHeight:CGFloat = KTabBarHeight - KTabBar_UIHeight | ||
| 21 | 29 | ||
| 22 | //MARK: - 常用三方key | 30 | //MARK: - 常用三方key |
| 23 | let kBucketName_QN:String = "mam-wjjtest-802" | 31 | let kBucketName_QN:String = "mam-wjjtest-802" |
metaCode/Classes/Main/HomePage/Controller/GoodsManager/CNLiveGoodsCategoryController.swift
| @@ -23,8 +23,6 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -23,8 +23,6 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 23 | 23 | ||
| 24 | let kCNLiveShopClassifyCellIdentifier = "kCNLiveShopClassifyCellIdentifier" | 24 | let kCNLiveShopClassifyCellIdentifier = "kCNLiveShopClassifyCellIdentifier" |
| 25 | 25 | ||
| 26 | - // | ||
| 27 | - var successCompleteBlock:successComplete? | ||
| 28 | // MARK: - 属性 | 26 | // MARK: - 属性 |
| 29 | //开始输入前的文本 | 27 | //开始输入前的文本 |
| 30 | var firCategoryId:String? | 28 | var firCategoryId:String? |
| @@ -113,7 +111,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -113,7 +111,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 113 | _temp_selectFirCategoryModel | 111 | _temp_selectFirCategoryModel |
| 114 | } | 112 | } |
| 115 | set{ | 113 | set{ |
| 116 | - _temp_selectFirCategoryModel = newValue! | 114 | + if newValue != nil{ |
| 115 | + _temp_selectFirCategoryModel = newValue! | ||
| 116 | + }else{ | ||
| 117 | + return | ||
| 118 | + } | ||
| 117 | if (_temp_selectFirCategoryModel?.id!.count)! > 0{ | 119 | if (_temp_selectFirCategoryModel?.id!.count)! > 0{ |
| 118 | self.firCategoryBtn?.setTitle(_temp_selectFirCategoryModel?.title, for: .normal) | 120 | self.firCategoryBtn?.setTitle(_temp_selectFirCategoryModel?.title, for: .normal) |
| 119 | }else{ | 121 | }else{ |
| @@ -128,7 +130,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -128,7 +130,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 128 | _temp_selectSecCategoryModel | 130 | _temp_selectSecCategoryModel |
| 129 | } | 131 | } |
| 130 | set{ | 132 | set{ |
| 131 | - _temp_selectSecCategoryModel = newValue! | 133 | + if newValue != nil{ |
| 134 | + _temp_selectSecCategoryModel = newValue! | ||
| 135 | + }else{ | ||
| 136 | + return | ||
| 137 | + } | ||
| 132 | if (_temp_selectSecCategoryModel?.id?.count)! > 0{ | 138 | if (_temp_selectSecCategoryModel?.id?.count)! > 0{ |
| 133 | self.secCategoryBtn?.setTitle(_temp_selectSecCategoryModel?.title, for: .normal) | 139 | self.secCategoryBtn?.setTitle(_temp_selectSecCategoryModel?.title, for: .normal) |
| 134 | self.secCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal) | 140 | self.secCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal) |
| @@ -149,8 +155,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -149,8 +155,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 149 | _temp_selectThiCategoryModel | 155 | _temp_selectThiCategoryModel |
| 150 | } | 156 | } |
| 151 | set{ | 157 | set{ |
| 152 | - _temp_selectThiCategoryModel = newValue! | ||
| 153 | - | 158 | + if newValue != nil{ |
| 159 | + _temp_selectThiCategoryModel = newValue! | ||
| 160 | + }else{ | ||
| 161 | + return | ||
| 162 | + } | ||
| 154 | if _temp_selectThiCategoryModel!.id!.count > 0{ | 163 | if _temp_selectThiCategoryModel!.id!.count > 0{ |
| 155 | self.thiCategoryBtn?.setTitle(_temp_selectThiCategoryModel?.title, for: .normal) | 164 | self.thiCategoryBtn?.setTitle(_temp_selectThiCategoryModel?.title, for: .normal) |
| 156 | self.thiCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal) | 165 | self.thiCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal) |
| @@ -486,7 +495,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -486,7 +495,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 486 | @param pid 父级id | 495 | @param pid 父级id |
| 487 | @param level 第几级 | 496 | @param level 第几级 |
| 488 | */ | 497 | */ |
| 489 | - func postDataWithPid(pid:String,level:Int,successCompleteBlock:successComplete){ | 498 | + func postDataWithPid(pid:String,level:Int,successCompleteBlock:@escaping successComplete){ |
| 490 | showLoading(message: "") | 499 | showLoading(message: "") |
| 491 | CNLiveShopGoodListViewModel.getGetGroupWithUid(uid: DSUserInfoManager.shared.dsUserInfo.uid!, pid: pid) { result, status in | 500 | CNLiveShopGoodListViewModel.getGetGroupWithUid(uid: DSUserInfoManager.shared.dsUserInfo.uid!, pid: pid) { result, status in |
| 492 | hiddenLoading() | 501 | hiddenLoading() |
| @@ -546,7 +555,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | @@ -546,7 +555,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo | ||
| 546 | } | 555 | } |
| 547 | self.tableView.reloadData() | 556 | self.tableView.reloadData() |
| 548 | self.tableView.setContentOffset(CGPointZero, animated: true) | 557 | self.tableView.setContentOffset(CGPointZero, animated: true) |
| 549 | - self.successCompleteBlock!() | 558 | + successCompleteBlock() |
| 550 | 559 | ||
| 551 | }else if (status == .failed){ | 560 | }else if (status == .failed){ |
| 552 | // self.network_type = .failed | 561 | // self.network_type = .failed |
metaCode/Classes/Main/HomePage/Controller/GoodsManager/CNLiveModalPresentationViewController.swift
| @@ -27,9 +27,10 @@ class CNLiveModalPresentationViewController:UIViewController{ | @@ -27,9 +27,10 @@ class CNLiveModalPresentationViewController:UIViewController{ | ||
| 27 | self.view.backgroundColor = .clear | 27 | self.view.backgroundColor = .clear |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | - func showingAnimationWithCompletion(completion:completionBlock){ | 30 | + func showingAnimationWithCompletion(completion:@escaping completionBlock){ |
| 31 | 31 | ||
| 32 | self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-(self.contentView?.top)!) | 32 | self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-(self.contentView?.top)!) |
| 33 | + | ||
| 33 | UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) { | 34 | UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) { |
| 34 | self.contentView?.transform = CGAffineTransformIdentity | 35 | self.contentView?.transform = CGAffineTransformIdentity |
| 35 | } completion: { finished in | 36 | } completion: { finished in |
| @@ -37,7 +38,7 @@ class CNLiveModalPresentationViewController:UIViewController{ | @@ -37,7 +38,7 @@ class CNLiveModalPresentationViewController:UIViewController{ | ||
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | - func hidingAnimationWithCompletion(completion:completionBlock){ | 41 | + func hidingAnimationWithCompletion(completion:@escaping completionBlock){ |
| 41 | UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) { | 42 | UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) { |
| 42 | self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-self.contentView!.top) | 43 | self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-self.contentView!.top) |
| 43 | } completion: { finished in | 44 | } completion: { finished in |
metaCode/Classes/Main/HomePage/Controller/GoodsManager/CNLiveShopNewProductController.swift
| @@ -45,7 +45,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | @@ -45,7 +45,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | ||
| 45 | let vc = CNLiveGoodsCategoryController() | 45 | let vc = CNLiveGoodsCategoryController() |
| 46 | 46 | ||
| 47 | vc.categoryType = .shop | 47 | vc.categoryType = .shop |
| 48 | - if self.shopGoodsDetailsModel.id!.count > 0{ | 48 | + if self.shopGoodsDetailsModel.id?.count ?? 0 > 0{ |
| 49 | vc.firCategoryId = self.shopGoodsDetailsModel.category_id | 49 | vc.firCategoryId = self.shopGoodsDetailsModel.category_id |
| 50 | vc.secCategoryId = self.shopGoodsDetailsModel.category_id2 | 50 | vc.secCategoryId = self.shopGoodsDetailsModel.category_id2 |
| 51 | } | 51 | } |
| @@ -95,7 +95,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | @@ -95,7 +95,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | ||
| 95 | lastView = singleView | 95 | lastView = singleView |
| 96 | } | 96 | } |
| 97 | self.bgScrollView.contentSize = CGSize(width: self.bgScrollView.width, height: lastView?.bottom ?? 0) | 97 | self.bgScrollView.contentSize = CGSize(width: self.bgScrollView.width, height: lastView?.bottom ?? 0) |
| 98 | - self.selectCategoryVC!.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height) | 98 | + self.selectCategoryVC?.view.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height) |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | deinit { | 101 | deinit { |
| @@ -266,7 +266,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | @@ -266,7 +266,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{ | ||
| 266 | if self.selectCategoryVC == nil{ | 266 | if self.selectCategoryVC == nil{ |
| 267 | let vc = CNLiveGoodsCategoryController() | 267 | let vc = CNLiveGoodsCategoryController() |
| 268 | vc.categoryType = .goods | 268 | vc.categoryType = .goods |
| 269 | - if self.shopGoodsDetailsModel.id!.count > 0{ | 269 | + if self.shopGoodsDetailsModel.id?.count ?? 0 > 0{ |
| 270 | vc.firCategoryId = self.shopGoodsDetailsModel.groupid | 270 | vc.firCategoryId = self.shopGoodsDetailsModel.groupid |
| 271 | vc.secCategoryId = self.shopGoodsDetailsModel.groupid2 | 271 | vc.secCategoryId = self.shopGoodsDetailsModel.groupid2 |
| 272 | vc.thiCategoryId = self.shopGoodsDetailsModel.groupid3 | 272 | vc.thiCategoryId = self.shopGoodsDetailsModel.groupid3 |
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveAddGoodsSelectUploadImageView.swift
| @@ -10,6 +10,7 @@ import UIKit | @@ -10,6 +10,7 @@ import UIKit | ||
| 10 | import UniformTypeIdentifiers | 10 | import UniformTypeIdentifiers |
| 11 | import AVFoundation | 11 | import AVFoundation |
| 12 | import HXPHPicker | 12 | import HXPHPicker |
| 13 | +import SKPhotoBrowser | ||
| 13 | ///类型 | 14 | ///类型 |
| 14 | enum CNLiveSelectUploadImageViewDisplayType:Int { | 15 | enum CNLiveSelectUploadImageViewDisplayType:Int { |
| 15 | ///选择 | 16 | ///选择 |
| @@ -49,7 +50,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -49,7 +50,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | /// 高度类型 | 52 | /// 高度类型 |
| 52 | - var heightStyle:CNLiveSelectUploadImageViewHeightStyle | 53 | + var heightStyle:CNLiveSelectUploadImageViewHeightStyle? |
| 53 | /// 每张图的间距 默认DS_adapt_length(15) | 54 | /// 每张图的间距 默认DS_adapt_length(15) |
| 54 | var _space:CGFloat = 15 | 55 | var _space:CGFloat = 15 |
| 55 | var space:CGFloat{ | 56 | var space:CGFloat{ |
| @@ -121,7 +122,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -121,7 +122,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 121 | 122 | ||
| 122 | // MARK: - 展示属性 | 123 | // MARK: - 展示属性 |
| 123 | /// 获取的网络图片数组 | 124 | /// 获取的网络图片数组 |
| 124 | - var _networkImageArr:Array<String> | 125 | + var _networkImageArr:Array<String> = Array() |
| 125 | var networkImageArr:Array<String>{ | 126 | var networkImageArr:Array<String>{ |
| 126 | get{ | 127 | get{ |
| 127 | _networkImageArr | 128 | _networkImageArr |
| @@ -514,7 +515,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -514,7 +515,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 514 | self.addSubview(singleImageView) | 515 | self.addSubview(singleImageView) |
| 515 | } | 516 | } |
| 516 | }else{ | 517 | }else{ |
| 517 | - if self.networkVideoUrl!.count > 0{ | 518 | + if self.networkVideoUrl?.count ?? 0 > 0{ |
| 518 | var model = CNLiveSelectUploadImageModel() | 519 | var model = CNLiveSelectUploadImageModel() |
| 519 | model.videoUrl = self.networkVideoUrl | 520 | model.videoUrl = self.networkVideoUrl |
| 520 | model.imageUrl = self.networkVideoImageUrl | 521 | model.imageUrl = self.networkVideoImageUrl |
| @@ -575,13 +576,9 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -575,13 +576,9 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 575 | UIApplication.shared.keyWindow?.endEditing(true) | 576 | UIApplication.shared.keyWindow?.endEditing(true) |
| 576 | if model.isVideo! == true{ | 577 | if model.isVideo! == true{ |
| 577 | if model.localVideoUrl != nil{ | 578 | if model.localVideoUrl != nil{ |
| 578 | - if ([[DSToolsModuleManager sharedManager].delegate respondsToSelector:@selector(skipPlayerVCWithPlayURL:coverImage:coverImageUrl:)]) { | ||
| 579 | - [[DSToolsModuleManager sharedManager].delegate skipPlayerVCWithPlayURL:model.localVideoUrl coverImage:model.image coverImageUrl:nil]; | ||
| 580 | - } | 579 | + CNLiveCommonManager.shared.skipPlayerVCWithPlayURL(playURL: URL(string: model.videoUrl!)!, coverImage: model.image!, coverImageUrl: nil) |
| 581 | }else if model.videoUrl?.count ?? 0 > 0{ | 580 | }else if model.videoUrl?.count ?? 0 > 0{ |
| 582 | - if ([[DSToolsModuleManager sharedManager].delegate respondsToSelector:@selector(skipPlayerVCWithPlayURL:coverImage:coverImageUrl:)]) { | ||
| 583 | - [[DSToolsModuleManager sharedManager].delegate skipPlayerVCWithPlayURL:[NSURL URLWithString:model.videoUrl] coverImage:nil coverImageUrl:model.imageUrl]; | ||
| 584 | - } | 581 | + CNLiveCommonManager.shared.skipPlayerVCWithPlayURL(playURL: model.localVideoUrl!, coverImage: nil, coverImageUrl: model.imageUrl) |
| 585 | }else{ | 582 | }else{ |
| 586 | //TODO:后面再调整具体的配置 | 583 | //TODO:后面再调整具体的配置 |
| 587 | // 设置与微信主题一致的配置 | 584 | // 设置与微信主题一致的配置 |
| @@ -619,29 +616,23 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -619,29 +616,23 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 619 | return | 616 | return |
| 620 | } | 617 | } |
| 621 | let subviews = self.subviews | 618 | let subviews = self.subviews |
| 622 | - let currentPage = 0 | ||
| 623 | - var sourceDatas = NSMutableArray() | 619 | + var currentPage = 0 |
| 620 | + var images = [SKPhoto]() | ||
| 624 | for i in 0..<self.uploadImageUrls.count { | 621 | for i in 0..<self.uploadImageUrls.count { |
| 625 | var cmodel = self.uploadImageUrls[i] | 622 | var cmodel = self.uploadImageUrls[i] |
| 626 | if cmodel.isUploading == nil && cmodel.imageUrl?.count ?? 0 > 0{ | 623 | if cmodel.isUploading == nil && cmodel.imageUrl?.count ?? 0 > 0{ |
| 627 | - YBIBImageData * data = [YBIBImageData new]; | ||
| 628 | - data.imageURL = [NSURL URLWithString:cmodel.imageUrl]; | ||
| 629 | - for (DSSelUplSingleImageView * singleImageView in subviews) { | ||
| 630 | - if ([singleImageView.model.imageUrl isEqualToString:cmodel.imageUrl]) { | ||
| 631 | - data.projectiveView = singleImageView.displayImageView; | ||
| 632 | - break; | ||
| 633 | - } | ||
| 634 | - } | ||
| 635 | - [sourceDatas addObject:data]; | 624 | + let photo = SKPhoto.photoWithImageURL(cmodel.imageUrl!) |
| 625 | + photo.shouldCachePhotoURLImage = false | ||
| 626 | + images.append(photo) | ||
| 636 | } | 627 | } |
| 637 | - if ([cmodel.imageUrl isEqualToString:model.imageUrl]) { | ||
| 638 | - currentPage = i; | 628 | + if cmodel.imageUrl == model.imageUrl{ |
| 629 | + currentPage = i | ||
| 639 | } | 630 | } |
| 640 | } | 631 | } |
| 641 | - YBImageBrowser * browser = [YBImageBrowser new]; | ||
| 642 | - browser.dataSourceArray = [sourceDatas copy]; | ||
| 643 | - browser.currentPage = currentPage; | ||
| 644 | - [browser show]; | 632 | + |
| 633 | + let browser = SKPhotoBrowser(photos: images) | ||
| 634 | + browser.initializePageIndex(currentPage) | ||
| 635 | + currentViewController()?.present(browser, animated: true) | ||
| 645 | } | 636 | } |
| 646 | } | 637 | } |
| 647 | } | 638 | } |
| @@ -652,14 +643,14 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | @@ -652,14 +643,14 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat | ||
| 652 | UIApplication.shared.keyWindow?.endEditing(true) | 643 | UIApplication.shared.keyWindow?.endEditing(true) |
| 653 | let subviews = self.subviews | 644 | let subviews = self.subviews |
| 654 | for i in 0..<subviews.count { | 645 | for i in 0..<subviews.count { |
| 655 | - var singleImageView = self.viewWithTag(i+1+DS_SUIV_ADD_TAG_COUNT) as! CNLiveSelUplSingleImageView | 646 | + let singleImageView = self.viewWithTag(i+1+DS_SUIV_ADD_TAG_COUNT) as! CNLiveSelUplSingleImageView |
| 656 | if model.imageUrl == singleImageView.model?.imageUrl{ | 647 | if model.imageUrl == singleImageView.model?.imageUrl{ |
| 657 | if singleImageView.model?.isVideo == true{ | 648 | if singleImageView.model?.isVideo == true{ |
| 658 | if singleImageView.model?.isUploading == true{ | 649 | if singleImageView.model?.isUploading == true{ |
| 659 | UploadManager.shared.cancelUploadKey(key: singleImageView.model!.uploadKey!) | 650 | UploadManager.shared.cancelUploadKey(key: singleImageView.model!.uploadKey!) |
| 660 | }else{ | 651 | }else{ |
| 661 | self.replaceVideoUrls.append(singleImageView.model!) | 652 | self.replaceVideoUrls.append(singleImageView.model!) |
| 662 | - var videoModel = CNLiveSelectUploadImageModel() | 653 | + let videoModel = CNLiveSelectUploadImageModel() |
| 663 | videoModel.isVideo = true | 654 | videoModel.isVideo = true |
| 664 | self.uploadVideoModel = videoModel | 655 | self.uploadVideoModel = videoModel |
| 665 | } | 656 | } |
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveSelUplSingleImageView.swift
| @@ -80,7 +80,7 @@ class CNLiveSelUplSingleImageView: UIView { | @@ -80,7 +80,7 @@ class CNLiveSelUplSingleImageView: UIView { | ||
| 80 | /// 是否隐藏删除按钮 | 80 | /// 是否隐藏删除按钮 |
| 81 | var isHideDeleteBtn : Bool? | 81 | var isHideDeleteBtn : Bool? |
| 82 | /// 是否是封面 | 82 | /// 是否是封面 |
| 83 | - var isCover : Bool | 83 | + var isCover : Bool = false |
| 84 | /// 赋值 | 84 | /// 赋值 |
| 85 | /// @param model 数据 | 85 | /// @param model 数据 |
| 86 | /// @param isHideDeleteBtn 是否隐藏删除按钮 | 86 | /// @param isHideDeleteBtn 是否隐藏删除按钮 |
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveShopAddGoodsSingleView.swift
| @@ -57,7 +57,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg | @@ -57,7 +57,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg | ||
| 57 | var line = UIImageView() | 57 | var line = UIImageView() |
| 58 | var starImageView = UIImageView() | 58 | var starImageView = UIImageView() |
| 59 | //开始输入前的文本 | 59 | //开始输入前的文本 |
| 60 | - var beginText:String | 60 | + var beginText:String? |
| 61 | 61 | ||
| 62 | override init(frame: CGRect) { | 62 | override init(frame: CGRect) { |
| 63 | super.init(frame: frame) | 63 | super.init(frame: frame) |
| @@ -457,7 +457,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg | @@ -457,7 +457,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg | ||
| 457 | } | 457 | } |
| 458 | var isFindDecimalPoint = false | 458 | var isFindDecimalPoint = false |
| 459 | var behindDecimalPointLength = 0 | 459 | var behindDecimalPointLength = 0 |
| 460 | - if newStr?.count ?? 0 > oldStr.count{ | 460 | + if newStr?.count ?? 0 > oldStr!.count{ |
| 461 | for i in 0..<(newStr?.count ?? 0) { | 461 | for i in 0..<(newStr?.count ?? 0) { |
| 462 | let newNextStr = newStr?.subString(start: i, length: 1) | 462 | let newNextStr = newStr?.subString(start: i, length: 1) |
| 463 | if (!isFindDecimalPoint && newNextStr == "."){ | 463 | if (!isFindDecimalPoint && newNextStr == "."){ |
metaCode/Classes/Main/HomePage/ViewModel/GoodsManager/CNLiveShopGoodListViewModel.swift
| @@ -246,8 +246,9 @@ class CNLiveShopGoodListViewModel:NSObject{ | @@ -246,8 +246,9 @@ class CNLiveShopGoodListViewModel:NSObject{ | ||
| 246 | CNLiveNetworking.requestNetwork(with: .GET, urlString: APPBaseWjjBUrl+"/api/v1/getGroup", param: param as! [String : String], cacheType: .networkOnly) { task, result, error in | 246 | CNLiveNetworking.requestNetwork(with: .GET, urlString: APPBaseWjjBUrl+"/api/v1/getGroup", param: param as! [String : String], cacheType: .networkOnly) { task, result, error in |
| 247 | hiddenLoading() | 247 | hiddenLoading() |
| 248 | if (error == nil) { | 248 | if (error == nil) { |
| 249 | - let resp = result as! NSDictionary | 249 | + let res = result as! NSDictionary |
| 250 | var dataArr:[BaseModel] = [] | 250 | var dataArr:[BaseModel] = [] |
| 251 | + let resp = res["data"] as! NSDictionary | ||
| 251 | let respArr = resp["list"] as! NSArray | 252 | let respArr = resp["list"] as! NSArray |
| 252 | for dic in respArr{ | 253 | for dic in respArr{ |
| 253 | let dataDic = dic as! NSDictionary | 254 | let dataDic = dic as! NSDictionary |
metaCode/Classes/Main/MinePage/Controller/CNLiveMineInfoViewController.swift
| @@ -158,7 +158,7 @@ class CNLiveMineInfoViewController: CNLiveBaseViewController, PhotoPickerControl | @@ -158,7 +158,7 @@ class CNLiveMineInfoViewController: CNLiveBaseViewController, PhotoPickerControl | ||
| 158 | extension CNLiveMineInfoViewController { | 158 | extension CNLiveMineInfoViewController { |
| 159 | 159 | ||
| 160 | func pickerController(_ pickerController: PhotoPickerController, | 160 | func pickerController(_ pickerController: PhotoPickerController, |
| 161 | - didFinishSelection result: CNLiveMineInputViewControllerPickerResult) { | 161 | + didFinishSelection result: PickerResult) { |
| 162 | result.getImage { [weak self] (image, photoAsset, index) in | 162 | result.getImage { [weak self] (image, photoAsset, index) in |
| 163 | if let image = image { | 163 | if let image = image { |
| 164 | self!._select_image = image | 164 | self!._select_image = image |
metaCode/Classes/Main/Model/GoodsDetail/CNLiveSelectUploadImageModel.swift
| @@ -8,10 +8,6 @@ | @@ -8,10 +8,6 @@ | ||
| 8 | import Foundation | 8 | import Foundation |
| 9 | 9 | ||
| 10 | class CNLiveSelectUploadImageModel: BaseModel,Equatable { | 10 | class CNLiveSelectUploadImageModel: BaseModel,Equatable { |
| 11 | - static func == (lhs: CNLiveSelectUploadImageModel, rhs: CNLiveSelectUploadImageModel) -> Bool { | ||
| 12 | - | ||
| 13 | - } | ||
| 14 | - | ||
| 15 | 11 | ||
| 16 | /** | 12 | /** |
| 17 | 是否是选取图片占位 | 13 | 是否是选取图片占位 |
| @@ -49,4 +45,25 @@ class CNLiveSelectUploadImageModel: BaseModel,Equatable { | @@ -49,4 +45,25 @@ class CNLiveSelectUploadImageModel: BaseModel,Equatable { | ||
| 49 | 上传百分比 0~1 | 45 | 上传百分比 0~1 |
| 50 | */ | 46 | */ |
| 51 | var uploadingPercent:CGFloat? | 47 | var uploadingPercent:CGFloat? |
| 48 | + | ||
| 49 | + static func == (lhs: CNLiveSelectUploadImageModel, rhs: CNLiveSelectUploadImageModel) -> Bool { | ||
| 50 | + | ||
| 51 | + if lhs.isSelectPhotoPlaceholder == rhs.isSelectPhotoPlaceholder && | ||
| 52 | + lhs.isVideo == rhs.isVideo && | ||
| 53 | + lhs.localVideoUrl == rhs.localVideoUrl && | ||
| 54 | + lhs.videoUrl == rhs.videoUrl && | ||
| 55 | + lhs.imageUrl == rhs.imageUrl && | ||
| 56 | + lhs.image == rhs.image && | ||
| 57 | + lhs.isUploading == rhs.isUploading && | ||
| 58 | + lhs.uploadKey == rhs.uploadKey && | ||
| 59 | + lhs.uploadingPercent == rhs.uploadingPercent | ||
| 60 | + { | ||
| 61 | + return true | ||
| 62 | + } | ||
| 63 | + else | ||
| 64 | + { | ||
| 65 | + return false | ||
| 66 | + | ||
| 67 | + } | ||
| 68 | + } | ||
| 52 | } | 69 | } |
metaCode/Classes/Main/Util/CNLiveCommonManager.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLiveCommonManager.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/29. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +class CNLiveCommonManager: NSObject{ | ||
| 12 | + | ||
| 13 | + //单例类 | ||
| 14 | + static let shared = CNLiveCommonManager() | ||
| 15 | + | ||
| 16 | + /// 跳转播放器 | ||
| 17 | + /// @param playURL 播放URL | ||
| 18 | + /// @param coverImage 封面图 | ||
| 19 | + /// @param coverImageUrl 封面图url | ||
| 20 | + func skipPlayerVCWithPlayURL(playURL:URL,coverImage:UIImage?,coverImageUrl:String?){ | ||
| 21 | + var vc = CNLivePlayerViewController() | ||
| 22 | + vc.setPlayUrl(playUrl: playURL, isLive: false) | ||
| 23 | + vc.coverImageUrl = coverImageUrl | ||
| 24 | + currentViewController()?.navigationController?.pushViewController(vc, animated: false) | ||
| 25 | + } | ||
| 26 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLiveGradientView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLiveGradientView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/27. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLiveGradientView:UIView{ | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + 颜色数组 | ||
| 14 | + */ | ||
| 15 | + var _colors:Array<UIColor> = [] | ||
| 16 | + var colors:Array<UIColor>{ | ||
| 17 | + get{ | ||
| 18 | + _colors | ||
| 19 | + } | ||
| 20 | + set{ | ||
| 21 | + _colors = newValue | ||
| 22 | + var gLayerColors = NSMutableArray() | ||
| 23 | + | ||
| 24 | + for (_,color) in _colors.enumerated() { | ||
| 25 | + gLayerColors.add(color.cgColor) | ||
| 26 | + } | ||
| 27 | + self.gradientLayer.colors = gLayerColors as? [Any] | ||
| 28 | + | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + 起点 | ||
| 34 | + */ | ||
| 35 | + var _startPoint:CGPoint? | ||
| 36 | + var startPoint:CGPoint?{ | ||
| 37 | + get{ | ||
| 38 | + _startPoint | ||
| 39 | + } | ||
| 40 | + set{ | ||
| 41 | + _startPoint = newValue | ||
| 42 | + self.gradientLayer.startPoint = _startPoint! | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + /** | ||
| 46 | + 终点 | ||
| 47 | + */ | ||
| 48 | + var _endPoint:CGPoint? | ||
| 49 | + var endPoint:CGPoint?{ | ||
| 50 | + get{ | ||
| 51 | + _endPoint | ||
| 52 | + } | ||
| 53 | + set{ | ||
| 54 | + _endPoint = newValue | ||
| 55 | + self.gradientLayer.endPoint = _endPoint! | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + /** | ||
| 59 | + 透明度 | ||
| 60 | + */ | ||
| 61 | + var _opacity:Float = 0 | ||
| 62 | + var opacity:Float{ | ||
| 63 | + get{ | ||
| 64 | + _opacity | ||
| 65 | + } | ||
| 66 | + set{ | ||
| 67 | + _opacity = newValue | ||
| 68 | + self.gradientLayer.opacity = _opacity | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + // MARK: - CAGradientLayer | ||
| 72 | + lazy var gradientLayer :CAGradientLayer = { | ||
| 73 | + let gradientLayer = CAGradientLayer() | ||
| 74 | + self.layer.addSublayer(gradientLayer) | ||
| 75 | + return gradientLayer | ||
| 76 | + }() | ||
| 77 | + | ||
| 78 | + override init(frame: CGRect) { | ||
| 79 | + super.init(frame: frame) | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + required init?(coder: NSCoder) { | ||
| 83 | + fatalError("init(coder:) has not been implemented") | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // MARK: - layoutSubviews | ||
| 87 | + override func layoutSubviews() { | ||
| 88 | + super.layoutSubviews() | ||
| 89 | + self.gradientLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height) | ||
| 90 | + } | ||
| 91 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerBottomNaviView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerBottomNaviView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +//点击播放回调 | ||
| 11 | +typealias clickPlayBtnCallBackBlock = () -> Void | ||
| 12 | +//进度条滑动中回调 | ||
| 13 | +typealias changeSliderValueCallBackBlock = (_ value:CGFloat) -> Void | ||
| 14 | +//进度条结束滑动回调 | ||
| 15 | +typealias endChangeSliderValueCallBackBlock = (_ value:CGFloat) -> Void | ||
| 16 | +//点击横竖屏切换按钮回调 | ||
| 17 | +typealias clickFrameBtnCallBackBlock = () -> Void | ||
| 18 | + | ||
| 19 | + | ||
| 20 | +class CNLivePlayerBottomNaviView:UIView{ | ||
| 21 | + | ||
| 22 | + // MARK: - UI | ||
| 23 | + /// 阴影背景 | ||
| 24 | + var bgGradientView:CNLiveGradientView? | ||
| 25 | + /// 播放暂停按钮 | ||
| 26 | + var playBtn:UIButton? | ||
| 27 | + /// 播放暂停按钮图片 | ||
| 28 | + var playImageView:UIImageView? | ||
| 29 | + /// 时间 | ||
| 30 | + var timeLab:UILabel? | ||
| 31 | + /// 横竖屏切换按钮 | ||
| 32 | + var frameBtn:UIButton? | ||
| 33 | + /// 横竖屏切换按钮图片 | ||
| 34 | + var frameImageView:UIImageView? | ||
| 35 | + /// 滑动进度条 | ||
| 36 | + var progressSlider:CNLivePlayerProgressSlider? | ||
| 37 | + | ||
| 38 | + // MARK: - 属性 | ||
| 39 | + /// 是否是横屏 | ||
| 40 | + var _isLandscape:Bool? | ||
| 41 | + var isLandscape:Bool?{ | ||
| 42 | + get{ | ||
| 43 | + _isLandscape | ||
| 44 | + } | ||
| 45 | + set{ | ||
| 46 | + _isLandscape = newValue | ||
| 47 | + if _isLandscape!{ | ||
| 48 | + self.frameImageView?.image = UIImage(named: "DS_player_reduce") | ||
| 49 | + }else{ | ||
| 50 | + self.frameImageView?.image = UIImage(named: "DS_player_magnify") | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + /// 时间格式 | ||
| 56 | + var _timeStyle:CNLivePlayerBottomTimeStyle = .HH_MM_SS | ||
| 57 | + var timeStyle:CNLivePlayerBottomTimeStyle{ | ||
| 58 | + get { | ||
| 59 | + _timeStyle | ||
| 60 | + } | ||
| 61 | + set{ | ||
| 62 | + _timeStyle = newValue | ||
| 63 | + var timeWidth:CGFloat = 0 | ||
| 64 | + if _timeStyle == .MM_SS{ | ||
| 65 | + timeWidth = 80 | ||
| 66 | + }else{ | ||
| 67 | + timeWidth = 110 | ||
| 68 | + } | ||
| 69 | + self.timeLab?.frame = CGRect(x: self.frameBtn!.left-timeWidth-5, y: 0, width: timeWidth, height: 44) | ||
| 70 | + let leftMargin = self.playBtn!.right+5 | ||
| 71 | + let rightMargin = self.width-self.timeLab!.left+15 | ||
| 72 | + self.progressSlider?.frame = CGRect(x: self.playBtn!.right+5, y: 0, width: self.width-leftMargin-rightMargin, height: 44) | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + // MARK: - 回调 | ||
| 77 | + /// 点击播放回调 | ||
| 78 | + var clickPlayBtnCallBack:clickPlayBtnCallBackBlock? | ||
| 79 | + /// 进度条滑动中回调 | ||
| 80 | + var changeSliderValueCallBack:changeSliderValueCallBackBlock? | ||
| 81 | + /// 进度条结束滑动回调 | ||
| 82 | + var endChangeSliderValueCallBack:endChangeSliderValueCallBackBlock? | ||
| 83 | + /// 点击横竖屏切换按钮回调 | ||
| 84 | + var clickFrameBtnCallBack:clickFrameBtnCallBackBlock? | ||
| 85 | + | ||
| 86 | + | ||
| 87 | + // MARK: - init | ||
| 88 | + init() { | ||
| 89 | + super.init(frame: CGRectZero) | ||
| 90 | + self.clipsToBounds = false | ||
| 91 | + self.initUI() | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + required init?(coder: NSCoder) { | ||
| 95 | + fatalError("init(coder:) has not been implemented") | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + override func layoutSubviews() { | ||
| 99 | + super.layoutSubviews() | ||
| 100 | + self.bgGradientView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 101 | + self.playBtn?.frame = CGRect(x: self.isLandscape! ? KStatusBarHeight : 5, y: 0, width: 44, height: 44) | ||
| 102 | + self.playImageView?.frame = CGRect(x: (self.playBtn!.width-22)/2, y: (self.playBtn!.height-22)/2, width: 22, height: 22) | ||
| 103 | + self.frameBtn?.frame = CGRect(x: self.width-44-(self.isLandscape! ? KTabBarHeight-KTabBar_UIHeight : 0), y: 0, width: 44, height: 44) | ||
| 104 | + self.frameImageView?.frame = CGRect(x: (self.frameBtn!.height-22)/2, y: (self.frameBtn!.height-22)/2, width: 22, height: 22) | ||
| 105 | + self.timeStyle = self.timeStyle | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // MARK: - initUI | ||
| 109 | + func initUI(){ | ||
| 110 | + self.bgGradientView = CNLiveGradientView(frame: CGRectZero) | ||
| 111 | + self.bgGradientView!.colors = [UIColor(white: 0, alpha: 0.4),UIColor(white: 0, alpha: 0)] | ||
| 112 | + self.bgGradientView!.startPoint = CGPoint(x: 0.5, y: 1) | ||
| 113 | + self.bgGradientView!.endPoint = CGPoint(x: 0.5, y: 0) | ||
| 114 | + self.bgGradientView!.opacity = 1 | ||
| 115 | + self.addSubview(self.bgGradientView!) | ||
| 116 | + | ||
| 117 | + self.playBtn = UIButton(type: .custom) | ||
| 118 | + self.playBtn?.addTarget(self, action: #selector(playBtnClick), for: .touchUpInside) | ||
| 119 | + self.addSubview(self.playBtn!) | ||
| 120 | + | ||
| 121 | + self.playImageView = UIImageView() | ||
| 122 | + self.playImageView!.image = UIImage(named: "DS_player_start") | ||
| 123 | + self.playImageView!.clipsToBounds = true | ||
| 124 | + self.playImageView!.contentMode = .scaleAspectFit | ||
| 125 | + self.playBtn?.addSubview(self.playImageView!) | ||
| 126 | + | ||
| 127 | + self.frameBtn = UIButton(type: .custom) | ||
| 128 | + self.frameBtn?.addTarget(self, action: #selector(frameBtnClick), for: .touchUpInside) | ||
| 129 | + self.addSubview(self.frameBtn!) | ||
| 130 | + | ||
| 131 | + self.frameImageView = UIImageView() | ||
| 132 | + self.frameImageView?.image = UIImage(named: "DS_player_magnify") | ||
| 133 | + self.frameImageView?.clipsToBounds = true | ||
| 134 | + self.frameImageView?.contentMode = .scaleAspectFit | ||
| 135 | + self.frameBtn?.addSubview(self.frameImageView!) | ||
| 136 | + | ||
| 137 | + self.timeLab = UILabel() | ||
| 138 | + self.timeLab?.textColor = .white | ||
| 139 | + self.timeLab?.font = Font_12 | ||
| 140 | + self.timeLab?.textAlignment = .center | ||
| 141 | + self.timeLab?.text = "00:00/00:00" | ||
| 142 | + self.addSubview(self.timeLab!) | ||
| 143 | + | ||
| 144 | + self.progressSlider = CNLivePlayerProgressSlider() | ||
| 145 | + self.progressSlider?.changeSliderValueCallBack = {[weak self] value in | ||
| 146 | + self?.changeSliderValueCallBack!(value) | ||
| 147 | + } | ||
| 148 | + self.progressSlider?.endChangeSliderValueCallBack = { | ||
| 149 | + [weak self] value in | ||
| 150 | + self?.endChangeSliderValueCallBack!(value) | ||
| 151 | + } | ||
| 152 | + self.addSubview(self.progressSlider!) | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + // MARK: - 触发事件 | ||
| 156 | + @objc func playBtnClick(){ | ||
| 157 | + self.clickPlayBtnCallBack!() | ||
| 158 | + } | ||
| 159 | + @objc func frameBtnClick(){ | ||
| 160 | + self.clickFrameBtnCallBack!() | ||
| 161 | + } | ||
| 162 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerControlView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerControlView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | +import PLPlayerKit | ||
| 10 | +import UIKit | ||
| 11 | +import Kingfisher | ||
| 12 | +import MediaPlayer | ||
| 13 | + | ||
| 14 | +/// 点击返回回调 | ||
| 15 | +typealias clickBackBtnActionBlock = () -> Void | ||
| 16 | +/// 点击放大放小回调 | ||
| 17 | +typealias clickFrameBtnActionBlock = () -> Void | ||
| 18 | +/// 点击播放按钮回调 | ||
| 19 | +typealias clickPlayBtnActionBlock = () -> Void | ||
| 20 | +/// 点击暂停按钮回调 | ||
| 21 | +typealias clickPauseBtnActionBlock = () -> Void | ||
| 22 | +/// 点击刷新播放按钮回调 | ||
| 23 | +typealias clickRefreshBtnActionBlock = () -> Void | ||
| 24 | +/// 隐藏/显示视频上面的控件回调 | ||
| 25 | +typealias controlSwitchAlphaMessageStateCallBackBlock = () -> Void | ||
| 26 | +/// 锁屏/解锁屏回调 | ||
| 27 | +typealias controlSwitchLockScreenCallBackBlock = () -> Void | ||
| 28 | + | ||
| 29 | +///手势样式 | ||
| 30 | +enum CNLivePlayerPanGestureOperation:Int { | ||
| 31 | + ///啥也没操作 | ||
| 32 | + case none = 1 | ||
| 33 | + ///进度 | ||
| 34 | + case progress | ||
| 35 | + ///亮度 | ||
| 36 | + case light | ||
| 37 | + ///音量 | ||
| 38 | + case volume | ||
| 39 | +} | ||
| 40 | +let kDSPlayerAutoHideControlsTime = 5 | ||
| 41 | +let kDSPlayerAutoHideBrightnessViewTime = 3 | ||
| 42 | + | ||
| 43 | +class CNLivePlayerControlView:UIView,CNLivePlayerGestureViewDelegate{ | ||
| 44 | + | ||
| 45 | + // MARK: - player | ||
| 46 | + /// 播放器 | ||
| 47 | + weak var player:PLPlayer? | ||
| 48 | + /// 视频链接是否为直播 | ||
| 49 | + var isLive:Bool? | ||
| 50 | + // MARK: - UI | ||
| 51 | + /// 封面图 | ||
| 52 | + var _coverImageView:UIImageView? | ||
| 53 | + var coverImageView:UIImageView?{ | ||
| 54 | + get{ | ||
| 55 | + if (_coverImageView == nil) { | ||
| 56 | + _coverImageView = UIImageView() | ||
| 57 | + _coverImageView?.clipsToBounds = true | ||
| 58 | + _coverImageView?.contentMode = .scaleAspectFit | ||
| 59 | + } | ||
| 60 | + return _coverImageView | ||
| 61 | + } | ||
| 62 | + set{ | ||
| 63 | + _coverImageView = newValue | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + /// 手势界面 | ||
| 67 | + var _gestureView:CNLivePlayerGestureView? | ||
| 68 | + var gestureView:CNLivePlayerGestureView?{ | ||
| 69 | + get{ | ||
| 70 | + if (_gestureView == nil) { | ||
| 71 | + _gestureView = CNLivePlayerGestureView() | ||
| 72 | + _gestureView?.delegate = self | ||
| 73 | + } | ||
| 74 | + return _gestureView | ||
| 75 | + } | ||
| 76 | + set{ | ||
| 77 | + _gestureView = newValue | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + /// 顶部导航 | ||
| 81 | + var _topNaviView:CNLivePlayerTopNaviView? | ||
| 82 | + var topNaviView:CNLivePlayerTopNaviView?{ | ||
| 83 | + get{ | ||
| 84 | + if (_topNaviView == nil) { | ||
| 85 | + _topNaviView = CNLivePlayerTopNaviView() | ||
| 86 | + _topNaviView?.clickBackCallBack = { | ||
| 87 | + [weak self] in | ||
| 88 | + self?.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 89 | + self?.clickBackBtnAction!() | ||
| 90 | + } | ||
| 91 | + } | ||
| 92 | + return _topNaviView | ||
| 93 | + } | ||
| 94 | + set{ | ||
| 95 | + _topNaviView = newValue | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + /// 底部导航 | ||
| 99 | + var _bottomNaviView:CNLivePlayerBottomNaviView? | ||
| 100 | + var bottomNaviView:CNLivePlayerBottomNaviView?{ | ||
| 101 | + get{ | ||
| 102 | + if (_bottomNaviView == nil) { | ||
| 103 | + _bottomNaviView = CNLivePlayerBottomNaviView() | ||
| 104 | + _bottomNaviView?.playBtn?.isHidden = true | ||
| 105 | + _bottomNaviView?.progressSlider?.isHidden = true | ||
| 106 | + _bottomNaviView?.timeLab?.isHidden = true | ||
| 107 | + _bottomNaviView?.frameBtn?.isHidden = true | ||
| 108 | + _bottomNaviView?.clickPlayBtnCallBack = { | ||
| 109 | + [weak self] in | ||
| 110 | + self?.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 111 | + self?.playBtnClick() | ||
| 112 | + } | ||
| 113 | + _bottomNaviView?.changeSliderValueCallBack = { [weak self]value in | ||
| 114 | + self?.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 115 | + self?.displayFastForwardPreviewViewWithForwardTime(forwardTime: CMTimeGetSeconds((self?.player!.totalDuration)!)*value) | ||
| 116 | + } | ||
| 117 | + _bottomNaviView?.endChangeSliderValueCallBack = { [weak self] value in | ||
| 118 | + if self?.panGestureOperation == .progress{ | ||
| 119 | + //快进中不修改 | ||
| 120 | + return | ||
| 121 | + } | ||
| 122 | + self?.fastForwardPreviewView?.alpha = 0 | ||
| 123 | + let second = CMTimeGetSeconds((self?.player!.totalDuration)!)*value | ||
| 124 | + self!.loadingView?.startAnimate() | ||
| 125 | + self?.player?.seek(to: CMTime(value: Int64(second)*30, timescale: 30)) | ||
| 126 | + } | ||
| 127 | + _bottomNaviView?.clickFrameBtnCallBack = { | ||
| 128 | + [weak self] in | ||
| 129 | + self?.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 130 | + self?.clickFrameBtnAction!() | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | + return _bottomNaviView | ||
| 134 | + } | ||
| 135 | + set{ | ||
| 136 | + _bottomNaviView = newValue | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + /// 中间圆形播放暂停按钮 | ||
| 140 | + var _circlePlayBtn:UIButton? | ||
| 141 | + var circlePlayBtn:UIButton?{ | ||
| 142 | + get{ | ||
| 143 | + if (_circlePlayBtn == nil) { | ||
| 144 | + _circlePlayBtn = UIButton(type: .custom) | ||
| 145 | + _circlePlayBtn?.setBackgroundImage(UIImage(named: "DS_player_circle_start"), for: .normal) | ||
| 146 | + _circlePlayBtn?.addTarget(self, action: #selector(playBtnClick), for: .touchUpInside) | ||
| 147 | + } | ||
| 148 | + return _circlePlayBtn | ||
| 149 | + } | ||
| 150 | + set{ | ||
| 151 | + _circlePlayBtn = newValue | ||
| 152 | + } | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + /// 底部进度条(当底部导航隐藏了才会显示) | ||
| 156 | + var _bottomProgressView:CNLivePlayerProgressView? | ||
| 157 | + var bottomProgressView:CNLivePlayerProgressView?{ | ||
| 158 | + get{ | ||
| 159 | + if (_bottomProgressView == nil) { | ||
| 160 | + _bottomProgressView = CNLivePlayerProgressView() | ||
| 161 | + _bottomProgressView?.alpha = 0 | ||
| 162 | + _bottomProgressView?.isHidden = true | ||
| 163 | + } | ||
| 164 | + return _bottomProgressView | ||
| 165 | + } | ||
| 166 | + set{ | ||
| 167 | + _bottomProgressView = newValue | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + /// loading加载框 | ||
| 172 | + var _loadingView:CNLivePlayerLoadingView? | ||
| 173 | + var loadingView:CNLivePlayerLoadingView?{ | ||
| 174 | + get{ | ||
| 175 | + if (_loadingView == nil) { | ||
| 176 | + _loadingView = CNLivePlayerLoadingView() | ||
| 177 | + } | ||
| 178 | + return _loadingView | ||
| 179 | + } | ||
| 180 | + set{ | ||
| 181 | + _loadingView = newValue | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + /// 失败界面 | ||
| 186 | + var _failureView:CNLivePlayerFailureView? | ||
| 187 | + var failureView:CNLivePlayerFailureView?{ | ||
| 188 | + get{ | ||
| 189 | + if (_failureView == nil) { | ||
| 190 | + _failureView = CNLivePlayerFailureView() | ||
| 191 | + _failureView?.isHidden = true | ||
| 192 | + _failureView?.clickRefreshCallBack = { | ||
| 193 | + [weak self] in | ||
| 194 | + self?.clickRefreshBtnAction!() | ||
| 195 | + } | ||
| 196 | + _failureView?.clickBackCallBack = {[weak self] in | ||
| 197 | + self?.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 198 | + self?.clickBackBtnAction!() | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + return _failureView | ||
| 202 | + } | ||
| 203 | + set{ | ||
| 204 | + _failureView = newValue | ||
| 205 | + } | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + /// 锁屏按钮 | ||
| 209 | + var _lockBtn:UIButton? | ||
| 210 | + var lockBtn:UIButton?{ | ||
| 211 | + get{ | ||
| 212 | + if (_lockBtn == nil) { | ||
| 213 | + _lockBtn = UIButton(type: .custom) | ||
| 214 | + _lockBtn?.setBackgroundImage(UIImage(named: "DS_player_lock_open"), for: .normal) | ||
| 215 | + _lockBtn?.addTarget(self, action: #selector(lockBtnClick), for: .touchUpInside) | ||
| 216 | + _lockBtn?.alpha = 0 | ||
| 217 | + } | ||
| 218 | + return _lockBtn | ||
| 219 | + } | ||
| 220 | + set{ | ||
| 221 | + _lockBtn = newValue | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | + // MARK: - 属性 | ||
| 225 | + /// 封面图(不传封面图就不显示) | ||
| 226 | + var _coverImage:UIImage? | ||
| 227 | + var coverImage:UIImage?{ | ||
| 228 | + get{ | ||
| 229 | + _coverImage | ||
| 230 | + } | ||
| 231 | + set{ | ||
| 232 | + _coverImage = newValue | ||
| 233 | + self.coverImageView?.image = _coverImage | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | + /// 封面图url(先检测封面图,后检测封面图url,不传封面图就不显示) | ||
| 237 | + var _coverImageUrl:String? | ||
| 238 | + var coverImageUrl:String?{ | ||
| 239 | + get{ | ||
| 240 | + _coverImageUrl | ||
| 241 | + } | ||
| 242 | + set{ | ||
| 243 | + _coverImageUrl = newValue | ||
| 244 | + self.coverImageView?.kf.setImage(with: URL(string: _coverImageUrl!)) | ||
| 245 | + } | ||
| 246 | + } | ||
| 247 | + | ||
| 248 | + /// 封面填充属性 | ||
| 249 | + var _coverImageViewContentMode:UIView.ContentMode? | ||
| 250 | + var coverImageViewContentMode:UIView.ContentMode?{ | ||
| 251 | + get{ | ||
| 252 | + _coverImageViewContentMode | ||
| 253 | + } | ||
| 254 | + set{ | ||
| 255 | + _coverImageViewContentMode = newValue | ||
| 256 | + self.coverImageView?.contentMode = _coverImageViewContentMode! | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + /// 是否隐藏信息视图 | ||
| 261 | + var isAlphaMessage:Bool? | ||
| 262 | + /// 是否锁屏 | ||
| 263 | + var isLockScreen:Bool? | ||
| 264 | + /// 全屏样式 | ||
| 265 | + var _fullScreenType:CNLivePlayerFullScreenType? | ||
| 266 | + var fullScreenType:CNLivePlayerFullScreenType?{ | ||
| 267 | + get{ | ||
| 268 | + _fullScreenType | ||
| 269 | + } | ||
| 270 | + set{ | ||
| 271 | + _fullScreenType = newValue | ||
| 272 | + self.layoutSubviews() | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + /// 是否全屏 | ||
| 277 | + var _isFullScreen:Bool? | ||
| 278 | + var isFullScreen:Bool?{ | ||
| 279 | + get{ | ||
| 280 | + _isFullScreen | ||
| 281 | + } | ||
| 282 | + set{ | ||
| 283 | + _isFullScreen = newValue | ||
| 284 | +// [DSCnliveShopSDKManager sharedManager].isNeedLandscapeMask = _isFullScreen; | ||
| 285 | + | ||
| 286 | + } | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + /// 当前屏幕方向 | ||
| 290 | + var _currentOrientation:UIDeviceOrientation? | ||
| 291 | + var currentOrientation:UIDeviceOrientation?{ | ||
| 292 | + get{ | ||
| 293 | + _currentOrientation | ||
| 294 | + } | ||
| 295 | + set{ | ||
| 296 | + _currentOrientation = newValue | ||
| 297 | + if (_currentOrientation == .landscapeLeft || | ||
| 298 | + _currentOrientation == .landscapeRight) { | ||
| 299 | + self.topNaviView!.isLandscape = true | ||
| 300 | + self.bottomNaviView!.isLandscape = true | ||
| 301 | + }else { | ||
| 302 | + self.topNaviView!.isLandscape = false | ||
| 303 | + self.bottomNaviView!.isLandscape = false | ||
| 304 | + } | ||
| 305 | + self.layoutSubviews() | ||
| 306 | + } | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + /** | ||
| 310 | + 竖屏顶部信息view的高度 | ||
| 311 | + fullScreenType == DSPlayerFullScreenTypeInCurrentViewOrientation 时默认 导航高度 | ||
| 312 | + fullScreenType == DSPlayerFullScreenTypeInWindowOrientation 时默认 50 | ||
| 313 | + fullScreenType == DSPlayerFullScreenTypeFullDisplayOfVideoInterface 时默认 导航高度 | ||
| 314 | + */ | ||
| 315 | + var _portraitTopNaviHeight:CGFloat = 0 | ||
| 316 | + var portraitTopNaviHeight:CGFloat{ | ||
| 317 | + get{ | ||
| 318 | + if (_portraitTopNaviHeight > 0) { | ||
| 319 | + return _portraitTopNaviHeight | ||
| 320 | + } | ||
| 321 | + switch (_fullScreenType) { | ||
| 322 | + case .inCurrentViewOrientation: break | ||
| 323 | + case .fullDisplayOfVideoInterface: | ||
| 324 | + _portraitTopNaviHeight = KNavigationHeight | ||
| 325 | + break | ||
| 326 | + case .inWindowOrientation: | ||
| 327 | + _portraitTopNaviHeight = 50 | ||
| 328 | + break | ||
| 329 | + case .none: break | ||
| 330 | + | ||
| 331 | + } | ||
| 332 | + return _portraitTopNaviHeight | ||
| 333 | + } | ||
| 334 | + set{ | ||
| 335 | + _portraitTopNaviHeight = newValue | ||
| 336 | + | ||
| 337 | + } | ||
| 338 | + } | ||
| 339 | + /** | ||
| 340 | + 竖屏底部信息view的高度 | ||
| 341 | + fullScreenType == DSPlayerFullScreenTypeInCurrentViewOrientation 时默认 普通屏 50 iPhoneX系列 50+底部安全区域 | ||
| 342 | + fullScreenType == DSPlayerFullScreenTypeInWindowOrientation 时默认 50 | ||
| 343 | + fullScreenType == DSPlayerFullScreenTypeFullDisplayOfVideoInterface 时默认 50 | ||
| 344 | + */ | ||
| 345 | + var _portraitBottomNaviHeight:CGFloat = 50 | ||
| 346 | + var portraitBottomNaviHeight:CGFloat{ | ||
| 347 | + get{ | ||
| 348 | + if (_portraitBottomNaviHeight > 0) { | ||
| 349 | + return _portraitBottomNaviHeight | ||
| 350 | + } | ||
| 351 | + switch (_fullScreenType) { | ||
| 352 | + case .inWindowOrientation: break | ||
| 353 | + case .fullDisplayOfVideoInterface: | ||
| 354 | + _portraitBottomNaviHeight = 50 | ||
| 355 | + break | ||
| 356 | + case .inCurrentViewOrientation: | ||
| 357 | + _portraitBottomNaviHeight = 50+KTabBar_UI_OffsetHeight | ||
| 358 | + break | ||
| 359 | + case .none: break | ||
| 360 | + | ||
| 361 | + } | ||
| 362 | + return _portraitBottomNaviHeight | ||
| 363 | + } | ||
| 364 | + set{ | ||
| 365 | + _portraitBottomNaviHeight = newValue | ||
| 366 | + } | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + // MARK: - 回调 | ||
| 370 | + /// 点击返回回调 | ||
| 371 | + var clickBackBtnAction:clickBackBtnActionBlock? | ||
| 372 | + /// 点击放大放小回调 | ||
| 373 | + var clickFrameBtnAction:clickFrameBtnActionBlock? | ||
| 374 | + /// 点击播放按钮回调 | ||
| 375 | + var clickPlayBtnAction:clickPlayBtnActionBlock? | ||
| 376 | + /// 点击暂停按钮回调 | ||
| 377 | + var clickPauseBtnAction:clickPauseBtnActionBlock? | ||
| 378 | + /// 点击刷新播放按钮回调 | ||
| 379 | + var clickRefreshBtnAction:clickRefreshBtnActionBlock? | ||
| 380 | + /// 隐藏/显示视频上面的控件回调 | ||
| 381 | + var switchAlphaMessageStateCallBack:controlSwitchAlphaMessageStateCallBackBlock? | ||
| 382 | + /// 锁屏/解锁屏回调 | ||
| 383 | + var switchLockScreenCallBack:controlSwitchLockScreenCallBackBlock? | ||
| 384 | + | ||
| 385 | + //快进预览界面 | ||
| 386 | + var _fastForwardPreviewView:CNLivePlayerFastForwardPreviewView? | ||
| 387 | + var fastForwardPreviewView:CNLivePlayerFastForwardPreviewView?{ | ||
| 388 | + get{ | ||
| 389 | + if (_fastForwardPreviewView == nil) { | ||
| 390 | + _fastForwardPreviewView = CNLivePlayerFastForwardPreviewView() | ||
| 391 | + _fastForwardPreviewView?.alpha = 0 | ||
| 392 | + } | ||
| 393 | + return _fastForwardPreviewView | ||
| 394 | + } | ||
| 395 | + set{ | ||
| 396 | + _fastForwardPreviewView = newValue | ||
| 397 | + } | ||
| 398 | + } | ||
| 399 | + //亮度view | ||
| 400 | + var _brightnessView:CNLivePlayerVolumeBrightnessView? | ||
| 401 | + var brightnessView:CNLivePlayerVolumeBrightnessView?{ | ||
| 402 | + get{ | ||
| 403 | + if (_brightnessView == nil) { | ||
| 404 | + _brightnessView = CNLivePlayerVolumeBrightnessView() | ||
| 405 | + _brightnessView?.alpha = 0 | ||
| 406 | + } | ||
| 407 | + return _brightnessView | ||
| 408 | + } | ||
| 409 | + set{ | ||
| 410 | + _brightnessView = newValue | ||
| 411 | + } | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + //自动隐藏控件倒计时(默认5s) | ||
| 415 | + var _autoHideControlsTime:CGFloat = 5.0 | ||
| 416 | + var autoHideControlsTime:CGFloat{ | ||
| 417 | + get{ | ||
| 418 | + _autoHideControlsTime | ||
| 419 | + } | ||
| 420 | + set{ | ||
| 421 | + _autoHideControlsTime = newValue | ||
| 422 | + if _autoHideControlsTime <= 0 && !self.isAlphaMessage! && self.player?.status == .statusPlaying{ | ||
| 423 | + self.isAlphaMessage = true | ||
| 424 | + self.hideOrDisplayControls() | ||
| 425 | + } | ||
| 426 | + } | ||
| 427 | + } | ||
| 428 | + | ||
| 429 | + //自动隐藏亮度控件倒计时(默认3s) | ||
| 430 | + var _autoHideBrightnessViewTime:CGFloat = 3.0 | ||
| 431 | + var autoHideBrightnessViewTime:CGFloat{ | ||
| 432 | + get{ | ||
| 433 | + _autoHideBrightnessViewTime | ||
| 434 | + } | ||
| 435 | + set{ | ||
| 436 | + _autoHideBrightnessViewTime = newValue | ||
| 437 | + UIView.animate(withDuration: CGFloat(kDSPlayerAnimateTimeInterval)) { | ||
| 438 | + [weak self] in | ||
| 439 | + if self!.autoHideBrightnessViewTime <= 0{ | ||
| 440 | + self!.brightnessView?.alpha = 0 | ||
| 441 | + }else{ | ||
| 442 | + self?.brightnessView?.alpha = 1 | ||
| 443 | + } | ||
| 444 | + } | ||
| 445 | + } | ||
| 446 | + } | ||
| 447 | + //滑动手势操作内容 | ||
| 448 | + var panGestureOperation:CNLivePlayerPanGestureOperation? | ||
| 449 | + //音量调整 | ||
| 450 | + var volumeViewSlider:UISlider? | ||
| 451 | + //当前快进时间 | ||
| 452 | + var currentFastForwordPlayTime:Double = 0 | ||
| 453 | + | ||
| 454 | + // MARK: - init | ||
| 455 | + init() { | ||
| 456 | + super.init(frame: CGRectZero) | ||
| 457 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 458 | + self.initializeThings() | ||
| 459 | + } | ||
| 460 | + | ||
| 461 | + required init?(coder: NSCoder) { | ||
| 462 | + fatalError("init(coder:) has not been implemented") | ||
| 463 | + } | ||
| 464 | + | ||
| 465 | + override init(frame: CGRect) { | ||
| 466 | + super.init(frame: frame) | ||
| 467 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 468 | + self.initializeThings() | ||
| 469 | + } | ||
| 470 | + | ||
| 471 | + func initializeThings(){ | ||
| 472 | + self.initUI() | ||
| 473 | + self.configureVolume() | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + deinit { | ||
| 477 | + print("DSPlayerControlView释放") | ||
| 478 | + } | ||
| 479 | + | ||
| 480 | + // MARK: - layoutSubviews | ||
| 481 | + override func layoutSubviews() { | ||
| 482 | + super.layoutSubviews() | ||
| 483 | + self.coverImageView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 484 | + self.gestureView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 485 | + self.circlePlayBtn?.frame = CGRect(x: (self.width-44)/2, y: (self.height-44)/2, width: 44, height: 44) | ||
| 486 | + if (self.currentOrientation == .landscapeLeft || | ||
| 487 | + self.currentOrientation == .landscapeRight) { | ||
| 488 | + self.topNaviView?.frame = CGRect(x: 0, y: 0, width: self.width, height: 20+44) | ||
| 489 | + self.bottomNaviView?.frame = CGRect(x: 0, y: self.height-50, width: self.width, height: 50) | ||
| 490 | + }else{ | ||
| 491 | + self.topNaviView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.portraitTopNaviHeight) | ||
| 492 | + self.bottomNaviView?.frame = CGRect(x: 0, y: self.height-self.portraitBottomNaviHeight, width: self.width, height: self.portraitBottomNaviHeight) | ||
| 493 | + | ||
| 494 | + } | ||
| 495 | + self.bottomProgressView?.frame = CGRect(x: 0, y: self.height-2, width: self.width, height: 2) | ||
| 496 | + self.lockBtn?.frame = CGRect(x: KStatusBarHeight, y: (self.height-42)/2, width: 42, height: 42) | ||
| 497 | + self.fastForwardPreviewView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 498 | + self.loadingView?.frame = CGRect(x: (self.width-50)/2, y: (self.height-50)/2, width: 50, height: 50) | ||
| 499 | + self.brightnessView?.frame = CGRect(x: (self.width-155)/2, y: (self.height-45)/2, width: 155, height: 45) | ||
| 500 | + self.failureView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 501 | + } | ||
| 502 | + | ||
| 503 | + // MARK: - initUI | ||
| 504 | + func initUI(){ | ||
| 505 | + self.addSubview(self.coverImageView!) | ||
| 506 | + self.addSubview(self.gestureView!) | ||
| 507 | + self.addSubview(self.topNaviView!) | ||
| 508 | + self.addSubview(self.bottomNaviView!) | ||
| 509 | + self.addSubview(self.bottomProgressView!) | ||
| 510 | + self.addSubview(self.lockBtn!) | ||
| 511 | + self.addSubview(self.fastForwardPreviewView!) | ||
| 512 | + self.addSubview(self.loadingView!) | ||
| 513 | + self.addSubview(self.brightnessView!) | ||
| 514 | + self.addSubview(self.failureView!) | ||
| 515 | + } | ||
| 516 | + | ||
| 517 | + func displayFastForwardPreviewViewWithForwardTime(forwardTime:Double){ | ||
| 518 | + self.fastForwardPreviewView?.alpha = 1 | ||
| 519 | + let totalSecond = CMTimeGetSeconds(self.player!.totalDuration) | ||
| 520 | + if totalSecond > 0{ | ||
| 521 | + if totalSecond > 3600{ | ||
| 522 | + let c_second = Int(forwardTime)%60 | ||
| 523 | + let c_minute = Int(forwardTime)/60%60 | ||
| 524 | + let c_hour = Int(forwardTime)/3600 | ||
| 525 | + let t_second = Int(totalSecond)%60 | ||
| 526 | + let t_minute = Int(totalSecond)/60%60 | ||
| 527 | + let t_hour = Int(totalSecond)/3600 | ||
| 528 | + self.fastForwardPreviewView?.time = String(format: "%02ld:%02ld:%02ld/%02ld:%02ld:%02ld", c_hour, c_minute, c_second, t_hour, t_minute, t_second) | ||
| 529 | + }else{ | ||
| 530 | + let c_second = Int(forwardTime)%60 | ||
| 531 | + let c_minute = Int(forwardTime)/60 | ||
| 532 | + let t_second = Int(totalSecond)%60 | ||
| 533 | + let t_minute = Int(totalSecond)/60 | ||
| 534 | + self.fastForwardPreviewView?.time = String(format: "%02ld:%02ld/%02ld:%02ld", c_minute, c_second, t_minute, t_second) | ||
| 535 | + } | ||
| 536 | + self.fastForwardPreviewView?.value = forwardTime/totalSecond | ||
| 537 | + }else{ | ||
| 538 | + self.fastForwardPreviewView?.time = "00:00/00:00" | ||
| 539 | + self.fastForwardPreviewView?.value = 0 | ||
| 540 | + } | ||
| 541 | + } | ||
| 542 | + | ||
| 543 | + @objc func playBtnClick(){ | ||
| 544 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 545 | + if self.player!.isPlaying{ | ||
| 546 | + self.clickPauseBtnAction!() | ||
| 547 | + }else{ | ||
| 548 | + self.clickPlayBtnAction!() | ||
| 549 | + } | ||
| 550 | + } | ||
| 551 | + | ||
| 552 | + @objc func lockBtnClick(){ | ||
| 553 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 554 | + self.isLockScreen = !self.isLockScreen! | ||
| 555 | + if self.isLockScreen!{ | ||
| 556 | + self.lockBtn?.setBackgroundImage(UIImage(named: "DS_player_lock_close"), for: .normal) | ||
| 557 | + self.topNaviView?.isUserInteractionEnabled = false | ||
| 558 | + self.bottomNaviView?.isUserInteractionEnabled = false | ||
| 559 | + self.gestureView?.private_style = .singleTap | ||
| 560 | + }else{ | ||
| 561 | + self.lockBtn?.setBackgroundImage(UIImage(named: "DS_player_lock_open"), for: .normal) | ||
| 562 | + self.topNaviView?.isUserInteractionEnabled = true | ||
| 563 | + self.bottomNaviView?.isUserInteractionEnabled = true | ||
| 564 | + self.gestureView?.private_style = .nonePrivate | ||
| 565 | + } | ||
| 566 | + self.hideOrDisplayControls() | ||
| 567 | + self.switchLockScreenCallBack!() | ||
| 568 | + } | ||
| 569 | + // MARK: - 隐藏/显示视频上面的控件 | ||
| 570 | + func hideOrDisplayControls(){ | ||
| 571 | + self.switchAlphaMessageStateCallBack!() | ||
| 572 | + UIView.animate(withDuration: CGFloat(kDSPlayerAnimateTimeInterval)) { | ||
| 573 | + if self.isLockScreen! == false{ | ||
| 574 | + if self.isAlphaMessage!{ | ||
| 575 | + self.topNaviView?.alpha = 0 | ||
| 576 | + self.bottomNaviView?.alpha = 0 | ||
| 577 | + self.bottomProgressView?.alpha = 1 | ||
| 578 | + self.lockBtn?.alpha = 0 | ||
| 579 | + }else{ | ||
| 580 | + if (self.currentOrientation == .landscapeLeft || | ||
| 581 | + self.currentOrientation == .landscapeRight) { | ||
| 582 | + self.lockBtn?.alpha = 1 | ||
| 583 | + }else { | ||
| 584 | + self.lockBtn?.alpha = 0 | ||
| 585 | + } | ||
| 586 | + self.topNaviView?.alpha = 1 | ||
| 587 | + self.bottomNaviView?.alpha = 1 | ||
| 588 | + self.bottomProgressView?.alpha = 0 | ||
| 589 | + } | ||
| 590 | + }else{ | ||
| 591 | + if (self.isAlphaMessage!) { | ||
| 592 | + self.topNaviView?.alpha = 0 | ||
| 593 | + self.bottomNaviView?.alpha = 0 | ||
| 594 | + self.bottomProgressView?.alpha = 1 | ||
| 595 | + self.lockBtn?.alpha = 0 | ||
| 596 | + }else { | ||
| 597 | + self.topNaviView?.alpha = 0 | ||
| 598 | + self.bottomNaviView?.alpha = 0 | ||
| 599 | + self.bottomProgressView?.alpha = 1 | ||
| 600 | + self.lockBtn?.alpha = 1 | ||
| 601 | + } | ||
| 602 | + } | ||
| 603 | + } | ||
| 604 | + } | ||
| 605 | + | ||
| 606 | + // MARK: - 亮度 | ||
| 607 | + func addLight(light:CGFloat){ | ||
| 608 | + self.autoHideBrightnessViewTime = CGFloat(kDSPlayerAutoHideBrightnessViewTime) | ||
| 609 | + var nLight = light + UIScreen.main.brightness | ||
| 610 | + if nLight > 1{ | ||
| 611 | + nLight = 1 | ||
| 612 | + }else if nLight < 0{ | ||
| 613 | + nLight = 0 | ||
| 614 | + } | ||
| 615 | + UIScreen.main.brightness = nLight | ||
| 616 | + self.brightnessView?.value = nLight | ||
| 617 | + } | ||
| 618 | + | ||
| 619 | + // MARK: - 音量 | ||
| 620 | + func configureVolume(){ | ||
| 621 | + let volumeView = MPVolumeView() | ||
| 622 | + self.volumeViewSlider = nil | ||
| 623 | + for view in volumeView.subviews{ | ||
| 624 | + if view.isKind(of: MPVolumeView.self){ | ||
| 625 | + self.volumeViewSlider = view as? UISlider | ||
| 626 | + break | ||
| 627 | + } | ||
| 628 | + } | ||
| 629 | + } | ||
| 630 | + | ||
| 631 | + func addVolume(volume:CGFloat){ | ||
| 632 | + var nVolume = volume + CGFloat(self.volumeViewSlider!.value) | ||
| 633 | + if nVolume > 1{ | ||
| 634 | + nVolume = 1 | ||
| 635 | + }else if nVolume < 0{ | ||
| 636 | + nVolume = 0 | ||
| 637 | + } | ||
| 638 | + self.volumeViewSlider?.value = Float(nVolume) | ||
| 639 | + } | ||
| 640 | + | ||
| 641 | + // MARK: - 进度赋值 | ||
| 642 | + func assignVideoPlayProgressWithTime(time:Double){ | ||
| 643 | + let totalSecond = CMTimeGetSeconds(self.player!.totalDuration) | ||
| 644 | + if totalSecond > 0{ | ||
| 645 | + if totalSecond > 3600{ | ||
| 646 | + | ||
| 647 | + | ||
| 648 | + let c_second = Int(ceil(time))%60 | ||
| 649 | + let c_minute = Int(ceil(time))/60%60 | ||
| 650 | + let c_hour = Int(ceil(time))/3600 | ||
| 651 | + let t_second = Int(totalSecond)%60 | ||
| 652 | + let t_minute = Int(totalSecond)/60%60 | ||
| 653 | + let t_hour = Int(totalSecond)/3600 | ||
| 654 | + self.bottomNaviView?.timeLab?.text = String(format: "%02ld:%02ld:%02ld/%02ld:%02ld:%02ld", c_hour, c_minute, c_second, t_hour, t_minute, t_second+1) | ||
| 655 | + self.bottomNaviView?.timeStyle = .HH_MM_SS | ||
| 656 | + }else{ | ||
| 657 | + let c_second = Int(ceil(time))%60 | ||
| 658 | + let c_minute = Int(ceil(time))/60 | ||
| 659 | + let t_second = Int(totalSecond)%60 | ||
| 660 | + let t_minute = Int(totalSecond)/60 | ||
| 661 | + self.bottomNaviView?.timeLab?.text = String(format: "%02ld:%02ld/%02ld:%02ld", c_minute, c_second, t_minute, t_second+1) | ||
| 662 | + self.bottomNaviView?.timeStyle = .MM_SS | ||
| 663 | + } | ||
| 664 | + self.bottomNaviView?.progressSlider?.value = time / totalSecond | ||
| 665 | + }else{ | ||
| 666 | + self.bottomNaviView?.timeLab?.text = "00:00/00:00" | ||
| 667 | + self.bottomNaviView?.timeStyle = .MM_SS | ||
| 668 | + self.bottomNaviView?.progressSlider?.value = 0 | ||
| 669 | + } | ||
| 670 | + self.bottomProgressView?.value = self.bottomNaviView!.progressSlider!.value | ||
| 671 | + } | ||
| 672 | + | ||
| 673 | + // MARK: - CNLivePlayerGestureViewDelegate | ||
| 674 | + func gestureViewSingleTap(gestureView: CNLivePlayerGestureView, recognizer: UITapGestureRecognizer) { | ||
| 675 | + | ||
| 676 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 677 | + self.isAlphaMessage = !self.isAlphaMessage! | ||
| 678 | + self.hideOrDisplayControls() | ||
| 679 | + } | ||
| 680 | + | ||
| 681 | + func gestureViewDoubleTap(gestureView: CNLivePlayerGestureView, recognizer: UITapGestureRecognizer) { | ||
| 682 | + if (self.loadingView!.isLoading!) { | ||
| 683 | + return | ||
| 684 | + } | ||
| 685 | + | ||
| 686 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 687 | + self.playBtnClick() | ||
| 688 | + } | ||
| 689 | + | ||
| 690 | + func gestureViewPan(gestureView: CNLivePlayerGestureView, panGestureRecognizer: UIPanGestureRecognizer) { | ||
| 691 | + | ||
| 692 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 693 | + let second = CMTimeGetSeconds(self.player!.totalDuration) | ||
| 694 | + | ||
| 695 | + switch (panGestureRecognizer.state) { | ||
| 696 | + case .began: | ||
| 697 | + self.isUserInteractionEnabled = false | ||
| 698 | + let velocity = panGestureRecognizer.velocity(in: panGestureRecognizer.view) | ||
| 699 | + if abs(velocity.y) < abs(velocity.x){ | ||
| 700 | + if self.isLive!{ | ||
| 701 | + panGestureRecognizer.isEnabled = false | ||
| 702 | + let delayTime = DispatchTime.now() + DispatchTimeInterval.seconds(Int(0.1)) | ||
| 703 | + DispatchQueue.main.asyncAfter(deadline: delayTime) { | ||
| 704 | + panGestureRecognizer.isEnabled = true | ||
| 705 | + } | ||
| 706 | + return | ||
| 707 | + } | ||
| 708 | + self.panGestureOperation = .progress | ||
| 709 | + self.currentFastForwordPlayTime = CMTimeGetSeconds(self.player!.currentTime) | ||
| 710 | + }else if (abs(velocity.y) > abs(velocity.x)) { | ||
| 711 | + let startPoint = panGestureRecognizer.location(in: panGestureRecognizer.view) | ||
| 712 | + if (startPoint.x < panGestureRecognizer.view!.width/2) { | ||
| 713 | + self.panGestureOperation = .light | ||
| 714 | + }else { | ||
| 715 | + self.panGestureOperation = .volume | ||
| 716 | + } | ||
| 717 | + } | ||
| 718 | + break | ||
| 719 | + case .changed: | ||
| 720 | + let translation = panGestureRecognizer.translation(in: panGestureRecognizer.view) | ||
| 721 | + switch self.panGestureOperation{ | ||
| 722 | + case .progress: | ||
| 723 | + self.currentFastForwordPlayTime = self.currentFastForwordPlayTime + translation.x/5 | ||
| 724 | + if (self.currentFastForwordPlayTime > second) { | ||
| 725 | + self.currentFastForwordPlayTime = second | ||
| 726 | + } | ||
| 727 | + self.assignVideoPlayProgressWithTime(time: self.currentFastForwordPlayTime) | ||
| 728 | + self.displayFastForwardPreviewViewWithForwardTime(forwardTime: self.currentFastForwordPlayTime) | ||
| 729 | + break | ||
| 730 | + case .light: | ||
| 731 | + self.addLight(light: -translation.y/100) | ||
| 732 | + break | ||
| 733 | + case .volume: | ||
| 734 | + self.addVolume(volume: -translation.y/100) | ||
| 735 | + break | ||
| 736 | + | ||
| 737 | + case nil: | ||
| 738 | + break | ||
| 739 | + case .some(.none): | ||
| 740 | + break | ||
| 741 | + } | ||
| 742 | + break | ||
| 743 | + case .ended: | ||
| 744 | + break | ||
| 745 | + case .cancelled: | ||
| 746 | + break | ||
| 747 | + case .failed: | ||
| 748 | + if (self.panGestureOperation == .progress) { | ||
| 749 | + self.loadingView?.startAnimate() | ||
| 750 | + self.player?.seek(to: CMTime(value: Int64(self.currentFastForwordPlayTime)*30, timescale: 30)) | ||
| 751 | + self.currentFastForwordPlayTime = 0 | ||
| 752 | + self.fastForwardPreviewView!.alpha = 0 | ||
| 753 | + } | ||
| 754 | + self.panGestureOperation = CNLivePlayerPanGestureOperation.none | ||
| 755 | + self.isUserInteractionEnabled = true | ||
| 756 | + break | ||
| 757 | + case .possible: break | ||
| 758 | + | ||
| 759 | + @unknown default: break | ||
| 760 | + | ||
| 761 | + } | ||
| 762 | + panGestureRecognizer.setTranslation(CGPointZero, in: panGestureRecognizer.view) | ||
| 763 | + } | ||
| 764 | + | ||
| 765 | + // MARK: - 方法 | ||
| 766 | + /// 定时器触发方法 | ||
| 767 | + /// @param timeInterval 与上次间隔几秒 | ||
| 768 | + func timerTriggeringMethod(timeInterval:Double){ | ||
| 769 | + if (self.autoHideControlsTime > 0) { | ||
| 770 | + self.autoHideControlsTime = self.autoHideControlsTime - timeInterval | ||
| 771 | + } | ||
| 772 | + if (self.autoHideBrightnessViewTime > 0) { | ||
| 773 | + self.autoHideBrightnessViewTime = self.autoHideBrightnessViewTime - timeInterval | ||
| 774 | + } | ||
| 775 | + //快进中不修改 | ||
| 776 | + if (self.panGestureOperation == .progress) { | ||
| 777 | + return | ||
| 778 | + } | ||
| 779 | + self.assignVideoPlayProgressWithTime(time: CMTimeGetSeconds(self.player!.currentTime)) | ||
| 780 | + } | ||
| 781 | + /// 重置隐藏时间 | ||
| 782 | + func resetHideTime(){ | ||
| 783 | + self.autoHideControlsTime = CGFloat(kDSPlayerAutoHideControlsTime) | ||
| 784 | + } | ||
| 785 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerEnum.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerEnum.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +/////全屏样式 | ||
| 10 | +enum CNLivePlayerFullScreenType:Int { | ||
| 11 | + ///在当前DSPlayView中旋转,用于当前播放界面为全屏样式 | ||
| 12 | + case inCurrentViewOrientation | ||
| 13 | + ///在window中旋转,用于小屏不是全屏显示且大屏要全屏显示 | ||
| 14 | + case inWindowOrientation | ||
| 15 | + //小屏视频展示为裁剪显示,全屏为全部展示,用于竖屏视频显示全屏属性(暂未开发) | ||
| 16 | + case fullDisplayOfVideoInterface | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +///手势样式 | ||
| 20 | +enum CNLivePlayerGestureStyle:Int { | ||
| 21 | + ///存在单点、双点、滑动手势 | ||
| 22 | + case all | ||
| 23 | + ///存在单点、双点手势 | ||
| 24 | + case allButPanGesture | ||
| 25 | + ///存在单点手势 | ||
| 26 | + case singleTap | ||
| 27 | + ///不存在任何手势 | ||
| 28 | + case none | ||
| 29 | + ///没有私有手势处理 只有private_style可用 | ||
| 30 | + case nonePrivate | ||
| 31 | +} | ||
| 32 | + | ||
| 33 | +///分类类型 | ||
| 34 | +enum CNLivePlayerBottomTimeStyle:Int { | ||
| 35 | + ///时间格式mm:ss | ||
| 36 | + case MM_SS | ||
| 37 | + ///时间格式HH:mm:ss | ||
| 38 | + case HH_MM_SS | ||
| 39 | +} | ||
| 40 | + |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerFailureView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerFailureView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +//点击刷新回调 | ||
| 11 | +typealias clickRefreshCallBackBlock = () -> Void | ||
| 12 | +//点击返回回调 | ||
| 13 | +typealias clickBackCallBackBlock = () -> Void | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +class CNLivePlayerFailureView:UIView{ | ||
| 17 | + | ||
| 18 | + // MARK: - 属性 | ||
| 19 | + //失败原因 | ||
| 20 | + var _errorMessage:String? | ||
| 21 | + var errorMessage:String?{ | ||
| 22 | + get{ | ||
| 23 | + _errorMessage | ||
| 24 | + } | ||
| 25 | + set{ | ||
| 26 | + _errorMessage = newValue | ||
| 27 | + self.titleLab?.text = _errorMessage | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + // MARK: - 回调 | ||
| 32 | + //点击刷新回调 | ||
| 33 | + var clickRefreshCallBack:clickRefreshCallBackBlock? | ||
| 34 | + //点击返回回调 | ||
| 35 | + var clickBackCallBack:clickBackCallBackBlock? | ||
| 36 | + //返回按钮 | ||
| 37 | + var backBtn:UIButton? | ||
| 38 | + //返回按钮图片 | ||
| 39 | + var backImageView:UIImageView?//DSImageView | ||
| 40 | + var titleLab:UILabel? | ||
| 41 | + var refreshBtn:UIButton? | ||
| 42 | + | ||
| 43 | + required init?(coder: NSCoder) { | ||
| 44 | + fatalError("init(coder:) has not been implemented") | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + init() { | ||
| 48 | + super.init(frame: CGRectZero) | ||
| 49 | + self.backgroundColor = .black | ||
| 50 | + self.initUI() | ||
| 51 | + } | ||
| 52 | + override func layoutSubviews() { | ||
| 53 | + super.layoutSubviews() | ||
| 54 | + self.backBtn?.frame = CGRect(x: 0, y: KStatusBarHeight, width: KNavigationHeight-KStatusBarHeight, height: KNavigationHeight-KStatusBarHeight) | ||
| 55 | + self.backImageView?.frame = CGRect(x: (self.backBtn!.width - 22)*0.5, y: (self.backBtn!.height - 22)*0.5, width: 22, height: 22) | ||
| 56 | + self.titleLab?.frame = CGRect(x: 5, y: 0, width: self.width - 5*2, height: 20) | ||
| 57 | + self.refreshBtn?.frame = CGRect(x: (self.width-70)*0.5, y: 0, width: 80, height: 32) | ||
| 58 | + self.titleLab?.top = (self.height - (self.titleLab!.height+12+self.refreshBtn!.height))*0.5 | ||
| 59 | + self.refreshBtn?.top = self.titleLab!.bottom + 12 | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + // MARK: - initUI | ||
| 63 | + func initUI(){ | ||
| 64 | + self.backBtn = UIButton(type: .custom) | ||
| 65 | + self.backBtn?.addTarget(self, action: #selector(backBtnClick), for: .touchUpInside) | ||
| 66 | + self.addSubview(self.backBtn!) | ||
| 67 | + | ||
| 68 | + self.backImageView = UIImageView() | ||
| 69 | + self.backImageView?.clipsToBounds = true | ||
| 70 | + self.backImageView?.contentMode = .scaleAspectFit | ||
| 71 | + self.backImageView?.image = UIImage(named: "DS_player_nav_back") | ||
| 72 | + self.backBtn?.addSubview(self.backImageView!) | ||
| 73 | + self.titleLab = UILabel() | ||
| 74 | + self.titleLab?.textAlignment = .center | ||
| 75 | + self.titleLab?.font = Font_14 | ||
| 76 | + self.titleLab?.textColor = .white | ||
| 77 | + self.addSubview(self.titleLab!) | ||
| 78 | + | ||
| 79 | + self.refreshBtn = UIButton(type: .custom) | ||
| 80 | + self.refreshBtn?.layer.cornerRadius = 32/2 | ||
| 81 | + self.refreshBtn?.clipsToBounds = true | ||
| 82 | + self.refreshBtn?.setTitle("刷新重试", for: .normal) | ||
| 83 | + self.refreshBtn?.setTitleColor(.white, for: .normal) | ||
| 84 | + self.refreshBtn?.backgroundColor = HexColor("#ff725c") | ||
| 85 | + self.refreshBtn?.titleLabel?.font = Font_13 | ||
| 86 | + self.refreshBtn?.addTarget(self, action: #selector(refreshBtnClick), for: .touchUpInside) | ||
| 87 | + self.addSubview(self.refreshBtn!) | ||
| 88 | + | ||
| 89 | + | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + // MARK: - 触发事件 | ||
| 93 | + @objc func refreshBtnClick(){ | ||
| 94 | + self.clickRefreshCallBack!() | ||
| 95 | + } | ||
| 96 | + @objc func backBtnClick(){ | ||
| 97 | + self.clickBackCallBack!() | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerFastForwardPreviewView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerFastForwardPreviewView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/27. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerFastForwardPreviewView:UIView{ | ||
| 11 | + //快进进度0~1 | ||
| 12 | + var _value:CGFloat = 0 | ||
| 13 | + var value:CGFloat{ | ||
| 14 | + get{ | ||
| 15 | + _value | ||
| 16 | + } | ||
| 17 | + set{ | ||
| 18 | + _value = newValue | ||
| 19 | + if (_value > 1) { | ||
| 20 | + _value = 1 | ||
| 21 | + }else if (_value < 0) { | ||
| 22 | + _value = 0 | ||
| 23 | + } | ||
| 24 | + var progressViewFrame = self.progressView!.frame | ||
| 25 | + progressViewFrame.size.width = self.totalView!.frame.size.width*_value | ||
| 26 | + self.progressView?.frame = progressViewFrame | ||
| 27 | + } | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + //时间 | ||
| 31 | + var _time:String? | ||
| 32 | + var time:String?{ | ||
| 33 | + get{ | ||
| 34 | + _time | ||
| 35 | + } | ||
| 36 | + set{ | ||
| 37 | + _time = newValue | ||
| 38 | + self.timeLab?.text = _time | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + //时间文本 | ||
| 42 | + var timeLab:UILabel? | ||
| 43 | + var totalView:UIView? | ||
| 44 | + var progressView:UIView? | ||
| 45 | + | ||
| 46 | + init() { | ||
| 47 | + super.init(frame: CGRectZero) | ||
| 48 | + self.backgroundColor = UIColor(white: 0, alpha: 0.6) | ||
| 49 | + self.initUI() | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + required init?(coder: NSCoder) { | ||
| 53 | + fatalError("init(coder:) has not been implemented") | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + override func layoutSubviews() { | ||
| 57 | + super.layoutSubviews() | ||
| 58 | + self.timeLab?.frame = CGRect(x: 5, y: 0, width: self.width-5*2, height: 20) | ||
| 59 | + self.timeLab?.top = (self.height-self.timeLab!.height-10-2)/2 | ||
| 60 | + self.totalView?.frame = CGRect(x: (self.width-120)/2, y: self.timeLab!.bottom+10, width: 120, height: 2) | ||
| 61 | + self.progressView?.frame = CGRect(x: self.totalView!.left, y: self.totalView!.top, width: self.totalView!.width*self.value, height: self.totalView!.height) | ||
| 62 | + | ||
| 63 | + } | ||
| 64 | + // MARK: - initUI | ||
| 65 | + func initUI(){ | ||
| 66 | + self.timeLab = UILabel() | ||
| 67 | + self.timeLab?.textAlignment = .center | ||
| 68 | + self.timeLab?.font = Font_14 | ||
| 69 | + self.timeLab?.textColor = .white | ||
| 70 | + self.addSubview(self.timeLab!) | ||
| 71 | + | ||
| 72 | + self.totalView = UIView() | ||
| 73 | + self.totalView?.backgroundColor = UIColor(white: 1, alpha: 0.2) | ||
| 74 | + self.totalView?.clipsToBounds = true | ||
| 75 | + self.totalView?.layer.cornerRadius = 1 | ||
| 76 | + self.addSubview(self.totalView!) | ||
| 77 | + | ||
| 78 | + self.progressView = UIView() | ||
| 79 | + self.progressView?.backgroundColor = .white | ||
| 80 | + self.progressView?.clipsToBounds = true | ||
| 81 | + self.progressView?.layer.cornerRadius = 1 | ||
| 82 | + self.addSubview(self.progressView!) | ||
| 83 | + } | ||
| 84 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerGestureView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerGestureView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +protocol CNLivePlayerGestureViewDelegate:NSObjectProtocol{ | ||
| 11 | + /// 单点 | ||
| 12 | + /// @param gestureView 手势视图 | ||
| 13 | + /// @param recognizer 手势 | ||
| 14 | + func gestureViewSingleTap(gestureView:CNLivePlayerGestureView,recognizer:UITapGestureRecognizer) | ||
| 15 | + /// 点两次 | ||
| 16 | + /// @param gestureView 手势视图 | ||
| 17 | + /// @param recognizer 手势 | ||
| 18 | + func gestureViewDoubleTap(gestureView:CNLivePlayerGestureView,recognizer:UITapGestureRecognizer) | ||
| 19 | + /// 滑动手势 | ||
| 20 | + /// @param gestureView 手势视图 | ||
| 21 | + /// @param panGestureRecognizer 手势 | ||
| 22 | + func gestureViewPan(gestureView:CNLivePlayerGestureView,panGestureRecognizer:UIPanGestureRecognizer) | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | + | ||
| 26 | +class CNLivePlayerGestureView:UIView{ | ||
| 27 | + | ||
| 28 | + /// 代理 | ||
| 29 | + weak var delegate:CNLivePlayerGestureViewDelegate? | ||
| 30 | + /// 单击手势 | ||
| 31 | + var singleTapGestureRecognizer:UITapGestureRecognizer? | ||
| 32 | + /// 双击手势 | ||
| 33 | + var doubleTapGestureRecognizer:UITapGestureRecognizer? | ||
| 34 | + /// 滑动手势 | ||
| 35 | + var panGestureRecognizer:UIPanGestureRecognizer? | ||
| 36 | + /// 手势样式 默认都存在 | ||
| 37 | + var _style:CNLivePlayerGestureStyle = .all | ||
| 38 | + var style:CNLivePlayerGestureStyle{ | ||
| 39 | + get{ | ||
| 40 | + _style | ||
| 41 | + } | ||
| 42 | + set{ | ||
| 43 | + _style = newValue | ||
| 44 | + self.removeGestureRecognizer(self.singleTapGestureRecognizer!) | ||
| 45 | + self.singleTapGestureRecognizer = nil | ||
| 46 | + self.removeGestureRecognizer(self.doubleTapGestureRecognizer!) | ||
| 47 | + self.doubleTapGestureRecognizer = nil | ||
| 48 | + self.removeGestureRecognizer(self.panGestureRecognizer!) | ||
| 49 | + self.panGestureRecognizer = nil | ||
| 50 | + self.addGesture() | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + // MARK: - 内部使用 | ||
| 55 | + /// 内部操作手势样式 外部别修改 | ||
| 56 | + var _private_style:CNLivePlayerGestureStyle = .all | ||
| 57 | + var private_style:CNLivePlayerGestureStyle{ | ||
| 58 | + get{ | ||
| 59 | + _private_style | ||
| 60 | + } | ||
| 61 | + set{ | ||
| 62 | + _private_style = newValue | ||
| 63 | + self.removeGestureRecognizer(self.singleTapGestureRecognizer!) | ||
| 64 | + self.singleTapGestureRecognizer = nil | ||
| 65 | + self.removeGestureRecognizer(self.doubleTapGestureRecognizer!) | ||
| 66 | + self.doubleTapGestureRecognizer = nil | ||
| 67 | + self.removeGestureRecognizer(self.panGestureRecognizer!) | ||
| 68 | + self.panGestureRecognizer = nil | ||
| 69 | + self.addGesture() | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + // MARK: - init | ||
| 74 | + init() { | ||
| 75 | + super.init(frame: CGRectZero) | ||
| 76 | + self.private_style = .allButPanGesture | ||
| 77 | + self.addGesture() | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + required init?(coder: NSCoder) { | ||
| 81 | + fatalError("init(coder:) has not been implemented") | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + // MARK: - 手势 | ||
| 85 | + func addGesture(){ | ||
| 86 | + if self.style == .none{ | ||
| 87 | + return | ||
| 88 | + } | ||
| 89 | + if ((self.private_style == .nonePrivate && (self.style == .all || self.style == .allButPanGesture || self.style == .singleTap)) || self.private_style == .all || self.private_style == .allButPanGesture || self.private_style == .singleTap){ | ||
| 90 | + self.singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(singleTapGestureRecognizer(_:))) | ||
| 91 | + self.addGestureRecognizer(self.singleTapGestureRecognizer!) | ||
| 92 | + } | ||
| 93 | + if ((self.private_style == .nonePrivate && (self.style == .all || self.style == .allButPanGesture)) || self.private_style == .all || self.private_style == .allButPanGesture) { | ||
| 94 | + self.doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognizer(_:))) | ||
| 95 | + self.doubleTapGestureRecognizer!.numberOfTapsRequired = 2 | ||
| 96 | + self.addGestureRecognizer(self.doubleTapGestureRecognizer!) | ||
| 97 | + self.singleTapGestureRecognizer?.require(toFail: self.doubleTapGestureRecognizer!) | ||
| 98 | + } | ||
| 99 | + if ((self.private_style == .nonePrivate && self.style == .all) || self.private_style == .all) { | ||
| 100 | + self.panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognizer(_:))) | ||
| 101 | + self.panGestureRecognizer?.maximumNumberOfTouches = 1 | ||
| 102 | + self.addGestureRecognizer(self.panGestureRecognizer!) | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + // MARK: - 触发事件 | ||
| 108 | + @objc func singleTapGestureRecognizer(_ recognizer:UITapGestureRecognizer){ | ||
| 109 | + self.delegate?.gestureViewSingleTap(gestureView: self, recognizer: recognizer) | ||
| 110 | + } | ||
| 111 | + @objc func doubleTapGestureRecognizer(_ recognizer:UITapGestureRecognizer){ | ||
| 112 | + self.delegate?.gestureViewDoubleTap(gestureView: self, recognizer: recognizer) | ||
| 113 | + } | ||
| 114 | + @objc func panGestureRecognizer(_ panGestureRecognizer:UIPanGestureRecognizer){ | ||
| 115 | + self.delegate?.gestureViewPan(gestureView: self, panGestureRecognizer: panGestureRecognizer) | ||
| 116 | + } | ||
| 117 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerKVOModel.swift
0 → 100644
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerLandscapeViewController.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerLandscapeViewController.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/28. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerLandscapeViewController:CNLiveBaseViewController{ | ||
| 11 | + var interfaceOrientationMask: UIInterfaceOrientationMask? | ||
| 12 | + override func viewDidLoad() { | ||
| 13 | + super.viewDidLoad() | ||
| 14 | + self.topNavView.removeFromSuperview() | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + // MARK: - 屏幕旋转 | ||
| 18 | + | ||
| 19 | +// -(BOOL)shouldAutorotate | ||
| 20 | +// { | ||
| 21 | +// return YES; | ||
| 22 | +// } | ||
| 23 | + | ||
| 24 | +// -(UIInterfaceOrientationMask)supportedInterfaceOrientations | ||
| 25 | +// { | ||
| 26 | +// if (self.interfaceOrientationMask) { | ||
| 27 | +// return self.interfaceOrientationMask; | ||
| 28 | +// } | ||
| 29 | +// return UIInterfaceOrientationMaskLandscape; | ||
| 30 | +// } | ||
| 31 | + | ||
| 32 | + | ||
| 33 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerLoadingView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerLoadingView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerLoadingView:UIView,CAAnimationDelegate{ | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + 是否在加载中 | ||
| 14 | + */ | ||
| 15 | + var _isLoading:Bool? | ||
| 16 | + var isLoading:Bool?{ | ||
| 17 | + get{ | ||
| 18 | + _isLoading | ||
| 19 | + } | ||
| 20 | + set{ | ||
| 21 | + _isLoading = newValue | ||
| 22 | + } | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + // MARK: - loadingLayer | ||
| 26 | + lazy var loadingLayer :CAShapeLayer = { | ||
| 27 | + let loadingLayer = CAShapeLayer() | ||
| 28 | + loadingLayer.lineWidth = 3 | ||
| 29 | + loadingLayer.fillColor = UIColor.clear.cgColor | ||
| 30 | + loadingLayer.strokeColor = UIColor.white.cgColor | ||
| 31 | + loadingLayer.lineCap = .round | ||
| 32 | + return loadingLayer | ||
| 33 | + }() | ||
| 34 | + | ||
| 35 | + //开始角度 | ||
| 36 | + var beginAngle:CGFloat = 0.0 | ||
| 37 | + //动画角度 | ||
| 38 | + var animateAngle:CGFloat = 0.0 | ||
| 39 | + | ||
| 40 | + // MARK: - init | ||
| 41 | + override init(frame: CGRect) { | ||
| 42 | + super.init(frame: frame) | ||
| 43 | + self.alpha = 0 | ||
| 44 | + self.beginAngle = 0 | ||
| 45 | + self.animateAngle = .pi*10/3 | ||
| 46 | + self.layer.addSublayer(self.loadingLayer) | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + required init?(coder: NSCoder) { | ||
| 50 | + fatalError("init(coder:) has not been implemented") | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + deinit { | ||
| 54 | + self.stopAnimate() | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + override func layoutSubviews() { | ||
| 58 | + super.layoutSubviews() | ||
| 59 | + let path = UIBezierPath(arcCenter: CGPoint(x: self.width/2, y: self.height/2), radius: self.width/2-3, startAngle: self.beginAngle, endAngle: self.animateAngle, clockwise: true) | ||
| 60 | + self.loadingLayer.path = path.cgPath | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // MARK: - 动画 | ||
| 64 | + /** | ||
| 65 | + 开启动画 | ||
| 66 | + */ | ||
| 67 | + func startAnimate(){ | ||
| 68 | + self.isLoading = true | ||
| 69 | + self.loadingLayer.removeAllAnimations() | ||
| 70 | + self.alpha = 1 | ||
| 71 | + var strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart") | ||
| 72 | + strokeStartAnimation.fromValue = 0 | ||
| 73 | + strokeStartAnimation.toValue = 1 | ||
| 74 | + strokeStartAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) | ||
| 75 | + var strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd") | ||
| 76 | + strokeEndAnimation.fromValue = 0 | ||
| 77 | + strokeEndAnimation.toValue = 1 | ||
| 78 | + strokeEndAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) | ||
| 79 | + strokeEndAnimation.duration = 1 | ||
| 80 | + | ||
| 81 | + var strokeAniamtionGroup = CAAnimationGroup() | ||
| 82 | + strokeAniamtionGroup.duration = 1.5 | ||
| 83 | + strokeAniamtionGroup.fillMode = .forwards | ||
| 84 | + strokeAniamtionGroup.isRemovedOnCompletion = false | ||
| 85 | + strokeAniamtionGroup.delegate = self | ||
| 86 | + strokeAniamtionGroup.animations = [strokeEndAnimation, strokeStartAnimation] | ||
| 87 | + self.loadingLayer.add(strokeAniamtionGroup, forKey: "strokeAniamtionGroup") | ||
| 88 | + | ||
| 89 | + } | ||
| 90 | + /** | ||
| 91 | + 结束动画 | ||
| 92 | + */ | ||
| 93 | + func stopAnimate(){ | ||
| 94 | + self.isLoading = false | ||
| 95 | + self.loadingLayer.removeAllAnimations() | ||
| 96 | + self.beginAngle = 0 | ||
| 97 | + self.alpha = 0 | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + // MARK: - CAAnimationDelegate | ||
| 101 | + func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { | ||
| 102 | + if self.loadingLayer.animation(forKey: "strokeAniamtionGroup") == anim{ | ||
| 103 | + self.beginAngle = self.beginAngle + self.animateAngle | ||
| 104 | + let path = UIBezierPath(arcCenter: CGPoint(x: self.width/2, y: self.height/2), radius: self.width/2-3, startAngle: self.beginAngle, endAngle: self.beginAngle+self.animateAngle, clockwise: true) | ||
| 105 | + self.loadingLayer.path = path.cgPath | ||
| 106 | + self.startAnimate() | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | +} | ||
| 110 | + |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerProgressSlider.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerProgressSlider.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/27. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerProgressSlider:UIView{ | ||
| 11 | + | ||
| 12 | + // MARK: - 属性 | ||
| 13 | + /// 全部进度颜色 | ||
| 14 | + var _totalColor:UIColor? | ||
| 15 | + var totalColor:UIColor?{ | ||
| 16 | + get{ | ||
| 17 | + _totalColor | ||
| 18 | + } | ||
| 19 | + set{ | ||
| 20 | + _totalColor = newValue | ||
| 21 | + self.totalView?.backgroundColor = (_totalColor != nil) ? _totalColor : UIColor(white: 1, alpha: 0.2) | ||
| 22 | + } | ||
| 23 | + } | ||
| 24 | + /// 缓冲进度颜色 | ||
| 25 | + var _bufferColor:UIColor? | ||
| 26 | + var bufferColor:UIColor?{ | ||
| 27 | + get { | ||
| 28 | + _bufferColor | ||
| 29 | + } | ||
| 30 | + set{ | ||
| 31 | + _bufferColor = newValue | ||
| 32 | + self.bufferView?.backgroundColor = (_bufferColor != nil) ? _bufferColor : UIColor(white: 1, alpha: 0.4) | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + /// 当前进度颜色 | ||
| 36 | + var _currentColor:UIColor? | ||
| 37 | + var currentColor:UIColor?{ | ||
| 38 | + get{ | ||
| 39 | + _currentColor | ||
| 40 | + } | ||
| 41 | + set{ | ||
| 42 | + _currentColor = newValue | ||
| 43 | + self.slider?.minimumTrackTintColor = (_currentColor != nil) ? _currentColor : UIColor(white: 1, alpha: 1) | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + /// 缓冲 0~1 | ||
| 48 | + var _bufferValue:CGFloat = 0.0 | ||
| 49 | + var bufferValue:CGFloat{ | ||
| 50 | + get{ | ||
| 51 | + _bufferValue | ||
| 52 | + } | ||
| 53 | + set{ | ||
| 54 | + _bufferValue = newValue | ||
| 55 | + if (_bufferValue > 1) { | ||
| 56 | + _bufferValue = 1 | ||
| 57 | + }else if (_bufferValue < 0) { | ||
| 58 | + _bufferValue = 0 | ||
| 59 | + } | ||
| 60 | + var bufferViewFrame = self.bufferView?.frame | ||
| 61 | + bufferViewFrame?.size.width = self.width*_bufferValue | ||
| 62 | + self.bufferView?.frame = bufferViewFrame! | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + /// 进度 0~1 | ||
| 67 | + var _value:CGFloat = 0.0 | ||
| 68 | + var value:CGFloat{ | ||
| 69 | + get{ | ||
| 70 | + _value | ||
| 71 | + } | ||
| 72 | + set{ | ||
| 73 | + _value = newValue | ||
| 74 | + if (_value > 1) { | ||
| 75 | + _value = 1 | ||
| 76 | + }else if (_value < 0) { | ||
| 77 | + _value = 0 | ||
| 78 | + } | ||
| 79 | + if self.isDraggingSlideBlock!{ | ||
| 80 | + self.slider?.value = Float(_value) | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + // MARK: - 回调 | ||
| 86 | + /// 滑动中回调 | ||
| 87 | + var changeSliderValueCallBack:changeSliderValueCallBackBlock? | ||
| 88 | + /// 结束滑动回调 | ||
| 89 | + var endChangeSliderValueCallBack:endChangeSliderValueCallBackBlock? | ||
| 90 | + //总进度view | ||
| 91 | + var totalView:UIView? | ||
| 92 | + //缓冲view | ||
| 93 | + var bufferView:UIView? | ||
| 94 | + //滑块 | ||
| 95 | + var slider:CNLivePlayerSlider? | ||
| 96 | + //是否在拖动滑块 | ||
| 97 | + var isDraggingSlideBlock:Bool? | ||
| 98 | + | ||
| 99 | + // MARK: - init | ||
| 100 | + init() { | ||
| 101 | + super.init(frame: CGRectZero) | ||
| 102 | + self.backgroundColor = .clear | ||
| 103 | + self.initUI() | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + required init?(coder: NSCoder) { | ||
| 107 | + fatalError("init(coder:) has not been implemented") | ||
| 108 | + } | ||
| 109 | + override func layoutSubviews() { | ||
| 110 | + super.layoutSubviews() | ||
| 111 | + self.totalView?.frame = CGRect(x: 0, y: (self.height-self.slider!.sliderHeight)/2, width: self.width, height: self.slider!.sliderHeight) | ||
| 112 | + self.bufferView?.frame = CGRect(x: 0, y: (self.height-self.slider!.sliderHeight)/2, width: self.width*self.bufferValue, height: self.slider!.sliderHeight) | ||
| 113 | + self.slider?.frame = self.bounds | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + // MARK: - initUI | ||
| 117 | + func initUI(){ | ||
| 118 | + self.totalView = UIView() | ||
| 119 | + self.totalView?.backgroundColor = (self.totalColor != nil) ? self.totalColor : UIColor(white: 1, alpha: 0.2) | ||
| 120 | + self.addSubview(self.totalView!) | ||
| 121 | + | ||
| 122 | + self.bufferView = UIView() | ||
| 123 | + self.bufferView?.backgroundColor = (self.bufferColor != nil) ? self.bufferColor : UIColor(white: 1, alpha: 0.4) | ||
| 124 | + self.addSubview(self.bufferView!) | ||
| 125 | + | ||
| 126 | + self.slider = CNLivePlayerSlider() | ||
| 127 | + self.slider!.minimumTrackTintColor = (self.currentColor != nil) ? self.currentColor : UIColor(white: 1, alpha: 1) | ||
| 128 | + self.slider!.maximumTrackTintColor = .clear | ||
| 129 | + self.slider?.setThumbImage(self.getSlideBlockImage(), for: .normal) | ||
| 130 | + self.slider?.addTarget(self, action: #selector(sliderWillDragging), for: .touchDown) | ||
| 131 | + self.slider?.addTarget(self, action: #selector(sliderValueChanged), for: .valueChanged) | ||
| 132 | + self.slider?.addTarget(self, action: #selector(sliderEndDragging), for: .touchUpInside) | ||
| 133 | + self.slider?.addTarget(self, action: #selector(sliderEndDragging), for: .touchUpOutside) | ||
| 134 | + self.addSubview(self.slider!) | ||
| 135 | + } | ||
| 136 | + // MARK: - 触发事件 | ||
| 137 | + @objc func sliderWillDragging(){ | ||
| 138 | + self.isDraggingSlideBlock = true | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + @objc func sliderValueChanged(){ | ||
| 142 | + self.changeSliderValueCallBack!(CGFloat(self.slider!.value)) | ||
| 143 | + | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + @objc func sliderEndDragging(){ | ||
| 147 | + self.isDraggingSlideBlock = false | ||
| 148 | + self.endChangeSliderValueCallBack!(CGFloat(self.slider!.value)) | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // MARK: - 获取滑块图片 | ||
| 152 | + func getSlideBlockImage()->UIImage{ | ||
| 153 | + | ||
| 154 | + UIGraphicsBeginImageContextWithOptions(CGSizeMake(18, 18), false, 0) | ||
| 155 | + let context = UIGraphicsGetCurrentContext() | ||
| 156 | + context?.setFillColor(UIColor.white.cgColor) | ||
| 157 | + let rect = CGRect(x: 0, y: 0, width: 18, height: 18) | ||
| 158 | + context?.addEllipse(in: rect) | ||
| 159 | + context?.fillPath() | ||
| 160 | + let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() | ||
| 161 | + return image | ||
| 162 | + } | ||
| 163 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerProgressView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerProgressView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerProgressView:UIView{ | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + 全部进度颜色 | ||
| 14 | + */ | ||
| 15 | + var _totalColor:UIColor? | ||
| 16 | + var totalColor:UIColor?{ | ||
| 17 | + get{ | ||
| 18 | + _totalColor | ||
| 19 | + } | ||
| 20 | + set{ | ||
| 21 | + _totalColor = newValue | ||
| 22 | + self.backgroundColor = (_totalColor != nil) ? _totalColor : UIColor(white: 1, alpha: 0.2) | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | + /** | ||
| 26 | + 缓冲进度颜色 | ||
| 27 | + */ | ||
| 28 | + var _bufferColor:UIColor? | ||
| 29 | + var bufferColor:UIColor?{ | ||
| 30 | + get{ | ||
| 31 | + _bufferColor | ||
| 32 | + } | ||
| 33 | + set{ | ||
| 34 | + _bufferColor = newValue | ||
| 35 | + self.bufferView.backgroundColor = (_bufferColor != nil) ? _bufferColor : UIColor(white: 1, alpha: 0.4) | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + /** | ||
| 39 | + 当前进度颜色 | ||
| 40 | + */ | ||
| 41 | + var _currentColor:UIColor? | ||
| 42 | + var currentColor:UIColor?{ | ||
| 43 | + get{ | ||
| 44 | + _currentColor | ||
| 45 | + } | ||
| 46 | + set{ | ||
| 47 | + _currentColor = newValue | ||
| 48 | + self.progressView.backgroundColor = (_currentColor != nil) ? _currentColor : UIColor(white: 1, alpha: 1) | ||
| 49 | + } | ||
| 50 | + } | ||
| 51 | + /** | ||
| 52 | + 缓冲 0~1 | ||
| 53 | + */ | ||
| 54 | + var _bufferValue:CGFloat = 0.0 | ||
| 55 | + var bufferValue:CGFloat{ | ||
| 56 | + get{ | ||
| 57 | + _bufferValue | ||
| 58 | + } | ||
| 59 | + set{ | ||
| 60 | + _bufferValue = newValue | ||
| 61 | + if (_bufferValue > 1) { | ||
| 62 | + _bufferValue = 1 | ||
| 63 | + }else if (_bufferValue < 0) { | ||
| 64 | + _bufferValue = 0 | ||
| 65 | + } | ||
| 66 | + var bufferViewFrame = self.bufferView.frame | ||
| 67 | + bufferViewFrame.size.width = self.frame.size.width * _bufferValue | ||
| 68 | + self.bufferView.frame = bufferViewFrame | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + /** | ||
| 72 | + 进度 0~1 | ||
| 73 | + */ | ||
| 74 | + var _value:CGFloat = 0.0 | ||
| 75 | + var value:CGFloat{ | ||
| 76 | + get{ | ||
| 77 | + _value | ||
| 78 | + } | ||
| 79 | + set{ | ||
| 80 | + _value = newValue | ||
| 81 | + if (_value > 1) { | ||
| 82 | + _value = 1 | ||
| 83 | + }else if (_value < 0) { | ||
| 84 | + _value = 0 | ||
| 85 | + } | ||
| 86 | + var progressViewFrame = self.progressView.frame | ||
| 87 | + progressViewFrame.size.width = self.frame.size.width * _value | ||
| 88 | + self.progressView.frame = progressViewFrame | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + //缓冲view | ||
| 92 | + lazy var bufferView :UIView = { | ||
| 93 | + let bufferView = UIView(frame: CGRect(x: 0, y: 0, width: self.width*self.bufferValue, height: self.height)) | ||
| 94 | + bufferView.backgroundColor = (self.bufferColor != nil) ? self.bufferColor : UIColor(white: 1, alpha: 0.4) | ||
| 95 | + return bufferView | ||
| 96 | + }() | ||
| 97 | + | ||
| 98 | + //进度view | ||
| 99 | + lazy var progressView :UIView = { | ||
| 100 | + let progressView = UIView(frame: CGRect(x: 0, y: 0, width: self.width*self.value, height: self.height)) | ||
| 101 | + progressView.backgroundColor = (self.currentColor != nil) ? self.currentColor : UIColor(white: 1, alpha: 1) | ||
| 102 | + return progressView | ||
| 103 | + }() | ||
| 104 | + | ||
| 105 | + // MARK: - init | ||
| 106 | + init() { | ||
| 107 | + super.init(frame: CGRectZero) | ||
| 108 | + self.backgroundColor = UIColor(white: 1, alpha: 0.2) | ||
| 109 | + self.initUI() | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + required init?(coder: NSCoder) { | ||
| 113 | + fatalError("init(coder:) has not been implemented") | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + override init(frame: CGRect) { | ||
| 117 | + super.init(frame: frame) | ||
| 118 | + self.backgroundColor = UIColor(white: 1, alpha: 0.2) | ||
| 119 | + self.initUI() | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + override func layoutSubviews() { | ||
| 123 | + super.layoutSubviews() | ||
| 124 | + self.bufferView.frame = CGRect(x: 0, y: 0, width: self.width * self.bufferValue, height: self.height) | ||
| 125 | + self.progressView.frame = CGRect(x: 0, y: 0, width: self.width * self.value, height: self.height) | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + // MARK: - initUI | ||
| 129 | + func initUI(){ | ||
| 130 | + self.addSubview(self.bufferView) | ||
| 131 | + self.addSubview(self.progressView) | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerSlider.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerSlider.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/27. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerSlider:UISlider{ | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + 滑动条的高度 | ||
| 14 | + */ | ||
| 15 | + var _sliderHeight:CGFloat = 0.0 | ||
| 16 | + var sliderHeight:CGFloat{ | ||
| 17 | + get{ | ||
| 18 | + if _sliderHeight == 0{ | ||
| 19 | + _sliderHeight = 2 | ||
| 20 | + } | ||
| 21 | + return _sliderHeight | ||
| 22 | + } | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + override func trackRect(forBounds bounds: CGRect) -> CGRect { | ||
| 26 | + return CGRect(x: 0, y: (self.frame.size.height-self.sliderHeight)/2, width: self.frame.size.width, height: self.sliderHeight) | ||
| 27 | + } | ||
| 28 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerTopNaviView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerTopNaviView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerTopNaviView:UIView{ | ||
| 11 | + | ||
| 12 | + // MARK: - UI | ||
| 13 | + /// 阴影背景 | ||
| 14 | + var bgGradientView:CNLiveGradientView? | ||
| 15 | + /// 时间 横屏显示 | ||
| 16 | + var timeLab:UILabel? | ||
| 17 | + /// 电量 横屏显示 | ||
| 18 | + var batteryImageView:UILabel? | ||
| 19 | + /// 电量框 横屏显示 | ||
| 20 | + var batteryFrameImageView:UILabel? | ||
| 21 | + /// 网络状态 横屏显示 | ||
| 22 | + var netStatusLab:UILabel? | ||
| 23 | + /// 返回按钮 | ||
| 24 | + var backBtn:UIButton? | ||
| 25 | + /// 返回按钮图片 | ||
| 26 | + var backImageView:UIImageView? | ||
| 27 | + /// 标题 | ||
| 28 | + var titleLab:UILabel? | ||
| 29 | + | ||
| 30 | + // MARK: - 属性 | ||
| 31 | + /// 是否是横屏 | ||
| 32 | + var isLandscape:Bool? | ||
| 33 | + | ||
| 34 | + // MARK: - 回调 | ||
| 35 | + /// 点击返回回调 | ||
| 36 | + var clickBackCallBack:clickBackCallBackBlock? | ||
| 37 | + | ||
| 38 | + // MARK: - init | ||
| 39 | + init() { | ||
| 40 | + super.init(frame: CGRectZero) | ||
| 41 | + self.initUI() | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + required init?(coder: NSCoder) { | ||
| 45 | + fatalError("init(coder:) has not been implemented") | ||
| 46 | + } | ||
| 47 | + override func layoutSubviews() { | ||
| 48 | + super.layoutSubviews() | ||
| 49 | + self.bgGradientView?.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 50 | + self.backBtn?.frame = CGRect(x: self.isLandscape! ? KStatusBarHeight : 5, y: self.height-44, width: 44, height: 44) | ||
| 51 | + self.backImageView?.frame = CGRect(x: (self.backBtn!.width-22)/2, y: (self.backBtn!.height-22)/2, width: 22, height: 22) | ||
| 52 | + } | ||
| 53 | + // MARK: - initUI | ||
| 54 | + func initUI(){ | ||
| 55 | + self.bgGradientView = CNLiveGradientView() | ||
| 56 | + self.bgGradientView?.colors = [UIColor(white: 0, alpha: 0.4),UIColor(white: 0, alpha: 0)] | ||
| 57 | + self.bgGradientView?.startPoint = CGPoint(x: 0.5, y: 0) | ||
| 58 | + self.bgGradientView?.endPoint = CGPoint(x: 0.5, y: 1) | ||
| 59 | + self.bgGradientView?.opacity = 1 | ||
| 60 | + self.addSubview(self.bgGradientView!) | ||
| 61 | + | ||
| 62 | + self.backBtn = UIButton(type: .custom) | ||
| 63 | + self.backBtn?.addTarget(self, action: #selector(backBtnClick), for: .touchUpInside) | ||
| 64 | + self.addSubview(self.backBtn!) | ||
| 65 | + | ||
| 66 | + self.backImageView = UIImageView() | ||
| 67 | + self.backImageView?.clipsToBounds = true | ||
| 68 | + self.backImageView?.contentMode = .scaleAspectFit | ||
| 69 | + self.backImageView?.image = UIImage(named: "DS_player_nav_back") | ||
| 70 | + self.backBtn?.addSubview(self.backImageView!) | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + // MARK: - 触发事件 | ||
| 76 | + @objc func backBtnClick(){ | ||
| 77 | + self.clickBackCallBack!() | ||
| 78 | + } | ||
| 79 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | +import PLPlayerKit | ||
| 10 | +import UIKit | ||
| 11 | + | ||
| 12 | +typealias popCallBackBlock = () -> Void | ||
| 13 | +typealias playerPausedCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 14 | +typealias playerPlayingCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 15 | +typealias playerDidToEndCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 16 | +typealias switchAlphaMessageStateCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 17 | +typealias switchLockScreenCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 18 | +typealias switchInterfaceOrientationCallBackBlock = (_ playerView: CNLivePlayerView) -> Void | ||
| 19 | + | ||
| 20 | +let kDSPlayerAnimateTimeInterval = 0.25//动画时间 | ||
| 21 | + | ||
| 22 | +class CNLivePlayerView:UIView,PLPlayerDelegate{ | ||
| 23 | + | ||
| 24 | + // MARK: - 播放设置 | ||
| 25 | + /// 初始化视频链接地址 为空为停止播放 | ||
| 26 | + var playUrl:URL? | ||
| 27 | + /// 视频链接是否为直播 | ||
| 28 | + var isLive:Bool? | ||
| 29 | + | ||
| 30 | + // MARK: - 播放属性 | ||
| 31 | + /// 是否循环播放(默认NO) | ||
| 32 | + var _isLoopPlay:Bool? | ||
| 33 | + var isLoopPlay:Bool?{ | ||
| 34 | + get{ | ||
| 35 | + _isLoopPlay | ||
| 36 | + } | ||
| 37 | + set{ | ||
| 38 | + _isLoopPlay = newValue | ||
| 39 | + if self.isLive!{ | ||
| 40 | + return | ||
| 41 | + } | ||
| 42 | + self.player?.loopPlay = _isLoopPlay! | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /// 开始播放时间 | ||
| 47 | + var startPlayTime:Double? | ||
| 48 | + /// 获取播放时间 | ||
| 49 | + func getPlayTime() -> Double{ | ||
| 50 | + return CMTimeGetSeconds(self.player!.currentTime) | ||
| 51 | + } | ||
| 52 | + /// 是否播放完成 | ||
| 53 | + var isPlayEnd:Bool? | ||
| 54 | + /// 是否用户手动暂停 | ||
| 55 | + var isUserStop:Bool? | ||
| 56 | + /// 控制器是否在进行disappear | ||
| 57 | + var _viewControllerIsDisappear:Bool? | ||
| 58 | + var viewControllerIsDisappear:Bool?{ | ||
| 59 | + get{ | ||
| 60 | + _viewControllerIsDisappear | ||
| 61 | + } | ||
| 62 | + set{ | ||
| 63 | + if (_viewControllerIsDisappear == true && viewControllerIsDisappear == false) { | ||
| 64 | + self.play() | ||
| 65 | + }else if (_viewControllerIsDisappear == false && viewControllerIsDisappear == true) { | ||
| 66 | + self.pauseWithIsRemoveKVOsAndNotifications(isRemove: true) | ||
| 67 | + } | ||
| 68 | + _viewControllerIsDisappear = newValue | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + | ||
| 73 | + // MARK: - 回调 | ||
| 74 | + /// 点击返回回调 | ||
| 75 | + var popCallBack:popCallBackBlock? | ||
| 76 | + /// 播放器暂停回调 | ||
| 77 | + var playerPausedCallBack:playerPausedCallBackBlock? | ||
| 78 | + /// 播放器继续播放回调 | ||
| 79 | + var playerPlayingCallBack:playerPlayingCallBackBlock? | ||
| 80 | + /// 播放完成回调 如果isLoopPlay==YES,播放完成时请调用stop方法 否则该类释放不掉 | ||
| 81 | + var playerDidToEndCallBack:playerDidToEndCallBackBlock? | ||
| 82 | + /// 隐藏/显示视频上面的控件回调 | ||
| 83 | + var switchAlphaMessageStateCallBack:switchAlphaMessageStateCallBackBlock? | ||
| 84 | + /// 锁屏/解锁屏回调 | ||
| 85 | + var switchLockScreenCallBack:switchLockScreenCallBackBlock? | ||
| 86 | + | ||
| 87 | + // MARK: - 预览界面 | ||
| 88 | + /// 预览界面 包含视频视图 控件视图 | ||
| 89 | + lazy var previewView :UIView = { | ||
| 90 | + let previewView = UIView() | ||
| 91 | + previewView.backgroundColor = .black | ||
| 92 | + previewView.clipsToBounds = true | ||
| 93 | + return previewView | ||
| 94 | + }() | ||
| 95 | + | ||
| 96 | + /// 控件视图 | ||
| 97 | + lazy var controlView :CNLivePlayerControlView = { | ||
| 98 | + let controlView = CNLivePlayerControlView() | ||
| 99 | + controlView.clickBackBtnAction = {[weak self] in | ||
| 100 | + if self?.controlView.isFullScreen == true{ | ||
| 101 | + self?.currentOrientation = .portrait | ||
| 102 | + }else{ | ||
| 103 | + self?.popCallBack!() | ||
| 104 | + currentViewController()?.navigationController?.popViewController(animated: false) | ||
| 105 | + } | ||
| 106 | + } | ||
| 107 | + controlView.clickFrameBtnAction = {[weak self] in | ||
| 108 | + if self?.controlView.isFullScreen == true{ | ||
| 109 | + self?.currentOrientation = .portrait | ||
| 110 | + }else{ | ||
| 111 | + self?.currentOrientation = .landscapeRight | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + controlView.clickPlayBtnAction = {[weak self] in | ||
| 115 | + self?.isUserStop = false | ||
| 116 | + self?.play() | ||
| 117 | + } | ||
| 118 | + controlView.clickPauseBtnAction = {[weak self] in | ||
| 119 | + self?.isUserStop = true | ||
| 120 | + self?.pauseWithIsRemoveKVOsAndNotifications(isRemove: false) | ||
| 121 | + } | ||
| 122 | + controlView.clickRefreshBtnAction = {[weak self] in | ||
| 123 | + if !(self?.isLocalUrl)! { | ||
| 124 | + showMessage(message: "当前网络不可用") | ||
| 125 | + return | ||
| 126 | + } | ||
| 127 | + self?.play() | ||
| 128 | + } | ||
| 129 | + controlView.switchAlphaMessageStateCallBack = {[weak self] in | ||
| 130 | + self?.switchAlphaMessageStateCallBack!(self!) | ||
| 131 | + } | ||
| 132 | + controlView.switchLockScreenCallBack = {[weak self] in | ||
| 133 | + self?.switchLockScreenCallBack!(self!) | ||
| 134 | + } | ||
| 135 | + return controlView | ||
| 136 | + }() | ||
| 137 | + | ||
| 138 | + // MARK: - 屏幕方向 | ||
| 139 | + /// 是否开启检测设备转屏 默认开启 | ||
| 140 | + var _isMonitorDeviceOrientation:Bool? | ||
| 141 | + var isMonitorDeviceOrientation:Bool?{ | ||
| 142 | + get{ | ||
| 143 | + _isMonitorDeviceOrientation | ||
| 144 | + } | ||
| 145 | + set{ | ||
| 146 | + _isMonitorDeviceOrientation = newValue | ||
| 147 | + self.removeNotification() | ||
| 148 | + self.registerNotification() | ||
| 149 | + } | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + /// 当前屏幕方向 | ||
| 153 | + var _currentOrientation: UIDeviceOrientation? | ||
| 154 | + var currentOrientation:UIDeviceOrientation?{ | ||
| 155 | + get{ | ||
| 156 | + _currentOrientation | ||
| 157 | + } | ||
| 158 | + set{ | ||
| 159 | + if (_currentOrientation == newValue || | ||
| 160 | + newValue == .unknown || | ||
| 161 | + newValue == .portraitUpsideDown) { | ||
| 162 | + return | ||
| 163 | + } | ||
| 164 | + _currentOrientation = newValue | ||
| 165 | + self.controlView.currentOrientation = _currentOrientation | ||
| 166 | + | ||
| 167 | + if (_currentOrientation == .landscapeLeft || | ||
| 168 | + _currentOrientation == .landscapeRight) { | ||
| 169 | + self.controlView.isFullScreen = true | ||
| 170 | + if self.subviews.contains(self.previewView){ | ||
| 171 | + | ||
| 172 | + let playerViewRect_onWindow = self.previewView.superview?.convert(self.previewView.frame, to: keyWindow) | ||
| 173 | + self.previewView.frame = playerViewRect_onWindow! | ||
| 174 | + keyWindow?.addSubview(self.previewView) | ||
| 175 | + UIView.animate(withDuration: CGFloat(kDSPlayerAnimateTimeInterval)) { | ||
| 176 | + if (self.currentOrientation == .landscapeLeft) { | ||
| 177 | + self.previewView.transform = CGAffineTransformMakeRotation(-.pi/2) | ||
| 178 | + }else { | ||
| 179 | + self.previewView.transform = CGAffineTransformMakeRotation(.pi/2) | ||
| 180 | + } | ||
| 181 | + self.previewView.frame = CGRect(x: 0, y: 0, width: KSreenWidth, height: KSreenHeight) | ||
| 182 | + self.layoutSubviews() | ||
| 183 | + | ||
| 184 | + if (!self.controlView.isAlphaMessage!) { | ||
| 185 | + self.controlView.lockBtn!.alpha = 1 | ||
| 186 | + } | ||
| 187 | + } | ||
| 188 | + }else{ | ||
| 189 | + UIView.animate(withDuration: CGFloat(kDSPlayerAnimateTimeInterval)) { | ||
| 190 | + self.player?.playerView?.transform = CGAffineTransformRotate(self.player!.playerView!.transform, .pi) | ||
| 191 | + self.controlView.transform = CGAffineTransformRotate(self.controlView.transform, .pi) | ||
| 192 | + } completion: { finished in | ||
| 193 | + | ||
| 194 | + self.previewView.transform = CGAffineTransformRotate(self.previewView.transform, .pi) | ||
| 195 | + self.player?.playerView?.transform = CGAffineTransformIdentity | ||
| 196 | + self.controlView.transform = CGAffineTransformIdentity | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | + let landscapeVC = CNLivePlayerLandscapeViewController() | ||
| 200 | + if _currentOrientation == .landscapeLeft{ | ||
| 201 | + landscapeVC.interfaceOrientationMask = .landscapeLeft | ||
| 202 | + }else{ | ||
| 203 | + landscapeVC.interfaceOrientationMask = .landscapeRight | ||
| 204 | + } | ||
| 205 | + | ||
| 206 | + self.fakeWindow!.rootViewController = landscapeVC | ||
| 207 | + }else { | ||
| 208 | + self.controlView.isFullScreen = false | ||
| 209 | + let playerViewRect_onWindow = (self.superview?.convert(self.frame, to: keyWindow))! | ||
| 210 | + UIView.animate(withDuration: CGFloat(kDSPlayerAnimateTimeInterval)) { | ||
| 211 | + self.previewView.transform = CGAffineTransformIdentity | ||
| 212 | + self.player?.playerView?.transform = CGAffineTransformIdentity | ||
| 213 | + self.controlView.transform = CGAffineTransformIdentity | ||
| 214 | + self.previewView.frame = playerViewRect_onWindow | ||
| 215 | + self.layoutSubviews() | ||
| 216 | + | ||
| 217 | + self.controlView.lockBtn!.alpha = 0 | ||
| 218 | + } completion: { finished in | ||
| 219 | + self.previewView.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 220 | + self.previewView.removeFromSuperview() | ||
| 221 | + self.insertSubview(self.previewView, at: 0) | ||
| 222 | + } | ||
| 223 | + let landscapeVC = CNLivePlayerLandscapeViewController() | ||
| 224 | + landscapeVC.interfaceOrientationMask = .portrait | ||
| 225 | + self.fakeWindow!.rootViewController = landscapeVC | ||
| 226 | + } | ||
| 227 | + self.switchInterfaceOrientationCallBack!(self) | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + /// 修改屏幕方向回调 | ||
| 232 | + var switchInterfaceOrientationCallBack:switchInterfaceOrientationCallBackBlock? | ||
| 233 | + | ||
| 234 | + //临时window | ||
| 235 | + var _fakeWindow:UIWindow? | ||
| 236 | + var fakeWindow:UIWindow?{ | ||
| 237 | + get{ | ||
| 238 | + if (_fakeWindow == nil) { | ||
| 239 | + if #available(iOS 13.0, *) { | ||
| 240 | + var windowScene:UIWindowScene? = nil | ||
| 241 | + for scene in UIApplication.shared.connectedScenes { | ||
| 242 | + if scene.activationState == .foregroundActive{ | ||
| 243 | + windowScene = scene as? UIWindowScene | ||
| 244 | + } | ||
| 245 | + if ((windowScene == nil) && UIApplication.shared.connectedScenes.count == 1) { | ||
| 246 | + windowScene = scene as? UIWindowScene | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + if (windowScene != nil){ | ||
| 250 | + _fakeWindow = UIWindow(windowScene: windowScene!) | ||
| 251 | + }else{ | ||
| 252 | + _fakeWindow = UIWindow(frame: CGRectZero) | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + }else { | ||
| 256 | + _fakeWindow = UIWindow(frame: CGRectZero) | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | + return _fakeWindow | ||
| 260 | + } | ||
| 261 | + set{ | ||
| 262 | + _fakeWindow = newValue | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + //播放器 | ||
| 267 | + var player:PLPlayer? | ||
| 268 | + //定时器 | ||
| 269 | + var timer:DispatchSourceTimer? | ||
| 270 | + //通知数组 | ||
| 271 | + lazy var notifications :NSMutableArray = { | ||
| 272 | + let notifications = NSMutableArray() | ||
| 273 | + return notifications | ||
| 274 | + }() | ||
| 275 | + | ||
| 276 | + //KVO数组 | ||
| 277 | + lazy var KVOs :NSMutableArray = { | ||
| 278 | + let KVOs = NSMutableArray() | ||
| 279 | + return KVOs | ||
| 280 | + }() | ||
| 281 | + //是否是本地的url | ||
| 282 | + var isLocalUrl:Bool? | ||
| 283 | + | ||
| 284 | + /// 初始化视频 | ||
| 285 | + /// @param playUrl 视频链接地址 为空为停止播放 | ||
| 286 | + /// @param isLive 是否为直播 | ||
| 287 | + // MARK: - 播放设置 | ||
| 288 | + func setPlayUrl(playUrl:URL,isLive:Bool){ | ||
| 289 | + self.stop() | ||
| 290 | + self.playUrl = playUrl | ||
| 291 | + self.isLive = isLive | ||
| 292 | + if self.playUrl?.scheme == "file"{ | ||
| 293 | + self.isLocalUrl = true | ||
| 294 | + }else { | ||
| 295 | + self.isLocalUrl = false | ||
| 296 | + } | ||
| 297 | + self.controlView.coverImageView?.alpha = 1 | ||
| 298 | + let option = PLPlayerOption.default() | ||
| 299 | + var format = kPLPLAY_FORMAT_UnKnown | ||
| 300 | + let urlString = self.playUrl?.absoluteString.lowercased() | ||
| 301 | + if urlString!.hasSuffix(".mp4"){ | ||
| 302 | + format = kPLPLAY_FORMAT_MP4 | ||
| 303 | + }else if urlString!.hasPrefix("rtmp:"){ | ||
| 304 | + format = kPLPLAY_FORMAT_FLV | ||
| 305 | + }else if urlString!.hasSuffix(".mp3") { | ||
| 306 | + format = kPLPLAY_FORMAT_MP3 | ||
| 307 | + }else if urlString!.hasSuffix(".m3u8") { | ||
| 308 | + format = kPLPLAY_FORMAT_M3U8 | ||
| 309 | + }else if urlString!.hasSuffix(".aac") { | ||
| 310 | + format = kPLPLAY_FORMAT_AAC | ||
| 311 | + } | ||
| 312 | + option.setOptionValue(format, forKey: PLPlayerOptionKeyVideoPreferFormat) | ||
| 313 | + option.setOptionValue(kPLLogNone, forKey: PLPlayerOptionKeyLogLevel) | ||
| 314 | + if self.isLive!{ | ||
| 315 | + self.player = PLPlayer(liveWith: self.playUrl as URL?, option: nil) | ||
| 316 | + self.player?.loopPlay = false | ||
| 317 | + self.controlView.bottomNaviView?.isHidden = false | ||
| 318 | + self.controlView.bottomNaviView?.playBtn?.isHidden = false | ||
| 319 | + self.controlView.bottomNaviView?.progressSlider?.isHidden = true | ||
| 320 | + self.controlView.bottomNaviView?.timeLab?.isHidden = true | ||
| 321 | + self.controlView.bottomNaviView?.frameBtn?.isHidden = false | ||
| 322 | + self.controlView.bottomProgressView?.isHidden = true | ||
| 323 | + }else{ | ||
| 324 | + self.player = PLPlayer(url: self.playUrl, option: nil) | ||
| 325 | + self.player!.loopPlay = self.isLoopPlay! | ||
| 326 | + | ||
| 327 | + self.controlView.bottomNaviView?.isHidden = false | ||
| 328 | + self.controlView.bottomNaviView?.playBtn!.isHidden = false | ||
| 329 | + self.controlView.bottomNaviView?.progressSlider!.isHidden = false | ||
| 330 | + self.controlView.bottomNaviView?.timeLab!.isHidden = false | ||
| 331 | + self.controlView.bottomNaviView!.frameBtn!.isHidden = false | ||
| 332 | + self.controlView.bottomProgressView!.isHidden = false | ||
| 333 | + } | ||
| 334 | + self.controlView.player = self.player | ||
| 335 | + self.controlView.isLive = self.isLive | ||
| 336 | + | ||
| 337 | + self.player!.delegateQueue = DispatchQueue.main | ||
| 338 | + self.player!.delegate = self | ||
| 339 | + self.player!.rotationMode = .noRotation | ||
| 340 | + self.player!.playerView!.contentMode = .scaleAspectFit | ||
| 341 | + self.player!.playerView!.backgroundColor = .black | ||
| 342 | + self.previewView.insertSubview(self.player!.playerView!, at: 0) | ||
| 343 | + self.layoutSubviews() | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + /// 结束播放 如果isLoopPlay==YES,播放完成时请调用stop方法 否则该类释放不掉 | ||
| 347 | + func stop(){ | ||
| 348 | + if self.player?.playerView?.superview != nil{ | ||
| 349 | + self.player?.playerView?.removeFromSuperview() | ||
| 350 | + } | ||
| 351 | + self.player?.stop() | ||
| 352 | + self.resetUIProperty() | ||
| 353 | + self.removeKVOsAndNotifications() | ||
| 354 | + } | ||
| 355 | + | ||
| 356 | + /// 暂停播放 | ||
| 357 | + /// @param isRemove 是否删除kvo、通知、定时器 | ||
| 358 | + func pauseWithIsRemoveKVOsAndNotifications(isRemove:Bool){ | ||
| 359 | + self.player?.pause() | ||
| 360 | + if isRemove{ | ||
| 361 | + self.removeKVOsAndNotifications() | ||
| 362 | + } | ||
| 363 | + } | ||
| 364 | + | ||
| 365 | + // MARK: - 播放状态 | ||
| 366 | + /// 开始/继续播放 | ||
| 367 | + func play(){ | ||
| 368 | +// if (![DSCommonManager sharedManager].isAllowPlayVideo) { | ||
| 369 | +// DS_showMessage(@"暂时无法播放视频"); | ||
| 370 | +// return; | ||
| 371 | +// } | ||
| 372 | + if (self.player!.status == .statusPlaying) { | ||
| 373 | + return | ||
| 374 | + } | ||
| 375 | + | ||
| 376 | + if (self.playUrl == nil) { | ||
| 377 | + return | ||
| 378 | + } | ||
| 379 | + | ||
| 380 | + self.controlView.failureView?.isHidden = true | ||
| 381 | + self.registerNotification() | ||
| 382 | + self.initTimer() | ||
| 383 | + | ||
| 384 | + self.controlView.gestureView?.private_style = .nonePrivate | ||
| 385 | + self.controlView.bottomNaviView?.progressSlider?.isUserInteractionEnabled = true | ||
| 386 | + | ||
| 387 | + if (self.player!.status == .statusPaused) { | ||
| 388 | + self.player?.resume() | ||
| 389 | + }else { | ||
| 390 | + self.player?.play() | ||
| 391 | + } | ||
| 392 | + } | ||
| 393 | + | ||
| 394 | + // MARK: - 定时器 | ||
| 395 | + func initTimer(){ | ||
| 396 | + self.invalidateTimer() | ||
| 397 | + let timeInterval = 0.01 | ||
| 398 | + self.timer = CNLiveTimer.bk_setupTimerWithTimeInterval(timeInterval: timeInterval, totalTime: kBKTimerRepeatsTime, handler: { [weak self] timer, lastTime in | ||
| 399 | + self?.controlView.timerTriggeringMethod(timeInterval: timeInterval) | ||
| 400 | + }) | ||
| 401 | + } | ||
| 402 | + func invalidateTimer(){ | ||
| 403 | + CNLiveTimer.bk_removeTimer(timer: self.timer!) | ||
| 404 | + } | ||
| 405 | + | ||
| 406 | + // MARK: - 初始化界面 | ||
| 407 | + func resetUIProperty(){ | ||
| 408 | + self.playUrl = nil | ||
| 409 | + self.controlView.bottomNaviView?.playBtn?.isHidden = true | ||
| 410 | + self.controlView.bottomNaviView?.progressSlider?.isHidden = true | ||
| 411 | + self.controlView.bottomNaviView?.progressSlider?.value = 0 | ||
| 412 | + self.controlView.bottomNaviView?.progressSlider?.bufferValue = 0 | ||
| 413 | + self.controlView.bottomNaviView?.timeLab?.isHidden = true | ||
| 414 | + self.controlView.bottomNaviView?.timeLab?.text = "00:00/00:00" | ||
| 415 | + self.controlView.bottomNaviView?.timeStyle = .MM_SS | ||
| 416 | + self.controlView.bottomNaviView?.frameBtn?.isHidden = true | ||
| 417 | + self.controlView.bottomNaviView?.isHidden = true | ||
| 418 | + self.controlView.bottomProgressView?.value = 0 | ||
| 419 | + self.controlView.bottomProgressView?.bufferValue = 0 | ||
| 420 | + self.controlView.gestureView?.style = .none | ||
| 421 | + } | ||
| 422 | + | ||
| 423 | + // MARK: - 删除kvo、通知、定时器 | ||
| 424 | + func removeKVOsAndNotifications(){ | ||
| 425 | + self.controlView.loadingView?.stopAnimate() | ||
| 426 | + self.removeNotification() | ||
| 427 | + self.invalidateTimer() | ||
| 428 | + } | ||
| 429 | + | ||
| 430 | + // MARK: - init | ||
| 431 | + init() { | ||
| 432 | + super.init(frame: CGRectZero) | ||
| 433 | + self.initializeThings() | ||
| 434 | + } | ||
| 435 | + override init(frame: CGRect) { | ||
| 436 | + super.init(frame: frame) | ||
| 437 | + self.initializeThings() | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + required init?(coder: NSCoder) { | ||
| 441 | + fatalError("init(coder:) has not been implemented") | ||
| 442 | + } | ||
| 443 | + func initializeThings(){ | ||
| 444 | + self.isMonitorDeviceOrientation = true | ||
| 445 | + self.backgroundColor = .black | ||
| 446 | + self.initUI() | ||
| 447 | + } | ||
| 448 | + deinit { | ||
| 449 | + self.stop() | ||
| 450 | + for obj in self.subviews{ | ||
| 451 | + obj.removeFromSuperview() | ||
| 452 | + } | ||
| 453 | + self.removeFromSuperview() | ||
| 454 | + | ||
| 455 | + } | ||
| 456 | + | ||
| 457 | + // MARK: - layoutSubviews | ||
| 458 | + override func layoutSubviews() { | ||
| 459 | + super.layoutSubviews() | ||
| 460 | + if self.subviews.contains(self.previewView){ | ||
| 461 | + self.previewView.frame = CGRect(x: 0, y: 0, width: self.width, height: self.height) | ||
| 462 | + } | ||
| 463 | + self.player?.playerView?.frame = CGRect(x: 0, y: 0, width: self.previewView.bounds.size.width, height: self.previewView.bounds.size.height) | ||
| 464 | + self.controlView.frame = CGRect(x: 0, y: 0, width: self.previewView.bounds.size.width, height: self.previewView.bounds.size.height) | ||
| 465 | + } | ||
| 466 | + | ||
| 467 | + // MARK: - initUI | ||
| 468 | + func initUI(){ | ||
| 469 | + self.addSubview(self.previewView) | ||
| 470 | + self.previewView.addSubview(self.controlView) | ||
| 471 | + } | ||
| 472 | + | ||
| 473 | + // MARK: - PLPlayerDelegate | ||
| 474 | + /** | ||
| 475 | + 告知代理对象播放器状态变更 | ||
| 476 | + */ | ||
| 477 | + func player(_ player: PLPlayer, statusDidChange state: PLPlayerStatus) { | ||
| 478 | + DispatchQueue.main.async { | ||
| 479 | + switch (state){ | ||
| 480 | + case .statusUnknow:break | ||
| 481 | + case .statusOpen: | ||
| 482 | + self.controlView.loadingView?.stopAnimate() | ||
| 483 | + break | ||
| 484 | + case .statusPreparing: | ||
| 485 | + self.controlView.loadingView?.startAnimate() | ||
| 486 | + self.controlView.bottomNaviView?.isUserInteractionEnabled = false | ||
| 487 | + break | ||
| 488 | + case .statusReady: | ||
| 489 | + self.controlView.loadingView?.startAnimate() | ||
| 490 | + break | ||
| 491 | + case .statusCaching: | ||
| 492 | + self.controlView.loadingView?.startAnimate() | ||
| 493 | + break | ||
| 494 | + case .statusPlaying: | ||
| 495 | + self.controlView.loadingView?.stopAnimate() | ||
| 496 | + self.isPlayEnd = false | ||
| 497 | + self.controlView.coverImageView?.alpha = 0 | ||
| 498 | + self.controlView.bottomNaviView?.isUserInteractionEnabled = true | ||
| 499 | + self.controlView.circlePlayBtn?.setBackgroundImage(UIImage(named: "DS_player_circle_pause"), for: .normal) | ||
| 500 | + self.controlView.bottomNaviView?.playImageView!.image = UIImage(named: "DS_player_pause") | ||
| 501 | + self.playerPlayingCallBack!(self) | ||
| 502 | + if self.startPlayTime! > 0{ | ||
| 503 | + self.controlView.loadingView?.startAnimate() | ||
| 504 | + self.player?.seek(to: CMTime(value: CMTimeValue(Int(self.startPlayTime!)*30), timescale: 30)) | ||
| 505 | + self.startPlayTime = 0 | ||
| 506 | + } | ||
| 507 | + break | ||
| 508 | + case .statusPaused: | ||
| 509 | + self.controlView.loadingView?.stopAnimate() | ||
| 510 | + self.controlView.circlePlayBtn?.setBackgroundImage(UIImage(named: "DS_player_circle_start"), for: .normal) | ||
| 511 | + self.controlView.bottomNaviView?.playImageView!.image = UIImage(named: "DS_player_start") | ||
| 512 | + self.playerPausedCallBack!(self) | ||
| 513 | + break | ||
| 514 | + case .statusStopped: | ||
| 515 | + self.controlView.loadingView?.stopAnimate() | ||
| 516 | + break | ||
| 517 | + case .statusError: | ||
| 518 | + self.controlView.loadingView?.stopAnimate() | ||
| 519 | + break | ||
| 520 | + case .stateAutoReconnecting: | ||
| 521 | + self.controlView.loadingView?.startAnimate() | ||
| 522 | + break | ||
| 523 | + case .statusCompleted: | ||
| 524 | + self.controlView.loadingView?.stopAnimate() | ||
| 525 | + self.isPlayEnd = true | ||
| 526 | + self.controlView.circlePlayBtn?.setBackgroundImage(UIImage(named: "DS_player_circle_start"), for: .normal) | ||
| 527 | + self.controlView.bottomNaviView?.playImageView!.image = UIImage(named: "DS_player_start") | ||
| 528 | + self.controlView.gestureView?.private_style = .none | ||
| 529 | + self.controlView.bottomNaviView?.progressSlider?.isUserInteractionEnabled = false | ||
| 530 | + self.playerDidToEndCallBack!(self) | ||
| 531 | + break | ||
| 532 | + @unknown default: break | ||
| 533 | + | ||
| 534 | + } | ||
| 535 | + } | ||
| 536 | + } | ||
| 537 | + | ||
| 538 | + /** | ||
| 539 | + 告知代理对象播放器因错误停止播放 | ||
| 540 | + */ | ||
| 541 | + func player(_ player: PLPlayer, stoppedWithError error: Error?) { | ||
| 542 | + DispatchQueue.main.async { [weak self] in | ||
| 543 | + self?.controlView.loadingView?.stopAnimate() | ||
| 544 | + let delayTime = DispatchTime.now() | ||
| 545 | + DispatchQueue.main.asyncAfter(deadline: delayTime) { | ||
| 546 | + self?.controlView.failureView?.isHidden = false | ||
| 547 | + if (self?.isLocalUrl == nil || self?.isLocalUrl == false){ | ||
| 548 | + //if (!self.isLocalUrl && [DSNetworkRequest shareClient].netStatus == DSNetworkStatusNotReachable) | ||
| 549 | + self?.controlView.failureView?.errorMessage = "当前网络不可用,请检查网络后重试" | ||
| 550 | + }else{ | ||
| 551 | + self?.controlView.failureView?.errorMessage = "视频加载失败" | ||
| 552 | + } | ||
| 553 | + } | ||
| 554 | + } | ||
| 555 | + } | ||
| 556 | + | ||
| 557 | + /** | ||
| 558 | + 点播已缓冲区域 | ||
| 559 | + */ | ||
| 560 | + func player(_ player: PLPlayer, loadedTimeRange timeRange: CMTime) { | ||
| 561 | + DispatchQueue.main.async { | ||
| 562 | + let totalSecond = CMTimeGetSeconds(self.player!.totalDuration) | ||
| 563 | + if totalSecond > 0{ | ||
| 564 | + let bufferSecond = CMTimeGetSeconds(timeRange) | ||
| 565 | + self.controlView.bottomNaviView?.progressSlider?.bufferValue = bufferSecond / totalSecond | ||
| 566 | + }else{ | ||
| 567 | + self.controlView.bottomNaviView?.progressSlider?.bufferValue = 0 | ||
| 568 | + } | ||
| 569 | + self.controlView.bottomProgressView?.bufferValue = self.controlView.bottomNaviView!.progressSlider!.bufferValue | ||
| 570 | + } | ||
| 571 | + } | ||
| 572 | + | ||
| 573 | + /** | ||
| 574 | + seekTo 完成的回调通知 | ||
| 575 | + */ | ||
| 576 | + func player(_ player: PLPlayer, seekToCompleted isCompleted: Bool) { | ||
| 577 | + DispatchQueue.main.async { | ||
| 578 | + self.controlView.loadingView?.stopAnimate() | ||
| 579 | + } | ||
| 580 | + } | ||
| 581 | + | ||
| 582 | + func registerNotification(){ | ||
| 583 | + self.removeNotification() | ||
| 584 | + /* | ||
| 585 | + [[DSCommonManager sharedManager] addObserver:self forKeyPath:@"netStatus" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];//网络状态 | ||
| 586 | + DSPlayerKVOModel * model = [[DSPlayerKVOModel alloc] init]; | ||
| 587 | + model.obj = [DSCommonManager sharedManager]; | ||
| 588 | + model.path = @"netStatus"; | ||
| 589 | + [self.KVOs addObject:model]; | ||
| 590 | + | ||
| 591 | + [[DSCommonManager sharedManager] addObserver:self forKeyPath:@"isAllowPlayVideo" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];//不允许播放视频 | ||
| 592 | + DSPlayerKVOModel * model1 = [[DSPlayerKVOModel alloc] init]; | ||
| 593 | + model1.obj = [DSCommonManager sharedManager]; | ||
| 594 | + model1.path = @"isAllowPlayVideo"; | ||
| 595 | + [self.KVOs addObject:model1]; | ||
| 596 | + */ | ||
| 597 | + if self.isMonitorDeviceOrientation!{ | ||
| 598 | + self.addNotificationWithSelector(aSelector: #selector(deviceOrientationDidChangeNotification), aName: UIDevice.orientationDidChangeNotification)//转屏通知 | ||
| 599 | + } | ||
| 600 | + self.addNotificationWithSelector(aSelector: #selector(audioSessionRouteChangeNotification), aName: AVAudioSession.routeChangeNotification)//播放设备切换通知 | ||
| 601 | + self.addNotificationWithSelector(aSelector: #selector(willResignActiveNotification), aName: UIApplication.willResignActiveNotification)//出app | ||
| 602 | + self.addNotificationWithSelector(aSelector: #selector(didBecomeActiveNotification), aName: UIApplication.didBecomeActiveNotification)//回app | ||
| 603 | + | ||
| 604 | + } | ||
| 605 | + | ||
| 606 | + func addNotificationWithSelector(aSelector:Selector,aName:Notification.Name){ | ||
| 607 | + NotificationCenter.default.addObserver(self, selector: aSelector, name: aName, object: nil) | ||
| 608 | + self.notifications.add(aName) | ||
| 609 | + } | ||
| 610 | + | ||
| 611 | + func removeNotification(){ | ||
| 612 | + for kvoMdl in self.KVOs { | ||
| 613 | + let kvoModel = kvoMdl as! CNLivePlayerKVOModel | ||
| 614 | + kvoModel.obj?.removeObserver(self, forKeyPath: kvoModel.path!) | ||
| 615 | + } | ||
| 616 | + self.KVOs.removeAllObjects() | ||
| 617 | + for tempNotificationName in self.notifications { | ||
| 618 | + let notificationName = tempNotificationName as! Notification.Name | ||
| 619 | + NotificationCenter.default.removeObserver(self, name: notificationName, object: nil) | ||
| 620 | + } | ||
| 621 | + self.notifications.removeAllObjects() | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + /** | ||
| 625 | + 转屏通知 | ||
| 626 | + */ | ||
| 627 | + @objc func deviceOrientationDidChangeNotification(){ | ||
| 628 | + DispatchQueue.main.async { | ||
| 629 | + //查看设备方向 | ||
| 630 | + var currentOrientation = UIDevice.current.orientation | ||
| 631 | + //设备方向和屏幕方向一直不操作 设备方向为倒向不操作 锁屏且屏幕方向为正不操作 | ||
| 632 | + if (self.currentOrientation == currentOrientation || currentOrientation == .portraitUpsideDown || | ||
| 633 | + (self.controlView.isLockScreen! && currentOrientation == .portrait)) { | ||
| 634 | + return | ||
| 635 | + } | ||
| 636 | + //修改 | ||
| 637 | + self.currentOrientation = currentOrientation | ||
| 638 | + } | ||
| 639 | + } | ||
| 640 | + | ||
| 641 | + /** | ||
| 642 | + 播放设备切换通知 | ||
| 643 | + */ | ||
| 644 | + @objc func audioSessionRouteChangeNotification(notification:Notification){ | ||
| 645 | + DispatchQueue.main.async { | ||
| 646 | + let reasonValue = notification.userInfo![AVAudioSessionRouteChangeReasonKey] as? Int | ||
| 647 | + //TODO 不知道转成功没有 | ||
| 648 | + let reason = Int(reasonValue ?? 0) | ||
| 649 | + if reason == AVAudioSession.RouteChangeReason.oldDeviceUnavailable.rawValue{ | ||
| 650 | + //耳机拔出停止播放 | ||
| 651 | + self.pauseWithIsRemoveKVOsAndNotifications(isRemove: false) | ||
| 652 | + } | ||
| 653 | + } | ||
| 654 | + } | ||
| 655 | + | ||
| 656 | + /** | ||
| 657 | + 去后台 | ||
| 658 | + */ | ||
| 659 | + @objc func willResignActiveNotification(){ | ||
| 660 | + DispatchQueue.main.async { | ||
| 661 | + self.pauseWithIsRemoveKVOsAndNotifications(isRemove: false) | ||
| 662 | + } | ||
| 663 | + } | ||
| 664 | + | ||
| 665 | + /** | ||
| 666 | + 回来 | ||
| 667 | + */ | ||
| 668 | + @objc func didBecomeActiveNotification(){ | ||
| 669 | + DispatchQueue.main.async { | ||
| 670 | + if !self.isUserStop! && !self.isPlayEnd!{ | ||
| 671 | + self.play() | ||
| 672 | + self.setNeedsLayout() | ||
| 673 | + } | ||
| 674 | + } | ||
| 675 | + } | ||
| 676 | + | ||
| 677 | + // MARK: - KVO | ||
| 678 | + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { | ||
| 679 | + /* | ||
| 680 | + if (!self.isLocalUrl && [keyPath isEqualToString:@"netStatus"]) { | ||
| 681 | + DSNetworkStatus lastNetworkStatus = [change[@"old"] integerValue]; | ||
| 682 | + DSNetworkStatus currentNetworkStatus = [change[@"new"] integerValue]; | ||
| 683 | + if (lastNetworkStatus == currentNetworkStatus) { | ||
| 684 | + return; | ||
| 685 | + } | ||
| 686 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 687 | + if (currentNetworkStatus != DSNetworkStatusNotReachable) { | ||
| 688 | + if (!self.isUserStop && !self.isPlayEnd) { | ||
| 689 | + [self play]; | ||
| 690 | + } | ||
| 691 | + }else { | ||
| 692 | + DS_showMessage(@"网络好像断开了~"); | ||
| 693 | + } | ||
| 694 | + }); | ||
| 695 | + }else if ([keyPath isEqualToString:@"isAllowPlayVideo"]) { | ||
| 696 | + BOOL flag = [change[@"new"] integerValue]; | ||
| 697 | + dispatch_async(dispatch_get_main_queue(), ^{ | ||
| 698 | + if (flag == NO) { | ||
| 699 | + [self pauseWithIsRemoveKVOsAndNotifications:NO]; | ||
| 700 | + } | ||
| 701 | + }); | ||
| 702 | + }*/ | ||
| 703 | + } | ||
| 704 | + | ||
| 705 | + | ||
| 706 | + // MARK: - 退出全屏 | ||
| 707 | + /// 退出全屏 | ||
| 708 | + func exitFullScreen(){ | ||
| 709 | + self.controlView.resetHideTime() | ||
| 710 | + if self.controlView.isFullScreen!{ | ||
| 711 | + self.currentOrientation = .portrait | ||
| 712 | + } | ||
| 713 | + } | ||
| 714 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerViewController.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerViewController.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/24. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +typealias popActionCallBackBlock = (_ time: Double,_ isPause:Bool,_ isPlayEnd:Bool) -> Void | ||
| 11 | + | ||
| 12 | +class CNLivePlayerViewController:CNLiveBaseViewController{ | ||
| 13 | + | ||
| 14 | + // MARK: - 播放设置 | ||
| 15 | + /** | ||
| 16 | + 初始化视频链接地址 为空为停止播放 | ||
| 17 | + */ | ||
| 18 | + var playUrl:URL? | ||
| 19 | + /** | ||
| 20 | + 视频链接是否为直播 | ||
| 21 | + */ | ||
| 22 | + var isLive:Bool? | ||
| 23 | + | ||
| 24 | + /// 初始化视频 | ||
| 25 | + /// @param playUrl 视频链接地址 为空为停止播放 | ||
| 26 | + /// @param playTime 播放时间 | ||
| 27 | + func setPlayUrl(playUrl:URL,playTime:Double){ | ||
| 28 | + self.playUrl = playUrl | ||
| 29 | + self.isLive = false | ||
| 30 | + if self.playUrl?.scheme == "file"{ | ||
| 31 | + self.isLocalUrl = true | ||
| 32 | + }else{ | ||
| 33 | + self.isLocalUrl = false | ||
| 34 | + } | ||
| 35 | + self.playerView?.setPlayUrl(playUrl: self.playUrl!, isLive: self.isLive!) | ||
| 36 | + self.playerView?.startPlayTime = playTime | ||
| 37 | + } | ||
| 38 | + // MARK: - 封面图 | ||
| 39 | + /** | ||
| 40 | + 封面图(不传封面图就不显示) | ||
| 41 | + */ | ||
| 42 | + var _coverImage:UIImage? | ||
| 43 | + var coverImage:UIImage?{ | ||
| 44 | + get{ | ||
| 45 | + _coverImage | ||
| 46 | + } | ||
| 47 | + set{ | ||
| 48 | + _coverImage = newValue | ||
| 49 | + self.playerView?.controlView.coverImage = self.coverImage | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + 封面图url(先检测封面图,后检测封面图url,不传封面图就不显示) | ||
| 55 | + */ | ||
| 56 | + var _coverImageUrl:String? | ||
| 57 | + var coverImageUrl:String?{ | ||
| 58 | + get{ | ||
| 59 | + _coverImageUrl | ||
| 60 | + } | ||
| 61 | + set{ | ||
| 62 | + _coverImageUrl = newValue | ||
| 63 | + self.playerView?.controlView.coverImageUrl = self.coverImageUrl | ||
| 64 | + } | ||
| 65 | + } | ||
| 66 | + // MARK: - 回调 | ||
| 67 | + /// 返回观看时间回调 | ||
| 68 | + var popActionCallBack:popActionCallBackBlock? | ||
| 69 | + | ||
| 70 | + //播放器 | ||
| 71 | + private var _playerView:CNLivePlayerView? | ||
| 72 | + private var playerView:CNLivePlayerView?{ | ||
| 73 | + get{ | ||
| 74 | + if (_playerView == nil) { | ||
| 75 | + _playerView = CNLivePlayerView() | ||
| 76 | + _playerView?.controlView.fullScreenType = .inCurrentViewOrientation | ||
| 77 | + _playerView?.popCallBack = {[weak self] in | ||
| 78 | + self!.popActionCallBack!(self!.playerView!.getPlayTime(), self!.playerView!.isUserStop!, self!.playerView!.isPlayEnd!) | ||
| 79 | + } | ||
| 80 | + _playerView?.switchAlphaMessageStateCallBack = { playerView in | ||
| 81 | + UIView.animate(withDuration: kDSPlayerAnimateTimeInterval) { | ||
| 82 | + if (playerView.controlView.isLockScreen! || playerView.controlView.isAlphaMessage!) { | ||
| 83 | + self.isStatusBarHidden = true | ||
| 84 | + self.setNeedsStatusBarAppearanceUpdate() | ||
| 85 | + }else { | ||
| 86 | + self.isStatusBarHidden = false | ||
| 87 | + } | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + _playerView?.switchInterfaceOrientationCallBack = { playerView in | ||
| 91 | + //全屏时不允许手势返回 | ||
| 92 | + if (playerView.controlView.isFullScreen!) { | ||
| 93 | + self.popGestureRecognizerEnable = false | ||
| 94 | + }else { | ||
| 95 | + self.popGestureRecognizerEnable = true | ||
| 96 | + } | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + return _playerView | ||
| 100 | + } | ||
| 101 | + set{ | ||
| 102 | + _playerView = newValue | ||
| 103 | + | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + //是否是本地的url | ||
| 108 | + private var isLocalUrl:Bool? | ||
| 109 | + | ||
| 110 | + var isStatusBarLight:Bool = true | ||
| 111 | + var isStatusBarHidden:Bool = true | ||
| 112 | + // MARK: - 播放链接 | ||
| 113 | + /** | ||
| 114 | + 初始化视频 | ||
| 115 | + | ||
| 116 | + @param playUrl 视频链接地址 为空为停止播放 | ||
| 117 | + @param isLive 是否为直播 | ||
| 118 | + */ | ||
| 119 | + func setPlayUrl(playUrl:URL,isLive:Bool){ | ||
| 120 | + self.playUrl = playUrl | ||
| 121 | + self.isLive = isLive | ||
| 122 | + if self.playUrl?.scheme == "file"{ | ||
| 123 | + self.isLocalUrl = true | ||
| 124 | + }else{ | ||
| 125 | + self.isLocalUrl = false | ||
| 126 | + } | ||
| 127 | + self.playerView?.setPlayUrl(playUrl: self.playUrl!, isLive: self.isLive!) | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + // MARK: - viewDidLoad | ||
| 131 | + override func viewDidLoad() { | ||
| 132 | + super.viewDidLoad() | ||
| 133 | + self.topNavView.removeFromSuperview() | ||
| 134 | + self.view.backgroundColor = .black | ||
| 135 | + self.view.addSubview(self.playerView!) | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + override func viewWillAppear(_ animated: Bool) { | ||
| 139 | + super.viewWillAppear(animated) | ||
| 140 | + isStatusBarLight = true | ||
| 141 | + setNeedsStatusBarAppearanceUpdate() | ||
| 142 | + self.playerView?.viewControllerIsDisappear = false | ||
| 143 | + } | ||
| 144 | + override var preferredStatusBarStyle: UIStatusBarStyle { | ||
| 145 | + let _ = super.preferredStatusBarStyle | ||
| 146 | + if isStatusBarLight == true{ | ||
| 147 | + return UIStatusBarStyle.lightContent | ||
| 148 | + }else{ | ||
| 149 | + return UIStatusBarStyle.default | ||
| 150 | + } | ||
| 151 | + } | ||
| 152 | + override var prefersStatusBarHidden: Bool{ | ||
| 153 | + return self.isStatusBarHidden | ||
| 154 | + } | ||
| 155 | + override func viewDidAppear(_ animated: Bool) { | ||
| 156 | + super.viewDidAppear(animated) | ||
| 157 | + if (!self.isLocalUrl!) { | ||
| 158 | +// if ([DSNetworkRequest shareClient].netStatus == DSNetworkStatusNotReachable) { | ||
| 159 | +// self.playerView.controlView.failureView.hidden = NO; | ||
| 160 | +// self.playerView.controlView.failureView.errorMessage = @"当前网络不可用,请检查网络后重试"; | ||
| 161 | +// return; | ||
| 162 | +// } | ||
| 163 | +// if ([DSNetworkRequest shareClient].netStatus == DSNetworkStatusWWAN) { | ||
| 164 | +// DS_showMessage(@"当前正在用流量播放"); | ||
| 165 | +// } | ||
| 166 | + } | ||
| 167 | + if (!self.playerView!.isUserStop! && !self.playerView!.isPlayEnd!) { | ||
| 168 | + self.playerView?.play() | ||
| 169 | + } | ||
| 170 | + } | ||
| 171 | + override func viewWillDisappear(_ animated: Bool) { | ||
| 172 | + super.viewWillDisappear(animated) | ||
| 173 | + isStatusBarLight = false | ||
| 174 | + self.playerView?.viewControllerIsDisappear = true | ||
| 175 | + } | ||
| 176 | + override func viewDidDisappear(_ animated: Bool) { | ||
| 177 | + super.viewDidDisappear(animated) | ||
| 178 | + self.playerView?.stop() | ||
| 179 | + } | ||
| 180 | + | ||
| 181 | + override func viewWillLayoutSubviews() { | ||
| 182 | + super.viewWillLayoutSubviews() | ||
| 183 | + self.playerView?.frame = CGRect(x: 0, y: 0, width: self.view.width, height: self.view.height) | ||
| 184 | + } | ||
| 185 | + deinit { | ||
| 186 | + print("CNLivePlayerViewController释放") | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + // MARK: - iPhoneX黑条隐藏 | ||
| 190 | + override var prefersHomeIndicatorAutoHidden: Bool{ | ||
| 191 | + return true | ||
| 192 | + } | ||
| 193 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLivePlayerVolumeBrightnessView.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLivePlayerVolumeBrightnessView.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/27. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +class CNLivePlayerVolumeBrightnessView:UIView{ | ||
| 11 | + /** | ||
| 12 | + 进度 0~1 | ||
| 13 | + */ | ||
| 14 | + var _value:CGFloat = 0 | ||
| 15 | + var value:CGFloat{ | ||
| 16 | + get{ | ||
| 17 | + _value | ||
| 18 | + } | ||
| 19 | + set{ | ||
| 20 | + _value = newValue | ||
| 21 | + if (_value > 1) { | ||
| 22 | + _value = 1 | ||
| 23 | + }else if (_value < 0) { | ||
| 24 | + _value = 0 | ||
| 25 | + } | ||
| 26 | + var progressViewFrame = self.progressView?.frame | ||
| 27 | + progressViewFrame?.size.width = self.totalView!.frame.size.width * _value | ||
| 28 | + self.progressView?.frame = progressViewFrame! | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + var sunImageView:UIImageView? | ||
| 33 | + var totalView:UIView? | ||
| 34 | + var progressView:UIView? | ||
| 35 | + | ||
| 36 | + init() { | ||
| 37 | + super.init(frame: CGRectZero) | ||
| 38 | + self.backgroundColor = UIColor(white: 0, alpha: 0.6) | ||
| 39 | + self.layer.cornerRadius = 6 | ||
| 40 | + self.clipsToBounds = true | ||
| 41 | + self.initUI() | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + required init?(coder: NSCoder) { | ||
| 45 | + fatalError("init(coder:) has not been implemented") | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + override func layoutSubviews() { | ||
| 49 | + super.layoutSubviews() | ||
| 50 | + self.sunImageView?.frame = CGRect(x: 10, y: (self.height-25)/2, width: 25, height: 25) | ||
| 51 | + self.totalView?.frame = CGRect(x: self.sunImageView!.right+10, y: 0, width: self.width-(self.sunImageView!.right+10*2), height: 2) | ||
| 52 | + self.totalView?.centerY = self.sunImageView!.centerY | ||
| 53 | + self.progressView?.frame = CGRect(x: self.totalView!.left, y: self.totalView!.top, width: self.totalView!.width*self.value, height: self.totalView!.height) | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + // MARK: - initUI | ||
| 57 | + func initUI(){ | ||
| 58 | + self.sunImageView = UIImageView() | ||
| 59 | + self.sunImageView?.clipsToBounds = true | ||
| 60 | + self.sunImageView?.contentMode = .scaleAspectFit | ||
| 61 | + self.sunImageView?.image = UIImage(named: "DS_player_sun") | ||
| 62 | + self.addSubview(self.sunImageView!) | ||
| 63 | + | ||
| 64 | + self.totalView = UIView() | ||
| 65 | + self.totalView?.backgroundColor = UIColor(white: 1, alpha: 0.2) | ||
| 66 | + self.totalView?.clipsToBounds = true | ||
| 67 | + self.totalView?.layer.cornerRadius = 1 | ||
| 68 | + self.addSubview(self.totalView!) | ||
| 69 | + | ||
| 70 | + self.progressView = UIView() | ||
| 71 | + self.progressView?.backgroundColor = .white | ||
| 72 | + self.progressView?.clipsToBounds = true | ||
| 73 | + self.progressView?.layer.cornerRadius = 1 | ||
| 74 | + self.addSubview(self.progressView!) | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | +} |
metaCode/Classes/Main/Util/CNLivePlayer/CNLiveTimer.swift
0 → 100644
| 1 | +// | ||
| 2 | +// CNLiveTimer.swift | ||
| 3 | +// metaCode | ||
| 4 | +// | ||
| 5 | +// Created by zx on 2023/11/29. | ||
| 6 | +// | ||
| 7 | + | ||
| 8 | +import Foundation | ||
| 9 | + | ||
| 10 | +//坑点 最初使用FLT_MIN为永远执行时间判断 后来发现bug 即FLT_MIN==0而不是float的最小值 | ||
| 11 | +//永远执行时间 | ||
| 12 | +let kBKTimerRepeatsTime:CGFloat = -999999 | ||
| 13 | +let kMinTimeInterval:CGFloat = 0.000001 | ||
| 14 | + | ||
| 15 | +typealias timerHandlerBlock = (_ timer:DispatchSourceTimer,_ lastTime:CGFloat) -> Void | ||
| 16 | + | ||
| 17 | +class CNLiveTimer:NSObject{ | ||
| 18 | + | ||
| 19 | + // MARK: - 创建定时器方法 | ||
| 20 | + /** | ||
| 21 | + 初始化定时器 | ||
| 22 | + | ||
| 23 | + @param timeInterval 时间间隔 (最多6位小数 即0.000001) | ||
| 24 | + @param totalTime 执行总时间 当 totalTime==kBKTimerRepeatsTime 时无限执行 | ||
| 25 | + @param handler 回调 | ||
| 26 | + @return 定时器 | ||
| 27 | + */ | ||
| 28 | + class func bk_setupTimerWithTimeInterval(timeInterval:TimeInterval,totalTime:CGFloat,handler:@escaping timerHandlerBlock)->DispatchSourceTimer{ | ||
| 29 | + let serialQueue = DispatchQueue.init(label: "CNLiveGCDTimer", target: DispatchQueue.global()) | ||
| 30 | + var timer = DispatchSource.makeTimerSource() | ||
| 31 | + var temp_timeInterval = timeInterval | ||
| 32 | + if temp_timeInterval < kMinTimeInterval{ | ||
| 33 | + temp_timeInterval = kMinTimeInterval | ||
| 34 | + } | ||
| 35 | + var lastTime = totalTime | ||
| 36 | + timer.schedule(deadline: .now()+temp_timeInterval, repeating: timeInterval, leeway: DispatchTimeInterval.never) | ||
| 37 | + timer.setEventHandler { | ||
| 38 | + | ||
| 39 | + if (totalTime != kBKTimerRepeatsTime) { | ||
| 40 | + lastTime = lastTime - temp_timeInterval | ||
| 41 | + | ||
| 42 | + //保留6位小数 取出整数和小数 | ||
| 43 | + let lastTimeStr = String(format: "%.6f", lastTime) | ||
| 44 | + let array = lastTimeStr.components(separatedBy: ".") | ||
| 45 | + //检测剩余时间是否为kMinTimeInterval 即0.000000 | ||
| 46 | + var flag = true | ||
| 47 | + let integer = array.first | ||
| 48 | + if integer == "0"{ | ||
| 49 | + //判断整数是否为0 | ||
| 50 | + let decimal = array.last | ||
| 51 | + for i in 0..<(decimal?.count ?? 0) { | ||
| 52 | + let range_string = decimal?.subString(start: i, length: 1) | ||
| 53 | + if range_string == "0"{ | ||
| 54 | + //判断小数所有位数是否为0 | ||
| 55 | + flag = false | ||
| 56 | + break | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + }else{ | ||
| 60 | + flag = false | ||
| 61 | + } | ||
| 62 | + if flag{ | ||
| 63 | + lastTime = 0 | ||
| 64 | + self.bk_removeTimer(timer: timer) | ||
| 65 | + }else{ | ||
| 66 | + if (lastTime <= 0) { | ||
| 67 | + lastTime = 0 | ||
| 68 | + self.bk_removeTimer(timer: timer) | ||
| 69 | + } | ||
| 70 | + } | ||
| 71 | + } | ||
| 72 | + DispatchQueue.main.async { | ||
| 73 | + handler(timer,lastTime) | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + timer.resume() | ||
| 77 | + return timer | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + // MARK: - 销毁定时器方法 | ||
| 81 | + /** | ||
| 82 | + 删除定时器 | ||
| 83 | + */ | ||
| 84 | + class func bk_removeTimer(timer:DispatchSourceTimer){ | ||
| 85 | + timer.cancel() | ||
| 86 | + // dispatch_source_cancel(timer);//在在创建多次,并且瞬间删除全部时有可能崩溃 所以用dispatch_cancel(timer)替代 | ||
| 87 | +// timer = nil | ||
| 88 | + } | ||
| 89 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/Contents.json
0 → 100644
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_pause.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_circle_pause@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_circle_pause@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_pause.imageset/DS_player_circle_pause@2x.png
0 → 100644
2.9 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_pause.imageset/DS_player_circle_pause@3x.png
0 → 100644
5.54 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_start.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_circle_start@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_circle_start@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_start.imageset/DS_player_circle_start@2x.png
0 → 100644
3.29 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_circle_start.imageset/DS_player_circle_start@3x.png
0 → 100644
5.88 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_close.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_lock_close@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_lock_close@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_close.imageset/DS_player_lock_close@2x.png
0 → 100644
2.42 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_close.imageset/DS_player_lock_close@3x.png
0 → 100644
4.27 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_open.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_lock_open@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_lock_open@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_open.imageset/DS_player_lock_open@2x.png
0 → 100644
2.43 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_lock_open.imageset/DS_player_lock_open@3x.png
0 → 100644
4.25 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_magnify.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_magnify@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_magnify@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_magnify.imageset/DS_player_magnify@2x.png
0 → 100644
880 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_magnify.imageset/DS_player_magnify@3x.png
0 → 100644
1.16 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_nav_back.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_nav_back@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_nav_back@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_nav_back.imageset/DS_player_nav_back@2x.png
0 → 100644
326 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_nav_back.imageset/DS_player_nav_back@3x.png
0 → 100644
579 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_pause.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_pause@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_pause@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_pause.imageset/DS_player_pause@2x.png
0 → 100644
241 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_pause.imageset/DS_player_pause@3x.png
0 → 100644
444 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_reduce.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_reduce@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_reduce@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_reduce.imageset/DS_player_reduce@2x.png
0 → 100644
721 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_reduce.imageset/DS_player_reduce@3x.png
0 → 100644
1.14 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_start.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_start@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_start@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_start.imageset/DS_player_start@2x.png
0 → 100644
689 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_start.imageset/DS_player_start@3x.png
0 → 100644
1.09 KB
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_sun.imageset/Contents.json
0 → 100644
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "scale" : "1x" | ||
| 6 | + }, | ||
| 7 | + { | ||
| 8 | + "filename" : "DS_player_sun@2x.png", | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "scale" : "2x" | ||
| 11 | + }, | ||
| 12 | + { | ||
| 13 | + "filename" : "DS_player_sun@3x.png", | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "scale" : "3x" | ||
| 16 | + } | ||
| 17 | + ], | ||
| 18 | + "info" : { | ||
| 19 | + "author" : "xcode", | ||
| 20 | + "version" : 1 | ||
| 21 | + } | ||
| 22 | +} |
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_sun.imageset/DS_player_sun@2x.png
0 → 100644
816 Bytes
metaCode/Supporting Files/Assets.xcassets/Player/DS_player_sun.imageset/DS_player_sun@3x.png
0 → 100644
1.13 KB