Commit dedcbc4f15b43b7858d08db5f58bb9892d9bde13

Authored by 张旭
1 parent 48f428d0

商品管理 , 分类 , 播放器等 , 有部分bug

Showing 64 changed files with 3445 additions and 51 deletions
... ... @@ -45,6 +45,11 @@ target 'metaCode' do
45 45 #轮播图
46 46 pod 'FSPagerView', '0.8.3'
47 47 #pod 'SDCycleScrollView', '~> 1.82'
  48 + #图片浏览器
  49 + pod 'SKPhotoBrowser'
  50 +
  51 + #视频播放器
  52 + pod 'PLPlayerKit'
48 53  
49 54 target 'metaCodeTests' do
50 55 inherit! :search_paths
... ...
metaCode.xcodeproj/project.pbxproj
... ... @@ -29,6 +29,25 @@
29 29 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */; };
30 30 191733042B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */; };
31 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 51 192336EB2AD9224300D47CD4 /* CNUpSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */; };
33 52 1926C28F2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */; };
34 53 1926C2912AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */; };
... ... @@ -221,6 +240,25 @@
221 240 191733012B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveSelUplSingleImageView.swift; sourceTree = "<group>"; };
222 241 191733032B0F216E007BCC04 /* NSDictionary+CNLiveExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDictionary+CNLiveExtensions.swift"; sourceTree = "<group>"; };
223 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 262 192336EA2AD9224300D47CD4 /* CNUpSlideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNUpSlideViewController.swift; sourceTree = "<group>"; };
225 263 1926C28E2AE0D76C00C71DC3 /* CNLiveDownSlideViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideViewModel.swift; sourceTree = "<group>"; };
226 264 1926C2902AE0FD4500C71DC3 /* CNLiveDownSlideModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CNLiveDownSlideModel.swift; sourceTree = "<group>"; };
... ... @@ -436,6 +474,31 @@
436 474 path = GoodsDetail;
437 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 502 19565EC32AF8ACC2007D6727 /* GoodsManager */ = {
440 503 isa = PBXGroup;
441 504 children = (
... ... @@ -503,10 +566,12 @@
503 566 19CC4D502ADD126D00308E2A /* Util */ = {
504 567 isa = PBXGroup;
505 568 children = (
  569 + 1917330B2B109691007BCC04 /* CNLivePlayer */,
506 570 19CC4D512ADD129800308E2A /* CNUpSlideAnimationTransition.swift */,
507 571 19FA201A2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift */,
508 572 19D2CE622AE8B65D00691757 /* CNLiveDownSlideTool.swift */,
509 573 19BB202A2AF382150094D962 /* CNLiveAdaptTool.swift */,
  574 + 191733302B170537007BCC04 /* CNLiveCommonManager.swift */,
510 575 );
511 576 path = Util;
512 577 sourceTree = "<group>";
... ... @@ -1246,11 +1311,14 @@
1246 1311 191732F32B084DBC007BCC04 /* CNLiveShopClassifySwitchTableViewCell.swift in Sources */,
1247 1312 191732E72B0615C1007BCC04 /* UIScrollView+CNLiveExtensions.swift in Sources */,
1248 1313 1917328E2B032583007BCC04 /* CNLiveRoundedRectView.swift in Sources */,
  1314 + 1917332F2B16C7C9007BCC04 /* CNLiveTimer.swift in Sources */,
1249 1315 7CD675292A270F6A008354C1 /* WJColorChange.m in Sources */,
1250 1316 79F4B11C2A33036E00993C03 /* CNLiveMineInfoAlertView.swift in Sources */,
1251 1317 79BB96A82AF223FB00AEA4AC /* CNLiveConfigAlertManager.swift in Sources */,
1252 1318 19BB1FF02AF0E5B30094D962 /* CNLiveShopDetailModel.swift in Sources */,
1253 1319 796398942A260C0100D045EB /* AppDelegate.swift in Sources */,
  1320 + 1917330D2B1096AB007BCC04 /* CNLivePlayerViewController.swift in Sources */,
  1321 + 1917330F2B10989C007BCC04 /* CNLivePlayerView.swift in Sources */,
1254 1322 7989B5C72A4BDC7200A19B10 /* CNLiveMineEarnListViewController.swift in Sources */,
1255 1323 191732902B0348F6007BCC04 /* CNLiveSwitchView.swift in Sources */,
1256 1324 792B53282AFCD7640009AB49 /* CNLiveShopOrderExpressDetailViewController.swift in Sources */,
... ... @@ -1268,6 +1336,7 @@
1268 1336 79282A3C2A2EDC2500B5F8CF /* NSString+CNLiveExtensions.swift in Sources */,
1269 1337 19D2CE632AE8B65D00691757 /* CNLiveDownSlideTool.swift in Sources */,
1270 1338 790B1FB82A41B6A60074CF00 /* CNLiveMineMessageViewController.swift in Sources */,
  1339 + 191733252B146078007BCC04 /* CNLivePlayerSlider.swift in Sources */,
1271 1340 19BB202B2AF382150094D962 /* CNLiveAdaptTool.swift in Sources */,
1272 1341 79E672032AFDFA9C00F2F768 /* CNLiveMineSignOutViewController.swift in Sources */,
1273 1342 19565ECD2AF8D256007D6727 /* CNLiveShopGoodsListClassifyView.swift in Sources */,
... ... @@ -1279,6 +1348,7 @@
1279 1348 19CC4D4B2ADD086F00308E2A /* CNUpSlideDetailViewController.swift in Sources */,
1280 1349 7C83B4402A52BB2B004BF4A4 /* CNGlobalEnum.swift in Sources */,
1281 1350 7C83B4442A541F36004BF4A4 /* NSDate+CNLiveExtensions.swift in Sources */,
  1351 + 1917332B2B15CDC6007BCC04 /* CNLivePlayerLandscapeViewController.swift in Sources */,
1282 1352 798916F12B0491A400D08302 /* CNLiveShopBodyTransListView.swift in Sources */,
1283 1353 7CD675482A274167008354C1 /* PGIndexBannerSubiew.m in Sources */,
1284 1354 790D019F2A2DD66E00C5978D /* CNLiveLoginViewModel.swift in Sources */,
... ... @@ -1288,6 +1358,7 @@
1288 1358 79EABB892AB4497700F3A4E2 /* CNLiveSaveStandDB.swift in Sources */,
1289 1359 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */,
1290 1360 19BB1FEA2AEF7B4A0094D962 /* CNLiveShopConsoleCell.swift in Sources */,
  1361 + 191733132B109F7B007BCC04 /* CNLivePlayerGestureView.swift in Sources */,
1291 1362 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */,
1292 1363 790B1FB62A41938F0074CF00 /* UIImage+CNLiveExtensions.swift in Sources */,
1293 1364 191732F82B08AB9D007BCC04 /* CNLiveShopClassilyViewModel.swift in Sources */,
... ... @@ -1305,6 +1376,7 @@
1305 1376 790D019D2A2DCBD000C5978D /* UIView+CNLiveExtensions.swift in Sources */,
1306 1377 79E496E82AB9674300127BF8 /* NSMutableAttributedString+CNLiveExtensions.swift in Sources */,
1307 1378 19CC4D472ADD006600308E2A /* CNDownSlideSingleCourseCell.swift in Sources */,
  1379 + 191733232B14601A007BCC04 /* CNLivePlayerProgressSlider.swift in Sources */,
1308 1380 191732FE2B0B3EBF007BCC04 /* CNLiveShopGoodsDetailsViewController.swift in Sources */,
1309 1381 79E496E32AB9357000127BF8 /* UITableViewCell+CNLiveExtension.swift in Sources */,
1310 1382 7C83B4422A541EBF004BF4A4 /* CALayer+CNLiveExtensions.swift in Sources */,
... ... @@ -1312,6 +1384,7 @@
1312 1384 798A44F72A3077ED00815935 /* CNLiveHotButton.swift in Sources */,
1313 1385 7CD6753D2A2740B0008354C1 /* CNMainView.swift in Sources */,
1314 1386 793CAF522A58FCA200882EF4 /* CNLiveMineExchangeViewController.swift in Sources */,
  1387 + 191733272B148BB1007BCC04 /* CNLivePlayerFastForwardPreviewView.swift in Sources */,
1315 1388 7CD675522A29C04B008354C1 /* CNLiveConfigstant.swift in Sources */,
1316 1389 79282A402A2F055100B5F8CF /* CNLiveConfigUserInfo.swift in Sources */,
1317 1390 1965FA402AFB38AA00F0F435 /* CNLiveAddGoodsSelectUploadImageView.swift in Sources */,
... ... @@ -1325,6 +1398,7 @@
1325 1398 792E57D92A3AA2F2005834DB /* CNLiveCommonBaseModel.swift in Sources */,
1326 1399 791C1C862AFB2EB4003E6362 /* CNLiveShopOrderExpressViewController.swift in Sources */,
1327 1400 7CD6753E2A2740B0008354C1 /* CNUpSlideView.swift in Sources */,
  1401 + 191733312B170537007BCC04 /* CNLiveCommonManager.swift in Sources */,
1328 1402 7CD675402A2740B0008354C1 /* CNDownSlideView.swift in Sources */,
1329 1403 191732F52B085BAE007BCC04 /* CNLiveShopClassilyIconTableViewCell.swift in Sources */,
1330 1404 191732E32B05F474007BCC04 /* CNLiveShopGoodsManageDetailsInputManager.swift in Sources */,
... ... @@ -1333,16 +1407,20 @@
1333 1407 798A44FD2A309EBA00815935 /* CNLiveTypeFeedBackViewController.swift in Sources */,
1334 1408 79656E382AAEBA8E00119A61 /* CNLiveMineInputViewController.swift in Sources */,
1335 1409 19CC4D522ADD129800308E2A /* CNUpSlideAnimationTransition.swift in Sources */,
  1410 + 1917331D2B10A15A007BCC04 /* CNLivePlayerFailureView.swift in Sources */,
1336 1411 7CD6754F2A2840B9008354C1 /* CNMetaCodeHomePageController.swift in Sources */,
1337 1412 79D094DC2B0765DD008CB1F3 /* CNLiveShopBodyCouponGoodsListView.swift in Sources */,
1338 1413 798916EF2B048EC800D08302 /* CNLiveShopTransListViewController.swift in Sources */,
1339 1414 7989B5C52A4BDC6000A19B10 /* CNLiveMineEarnViewController.swift in Sources */,
1340 1415 792E57DB2A3AE9F4005834DB /* CNLiveCommonQiniuTool.swift in Sources */,
1341 1416 191732F12B084822007BCC04 /* CNLiveShopClassifyInputTableViewCell.swift in Sources */,
  1417 + 191733212B143F3A007BCC04 /* CNLiveGradientView.swift in Sources */,
1342 1418 19BB1FE62AEB93B80094D962 /* CNLiveShopUserInfoModel.swift in Sources */,
1343 1419 7CD675472A274167008354C1 /* NewPagedFlowView.m in Sources */,
1344 1420 191732ED2B073C52007BCC04 /* CNLiveShopClassifyListModel.swift in Sources */,
1345 1421 79F4B11A2A32F21400993C03 /* CNLiveMineNickViewController.swift in Sources */,
  1422 + 191733112B109EDC007BCC04 /* CNLivePlayerControlView.swift in Sources */,
  1423 + 1917331F2B10A1BE007BCC04 /* CNLivePlayerEnum.swift in Sources */,
1346 1424 798A44FF2A30A0A800815935 /* CNLiveInputFeedBackViewController.swift in Sources */,
1347 1425 79282A442A2F1C1E00B5F8CF /* CNLiveLoginAuthView.swift in Sources */,
1348 1426 79BB96A62AF21E2800AEA4AC /* CNLiveShopOrderDetailViewController.swift in Sources */,
... ... @@ -1356,11 +1434,13 @@
1356 1434 7987BF3D2A497644000A1ABC /* CNLiveMineQuestViewController.swift in Sources */,
1357 1435 798A44EA2A30135D00815935 /* CNLiveMineBodyListView.swift in Sources */,
1358 1436 799172322AF08D1B00DC01A8 /* CNLiveShopOrderViewController.swift in Sources */,
  1437 + 1917332D2B15DB20007BCC04 /* CNLivePlayerKVOModel.swift in Sources */,
1359 1438 798A44F92A30835400815935 /* CNLiveHelpFeedBackViewController.swift in Sources */,
1360 1439 79A68C4A2A26E6CE00DC3B43 /* (null) in Sources */,
1361 1440 790D01852A2D89E100C5978D /* UIColor+CNLiveExtensions.swift in Sources */,
1362 1441 794FF1092B02131300385E85 /* CNLiveSaveSearchDB.swift in Sources */,
1363 1442 79396EED2A319F220053E1AF /* NSObject+CNLiveExtensions.swift in Sources */,
  1443 + 1917331B2B10A0EF007BCC04 /* CNLivePlayerLoadingView.swift in Sources */,
1364 1444 19FA201B2AE60423001F7186 /* CNLiveDownSlideModelLayout.swift in Sources */,
1365 1445 7C4931312A2F142F000E44B4 /* CNHomePageBackgroupView.swift in Sources */,
1366 1446 19BB1FF22AF21A950094D962 /* CNLliveShopDetailBannerCell.swift in Sources */,
... ... @@ -1370,6 +1450,7 @@
1370 1450 19565EC22AF616CA007D6727 /* CNLiveShopDetailOrderAssetCell.swift in Sources */,
1371 1451 1917330A2B10864F007BCC04 /* Array+CNLiveExtensions.swift in Sources */,
1372 1452 191732FB2B0AF34A007BCC04 /* CNLiveShopGoodsDetailsModel.swift in Sources */,
  1453 + 191733152B109FD7007BCC04 /* CNLivePlayerTopNaviView.swift in Sources */,
1373 1454 794FF1052B01FC8800385E85 /* CNLiveShopOrderSearchViewController.swift in Sources */,
1374 1455 798A44EC2A302DBE00815935 /* CNLiveMineAddInfoViewController.swift in Sources */,
1375 1456 791C1C882AFB6FD7003E6362 /* CNLiveShopOrderExpressFirmViewController.swift in Sources */,
... ... @@ -1384,6 +1465,7 @@
1384 1465 191733022B0C4EAB007BCC04 /* CNLiveSelUplSingleImageView.swift in Sources */,
1385 1466 798A44EE2A305AAC00815935 /* CNLiveBaseNavigationController.swift in Sources */,
1386 1467 7CD675422A2740F8008354C1 /* CNCustomIndexView.swift in Sources */,
  1468 + 191733292B148BF7007BCC04 /* CNLivePlayerVolumeBrightnessView.swift in Sources */,
1387 1469 7C4931292A2D8BA8000E44B4 /* CNLiveBaseTabBarViewController.swift in Sources */,
1388 1470 79F4B1162A32B96B00993C03 /* CNLiveMineInfoViewController.swift in Sources */,
1389 1471 791C1C8A2AFB84EE003E6362 /* CNLiveShopOrderExpressListViewController.swift in Sources */,
... ... @@ -1393,6 +1475,7 @@
1393 1475 7CD6753C2A2740B0008354C1 /* CNUpSlideViewRemindView.swift in Sources */,
1394 1476 79BB1C142B05C51900C5720C /* CNLiveShopCouponViewController.swift in Sources */,
1395 1477 798916ED2B048E8200D08302 /* CNLiveShopTransViewController.swift in Sources */,
  1478 + 191733172B10A017007BCC04 /* CNLivePlayerBottomNaviView.swift in Sources */,
1396 1479 19BB1FEC2AF0AB8E0094D962 /* CNLiveDownShopDetailController.swift in Sources */,
1397 1480 794FF1072B01FC9800385E85 /* CNLiveShopOrderSearchListViewController.swift in Sources */,
1398 1481 798A44E82A30134400815935 /* CNLiveMineHeaderView.swift in Sources */,
... ... @@ -1400,6 +1483,7 @@
1400 1483 79A267832AF8D7BC0088D9F6 /* CNLiveShopBodyCustomView.swift in Sources */,
1401 1484 791C1C8C2AFB85F8003E6362 /* CNLiveShopBodyExpressView.swift in Sources */,
1402 1485 790D019A2A2DCAE400C5978D /* CNLiveViewController.swift in Sources */,
  1486 + 191733192B10A05D007BCC04 /* CNLivePlayerProgressView.swift in Sources */,
1403 1487 79803E272AD68D3100F05F68 /* CNLiveMineShopViewController.swift in Sources */,
1404 1488 79A68C4C2A26EA6000DC3B43 /* (null) in Sources */,
1405 1489 79803E292AD6991200F05F68 /* CNLiveMineInputMessageView.swift in Sources */,
... ...
metaCode/Classes/Common/Base/CNLiveBaseViewController.swift
... ... @@ -116,6 +116,11 @@ class CNLiveBaseViewController: UIViewController {
116 116 private var leftNavSpace: CGFloat = 0.0
117 117 private var rightNavSpace: CGFloat = 0.0
118 118  
  119 + /**
  120 + 是否禁止右滑返回
  121 + */
  122 + var popGestureRecognizerEnable:Bool = false
  123 +
119 124 deinit {
120 125 log("主界面已销毁")
121 126 }
... ...
metaCode/Classes/Common/Util/CNLiveCommonQiniuTool.swift
... ... @@ -38,6 +38,7 @@ class UploadManager: NSObject {
38 38 static func uploadImage(imageData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String {
39 39 let key = UploadManager.createImageFileName()
40 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 49 static func uploadVideo(videoData: NSData, progressBlock:@escaping ProgressBlcok, successBlock: @escaping SuccessBlock) -> String {
49 50 let key = UploadManager.createVideoFileName()
50 51 UploadManager.uploadData(madiaData: videoData, key: key, progress: progressBlock, success: successBlock)
  52 + return key
51 53 }
52 54  
53 55 // MARK: - 取消上传
... ... @@ -61,7 +63,7 @@ class UploadManager: NSObject {
61 63 }
62 64 }
63 65 // MARK: - 删除云中图片
64   - func requestQiNiuDeleteImageUrl(imageUrl:String,resultBlock:downSlideResultBlock){
  66 + func requestQiNiuDeleteImageUrl(imageUrl:String,resultBlock:@escaping downSlideResultBlock){
65 67  
66 68 let param = NSMutableDictionary()
67 69 param.setValue(imageUrl, forKey: "img")
... ...
metaCode/Classes/Config/CNLiveConfigstant.swift
... ... @@ -18,6 +18,14 @@ let KStatusBarHeight:CGFloat = UIApplication.shared.statusBarFrame.height;
18 18 let KNavigationHeight:CGFloat = (KStatusBarHeight + 44)
19 19 ///tabbar高度
20 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 30 //MARK: - 常用三方key
23 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 23  
24 24 let kCNLiveShopClassifyCellIdentifier = "kCNLiveShopClassifyCellIdentifier"
25 25  
26   - //
27   - var successCompleteBlock:successComplete?
28 26 // MARK: - 属性
29 27 //开始输入前的文本
30 28 var firCategoryId:String?
... ... @@ -113,7 +111,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo
113 111 _temp_selectFirCategoryModel
114 112 }
115 113 set{
116   - _temp_selectFirCategoryModel = newValue!
  114 + if newValue != nil{
  115 + _temp_selectFirCategoryModel = newValue!
  116 + }else{
  117 + return
  118 + }
117 119 if (_temp_selectFirCategoryModel?.id!.count)! > 0{
118 120 self.firCategoryBtn?.setTitle(_temp_selectFirCategoryModel?.title, for: .normal)
119 121 }else{
... ... @@ -128,7 +130,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo
128 130 _temp_selectSecCategoryModel
129 131 }
130 132 set{
131   - _temp_selectSecCategoryModel = newValue!
  133 + if newValue != nil{
  134 + _temp_selectSecCategoryModel = newValue!
  135 + }else{
  136 + return
  137 + }
132 138 if (_temp_selectSecCategoryModel?.id?.count)! > 0{
133 139 self.secCategoryBtn?.setTitle(_temp_selectSecCategoryModel?.title, for: .normal)
134 140 self.secCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal)
... ... @@ -149,8 +155,11 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo
149 155 _temp_selectThiCategoryModel
150 156 }
151 157 set{
152   - _temp_selectThiCategoryModel = newValue!
153   -
  158 + if newValue != nil{
  159 + _temp_selectThiCategoryModel = newValue!
  160 + }else{
  161 + return
  162 + }
154 163 if _temp_selectThiCategoryModel!.id!.count > 0{
155 164 self.thiCategoryBtn?.setTitle(_temp_selectThiCategoryModel?.title, for: .normal)
156 165 self.thiCategoryBtn?.setTitleColor(HexColor("#333333"), for: .normal)
... ... @@ -486,7 +495,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo
486 495 @param pid 父级id
487 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 499 showLoading(message: "")
491 500 CNLiveShopGoodListViewModel.getGetGroupWithUid(uid: DSUserInfoManager.shared.dsUserInfo.uid!, pid: pid) { result, status in
492 501 hiddenLoading()
... ... @@ -546,7 +555,7 @@ class CNLiveGoodsCategoryController: CNLiveBaseViewController, UITableViewDataSo
546 555 }
547 556 self.tableView.reloadData()
548 557 self.tableView.setContentOffset(CGPointZero, animated: true)
549   - self.successCompleteBlock!()
  558 + successCompleteBlock()
550 559  
551 560 }else if (status == .failed){
552 561 // self.network_type = .failed
... ...
metaCode/Classes/Main/HomePage/Controller/GoodsManager/CNLiveModalPresentationViewController.swift
... ... @@ -27,9 +27,10 @@ class CNLiveModalPresentationViewController:UIViewController{
27 27 self.view.backgroundColor = .clear
28 28 }
29 29  
30   - func showingAnimationWithCompletion(completion:completionBlock){
  30 + func showingAnimationWithCompletion(completion:@escaping completionBlock){
31 31  
32 32 self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-(self.contentView?.top)!)
  33 +
33 34 UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) {
34 35 self.contentView?.transform = CGAffineTransformIdentity
35 36 } completion: { finished in
... ... @@ -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 42 UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut) {
42 43 self.contentView?.transform = CGAffineTransformMakeTranslation(0, self.view.height-self.contentView!.top)
43 44 } completion: { finished in
... ...
metaCode/Classes/Main/HomePage/Controller/GoodsManager/CNLiveShopNewProductController.swift
... ... @@ -45,7 +45,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{
45 45 let vc = CNLiveGoodsCategoryController()
46 46  
47 47 vc.categoryType = .shop
48   - if self.shopGoodsDetailsModel.id!.count > 0{
  48 + if self.shopGoodsDetailsModel.id?.count ?? 0 > 0{
49 49 vc.firCategoryId = self.shopGoodsDetailsModel.category_id
50 50 vc.secCategoryId = self.shopGoodsDetailsModel.category_id2
51 51 }
... ... @@ -95,7 +95,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{
95 95 lastView = singleView
96 96 }
97 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 101 deinit {
... ... @@ -266,7 +266,7 @@ class CNLiveShopNewProductController:CNLiveBaseViewController{
266 266 if self.selectCategoryVC == nil{
267 267 let vc = CNLiveGoodsCategoryController()
268 268 vc.categoryType = .goods
269   - if self.shopGoodsDetailsModel.id!.count > 0{
  269 + if self.shopGoodsDetailsModel.id?.count ?? 0 > 0{
270 270 vc.firCategoryId = self.shopGoodsDetailsModel.groupid
271 271 vc.secCategoryId = self.shopGoodsDetailsModel.groupid2
272 272 vc.thiCategoryId = self.shopGoodsDetailsModel.groupid3
... ...
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveAddGoodsSelectUploadImageView.swift
... ... @@ -10,6 +10,7 @@ import UIKit
10 10 import UniformTypeIdentifiers
11 11 import AVFoundation
12 12 import HXPHPicker
  13 +import SKPhotoBrowser
13 14 ///类型
14 15 enum CNLiveSelectUploadImageViewDisplayType:Int {
15 16 ///选择
... ... @@ -49,7 +50,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat
49 50 }
50 51  
51 52 /// 高度类型
52   - var heightStyle:CNLiveSelectUploadImageViewHeightStyle
  53 + var heightStyle:CNLiveSelectUploadImageViewHeightStyle?
53 54 /// 每张图的间距 默认DS_adapt_length(15)
54 55 var _space:CGFloat = 15
55 56 var space:CGFloat{
... ... @@ -121,7 +122,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat
121 122  
122 123 // MARK: - 展示属性
123 124 /// 获取的网络图片数组
124   - var _networkImageArr:Array<String>
  125 + var _networkImageArr:Array<String> = Array()
125 126 var networkImageArr:Array<String>{
126 127 get{
127 128 _networkImageArr
... ... @@ -514,7 +515,7 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat
514 515 self.addSubview(singleImageView)
515 516 }
516 517 }else{
517   - if self.networkVideoUrl!.count > 0{
  518 + if self.networkVideoUrl?.count ?? 0 > 0{
518 519 var model = CNLiveSelectUploadImageModel()
519 520 model.videoUrl = self.networkVideoUrl
520 521 model.imageUrl = self.networkVideoImageUrl
... ... @@ -575,13 +576,9 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat
575 576 UIApplication.shared.keyWindow?.endEditing(true)
576 577 if model.isVideo! == true{
577 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 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 582 }else{
586 583 //TODO:后面再调整具体的配置
587 584 // 设置与微信主题一致的配置
... ... @@ -619,29 +616,23 @@ class CNLiveAddGoodsSelectUploadImageView: UIView,UIImagePickerControllerDelegat
619 616 return
620 617 }
621 618 let subviews = self.subviews
622   - let currentPage = 0
623   - var sourceDatas = NSMutableArray()
  619 + var currentPage = 0
  620 + var images = [SKPhoto]()
624 621 for i in 0..<self.uploadImageUrls.count {
625 622 var cmodel = self.uploadImageUrls[i]
626 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 643 UIApplication.shared.keyWindow?.endEditing(true)
653 644 let subviews = self.subviews
654 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 647 if model.imageUrl == singleImageView.model?.imageUrl{
657 648 if singleImageView.model?.isVideo == true{
658 649 if singleImageView.model?.isUploading == true{
659 650 UploadManager.shared.cancelUploadKey(key: singleImageView.model!.uploadKey!)
660 651 }else{
661 652 self.replaceVideoUrls.append(singleImageView.model!)
662   - var videoModel = CNLiveSelectUploadImageModel()
  653 + let videoModel = CNLiveSelectUploadImageModel()
663 654 videoModel.isVideo = true
664 655 self.uploadVideoModel = videoModel
665 656 }
... ...
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveSelUplSingleImageView.swift
... ... @@ -80,7 +80,7 @@ class CNLiveSelUplSingleImageView: UIView {
80 80 /// 是否隐藏删除按钮
81 81 var isHideDeleteBtn : Bool?
82 82 /// 是否是封面
83   - var isCover : Bool
  83 + var isCover : Bool = false
84 84 /// 赋值
85 85 /// @param model 数据
86 86 /// @param isHideDeleteBtn 是否隐藏删除按钮
... ...
metaCode/Classes/Main/HomePage/View/GoodsManager/CNLiveShopAddGoodsSingleView.swift
... ... @@ -57,7 +57,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg
57 57 var line = UIImageView()
58 58 var starImageView = UIImageView()
59 59 //开始输入前的文本
60   - var beginText:String
  60 + var beginText:String?
61 61  
62 62 override init(frame: CGRect) {
63 63 super.init(frame: frame)
... ... @@ -457,7 +457,7 @@ class CNLiveShopAddGoodsSingleView: UIView, UITextFieldDelegate, UITextViewDeleg
457 457 }
458 458 var isFindDecimalPoint = false
459 459 var behindDecimalPointLength = 0
460   - if newStr?.count ?? 0 > oldStr.count{
  460 + if newStr?.count ?? 0 > oldStr!.count{
461 461 for i in 0..<(newStr?.count ?? 0) {
462 462 let newNextStr = newStr?.subString(start: i, length: 1)
463 463 if (!isFindDecimalPoint && newNextStr == "."){
... ...
metaCode/Classes/Main/HomePage/ViewModel/GoodsManager/CNLiveShopGoodListViewModel.swift
... ... @@ -246,8 +246,9 @@ class CNLiveShopGoodListViewModel:NSObject{
246 246 CNLiveNetworking.requestNetwork(with: .GET, urlString: APPBaseWjjBUrl+"/api/v1/getGroup", param: param as! [String : String], cacheType: .networkOnly) { task, result, error in
247 247 hiddenLoading()
248 248 if (error == nil) {
249   - let resp = result as! NSDictionary
  249 + let res = result as! NSDictionary
250 250 var dataArr:[BaseModel] = []
  251 + let resp = res["data"] as! NSDictionary
251 252 let respArr = resp["list"] as! NSArray
252 253 for dic in respArr{
253 254 let dataDic = dic as! NSDictionary
... ...
metaCode/Classes/Main/MinePage/Controller/CNLiveMineInfoViewController.swift
... ... @@ -158,7 +158,7 @@ class CNLiveMineInfoViewController: CNLiveBaseViewController, PhotoPickerControl
158 158 extension CNLiveMineInfoViewController {
159 159  
160 160 func pickerController(_ pickerController: PhotoPickerController,
161   - didFinishSelection result: CNLiveMineInputViewControllerPickerResult) {
  161 + didFinishSelection result: PickerResult) {
162 162 result.getImage { [weak self] (image, photoAsset, index) in
163 163 if let image = image {
164 164 self!._select_image = image
... ...
metaCode/Classes/Main/Model/GoodsDetail/CNLiveSelectUploadImageModel.swift
... ... @@ -8,10 +8,6 @@
8 8 import Foundation
9 9  
10 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 45 上传百分比 0~1
50 46 */
51 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
  1 +//
  2 +// CNLivePlayerKVOModel.swift
  3 +// metaCode
  4 +//
  5 +// Created by zx on 2023/11/28.
  6 +//
  7 +
  8 +import Foundation
  9 +
  10 +class CNLivePlayerKVOModel:BaseModel{
  11 + /**
  12 + KVO监听对象
  13 + */
  14 + var obj:(AnyObject)?
  15 + /**
  16 + KVO监听对象路径
  17 + */
  18 + var path:String?
  19 +
  20 +}
... ...
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
  1 +{
  2 + "info" : {
  3 + "author" : "xcode",
  4 + "version" : 1
  5 + }
  6 +}
... ...
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