From 1989abab7f284ce271f9d8e6ebd4244d4d33ba04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B9=9E?= Date: Tue, 11 Jun 2024 10:51:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HiBit.xcodeproj/project.pbxproj | 246 +++++++++ HiBit/Basics/Info.plist | 13 +- .../Home/Controllers/HBHomeViewController.h | 35 +- .../Home/Controllers/HBHomeViewController.m | 242 ++++++++- .../Common/Category/UIButton+GKEnlarge.h | 29 + .../Common/Category/UIButton+GKEnlarge.m | 64 +++ .../Common/GKLikeView/GKDoubleLikeView.h | 21 + .../Common/GKLikeView/GKDoubleLikeView.m | 73 +++ .../Player/Common/GKLikeView/GKLikeView.h | 27 + .../Player/Common/GKLikeView/GKLikeView.m | 189 +++++++ .../Common/GKLoadingView/GKBallLoadingView.h | 24 + .../Common/GKLoadingView/GKBallLoadingView.m | 261 +++++++++ .../GKLandscapeNavigationController.h | 25 + .../GKLandscapeNavigationController.m | 62 +++ .../GKLandscapeViewController.h | 37 ++ .../GKLandscapeViewController.m | 47 ++ .../GKRotationManager/GKLandscapeWindow.h | 21 + .../GKRotationManager/GKLandscapeWindow.m | 76 +++ .../GKRotationManager/GKRotationManager.h | 118 ++++ .../GKRotationManager/GKRotationManager.m | 275 ++++++++++ .../GKRotationManager_iOS_16_Later.h | 17 + .../GKRotationManager_iOS_16_Later.m | 139 +++++ .../GKRotationManager_iOS_9_15.h | 17 + .../GKRotationManager_iOS_9_15.m | 177 ++++++ .../Player/Manager/GKDYPlayerManager.h | 84 +++ .../Player/Manager/GKDYPlayerManager.m | 504 ++++++++++++++++++ .../Project/Player/Model/GKDUVideoInfoModel.h | 21 + .../Project/Player/Model/GKDUVideoInfoModel.m | 14 + HiBit/Project/Player/Model/GKDYVideoModel.h | 88 +++ HiBit/Project/Player/Model/GKDYVideoModel.m | 77 +++ .../Player/View/GKDYPanGestureRecognizer.h | 24 + .../Player/View/GKDYPanGestureRecognizer.m | 54 ++ HiBit/Project/Player/View/GKDYScrollView.h | 17 + HiBit/Project/Player/View/GKDYScrollView.m | 58 ++ HiBit/Project/Player/View/GKDYTitleView.h | 26 + HiBit/Project/Player/View/GKDYTitleView.m | 195 +++++++ HiBit/Project/Player/View/GKDYVideoCell.h | 29 + HiBit/Project/Player/View/GKDYVideoCell.m | 58 ++ .../Player/View/GKDYVideoControlView.h | 55 ++ .../Player/View/GKDYVideoControlView.m | 302 +++++++++++ .../Player/View/GKDYVideoFullscreenView.h | 21 + .../Player/View/GKDYVideoFullscreenView.m | 211 ++++++++ .../Project/Player/View/GKDYVideoItemButton.h | 17 + .../Project/Player/View/GKDYVideoItemButton.m | 33 ++ .../Player/View/GKDYVideoLandscapeCell.h | 26 + .../Player/View/GKDYVideoLandscapeCell.m | 110 ++++ .../Player/View/GKDYVideoLandscapeView.h | 37 ++ .../Player/View/GKDYVideoLandscapeView.m | 491 +++++++++++++++++ HiBit/Project/Player/View/GKDYVideoMaskView.h | 26 + HiBit/Project/Player/View/GKDYVideoMaskView.m | 48 ++ .../Player/View/GKDYVideoPortraitCell.h | 49 ++ .../Player/View/GKDYVideoPortraitCell.m | 174 ++++++ .../Player/View/GKDYVideoPortraitView.h | 64 +++ .../Player/View/GKDYVideoPortraitView.m | 393 ++++++++++++++ .../Player/View/GKDYVideoPreviewView.h | 22 + .../Player/View/GKDYVideoPreviewView.m | 108 ++++ .../Project/Player/View/GKDYVideoScrollView.h | 31 ++ .../Project/Player/View/GKDYVideoScrollView.m | 126 +++++ HiBit/Project/Player/View/GKDYVideoSlider.h | 33 ++ HiBit/Project/Player/View/GKDYVideoSlider.m | 212 ++++++++ .../Project/Player/View/GKDYVideoStatusBar.h | 27 + .../Project/Player/View/GKDYVideoStatusBar.m | 345 ++++++++++++ .../Project/Publics/CommonKeys/HBCommonKeys.h | 20 +- .../Project/Publics/CommonKeys/HBCommonKeys.m | 2 +- .../Project/Publics/CommonKeys/HBThirdKeys.h | 8 +- .../Manager/HBMultiLanguageManager.h | 4 +- 66 files changed, 6450 insertions(+), 29 deletions(-) create mode 100755 HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.h create mode 100755 HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.m create mode 100755 HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.h create mode 100755 HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.m create mode 100755 HiBit/Project/Player/Common/GKLikeView/GKLikeView.h create mode 100755 HiBit/Project/Player/Common/GKLikeView/GKLikeView.m create mode 100755 HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.h create mode 100755 HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.m create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.h create mode 100755 HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.m create mode 100755 HiBit/Project/Player/Manager/GKDYPlayerManager.h create mode 100755 HiBit/Project/Player/Manager/GKDYPlayerManager.m create mode 100644 HiBit/Project/Player/Model/GKDUVideoInfoModel.h create mode 100644 HiBit/Project/Player/Model/GKDUVideoInfoModel.m create mode 100755 HiBit/Project/Player/Model/GKDYVideoModel.h create mode 100755 HiBit/Project/Player/Model/GKDYVideoModel.m create mode 100755 HiBit/Project/Player/View/GKDYPanGestureRecognizer.h create mode 100755 HiBit/Project/Player/View/GKDYPanGestureRecognizer.m create mode 100755 HiBit/Project/Player/View/GKDYScrollView.h create mode 100755 HiBit/Project/Player/View/GKDYScrollView.m create mode 100755 HiBit/Project/Player/View/GKDYTitleView.h create mode 100755 HiBit/Project/Player/View/GKDYTitleView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoCell.h create mode 100755 HiBit/Project/Player/View/GKDYVideoCell.m create mode 100755 HiBit/Project/Player/View/GKDYVideoControlView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoControlView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoFullscreenView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoFullscreenView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoItemButton.h create mode 100755 HiBit/Project/Player/View/GKDYVideoItemButton.m create mode 100755 HiBit/Project/Player/View/GKDYVideoLandscapeCell.h create mode 100755 HiBit/Project/Player/View/GKDYVideoLandscapeCell.m create mode 100755 HiBit/Project/Player/View/GKDYVideoLandscapeView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoLandscapeView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoMaskView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoMaskView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoPortraitCell.h create mode 100755 HiBit/Project/Player/View/GKDYVideoPortraitCell.m create mode 100755 HiBit/Project/Player/View/GKDYVideoPortraitView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoPortraitView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoPreviewView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoPreviewView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoScrollView.h create mode 100755 HiBit/Project/Player/View/GKDYVideoScrollView.m create mode 100755 HiBit/Project/Player/View/GKDYVideoSlider.h create mode 100755 HiBit/Project/Player/View/GKDYVideoSlider.m create mode 100755 HiBit/Project/Player/View/GKDYVideoStatusBar.h create mode 100755 HiBit/Project/Player/View/GKDYVideoStatusBar.m diff --git a/HiBit.xcodeproj/project.pbxproj b/HiBit.xcodeproj/project.pbxproj index a2c2651..add3586 100644 --- a/HiBit.xcodeproj/project.pbxproj +++ b/HiBit.xcodeproj/project.pbxproj @@ -111,6 +111,35 @@ 91C871412C13111B0093790D /* HBHomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871402C13111B0093790D /* HBHomeViewController.m */; }; 91C871442C13112F0093790D /* HBDiscoverViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871432C13112F0093790D /* HBDiscoverViewController.m */; }; 91C871472C1311450093790D /* HBMineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871462C1311450093790D /* HBMineViewController.m */; }; + 91C8718E2C1314770093790D /* UIButton+GKEnlarge.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871492C1314770093790D /* UIButton+GKEnlarge.m */; }; + 91C8718F2C1314770093790D /* GKDoubleLikeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8714C2C1314770093790D /* GKDoubleLikeView.m */; }; + 91C871902C1314770093790D /* GKLikeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8714E2C1314770093790D /* GKLikeView.m */; }; + 91C871912C1314770093790D /* GKBallLoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871512C1314770093790D /* GKBallLoadingView.m */; }; + 91C871922C1314770093790D /* GKLandscapeNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871542C1314770093790D /* GKLandscapeNavigationController.m */; }; + 91C871932C1314770093790D /* GKLandscapeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871562C1314770093790D /* GKLandscapeViewController.m */; }; + 91C871942C1314770093790D /* GKLandscapeWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871582C1314770093790D /* GKLandscapeWindow.m */; }; + 91C871952C1314770093790D /* GKRotationManager_iOS_9_15.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8715A2C1314770093790D /* GKRotationManager_iOS_9_15.m */; }; + 91C871962C1314770093790D /* GKRotationManager_iOS_16_Later.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8715C2C1314770093790D /* GKRotationManager_iOS_16_Later.m */; }; + 91C871972C1314770093790D /* GKRotationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8715E2C1314770093790D /* GKRotationManager.m */; }; + 91C871992C1314770093790D /* GKDYPlayerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871652C1314770093790D /* GKDYPlayerManager.m */; }; + 91C8719A2C1314770093790D /* GKDUVideoInfoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871682C1314770093790D /* GKDUVideoInfoModel.m */; }; + 91C8719B2C1314770093790D /* GKDYVideoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8716A2C1314770093790D /* GKDYVideoModel.m */; }; + 91C8719C2C1314770093790D /* GKDYPanGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8716D2C1314770093790D /* GKDYPanGestureRecognizer.m */; }; + 91C8719D2C1314770093790D /* GKDYScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8716F2C1314770093790D /* GKDYScrollView.m */; }; + 91C8719E2C1314770093790D /* GKDYTitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871712C1314770093790D /* GKDYTitleView.m */; }; + 91C8719F2C1314770093790D /* GKDYVideoCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871732C1314770093790D /* GKDYVideoCell.m */; }; + 91C871A02C1314770093790D /* GKDYVideoControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871752C1314770093790D /* GKDYVideoControlView.m */; }; + 91C871A12C1314770093790D /* GKDYVideoFullscreenView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871772C1314770093790D /* GKDYVideoFullscreenView.m */; }; + 91C871A22C1314770093790D /* GKDYVideoItemButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871792C1314770093790D /* GKDYVideoItemButton.m */; }; + 91C871A32C1314770093790D /* GKDYVideoLandscapeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8717B2C1314770093790D /* GKDYVideoLandscapeCell.m */; }; + 91C871A42C1314770093790D /* GKDYVideoLandscapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8717D2C1314770093790D /* GKDYVideoLandscapeView.m */; }; + 91C871A52C1314770093790D /* GKDYVideoMaskView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8717F2C1314770093790D /* GKDYVideoMaskView.m */; }; + 91C871A62C1314770093790D /* GKDYVideoPortraitCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871812C1314770093790D /* GKDYVideoPortraitCell.m */; }; + 91C871A72C1314770093790D /* GKDYVideoPortraitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871832C1314770093790D /* GKDYVideoPortraitView.m */; }; + 91C871A82C1314770093790D /* GKDYVideoPreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871852C1314770093790D /* GKDYVideoPreviewView.m */; }; + 91C871A92C1314770093790D /* GKDYVideoScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871872C1314770093790D /* GKDYVideoScrollView.m */; }; + 91C871AA2C1314770093790D /* GKDYVideoSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C871892C1314770093790D /* GKDYVideoSlider.m */; }; + 91C871AB2C1314770093790D /* GKDYVideoStatusBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 91C8718B2C1314770093790D /* GKDYVideoStatusBar.m */; }; C8AC2283D47E2B99FF559E75 /* libPods-HiBit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 141F02EF5C0783797594009A /* libPods-HiBit.a */; }; /* End PBXBuildFile section */ @@ -327,6 +356,64 @@ 91C871432C13112F0093790D /* HBDiscoverViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HBDiscoverViewController.m; sourceTree = ""; }; 91C871452C1311450093790D /* HBMineViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBMineViewController.h; sourceTree = ""; }; 91C871462C1311450093790D /* HBMineViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HBMineViewController.m; sourceTree = ""; }; + 91C871482C1314770093790D /* UIButton+GKEnlarge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+GKEnlarge.h"; sourceTree = ""; }; + 91C871492C1314770093790D /* UIButton+GKEnlarge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+GKEnlarge.m"; sourceTree = ""; }; + 91C8714B2C1314770093790D /* GKDoubleLikeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDoubleLikeView.h; sourceTree = ""; }; + 91C8714C2C1314770093790D /* GKDoubleLikeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDoubleLikeView.m; sourceTree = ""; }; + 91C8714D2C1314770093790D /* GKLikeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKLikeView.h; sourceTree = ""; }; + 91C8714E2C1314770093790D /* GKLikeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLikeView.m; sourceTree = ""; }; + 91C871502C1314770093790D /* GKBallLoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKBallLoadingView.h; sourceTree = ""; }; + 91C871512C1314770093790D /* GKBallLoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKBallLoadingView.m; sourceTree = ""; }; + 91C871532C1314770093790D /* GKLandscapeNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKLandscapeNavigationController.h; sourceTree = ""; }; + 91C871542C1314770093790D /* GKLandscapeNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLandscapeNavigationController.m; sourceTree = ""; }; + 91C871552C1314770093790D /* GKLandscapeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKLandscapeViewController.h; sourceTree = ""; }; + 91C871562C1314770093790D /* GKLandscapeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLandscapeViewController.m; sourceTree = ""; }; + 91C871572C1314770093790D /* GKLandscapeWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKLandscapeWindow.h; sourceTree = ""; }; + 91C871582C1314770093790D /* GKLandscapeWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKLandscapeWindow.m; sourceTree = ""; }; + 91C871592C1314770093790D /* GKRotationManager_iOS_9_15.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKRotationManager_iOS_9_15.h; sourceTree = ""; }; + 91C8715A2C1314770093790D /* GKRotationManager_iOS_9_15.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKRotationManager_iOS_9_15.m; sourceTree = ""; }; + 91C8715B2C1314770093790D /* GKRotationManager_iOS_16_Later.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKRotationManager_iOS_16_Later.h; sourceTree = ""; }; + 91C8715C2C1314770093790D /* GKRotationManager_iOS_16_Later.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKRotationManager_iOS_16_Later.m; sourceTree = ""; }; + 91C8715D2C1314770093790D /* GKRotationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKRotationManager.h; sourceTree = ""; }; + 91C8715E2C1314770093790D /* GKRotationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKRotationManager.m; sourceTree = ""; }; + 91C871642C1314770093790D /* GKDYPlayerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYPlayerManager.h; sourceTree = ""; }; + 91C871652C1314770093790D /* GKDYPlayerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYPlayerManager.m; sourceTree = ""; }; + 91C871672C1314770093790D /* GKDUVideoInfoModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDUVideoInfoModel.h; sourceTree = ""; }; + 91C871682C1314770093790D /* GKDUVideoInfoModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDUVideoInfoModel.m; sourceTree = ""; }; + 91C871692C1314770093790D /* GKDYVideoModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoModel.h; sourceTree = ""; }; + 91C8716A2C1314770093790D /* GKDYVideoModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoModel.m; sourceTree = ""; }; + 91C8716C2C1314770093790D /* GKDYPanGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYPanGestureRecognizer.h; sourceTree = ""; }; + 91C8716D2C1314770093790D /* GKDYPanGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYPanGestureRecognizer.m; sourceTree = ""; }; + 91C8716E2C1314770093790D /* GKDYScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYScrollView.h; sourceTree = ""; }; + 91C8716F2C1314770093790D /* GKDYScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYScrollView.m; sourceTree = ""; }; + 91C871702C1314770093790D /* GKDYTitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYTitleView.h; sourceTree = ""; }; + 91C871712C1314770093790D /* GKDYTitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYTitleView.m; sourceTree = ""; }; + 91C871722C1314770093790D /* GKDYVideoCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoCell.h; sourceTree = ""; }; + 91C871732C1314770093790D /* GKDYVideoCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoCell.m; sourceTree = ""; }; + 91C871742C1314770093790D /* GKDYVideoControlView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoControlView.h; sourceTree = ""; }; + 91C871752C1314770093790D /* GKDYVideoControlView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoControlView.m; sourceTree = ""; }; + 91C871762C1314770093790D /* GKDYVideoFullscreenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoFullscreenView.h; sourceTree = ""; }; + 91C871772C1314770093790D /* GKDYVideoFullscreenView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoFullscreenView.m; sourceTree = ""; }; + 91C871782C1314770093790D /* GKDYVideoItemButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoItemButton.h; sourceTree = ""; }; + 91C871792C1314770093790D /* GKDYVideoItemButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoItemButton.m; sourceTree = ""; }; + 91C8717A2C1314770093790D /* GKDYVideoLandscapeCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoLandscapeCell.h; sourceTree = ""; }; + 91C8717B2C1314770093790D /* GKDYVideoLandscapeCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoLandscapeCell.m; sourceTree = ""; }; + 91C8717C2C1314770093790D /* GKDYVideoLandscapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoLandscapeView.h; sourceTree = ""; }; + 91C8717D2C1314770093790D /* GKDYVideoLandscapeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoLandscapeView.m; sourceTree = ""; }; + 91C8717E2C1314770093790D /* GKDYVideoMaskView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoMaskView.h; sourceTree = ""; }; + 91C8717F2C1314770093790D /* GKDYVideoMaskView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoMaskView.m; sourceTree = ""; }; + 91C871802C1314770093790D /* GKDYVideoPortraitCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoPortraitCell.h; sourceTree = ""; }; + 91C871812C1314770093790D /* GKDYVideoPortraitCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoPortraitCell.m; sourceTree = ""; }; + 91C871822C1314770093790D /* GKDYVideoPortraitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoPortraitView.h; sourceTree = ""; }; + 91C871832C1314770093790D /* GKDYVideoPortraitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoPortraitView.m; sourceTree = ""; }; + 91C871842C1314770093790D /* GKDYVideoPreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoPreviewView.h; sourceTree = ""; }; + 91C871852C1314770093790D /* GKDYVideoPreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoPreviewView.m; sourceTree = ""; }; + 91C871862C1314770093790D /* GKDYVideoScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoScrollView.h; sourceTree = ""; }; + 91C871872C1314770093790D /* GKDYVideoScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoScrollView.m; sourceTree = ""; }; + 91C871882C1314770093790D /* GKDYVideoSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoSlider.h; sourceTree = ""; }; + 91C871892C1314770093790D /* GKDYVideoSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoSlider.m; sourceTree = ""; }; + 91C8718A2C1314770093790D /* GKDYVideoStatusBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GKDYVideoStatusBar.h; sourceTree = ""; }; + 91C8718B2C1314770093790D /* GKDYVideoStatusBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GKDYVideoStatusBar.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -782,6 +869,7 @@ 916353402C12C10100593047 /* Project */ = { isa = PBXGroup; children = ( + 91C8718D2C1314770093790D /* Player */, 916353852C12C20B00593047 /* Publics */, 9163533F2C12C01E00593047 /* Services */, 91C871362C13108E0093790D /* Login */, @@ -1039,6 +1127,135 @@ path = Views; sourceTree = ""; }; + 91C8714A2C1314770093790D /* Category */ = { + isa = PBXGroup; + children = ( + 91C871482C1314770093790D /* UIButton+GKEnlarge.h */, + 91C871492C1314770093790D /* UIButton+GKEnlarge.m */, + ); + path = Category; + sourceTree = ""; + }; + 91C8714F2C1314770093790D /* GKLikeView */ = { + isa = PBXGroup; + children = ( + 91C8714B2C1314770093790D /* GKDoubleLikeView.h */, + 91C8714C2C1314770093790D /* GKDoubleLikeView.m */, + 91C8714D2C1314770093790D /* GKLikeView.h */, + 91C8714E2C1314770093790D /* GKLikeView.m */, + ); + path = GKLikeView; + sourceTree = ""; + }; + 91C871522C1314770093790D /* GKLoadingView */ = { + isa = PBXGroup; + children = ( + 91C871502C1314770093790D /* GKBallLoadingView.h */, + 91C871512C1314770093790D /* GKBallLoadingView.m */, + ); + path = GKLoadingView; + sourceTree = ""; + }; + 91C8715F2C1314770093790D /* GKRotationManager */ = { + isa = PBXGroup; + children = ( + 91C871532C1314770093790D /* GKLandscapeNavigationController.h */, + 91C871542C1314770093790D /* GKLandscapeNavigationController.m */, + 91C871552C1314770093790D /* GKLandscapeViewController.h */, + 91C871562C1314770093790D /* GKLandscapeViewController.m */, + 91C871572C1314770093790D /* GKLandscapeWindow.h */, + 91C871582C1314770093790D /* GKLandscapeWindow.m */, + 91C871592C1314770093790D /* GKRotationManager_iOS_9_15.h */, + 91C8715A2C1314770093790D /* GKRotationManager_iOS_9_15.m */, + 91C8715B2C1314770093790D /* GKRotationManager_iOS_16_Later.h */, + 91C8715C2C1314770093790D /* GKRotationManager_iOS_16_Later.m */, + 91C8715D2C1314770093790D /* GKRotationManager.h */, + 91C8715E2C1314770093790D /* GKRotationManager.m */, + ); + path = GKRotationManager; + sourceTree = ""; + }; + 91C871602C1314770093790D /* Common */ = { + isa = PBXGroup; + children = ( + 91C8714A2C1314770093790D /* Category */, + 91C8714F2C1314770093790D /* GKLikeView */, + 91C871522C1314770093790D /* GKLoadingView */, + 91C8715F2C1314770093790D /* GKRotationManager */, + ); + path = Common; + sourceTree = ""; + }; + 91C871662C1314770093790D /* Manager */ = { + isa = PBXGroup; + children = ( + 91C871642C1314770093790D /* GKDYPlayerManager.h */, + 91C871652C1314770093790D /* GKDYPlayerManager.m */, + ); + path = Manager; + sourceTree = ""; + }; + 91C8716B2C1314770093790D /* Model */ = { + isa = PBXGroup; + children = ( + 91C871672C1314770093790D /* GKDUVideoInfoModel.h */, + 91C871682C1314770093790D /* GKDUVideoInfoModel.m */, + 91C871692C1314770093790D /* GKDYVideoModel.h */, + 91C8716A2C1314770093790D /* GKDYVideoModel.m */, + ); + path = Model; + sourceTree = ""; + }; + 91C8718C2C1314770093790D /* View */ = { + isa = PBXGroup; + children = ( + 91C8716C2C1314770093790D /* GKDYPanGestureRecognizer.h */, + 91C8716D2C1314770093790D /* GKDYPanGestureRecognizer.m */, + 91C8716E2C1314770093790D /* GKDYScrollView.h */, + 91C8716F2C1314770093790D /* GKDYScrollView.m */, + 91C871702C1314770093790D /* GKDYTitleView.h */, + 91C871712C1314770093790D /* GKDYTitleView.m */, + 91C871722C1314770093790D /* GKDYVideoCell.h */, + 91C871732C1314770093790D /* GKDYVideoCell.m */, + 91C871742C1314770093790D /* GKDYVideoControlView.h */, + 91C871752C1314770093790D /* GKDYVideoControlView.m */, + 91C871762C1314770093790D /* GKDYVideoFullscreenView.h */, + 91C871772C1314770093790D /* GKDYVideoFullscreenView.m */, + 91C871782C1314770093790D /* GKDYVideoItemButton.h */, + 91C871792C1314770093790D /* GKDYVideoItemButton.m */, + 91C8717A2C1314770093790D /* GKDYVideoLandscapeCell.h */, + 91C8717B2C1314770093790D /* GKDYVideoLandscapeCell.m */, + 91C8717C2C1314770093790D /* GKDYVideoLandscapeView.h */, + 91C8717D2C1314770093790D /* GKDYVideoLandscapeView.m */, + 91C8717E2C1314770093790D /* GKDYVideoMaskView.h */, + 91C8717F2C1314770093790D /* GKDYVideoMaskView.m */, + 91C871802C1314770093790D /* GKDYVideoPortraitCell.h */, + 91C871812C1314770093790D /* GKDYVideoPortraitCell.m */, + 91C871822C1314770093790D /* GKDYVideoPortraitView.h */, + 91C871832C1314770093790D /* GKDYVideoPortraitView.m */, + 91C871842C1314770093790D /* GKDYVideoPreviewView.h */, + 91C871852C1314770093790D /* GKDYVideoPreviewView.m */, + 91C871862C1314770093790D /* GKDYVideoScrollView.h */, + 91C871872C1314770093790D /* GKDYVideoScrollView.m */, + 91C871882C1314770093790D /* GKDYVideoSlider.h */, + 91C871892C1314770093790D /* GKDYVideoSlider.m */, + 91C8718A2C1314770093790D /* GKDYVideoStatusBar.h */, + 91C8718B2C1314770093790D /* GKDYVideoStatusBar.m */, + ); + path = View; + sourceTree = ""; + }; + 91C8718D2C1314770093790D /* Player */ = { + isa = PBXGroup; + children = ( + 91C871602C1314770093790D /* Common */, + 91C871662C1314770093790D /* Manager */, + 91C8716B2C1314770093790D /* Model */, + 91C8718C2C1314770093790D /* View */, + ); + path = Player; + sourceTree = ""; + }; B36329ED094310C499FEBA2F /* Frameworks */ = { isa = PBXGroup; children = ( @@ -1184,28 +1401,43 @@ files = ( 916353892C12C20B00593047 /* HBNavigationController.m in Sources */, 916353002C12B6D400593047 /* NSUserDefaults+Extesion.m in Sources */, + 91C871A12C1314770093790D /* GKDYVideoFullscreenView.m in Sources */, + 91C871A92C1314770093790D /* GKDYVideoScrollView.m in Sources */, 916351402C12B12F00593047 /* AppDelegate.m in Sources */, + 91C871A72C1314770093790D /* GKDYVideoPortraitView.m in Sources */, 9163530D2C12B6D400593047 /* UINavigationController+Transparent.m in Sources */, 916352FA2C12B6D400593047 /* NSNumber+Extension.m in Sources */, 9163534D2C12C15300593047 /* HBNetWorkingUtilityResult.m in Sources */, 916353292C12B6D400593047 /* DGActivityIndicatorLineScalePulseOutRapidAnimation.m in Sources */, 916353A22C12C3DC00593047 /* HtyoNetWorking.m in Sources */, + 91C871992C1314770093790D /* GKDYPlayerManager.m in Sources */, 916353232C12B6D400593047 /* DGActivityIndicatorCookieTerminatorAnimation.m in Sources */, + 91C871A42C1314770093790D /* GKDYVideoLandscapeView.m in Sources */, 91C871412C13111B0093790D /* HBHomeViewController.m in Sources */, + 91C871A62C1314770093790D /* GKDYVideoPortraitCell.m in Sources */, + 91C8718F2C1314770093790D /* GKDoubleLikeView.m in Sources */, 9163530A2C12B6D400593047 /* NSLayoutConstraint+BSIBDesignable.m in Sources */, 9163534C2C12C15300593047 /* HBNetWorkingUtility.m in Sources */, + 91C8719A2C1314770093790D /* GKDUVideoInfoModel.m in Sources */, 916353352C12B6D400593047 /* SVIndefiniteAnimatedView.m in Sources */, 916353332C12B6D400593047 /* DGActivityIndicatorView.m in Sources */, 916353152C12B6D400593047 /* DGActivityIndicatorBallClipRotatePulseAnimation.m in Sources */, + 91C8719E2C1314770093790D /* GKDYTitleView.m in Sources */, 916353132C12B6D400593047 /* DGActivityIndicatorBallClipRotateAnimation.m in Sources */, + 91C871952C1314770093790D /* GKRotationManager_iOS_9_15.m in Sources */, 916353322C12B6D400593047 /* DGActivityIndicatorTwoDotsAnimation.m in Sources */, 916353862C12C20B00593047 /* HBColor.m in Sources */, 9163532B2C12B6D400593047 /* DGActivityIndicatorRotatingSandglassAnimation.m in Sources */, + 91C871912C1314770093790D /* GKBallLoadingView.m in Sources */, 9163530E2C12B6D400593047 /* UIViewController+present.m in Sources */, 916353212C12B6D400593047 /* DGActivityIndicatorBallZigZagAnimation.m in Sources */, + 91C871942C1314770093790D /* GKLandscapeWindow.m in Sources */, + 91C871922C1314770093790D /* GKLandscapeNavigationController.m in Sources */, 916353262C12B6D400593047 /* DGActivityIndicatorLineScaleAnimation.m in Sources */, 916353272C12B6D400593047 /* DGActivityIndicatorLineScalePartyAnimation.m in Sources */, + 91C871A52C1314770093790D /* GKDYVideoMaskView.m in Sources */, 916353102C12B6D400593047 /* NSString+AES.m in Sources */, + 91C871A22C1314770093790D /* GKDYVideoItemButton.m in Sources */, 9163538B2C12C20B00593047 /* HBViewController.m in Sources */, 9163531A2C12B6D400593047 /* DGActivityIndicatorBallRotateAnimation.m in Sources */, 916352F82C12B6D400593047 /* NSDate+Extension.m in Sources */, @@ -1214,9 +1446,13 @@ 9163531D2C12B6D400593047 /* DGActivityIndicatorBallScaleRippleAnimation.m in Sources */, 9163533A2C12B6D400593047 /* HUDManager.m in Sources */, 916353072C12B6D400593047 /* UIScreen+Extension.m in Sources */, + 91C8719D2C1314770093790D /* GKDYScrollView.m in Sources */, 916353282C12B6D400593047 /* DGActivityIndicatorLineScalePulseOutAnimation.m in Sources */, + 91C871972C1314770093790D /* GKRotationManager.m in Sources */, 9163534B2C12C15300593047 /* HBApiParams.m in Sources */, 9163531C2C12B6D400593047 /* DGActivityIndicatorBallScaleMultipleAnimation.m in Sources */, + 91C871A32C1314770093790D /* GKDYVideoLandscapeCell.m in Sources */, + 91C871AA2C1314770093790D /* GKDYVideoSlider.m in Sources */, 916353042C12B6D400593047 /* UIFont+Category.m in Sources */, 916353092C12B6D400593047 /* UITextField+Category.m in Sources */, 916353972C12C20B00593047 /* HBTableView.m in Sources */, @@ -1230,10 +1466,14 @@ 9163538D2C12C20B00593047 /* HBMultiLanguageManager.m in Sources */, 9163531F2C12B6D400593047 /* DGActivityIndicatorBallSpinFadeLoader.m in Sources */, 9163539A2C12C20B00593047 /* RSButton.m in Sources */, + 91C8719F2C1314770093790D /* GKDYVideoCell.m in Sources */, + 91C8718E2C1314770093790D /* UIButton+GKEnlarge.m in Sources */, 916353302C12B6D400593047 /* DGActivityIndicatorTriplePulseAnimation.m in Sources */, 916353022C12B6D400593047 /* UIControl+Extension.m in Sources */, 9163532D2C12B6D400593047 /* DGActivityIndicatorRotatingTrigonAnimation.m in Sources */, + 91C871902C1314770093790D /* GKLikeView.m in Sources */, 916353342C12B6D400593047 /* MBProgressHUD.m in Sources */, + 91C871A82C1314770093790D /* GKDYVideoPreviewView.m in Sources */, 916353242C12B6D400593047 /* DGActivityIndicatorDoubleBounceAnimation.m in Sources */, 9163538C2C12C20B00593047 /* HBMultiLanguageController.m in Sources */, 916353192C12B6D400593047 /* DGActivityIndicatorBallPulseSyncAnimation.m in Sources */, @@ -1241,6 +1481,7 @@ 9163533D2C12B6D400593047 /* KxMenu.m in Sources */, 916353A82C12C6AF00593047 /* NSNotificationCenter+Extension.m in Sources */, 91C8711E2C12ECF50093790D /* HBFirstStartController.m in Sources */, + 91C8719B2C1314770093790D /* GKDYVideoModel.m in Sources */, 9163531E2C12B6D400593047 /* DGActivityIndicatorBallScaleRippleMultipleAnimation.m in Sources */, 916353362C12B6D400593047 /* SVProgressAnimatedView.m in Sources */, 916353112C12B6D400593047 /* DGActivityIndicatorAnimation.m in Sources */, @@ -1248,6 +1489,7 @@ 9163531B2C12B6D400593047 /* DGActivityIndicatorBallScaleAnimation.m in Sources */, 916353182C12B6D400593047 /* DGActivityIndicatorBallPulseAnimation.m in Sources */, 916353872C12C20B00593047 /* HBCommonKeys.m in Sources */, + 91C871AB2C1314770093790D /* GKDYVideoStatusBar.m in Sources */, 916353052C12B6D400593047 /* UIImage+Category.m in Sources */, 916353962C12C20B00593047 /* HBRefreshNormalHeader.m in Sources */, 916353392C12B6D400593047 /* SVRadialGradientLayer.m in Sources */, @@ -1256,9 +1498,13 @@ 916353312C12B6D400593047 /* DGActivityIndicatorTripleRingsAnimation.m in Sources */, 916352FE2C12B6D400593047 /* NSString+Extension.m in Sources */, 916352FD2C12B6D400593047 /* NSObject+Tool.m in Sources */, + 91C8719C2C1314770093790D /* GKDYPanGestureRecognizer.m in Sources */, 9163530F2C12B6D400593047 /* GTMBase64.m in Sources */, + 91C871962C1314770093790D /* GKRotationManager_iOS_16_Later.m in Sources */, 916353062C12B6D400593047 /* UIImageView+Extension.m in Sources */, + 91C871A02C1314770093790D /* GKDYVideoControlView.m in Sources */, 9163530C2C12B6D400593047 /* UIView+Frame.m in Sources */, + 91C871932C1314770093790D /* GKLandscapeViewController.m in Sources */, 916353382C12B6D400593047 /* SVProgressHUD.m in Sources */, 9163534E2C12C15300593047 /* HBNetWorkingUtility+Services.m in Sources */, 916353142C12B6D400593047 /* DGActivityIndicatorBallClipRotateMultipleAnimation.m in Sources */, diff --git a/HiBit/Basics/Info.plist b/HiBit/Basics/Info.plist index 0c67376..1128120 100644 --- a/HiBit/Basics/Info.plist +++ b/HiBit/Basics/Info.plist @@ -1,5 +1,16 @@ - + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + NSExceptionAllowsInsecureHTTPLoads + + + + diff --git a/HiBit/Project/Home/Controllers/HBHomeViewController.h b/HiBit/Project/Home/Controllers/HBHomeViewController.h index 69576af..d9767f3 100644 --- a/HiBit/Project/Home/Controllers/HBHomeViewController.h +++ b/HiBit/Project/Home/Controllers/HBHomeViewController.h @@ -6,11 +6,44 @@ // #import "HBViewController.h" +#import "GKDYVideoModel.h" +#import +#import "GKDYVideoScrollView.h" NS_ASSUME_NONNULL_BEGIN -@interface HBHomeViewController : HBViewController +@class HBHomeViewController; + +@protocol HBHomeViewControllerDelegate + +@optional; + +- (void)playerVCDidClickShoot:(HBHomeViewController *)playerVC; + +//- (void)playerVC:(HBHomeViewController *)playerVC controlView:(GKDYVideoControlView *)controlView isCritical:(BOOL)isCritical; + +- (void)playerVC:(HBHomeViewController *)playerVC didDragDistance:(CGFloat)distance isEnd:(BOOL)isEnd; + +- (void)playerVC:(HBHomeViewController *)playerVC cellZoomBegan:(GKDYVideoModel *)model; + +- (void)playerVC:(HBHomeViewController *)playerVC cellZoomEnded:(GKDYVideoModel *)model isFullscreen:(BOOL)isFullscreen; + +- (void)playerVC:(HBHomeViewController *)playerVC commentShowOrHide:(BOOL)show; @end +@interface HBHomeViewController : HBViewController + +@property (nonatomic, weak) id delegate; + +@property (nonatomic, copy) NSString *tab; + +@property (nonatomic, strong) GKDYVideoModel * model; + + +- (void)refreshData:(nullable void(^)(void))completion; + +-(instancetype)initWithVideoId:(NSInteger)sid; + +@end NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Home/Controllers/HBHomeViewController.m b/HiBit/Project/Home/Controllers/HBHomeViewController.m index fedcf6b..55241ef 100644 --- a/HiBit/Project/Home/Controllers/HBHomeViewController.m +++ b/HiBit/Project/Home/Controllers/HBHomeViewController.m @@ -7,25 +7,247 @@ #import "HBHomeViewController.h" -@interface HBHomeViewController () +//#import "QJShereModalView.h" +//#import "QJVideoEpisodesModalView.h" + +#import "GKBallLoadingView.h" +#import "GKLikeView.h" +#import "GKDYVideoScrollView.h" +#import "GKDYVideoCell.h" +#import "GKDYPlayerManager.h" +#import "GKDYVideoPortraitCell.h" +#import "GKDYVideoLandscapeCell.h" + + +@interface HBHomeViewController () //,QJVideoEpisodesModalViewDelegate> + +@property (nonatomic, strong) GKDYPlayerManager * manager; +@property (assign, nonatomic) BOOL isDetails; +@property (assign, nonatomic) NSInteger sid; + +//@property (nonatomic, strong) QJVideoEpisodesModalView * episodesModalView; @end @implementation HBHomeViewController +- (instancetype)initWithVideoId:(NSInteger)sid { + self = [super init]; + if (self) { + self.isDetails = YES; + self.sid = sid; + } + return self; +} + - (void)viewDidLoad { [super viewDidLoad]; - // Do any additional setup after loading the view. + self.hbd_barAlpha = 0.0; + self.edgesForExtendedLayout = UIRectEdgeNone; + + [self initUI]; + [self setupRefresh]; + [self requestData]; } -/* -#pragma mark - Navigation - -// In a storyboard-based application, you will often want to do a little preparation before navigation -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - // Get the new view controller using [segue destinationViewController]. - // Pass the selected object to the new view controller. +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + self.manager.player.viewControllerDisappear = YES; } -*/ + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + self.manager.player.viewControllerDisappear = NO; +} + +- (void)dealloc { + NSLog(@"playerVC dealloc"); +} + +- (void)initUI { + + [self.view addSubview:self.manager.scrollView]; + + [self.manager.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.view); + }]; +} + +- (void)setupRefresh { + if (self.isDetails) return; // 详情也 不需要加载更多 + + @weakify(self); + self.manager.scrollView.mj_footer = [HBRefreshAutoNormalFooter footerWithRefreshingBlock:^{ + @strongify(self); + [self requestMore]; + }]; +} + +- (void)requestData { + GKBallLoadingView *loadingView = [GKBallLoadingView loadingViewInView:self.view]; + [loadingView startLoading]; + + self.manager.page = 1; + @weakify(loadingView); + [self requestData:^{ + @strongify(loadingView); + [loadingView stopLoading]; + [loadingView removeFromSuperview]; + }]; +} + +- (void)requestMore { + self.manager.page++; + [self requestData:nil]; +} + +- (void)refreshData:(void (^)(void))completion { + self.manager.page = 1; + [self requestData:completion]; +} + +- (void)requestData:(nullable void (^)(void))completion { + HBWeakSelf + + if (self.isDetails) { + + [HBNetWorkingUtility videos_fetchVideoDetailsWithSid:self.sid + complateBlock:^(BOOL success, id _Nonnull data, NSString * _Nonnull message) { + if (completion) completion(); + + if (success) { + GKDYVideoModel * model = [GKDYVideoModel mj_objectWithKeyValues:data[@"shortVideoInfo"]]; + NSArray * videoInfoModels = [GKDUVideoInfoModel mj_objectArrayWithKeyValuesArray:data[@"episode_list"]]; + GKDUVideoInfoModel * formModel = [GKDUVideoInfoModel mj_objectWithKeyValues:data[@"video_info"]]; + + for (GKDUVideoInfoModel * videoInfoModel in videoInfoModels) { + GKDYVideoModel * tempModel = [model copy]; + tempModel.videoInfo = videoInfoModel; + [weakSelf.manager.dataSources addObject:tempModel]; + } +// weakSelf.episodesModalView.models = weakSelf.manager.dataSources; +// weakSelf.episodesModalView.indexModel = formModel; + [weakSelf.manager.scrollView reloadData]; + [weakSelf.manager.scrollView scrollToPageWithIndex:(formModel.episode -1)]; + + } + }]; + } else { + [HBNetWorkingUtility discover_fetchRecommandsWithPage:self.manager.page + size:20 + complateBlock:^(BOOL success, id _Nonnull data, NSString * _Nonnull message) { + if (completion) completion(); + if (success) { + NSArray * models = [GKDYVideoModel mj_objectArrayWithKeyValuesArray:data[@"list"]]; + + if (weakSelf.manager.page == 1) { + [weakSelf.manager.dataSources removeAllObjects]; + } + [weakSelf.manager.dataSources addObjectsFromArray:models]; + [weakSelf.manager.scrollView reloadData]; + } + [weakSelf.manager.scrollView.mj_footer endRefreshingWithNoMoreData]; + }]; + } + +} + +- (GKDYVideoModel *)model { + return self.manager.currentCell.model; +} + +#pragma mark - GKDYPlayerManagerDelegate +- (void)scrollViewShouldLoadMore { + [self requestMore]; +} + +- (void)scrollViewDidPanDistance:(CGFloat)distance isEnd:(BOOL)isEnd { + if ([self.delegate respondsToSelector:@selector(playerVC:didDragDistance:isEnd:)]) { + [self.delegate playerVC:self didDragDistance:distance isEnd:isEnd]; + } +} + +- (void)cellZoomBegan:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(playerVC:cellZoomBegan:)]) { + [self.delegate playerVC:self cellZoomBegan:model]; + } +} + +- (void)cellZoomEnded:(GKDYVideoModel *)model isFullscreen:(BOOL)isFullscreen { + if ([self.delegate respondsToSelector:@selector(playerVC:cellZoomEnded:isFullscreen:)]) { + [self.delegate playerVC:self cellZoomEnded:model isFullscreen:isFullscreen]; + } +} + + +- (void)celldidClickShare:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell { +// [[QJShereModalView new] presentInView:nil]; +} + +- (void)celldidClickFavorite:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell { + if (self.isDetails) return; + + if (model.is_collect) { + [HBNetWorkingUtility customer_favoriteWithVideoId:model.cid complateBlock:nil]; + } else { + [HBNetWorkingUtility customer_unFavoriteWithVideoId:model.cid complateBlock:nil]; + } +} + +- (void)celldidClickEpiscode:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell { + if (!self.isDetails) { + HBHomeViewController * controller = [[HBHomeViewController alloc]initWithVideoId:model.cid]; + [self.navigationController pushViewController:controller animated:YES]; + } else { + +// self.episodesModalView.indexModel = self.manager.currentCell.model.videoInfo; +// [self.episodesModalView presentInView:nil]; + } +} + +-(void)videoEpisodesModalViewDidSelectItemWithModel:(GKDUVideoInfoModel *)model { + + if (self.isDetails) { + + + NSInteger row = 0; + for (int index = 0; index < self.manager.dataSources.count; index ++ ) { + GKDYVideoModel * tempModel = self.manager.dataSources[index]; + if (model.vid == tempModel.videoInfo.vid) { + row = index; + break;; + } + } + + [self.manager.scrollView scrollToPageWithIndex:row]; + } +} + +- (void)cellSwitchWithModel:(GKDYVideoModel *)model { + if (!self.isDetails) return; + [HBNetWorkingUtility videos_uploadPlayHistoryWithSid:model.cid + vId:model.videoInfo.vid + complateBlock:^(BOOL success, id _Nonnull data, NSString * _Nonnull message) { + + }]; +} + +#pragma mark - 懒加载 +- (GKDYPlayerManager *)manager { + if (!_manager) { + _manager = [[GKDYPlayerManager alloc] init]; + _manager.delegate = self; + } + return _manager; +} + +//- (QJVideoEpisodesModalView *)episodesModalView{ +// if (!_episodesModalView) { +// _episodesModalView = [QJVideoEpisodesModalView new]; +// _episodesModalView.delegate = self; +// } +// return _episodesModalView; +//} @end + diff --git a/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.h b/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.h new file mode 100755 index 0000000..b1fbaed --- /dev/null +++ b/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.h @@ -0,0 +1,29 @@ +// +// UIButton+GKEnlarge.h +// Example +// +// Created by QuintGao on 2023/3/15. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface UIButton (GKEnlarge) + +/* +扩大UIButton响应区域 + +使用 + [enlargeButton setEnlargeEdge:20.0]; +或者 + [enlargeButton setEnlargeEdgeWithTop:20 right:20 bottom:20 left:10]; +*/ + +- (void)setEnlargeEdge:(CGFloat)size; +- (void)setEnlargeEdgeWithTop:(CGFloat)top left:(CGFloat)left bottom:(CGFloat)bottom right:(CGFloat)right; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.m b/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.m new file mode 100755 index 0000000..b0ca067 --- /dev/null +++ b/HiBit/Project/Player/Common/Category/UIButton+GKEnlarge.m @@ -0,0 +1,64 @@ +// +// UIButton+GKEnlarge.m +// Example +// +// Created by QuintGao on 2023/3/15. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "UIButton+GKEnlarge.h" +#import + +@implementation UIButton (GKEnlarge) + +static char topNameKey; +static char rightNameKey; +static char bottomNameKey; +static char leftNameKey; + +- (void)setEnlargeEdge:(CGFloat)size +{ + objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:size], OBJC_ASSOCIATION_COPY_NONATOMIC); +} + +- (void)setEnlargeEdgeWithTop:(CGFloat)top left:(CGFloat)left bottom:(CGFloat)bottom right:(CGFloat)right +{ + objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC); + objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC); +} + +- (CGRect)enlargedRect +{ + NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey); + NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey); + NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey); + NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey); + if (topEdge && rightEdge && bottomEdge && leftEdge) + { + return CGRectMake(self.bounds.origin.x - leftEdge.floatValue, + self.bounds.origin.y - topEdge.floatValue, + self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue, + self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue); + } + else + { + return self.bounds; + } +} + +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event +{ + CGRect rect = [self enlargedRect]; + if (CGRectEqualToRect(rect, self.bounds)) + { + return [super pointInside:point withEvent:event]; + } + return CGRectContainsPoint(rect, point) ? YES : NO; +} + +@end diff --git a/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.h b/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.h new file mode 100755 index 0000000..a6783b6 --- /dev/null +++ b/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.h @@ -0,0 +1,21 @@ +// +// GKDoubleLikeView.h +// GKDYVideo +// +// Created by gaokun on 2019/6/19. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDoubleLikeView : NSObject + +- (void)createAnimationWithTouch:(UITouch *)touch; + +- (void)createAnimationWithPoint:(CGPoint)point view:(UIView *)view completion:(nullable void(^)(void))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.m b/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.m new file mode 100755 index 0000000..59b13c1 --- /dev/null +++ b/HiBit/Project/Player/Common/GKLikeView/GKDoubleLikeView.m @@ -0,0 +1,73 @@ +// +// GKDoubleLikeView.m +// GKDYVideo +// +// Created by gaokun on 2019/6/19. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import "GKDoubleLikeView.h" + +@interface GKDoubleLikeView() + +@property (nonatomic, copy) void(^completion)(void); + +@end + +@implementation GKDoubleLikeView + +- (void)createAnimationWithTouch:(UITouch *)touch { + if (touch.tapCount <= 1.0f) return; + + [self createAnimationWithPoint:[touch locationInView:touch.view] view:touch.view completion:nil]; +} + +- (void)createAnimationWithPoint:(CGPoint)point view:(UIView *)view completion:(nullable void (^)(void))completion { + self.completion = completion; + + UIImage *image = [UIImage imageNamed:@"player_favorite_selected"]; + UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 80, 80)]; + imgView.image = image; + imgView.contentMode = UIViewContentModeScaleAspectFill; + imgView.center = point; + + // 随机左右显示 + int leftOrRight = arc4random() % 2; + leftOrRight = leftOrRight ? leftOrRight : -1; + imgView.transform = CGAffineTransformRotate(imgView.transform, M_PI / 9.0f * leftOrRight); + [view addSubview:imgView]; + + // 出现的时候回弹一下 + __block UIImageView *blockImgV = imgView; + __block UIImage *blockImage = image; + + [UIView animateWithDuration:0.1 animations:^{ + blockImgV.transform = CGAffineTransformScale(blockImgV.transform, 1.2f, 1.2f); + } completion:^(BOOL finished) { + blockImgV.transform = CGAffineTransformScale(blockImgV.transform, 0.8f, 0.8f); + + // 向上飘,放大,透明 + [self performSelector:@selector(animationToTop:) withObject:@[blockImgV, blockImage] afterDelay:0.3f]; + }]; +} + +- (void)animationToTop:(NSArray *)imgObjects { + if (imgObjects && imgObjects.count > 0) { + __block UIImageView *imgView = (UIImageView *)imgObjects.firstObject; + __block UIImage *image = (UIImage *)imgObjects.lastObject; + [UIView animateWithDuration:1.0f animations:^{ + CGRect imgViewFrame = imgView.frame; + imgViewFrame.origin.y -= 100.0f; + imgView.frame = imgViewFrame; + imgView.transform = CGAffineTransformScale(imgView.transform, 1.8f, 1.8f); + imgView.alpha = 0.0f; + } completion:^(BOOL finished) { + [imgView removeFromSuperview]; + imgView = nil; + image = nil; + !self.completion ?: self.completion(); + }]; + } +} + +@end diff --git a/HiBit/Project/Player/Common/GKLikeView/GKLikeView.h b/HiBit/Project/Player/Common/GKLikeView/GKLikeView.h new file mode 100755 index 0000000..baa3833 --- /dev/null +++ b/HiBit/Project/Player/Common/GKLikeView/GKLikeView.h @@ -0,0 +1,27 @@ +// +// GKLikeView.h +// GKDYVideo +// +// Created by gaokun on 2019/5/27. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKLikeView : UIView + +@property (nonatomic, assign) BOOL isLike; + +@property (nonatomic, copy) void(^likeBlock)(void); + +- (void)startAnimationWithIsLike:(BOOL)isLike; + +- (void)setupLikeState:(BOOL)isLike; + +- (void)setupLikeCount:(NSString *)count; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKLikeView/GKLikeView.m b/HiBit/Project/Player/Common/GKLikeView/GKLikeView.m new file mode 100755 index 0000000..1788ae2 --- /dev/null +++ b/HiBit/Project/Player/Common/GKLikeView/GKLikeView.m @@ -0,0 +1,189 @@ +// +// GKLikeView.m +// GKDYVideo +// +// Created by gaokun on 2019/5/27. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import "GKLikeView.h" + +@interface GKLikeView() + +@property (nonatomic, strong) UIImageView *likeBeforeImgView; +@property (nonatomic, strong) UIImageView *likeAfterImgView; + +@property (nonatomic, strong) UILabel *countLabel; + +@end + +@implementation GKLikeView + +- (instancetype)init { + if (self = [super init]) { + [self addSubview:self.likeBeforeImgView]; + [self addSubview:self.likeAfterImgView]; + [self addSubview:self.countLabel]; + +// CGFloat imgWH = HBAdapt(40.0f); +// self.likeBeforeImgView.frame = CGRectMake(0, 0, imgWH, imgWH); +// self.likeAfterImgView.frame = CGRectMake(0, 0, imgWH, imgWH); + + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)]; + [self addGestureRecognizer:tapGesture]; + + [self.likeBeforeImgView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(self); + }]; + + [self.likeAfterImgView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.likeBeforeImgView); + }]; + + [self.countLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(self); + make.top.equalTo(self.likeBeforeImgView.mas_bottom).offset(4.0); + }]; + + + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; +// +// CGPoint imgCenter = self.likeBeforeImgView.center; +// imgCenter.x = self.frame.size.width / 2; +// self.likeBeforeImgView.center = imgCenter; +// self.likeAfterImgView.center = imgCenter; +// +// [self.countLabel sizeToFit]; +// +// CGFloat countX = (self.frame.size.width - self.countLabel.frame.size.width) / 2; +// CGFloat countY = self.frame.size.height - self.countLabel.frame.size.height; +// self.countLabel.frame = CGRectMake(countX, countY, self.countLabel.frame.size.width, self.countLabel.frame.size.height); +} + +- (void)setupLikeState:(BOOL)isLike { + self.isLike = isLike; + + if (isLike) { + self.likeAfterImgView.hidden = NO; + }else { + self.likeAfterImgView.hidden = YES; + } +} + +- (void)setupLikeCount:(NSString *)count { + self.countLabel.text = count; + + [self layoutSubviews]; +} + +- (void)startAnimationWithIsLike:(BOOL)isLike { + if (self.isLike == isLike) return; + + self.isLike = isLike; + + if (isLike) { + CGFloat length = 30; + CGFloat duration = 0.5f; + for (NSInteger i = 0; i < 6; i++) { + CAShapeLayer *layer = [CAShapeLayer layer]; + layer.position = self.likeBeforeImgView.center; + layer.fillColor = [UIColor colorWithRed:232.0/255.0 green:50.0/255.0 blue:85.0/255.0 alpha:1.0].CGColor; + + UIBezierPath *startPath = [UIBezierPath bezierPath]; + [startPath moveToPoint:CGPointMake(-2, -length)]; + [startPath addLineToPoint:CGPointMake(2, -length)]; + [startPath addLineToPoint:CGPointMake(0, 0)]; + layer.path = startPath.CGPath; + + layer.transform = CATransform3DMakeRotation(M_PI / 3.0f * i, 0, 0, 1.0); + [self.layer addSublayer:layer]; + + CAAnimationGroup *group = [CAAnimationGroup animation]; + group.removedOnCompletion = NO; + group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + group.fillMode = kCAFillModeForwards; + group.duration = duration; + + CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + scaleAnim.fromValue = @(0.0f); + scaleAnim.toValue = @(1.0f); + scaleAnim.duration = duration * 0.2f; + + UIBezierPath *endPath = [UIBezierPath bezierPath]; + [endPath moveToPoint:CGPointMake(-2, -length)]; + [endPath addLineToPoint:CGPointMake(2, -length)]; + [endPath addLineToPoint:CGPointMake(0, -length)]; + + CABasicAnimation *pathAnim = [CABasicAnimation animationWithKeyPath:@"path"]; + pathAnim.fromValue = (__bridge id)layer.path; + pathAnim.toValue = (__bridge id)endPath.CGPath; + pathAnim.beginTime = duration * 0.2f; + pathAnim.duration = duration * 0.8f; + + [group setAnimations:@[scaleAnim, pathAnim]]; + [layer addAnimation:group forKey:nil]; + } + self.likeAfterImgView.hidden = NO; + self.likeAfterImgView.alpha = 0.0f; + + self.likeAfterImgView.transform = CGAffineTransformMakeScale(0.1f, 0.1f); + + [UIView animateWithDuration:0.15 animations:^{ + self.likeAfterImgView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); + self.likeAfterImgView.alpha = 1.0f; + self.likeBeforeImgView.alpha = 0.0f; + } completion:^(BOOL finished) { + self.likeAfterImgView.transform = CGAffineTransformIdentity; + self.likeBeforeImgView.alpha = 1.0f; + }]; + }else { + self.likeAfterImgView.alpha = 1.0f; + self.likeAfterImgView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); + [UIView animateWithDuration:0.15 animations:^{ + self.likeAfterImgView.transform = CGAffineTransformMakeScale(0.3f, 0.3f); + } completion:^(BOOL finished) { + self.likeAfterImgView.transform = CGAffineTransformIdentity; + self.likeAfterImgView.hidden = YES; + }]; + } +} + +#pragma mark - UITapGestureRecognizer +- (void)tapAction:(UITapGestureRecognizer *)tap { + [self startAnimationWithIsLike:!self.isLike]; + !self.likeBlock ?: self.likeBlock(); +} + +#pragma mark - 懒加载 +- (UIImageView *)likeBeforeImgView { + if (!_likeBeforeImgView) { + _likeBeforeImgView = [UIImageView new]; + _likeBeforeImgView.image = [UIImage imageNamed:@"player_favorite_normal"]; + } + return _likeBeforeImgView; +} + +- (UIImageView *)likeAfterImgView { + if (!_likeAfterImgView) { + _likeAfterImgView = [UIImageView new]; + _likeAfterImgView.image = [UIImage imageNamed:@"player_favorite_selected"]; + } + return _likeAfterImgView; +} + +- (UILabel *)countLabel { + if (!_countLabel) { + _countLabel = [UILabel new]; + _countLabel.textColor = [UIColor whiteColor]; + _countLabel.font = [UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular]; + _countLabel.textAlignment = NSTextAlignmentCenter; + } + return _countLabel; +} + +@end diff --git a/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.h b/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.h new file mode 100755 index 0000000..a272e31 --- /dev/null +++ b/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.h @@ -0,0 +1,24 @@ +// +// GKBallLoadingView.h +// GKDYVideo +// +// Created by gaokun on 2019/5/7. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKBallLoadingView : UIView + ++ (instancetype)loadingViewInView:(UIView *)view; + +- (void)startLoadingWithProgress:(CGFloat)progress; + +- (void)startLoading; +- (void)stopLoading; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.m b/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.m new file mode 100755 index 0000000..0f37a5e --- /dev/null +++ b/HiBit/Project/Player/Common/GKLoadingView/GKBallLoadingView.m @@ -0,0 +1,261 @@ +// +// GKBallLoadingView.m +// GKDYVideo +// +// Created by gaokun on 2019/5/7. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import "GKBallLoadingView.h" + +#define kBallWidth 12.0f +#define kBallSpeed 0.7f +#define kBallZoomScale 0.25 +#define kBallPauseTime 0.18 + +#define GKColorRGBA(r, g, b, a) [UIColor colorWithRed:(r / 255.0) green:(g / 255.0) blue:(b / 255.0) alpha:a] +#define GKColorRGB(r, g, b) GKColorRGBA(r, g, b, 1.0) + +// 球的运动方向,以绿球向右、红球向左运动为正向 +typedef NS_ENUM(NSUInteger, GKBallMoveDirection) { + GKBallMoveDirectionPositive = 1, // 正向运动 + GKBallMoveDirectionNegative = -1 // 逆向运动 +}; + +@interface GKBallLoadingView() + +// 球容器视图 +@property (nonatomic, strong) UIView *containerView; + +// 绿球 +@property (nonatomic, strong) UIView *greenBall; + +// 红球 +@property (nonatomic, strong) UIView *redBall; + +// 黑球 +@property (nonatomic, strong) UIView *blackBall; + +@property (nonatomic, assign) GKBallMoveDirection moveDirection; + +// 定时器 +@property (nonatomic, strong) CADisplayLink *displayLink; + +@end + +@implementation GKBallLoadingView + ++ (instancetype)loadingViewInView:(UIView *)view { + GKBallLoadingView *loadingView = [[GKBallLoadingView alloc] initWithFrame:view.bounds]; + [view addSubview:loadingView]; + return loadingView; +} + +- (void)startLoadingWithProgress:(CGFloat)progress { + [self updateBallPositionWithProgress:progress]; +} + +- (void)startLoading { + [self startAnimation]; +} + +- (void)stopLoading { + [self stopAnimation]; +} + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self setupUI]; + } + return self; +} + +- (void)setupUI { + self.containerView = [[UIView alloc] init]; + self.containerView.center = self.center; + self.containerView.bounds = CGRectMake(0, 0, 2.1f * kBallWidth, 2.0f * kBallWidth); + [self addSubview:self.containerView]; + + // 绿球 + self.greenBall = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kBallWidth, kBallWidth)]; + self.greenBall.center = CGPointMake(kBallWidth * 0.5f, self.containerView.bounds.size.height * 0.5f); + self.greenBall.layer.cornerRadius = kBallWidth * 0.5f; + self.greenBall.layer.masksToBounds = YES; + self.greenBall.backgroundColor = GKColorRGB(35, 246, 235); + [self.containerView addSubview:self.greenBall]; + + // 红球 + self.redBall = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kBallWidth, kBallWidth)]; + self.redBall.center = CGPointMake(self.containerView.bounds.size.width - kBallWidth * 0.5f, self.containerView.bounds.size.height * 0.5f); + self.redBall.layer.cornerRadius = kBallWidth * 0.5f; + self.redBall.layer.masksToBounds = YES; + self.redBall.backgroundColor = GKColorRGB(255, 46, 86); + [self.containerView addSubview:self.redBall]; + + // 黑球 + // 第一次动画是正向,绿球在上,红球在下,阴影显示在绿球上 + self.blackBall = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kBallWidth, kBallWidth)]; + self.blackBall.backgroundColor = GKColorRGB(12, 11, 17); + self.blackBall.layer.cornerRadius = kBallWidth * 0.5f; + self.blackBall.layer.masksToBounds = YES; + [self.greenBall addSubview:self.blackBall]; + + // 方向 + self.moveDirection = GKBallMoveDirectionPositive; + [self.containerView bringSubviewToFront:self.greenBall]; + [self updateBallPositionWithProgress:0]; +} + +- (void)startAnimation { + [self pauseAnimation]; + + // 创建并开启定时器 + self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateBallAnimations)]; + [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; +} + +- (void)pauseAnimation { + if (self.displayLink) { + [self.displayLink invalidate]; + self.displayLink = nil; + } +} + +- (void)stopAnimation { + if (self.displayLink) { + [self.displayLink invalidate]; + self.displayLink = nil; + } + + // 取消延时方法 + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startAnimation) object:nil]; + + // 恢复初始化位置 + [self.greenBall addSubview:self.blackBall]; + [self.containerView bringSubviewToFront:self.greenBall]; + self.moveDirection = GKBallMoveDirectionPositive; + [self updateBallPositionWithProgress:0]; +} + +- (void)resetAnimation { + [self pauseAnimation]; + // 延时执行方法 + [self performSelector:@selector(startAnimation) withObject:nil afterDelay:kBallPauseTime]; +} + +- (void)updateBallPositionWithProgress:(CGFloat)progress { + CGPoint center = self.greenBall.center; + center.x = kBallWidth * 0.5 + 1.1 * kBallWidth * progress; + self.greenBall.center = center; + + center = self.redBall.center; + center.x = kBallWidth * 1.6 - 1.1 * kBallWidth * progress; + self.redBall.center = center; + + // 缩放动画,绿球放大,红球缩小 + if (progress != 0 && progress != 1) { + self.greenBall.transform = [self ballLargerTransformOfCenterX:center.x]; + self.redBall.transform = [self ballSmallerTransformOfCenterX:center.x]; + }else { + self.greenBall.transform = CGAffineTransformIdentity; + self.redBall.transform = CGAffineTransformIdentity; + } + + // 更新黑球位置 + CGRect blackBallFrame = [self.redBall convertRect:self.redBall.bounds toCoordinateSpace:self.greenBall]; + self.blackBall.frame = blackBallFrame; + self.blackBall.layer.cornerRadius = self.blackBall.bounds.size.width * 0.5f; +} + +- (void)updateBallAnimations { + if (self.moveDirection == GKBallMoveDirectionPositive) { // 正向 + CGPoint center = self.greenBall.center; + center.x += kBallSpeed; + self.greenBall.center = center; + + center = self.redBall.center; + center.x -= kBallSpeed; + self.redBall.center = center; + + // 缩放动画,绿球放大,红球缩小 + self.greenBall.transform = [self ballLargerTransformOfCenterX:center.x]; + self.redBall.transform = [self ballSmallerTransformOfCenterX:center.x]; + + // 更新黑球位置 + CGRect blackBallFrame = [self.redBall convertRect:self.redBall.bounds toCoordinateSpace:self.greenBall]; + self.blackBall.frame = blackBallFrame; + self.blackBall.layer.cornerRadius = self.blackBall.bounds.size.width * 0.5f; + + // 更新方向 改变三个球的相对位置 + if (CGRectGetMaxX(self.greenBall.frame) >= self.containerView.bounds.size.width || CGRectGetMinX(self.redBall.frame) <= 0) { + // 切换为反向 + self.moveDirection = GKBallMoveDirectionNegative; + + // 反向运动时,红球在上,绿球在下 + [self.containerView bringSubviewToFront:self.redBall]; + + // 黑球放在红球上面 + [self.redBall addSubview:self.blackBall]; + + // 重置动画 + [self resetAnimation]; + } + }else if (self.moveDirection == GKBallMoveDirectionNegative) { // 反向 + // 更新绿球位置 + CGPoint center = self.greenBall.center; + center.x -= kBallSpeed; + self.greenBall.center = center; + + // 更新红球位置 + center = self.redBall.center; + center.x += kBallSpeed; + self.redBall.center = center; + + // 缩放动画 红球放大 绿球缩小 + self.redBall.transform = [self ballLargerTransformOfCenterX:center.x]; + self.greenBall.transform = [self ballSmallerTransformOfCenterX:center.x]; + + // 更新黑球位置 + CGRect blackBallFrame = [self.greenBall convertRect:self.greenBall.bounds toCoordinateSpace:self.redBall]; + self.blackBall.frame = blackBallFrame; + self.blackBall.layer.cornerRadius = self.blackBall.bounds.size.width * 0.5f; + + // 更新方向 改变三个球的相对位置 + if (CGRectGetMinX(self.greenBall.frame) <= 0 || CGRectGetMaxX(self.redBall.frame) >= self.containerView.bounds.size.width) { + // 切换为正向 + self.moveDirection = GKBallMoveDirectionPositive; + // 正向运动 绿球在上 红球在下 + [self.containerView bringSubviewToFront:self.greenBall]; + // 黑球放在绿球上面 + [self.greenBall addSubview:self.blackBall]; + // 重置动画 + [self resetAnimation]; + } + } +} + +// 放大动画 +- (CGAffineTransform)ballLargerTransformOfCenterX:(CGFloat)centerX { + CGFloat cosValue = [self cosValueOfCenterX:centerX]; + return CGAffineTransformMakeScale(1 + cosValue * kBallZoomScale, 1 + cosValue * kBallZoomScale); +} + +// 缩小动画 +- (CGAffineTransform)ballSmallerTransformOfCenterX:(CGFloat)centerX { + CGFloat cosValue = [self cosValueOfCenterX:centerX]; + return CGAffineTransformMakeScale(1 - cosValue * kBallZoomScale, 1 - cosValue * kBallZoomScale); +} + +// 根据余弦函数获取变化区间 变化范围是0~1~0 +- (CGFloat)cosValueOfCenterX:(CGFloat)centerX { + // 移动距离 + CGFloat apart = centerX - self.containerView.bounds.size.width * 0.5f; + // 最大距离(球心距离Container中心距离) + CGFloat maxAppart = (self.containerView.bounds.size.width - kBallWidth) * 0.5f; + // 移动距离和最大距离的比例 + CGFloat angle = apart / maxAppart * M_PI_2; + // 获取比例对应余弦曲线的Y值 + return cos(angle); +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.h b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.h new file mode 100755 index 0000000..0de8654 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.h @@ -0,0 +1,25 @@ +// +// GKLandscapeNavigationController.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol GKLandscapeNavigationControllerDelegate; + +@interface GKLandscapeNavigationController : UINavigationController +- (instancetype)initWithRootViewController:(UIViewController *)rootViewController delegate:(nullable id)delegate; +@end + +@protocol GKLandscapeNavigationControllerDelegate + +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.m b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.m new file mode 100755 index 0000000..6dbc538 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeNavigationController.m @@ -0,0 +1,62 @@ +// +// GKLandscapeNavigationController.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKLandscapeNavigationController.h" + +@implementation GKLandscapeNavigationController { + __weak id _delegate; +} + +- (instancetype)initWithRootViewController:(UIViewController *)rootViewController delegate:(id)delegate { + if (self = [super initWithRootViewController:rootViewController]) { + _delegate = delegate; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [super setNavigationBarHidden:YES animated:NO]; +} + +- (void)setNavigationBarHidden:(BOOL)navigationBarHidden {} +- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated {} + +- (BOOL)shouldAutorotate { + return self.topViewController.shouldAutorotate; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return self.topViewController.supportedInterfaceOrientations; +} + +- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { + return self.topViewController.preferredInterfaceOrientationForPresentation; +} + +- (UIViewController *)childViewControllerForStatusBarStyle { + return self.topViewController; +} + +- (UIViewController *)childViewControllerForStatusBarHidden { + return self.topViewController; +} + +- (BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { + if (self.viewControllers.count < 1) { + [super pushViewController:viewController animated:animated]; + }else if ([_delegate respondsToSelector:@selector(pushViewController:animated:)]) { + [_delegate pushViewController:viewController animated:animated]; + } +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.h b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.h new file mode 100755 index 0000000..74385bf --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.h @@ -0,0 +1,37 @@ +// +// GKLandscapeViewController.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol GKLandscapeViewControllerDelegate; + +@interface GKLandscapeViewController : UIViewController + +@property (nonatomic, weak, nullable) id delegate; + +@property (nonatomic, assign) BOOL disableAnimations; + +@property (nonatomic, assign) BOOL statusBarHidden; + +@property (nonatomic, assign) UIStatusBarStyle statusBarStyle; + +@property (nonatomic, assign) UIStatusBarAnimation statusBarAnimation; + +@end + +@protocol GKLandscapeViewControllerDelegate + +@optional +- (BOOL)viewControllerShouldAutorotate:(GKLandscapeViewController *)viewController; +- (void)viewController:(GKLandscapeViewController *)viewController viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.m b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.m new file mode 100755 index 0000000..b9bfd26 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeViewController.m @@ -0,0 +1,47 @@ +// +// GKLandscapeViewController.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKLandscapeViewController.h" + +@implementation GKLandscapeViewController + +- (instancetype)init { + if (self = [super init]) { + _statusBarStyle = UIStatusBarStyleLightContent; + _statusBarAnimation = UIStatusBarAnimationSlide; + } + return self; +} + +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + if ([self.delegate respondsToSelector:@selector(viewController:viewWillTransitionToSize:withTransitionCoordinator:)]) { + [self.delegate viewController:self viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + } +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskAllButUpsideDown; +} + +- (BOOL)prefersHomeIndicatorAutoHidden { + return YES; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + return self.statusBarHidden; +} + +- (BOOL)prefersStatusBarHidden { + return self.statusBarStyle; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return self.statusBarAnimation; +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.h b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.h new file mode 100755 index 0000000..4decfff --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.h @@ -0,0 +1,21 @@ +// +// GKLandscapeWindow.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GKRotationManager; + +@interface GKLandscapeWindow : UIWindow + +@property (nonatomic, weak, nullable) GKRotationManager *rotationManager; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.m b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.m new file mode 100755 index 0000000..fc41715 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKLandscapeWindow.m @@ -0,0 +1,76 @@ +// +// GKLandscapeWindow.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKLandscapeWindow.h" + +@implementation GKLandscapeWindow { + CGRect _old_bounds; +} + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.frame = UIScreen.mainScreen.bounds; + self.windowLevel = UIWindowLevelStatusBar - 1; + if (@available(iOS 13.0, *)) { + if (self.windowScene == nil) { + self.windowScene = UIApplication.sharedApplication.keyWindow.windowScene; + } + if (self.windowScene == nil) { + self.windowScene = (UIWindowScene *) UIApplication.sharedApplication.connectedScenes.anyObject; + } + } + self.hidden = YES; + } + return self; +} + +#ifdef DEBUG +- (void)dealloc { + NSLog(@"%d \t %s", (int)__LINE__, __func__); +} +#endif + +- (void)setRootViewController:(UIViewController *)rootViewController { + [super setRootViewController:rootViewController]; + rootViewController.view.frame = self.bounds; + rootViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +} + +- (void)setBackgroundColor:(UIColor *)backgroundColor {} + +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { + return YES; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + // 如果是大屏转大屏 就不需要修改了 + if (!CGRectEqualToRect(_old_bounds, self.bounds)) { + _old_bounds = self.bounds; + + UIView *superview = self; + if (@available(iOS 13.0, *)) { + superview = self.subviews.firstObject; + } + + [UIView performWithoutAnimation:^{ + for (UIView *view in superview.subviews) { + if (view != self.rootViewController.view && [view isMemberOfClass:UIView.class]) { + view.backgroundColor = UIColor.clearColor; + for (UIView *subview in view.subviews) { + subview.backgroundColor = UIColor.clearColor; + } + } + } + }]; + } + self.rootViewController.view.frame = self.bounds; +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.h b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.h new file mode 100755 index 0000000..3c074ca --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.h @@ -0,0 +1,118 @@ +// +// GKRotationManager.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKLandscapeWindow.h" +#import "GKLandscapeViewController.h" + +typedef NS_OPTIONS(NSUInteger, GKInterfaceOrientationMask) { + GKInterfaceOrientationMaskUnknow = 0, + GKInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait), + GKInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft), + GKInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight), + GKInterfaceOrientationMaskPortraitUpsideDown = ( 1 << UIInterfaceOrientationPortraitUpsideDown), + GKInterfaceOrientationMaskLandscape = (GKInterfaceOrientationMaskLandscapeLeft | GKInterfaceOrientationMaskLandscapeRight), + GKInterfaceOrientationMaskAll = (GKInterfaceOrientationMaskPortrait | GKInterfaceOrientationMaskLandscapeLeft | GKInterfaceOrientationMaskLandscapeRight | GKInterfaceOrientationMaskPortraitUpsideDown), + GKInterfaceOrientationMaskAllButUpsideDown = (GKInterfaceOrientationMaskPortrait | GKInterfaceOrientationMaskLandscapeLeft | GKInterfaceOrientationMaskLandscapeRight) +}; + +NS_ASSUME_NONNULL_BEGIN + +@interface GKRotationManager : NSObject + ++ (GKInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window; ++ (instancetype)rotationManager; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)new NS_UNAVAILABLE; + +/// 横屏时的window +@property (nonatomic, strong, nullable) GKLandscapeWindow *window; + +/// 需要旋转的内容视图 +@property (nonatomic, weak) UIView *contentView; + +/// 旋转内容原来的父视图 +@property (nonatomic, weak) UIView *containerView; + +/// 是否允许自动旋转 +@property (nonatomic, assign) BOOL allowOrientationRotation; + +/// 自动旋转支持的方向 +@property (nonatomic, assign) GKInterfaceOrientationMask supportInterfaceOrientation; + +/// 当前的方向 +@property (nonatomic, assign) UIInterfaceOrientation currentOrientation; + +/// 是否全屏 +@property (nonatomic, assign, readonly) BOOL isFullscreen; + +/// 即将旋转回调 +@property (nonatomic, copy, nullable) void(^orientationWillChange)(BOOL isFullscreen); + +/// 结束旋转回调 +@property (nonatomic, copy, nullable) void(^orientationDidChanged)(BOOL isFullscreen); + +/// 旋转 +- (void)rotate; + +/// 旋转到指定方向 +- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated; + +/// 旋转到指定方向 +- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion; + +@end + +@interface GKRotationManager (Internal) + +/// 当前设备方向 +@property (nonatomic, assign, readonly) UIInterfaceOrientation currentDeviceOrientation; + +/// 旋转时是否禁止动画 +@property (nonatomic, assign) BOOL disableAnimations; + +- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window; + +- (UIInterfaceOrientation)getCurrentOrientation; + +- (__kindof GKLandscapeViewController *)landscapeViewController; + +- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void (^ __nullable)(void))completion; + +- (void)handleDeviceOrientationChange; + +- (BOOL)isSupportInterfaceOrientation:(UIInterfaceOrientation)orientation; + +- (void)willChangeOrientation:(UIInterfaceOrientation)orientation; + +- (void)didChangeOrientation:(UIInterfaceOrientation)orientation; + +@end + +NS_ASSUME_NONNULL_END + +#pragma mark - fix safe area + +NS_ASSUME_NONNULL_BEGIN +typedef NS_OPTIONS(NSUInteger, GKSafeAreaInsetsMask) { + GKSafeAreaInsetsMaskNone = 0, + GKSafeAreaInsetsMaskTop = 1 << 0, + GKSafeAreaInsetsMaskLeft = 1 << 1, + GKSafeAreaInsetsMaskBottom = 1 << 2, + GKSafeAreaInsetsMaskRight = 1 << 3, + + GKSafeAreaInsetsMaskHorizontal = GKSafeAreaInsetsMaskLeft | GKSafeAreaInsetsMaskRight, + GKSafeAreaInsetsMaskVertical = GKSafeAreaInsetsMaskTop | GKSafeAreaInsetsMaskBottom, + GKSafeAreaInsetsMaskAll = GKSafeAreaInsetsMaskHorizontal | GKSafeAreaInsetsMaskVertical +}API_DEPRECATED("deprecated!", ios(13.0, 16.0)); + +API_DEPRECATED("deprecated!", ios(13.0, 16.0)) @interface UIViewController (GKRotationSafeAreaFixing) +/// 禁止调整哪些方向的安全区域 +@property (nonatomic) GKSafeAreaInsetsMask disabledAdjustSafeAreaInsetsMask; +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.m b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.m new file mode 100755 index 0000000..f0f1e87 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager.m @@ -0,0 +1,275 @@ +// +// GKRotationManager.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKRotationManager.h" +#import "GKLandscapeWindow.h" +#import "GKLandscapeViewController.h" +#import "GKRotationManager_iOS_9_15.h" +#import "GKRotationManager_iOS_16_Later.h" +#import + +@interface GKRotationManager() + +@property (nonatomic, assign) BOOL isGeneratingDeviceOrientation; + +@end + +@implementation GKRotationManager + ++ (GKInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(UIWindow *)window { + if ([window isKindOfClass:GKLandscapeWindow.class]) { + GKRotationManager *manager = [(GKLandscapeWindow *)window rotationManager]; + if (manager != nil) { + return (GKInterfaceOrientationMask)[manager supportedInterfaceOrientationsForWindow:window]; + } + } + return GKInterfaceOrientationMaskUnknow; +} + ++ (instancetype)rotationManager { + if (@available(iOS 16.0, *)) { + return [[GKRotationManager_iOS_16_Later alloc] _init]; + }else { + return [[GKRotationManager_iOS_9_15 alloc] _init]; + } +} + +- (instancetype)_init { + if (self = [super init]) { + self.currentOrientation = UIInterfaceOrientationPortrait; + self.supportInterfaceOrientation = GKInterfaceOrientationMaskAll; + } + return self; +} + +- (void)addDeviceOrientationObserver { + self.isGeneratingDeviceOrientation = UIDevice.currentDevice.isGeneratingDeviceOrientationNotifications; + if (!self.isGeneratingDeviceOrientation) { + [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceOrientationChange) name:UIDeviceOrientationDidChangeNotification object:nil]; +} + +- (void)removeDeviceOrientationObserver { + if (!self.isGeneratingDeviceOrientation) { + [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; + } + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; +} + +- (void)dealloc { +#ifdef DEBUG + NSLog(@"%d -- [%@ %s]", (int)__LINE__, NSStringFromClass(self.class), sel_getName(_cmd)); +#endif + [_window setHidden:YES]; + [self removeDeviceOrientationObserver]; +} + +- (void)setAllowOrientationRotation:(BOOL)allowOrientationRotation { + _allowOrientationRotation = allowOrientationRotation; + + if (allowOrientationRotation) { + [self addDeviceOrientationObserver]; + }else { + [self removeDeviceOrientationObserver]; + } +} + +- (UIInterfaceOrientation)currentDeviceOrientation { + return (UIInterfaceOrientation)UIDevice.currentDevice.orientation; +} + +- (void)rotate { + UIInterfaceOrientation orientation = self.currentOrientation == UIInterfaceOrientationPortrait ? UIInterfaceOrientationLandscapeRight : UIInterfaceOrientationPortrait; + [self rotateToOrientation:orientation animated:YES]; +} + +- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated { + [self rotateToOrientation:orientation animated:animated completion:nil]; +} + +- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void (^)(void))completion { + self.currentOrientation = orientation; + if (UIInterfaceOrientationIsLandscape(orientation)) { + if (!self.window) { + self.window = [[GKLandscapeWindow alloc] init]; + self.window.rootViewController = self.landscapeViewController; + self.window.rotationManager = self; + } + } + self.disableAnimations = !animated; + if (UIDevice.currentDevice.systemVersion.doubleValue < 16.0) { + [self interfaceOrientation:UIInterfaceOrientationUnknown completion:nil]; + } + [self interfaceOrientation:orientation completion:completion]; +} + +@end + +@implementation GKRotationManager (Internal) + +@dynamic disableAnimations; + +- (void)setDisableAnimations:(BOOL)disableAnimations { + objc_setAssociatedObject(self, @selector(disableAnimations), @(disableAnimations), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (BOOL)disableAnimations { + return [objc_getAssociatedObject(self, _cmd) boolValue]; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (UIInterfaceOrientation)getCurrentOrientation { + if (@available(iOS 16.0, *)) { + NSArray *array = UIApplication.sharedApplication.connectedScenes.allObjects; + UIWindowScene *scene = array.firstObject; + return scene.interfaceOrientation; + }else { + return self.currentDeviceOrientation; + } +} + +- (GKLandscapeViewController *)landscapeViewController { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void (^)(void))completion { + // subclass implementation +} + +- (void)handleDeviceOrientationChange { + if (!self.allowOrientationRotation) return; + if (!UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) return; + UIInterfaceOrientation currentOrientation = self.currentDeviceOrientation; + if (currentOrientation == self.currentOrientation) return; + self.currentOrientation = currentOrientation; + if (currentOrientation == UIInterfaceOrientationPortraitUpsideDown) return; + + switch (currentOrientation) { + case UIInterfaceOrientationPortrait: { + if ([self _isSupportedPortrait]) { + [self rotateToOrientation:UIInterfaceOrientationPortrait animated:YES]; + } + } + break; + case UIInterfaceOrientationLandscapeLeft: { + if ([self _isSupportedLandscapeLeft]) { + [self rotateToOrientation:UIInterfaceOrientationLandscapeLeft animated:YES]; + } + } + break; + case UIInterfaceOrientationLandscapeRight: { + if ([self _isSupportedLandscapeRight]) { + [self rotateToOrientation:UIInterfaceOrientationLandscapeRight animated:YES]; + } + } + break; + default: break; + } +} + +- (BOOL)isSupportInterfaceOrientation:(UIInterfaceOrientation)orientation { + if (orientation == UIInterfaceOrientationPortrait) { + return [self _isSupportedPortrait]; + }else if (orientation == UIInterfaceOrientationLandscapeLeft) { + return [self _isSupportedLandscapeLeft]; + }else if (orientation == UIInterfaceOrientationLandscapeRight) { + return [self _isSupportedLandscapeRight]; + }else if (orientation == UIInterfaceOrientationPortraitUpsideDown) { + return [self _isSupportedPortraitUpsideDown]; + } + return NO; +} + +- (void)willChangeOrientation:(UIInterfaceOrientation)orientation { + _isFullscreen = UIInterfaceOrientationIsLandscape(orientation); + !self.orientationWillChange ?: self.orientationWillChange(_isFullscreen); +} + +- (void)didChangeOrientation:(UIInterfaceOrientation)orientation { + _isFullscreen = UIInterfaceOrientationIsLandscape(orientation); + !self.orientationDidChanged ?: self.orientationDidChanged(_isFullscreen); +} + +- (BOOL)_isSupportedPortrait { + return self.supportInterfaceOrientation & GKInterfaceOrientationMaskPortrait; +} + +- (BOOL)_isSupportedPortraitUpsideDown { + return self.supportInterfaceOrientation & GKInterfaceOrientationMaskPortraitUpsideDown; +} + +- (BOOL)_isSupportedLandscapeLeft { + return self.supportInterfaceOrientation & GKInterfaceOrientationMaskLandscapeLeft; +} + +- (BOOL)_isSupportedLandscapeRight { + return self.supportInterfaceOrientation & GKInterfaceOrientationMaskLandscapeRight; +} + +@end + +#pragma mark - fix safe area + +API_DEPRECATED("deprecated!", ios(13.0, 16.0)) @implementation GKRotationManager (GKRotationSafeAreaFixing) ++ (void)initialize { + if (@available(iOS 16.0, *)) return; + if (@available(iOS 13.0, *)) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class cls = UIViewController.class; + NSData *data = [NSData.alloc initWithBase64EncodedString:@"X3NldENvbnRlbnRPdmVybGF5SW5zZXRzOmFuZExlZnRNYXJnaW46cmlnaHRNYXJnaW46" options:kNilOptions]; + NSString *method = [NSString.alloc initWithData:data encoding:NSUTF8StringEncoding]; + SEL originalSelector = NSSelectorFromString(method); + SEL swizzledSelector = NSSelectorFromString([@"gk" stringByAppendingString:method]); + + Method originalMethod = class_getInstanceMethod(cls, originalSelector); + Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); + if ( originalMethod != NULL ) method_exchangeImplementations(originalMethod, swizzledMethod); + }); + } +} +@end + +API_DEPRECATED("deprecated!", ios(13.0, 16.0)) @implementation UIViewController (GKRotationSafeAreaFixing) +- (void)gk_setContentOverlayInsets:(UIEdgeInsets)insets andLeftMargin:(CGFloat)leftMargin rightMargin:(CGFloat)rightMargin { + GKSafeAreaInsetsMask mask = self.disabledAdjustSafeAreaInsetsMask; + if (mask & GKSafeAreaInsetsMaskTop) insets.top = 0; + if (mask & GKSafeAreaInsetsMaskLeft) insets.left = 0; + if (mask & GKSafeAreaInsetsMaskBottom) insets.bottom = 0; + if (mask & GKSafeAreaInsetsMaskRight) insets.right = 0; + + UIWindow *keyWindow = UIApplication.sharedApplication.keyWindow; + UIWindow *otherWindow = self.view.window; + if ([keyWindow isKindOfClass:GKLandscapeWindow.class] && otherWindow != nil) { + GKRotationManager *manager = ((GKLandscapeWindow *)keyWindow).rotationManager; + UIWindow *superviewWindow = manager.containerView.window; + if (superviewWindow != otherWindow) { + [self gk_setContentOverlayInsets:insets andLeftMargin:leftMargin rightMargin:rightMargin]; + } + }else { + [self gk_setContentOverlayInsets:insets andLeftMargin:leftMargin rightMargin:rightMargin]; + } +} + +- (void)setDisabledAdjustSafeAreaInsetsMask:(GKSafeAreaInsetsMask)disabledAdjustSafeAreaInsetsMask { + objc_setAssociatedObject(self, @selector(disabledAdjustSafeAreaInsetsMask), @(disabledAdjustSafeAreaInsetsMask), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (GKSafeAreaInsetsMask)disabledAdjustSafeAreaInsetsMask { + return [objc_getAssociatedObject(self, _cmd) integerValue]; +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.h b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.h new file mode 100755 index 0000000..c17dcdf --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.h @@ -0,0 +1,17 @@ +// +// GKRotationManager_iOS_16_Later.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKRotationManager.h" + +API_AVAILABLE(ios(16.0)) NS_ASSUME_NONNULL_BEGIN + +@interface GKRotationManager_iOS_16_Later : GKRotationManager + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.m b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.m new file mode 100755 index 0000000..4c98c7f --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_16_Later.m @@ -0,0 +1,139 @@ +// +// GKRotationManager_iOS_16_Later.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKRotationManager_iOS_16_Later.h" +#import "GKLandscapeViewController.h" + +@interface GKRotationManager_iOS_16_Later() + +@property (nonatomic, strong, readonly) GKLandscapeViewController *landscapeViewController; + +@end + +@implementation GKRotationManager_iOS_16_Later +@synthesize landscapeViewController = _landscapeViewController; +- (__kindof GKLandscapeViewController *)landscapeViewController { + if (!_landscapeViewController) { + _landscapeViewController = [[GKLandscapeViewController alloc] init]; + } + return _landscapeViewController; +} + +- (void)setNeedsUpdateOfSupportedInterfaceOrientations { + if (@available(iOS 16.0, *)) { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000 + [UIApplication.sharedApplication.keyWindow.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations]; + [self.window.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations]; +#else + [(id)UIApplication.sharedApplication.keyWindow.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations]; + [(id)self.window.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations]; +#endif + } +} + +- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void (^)(void))completion { + [super interfaceOrientation:orientation completion:completion]; + UIInterfaceOrientation fromOrientation = [self getCurrentOrientation]; + UIInterfaceOrientation toOrientation = orientation; + [self willChangeOrientation:toOrientation]; + self.currentOrientation = toOrientation; + + UIWindow *sourceWindow = self.containerView.window; + CGRect sourceFrame = [self.containerView convertRect:self.containerView.bounds toView:sourceWindow]; + CGRect screenBounds = UIScreen.mainScreen.bounds; + CGFloat maxSize = MAX(screenBounds.size.width, screenBounds.size.height); + CGFloat minSize = MIN(screenBounds.size.width, screenBounds.size.height); + + self.contentView.autoresizingMask = UIViewAutoresizingNone; + if (fromOrientation == UIInterfaceOrientationPortrait || self.contentView.superview != self.landscapeViewController.view) { + self.contentView.frame = sourceFrame; + [sourceWindow addSubview:self.contentView]; + [self.contentView layoutIfNeeded]; + if (!self.window.isKeyWindow) { + self.window.hidden = NO; + [self.window makeKeyAndVisible]; + } + }else if (toOrientation == UIInterfaceOrientationPortrait) { + [self.contentView removeFromSuperview]; + self.contentView.bounds = CGRectMake(0, 0, maxSize, minSize); + self.contentView.center = CGPointMake(minSize * 0.5, maxSize * 0.5); + self.contentView.transform = [self getRotationTransform:fromOrientation]; + [sourceWindow addSubview:self.contentView]; + [self.contentView layoutIfNeeded]; + [self.contentView snapshotViewAfterScreenUpdates:YES]; + [UIView performWithoutAnimation:^{ + [sourceWindow makeKeyAndVisible]; + self.window.hidden = YES; + }]; + } + [self setNeedsUpdateOfSupportedInterfaceOrientations]; + + CGRect rotationBounds = CGRectZero; + CGPoint rotationCenter = CGPointZero; + if (UIInterfaceOrientationIsLandscape(toOrientation)) { + rotationBounds = CGRectMake(0, 0, maxSize, minSize); + rotationCenter = (fromOrientation == UIInterfaceOrientationPortrait || self.contentView.superview != self.landscapeViewController.view) ? CGPointMake(minSize * 0.5, maxSize * 0.5) : CGPointMake(maxSize * 0.5, minSize * 0.5); + } + + CGAffineTransform rotationTransform = CGAffineTransformIdentity; + if (fromOrientation == UIInterfaceOrientationPortrait) { + rotationTransform = [self getRotationTransform:toOrientation]; + } + + if (self.disableAnimations) { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + } + [UIView animateWithDuration:0.3 animations:^{ + if (toOrientation == UIInterfaceOrientationPortrait) { + self.contentView.transform = rotationTransform; + self.contentView.frame = sourceFrame; + }else { + self.contentView.transform = rotationTransform; + self.contentView.bounds = rotationBounds; + self.contentView.center = rotationCenter; + } + [self.contentView layoutIfNeeded]; + } completion:^(BOOL finished) { + if (self.disableAnimations) { + [CATransaction commit]; + } + self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + if (toOrientation == UIInterfaceOrientationPortrait) { + [self.containerView addSubview:self.contentView]; + self.contentView.frame = self.containerView.bounds; + }else { + [self setNeedsUpdateOfSupportedInterfaceOrientations]; + self.contentView.transform = CGAffineTransformIdentity; + [self.landscapeViewController.view addSubview:self.contentView]; + self.contentView.frame = self.window.bounds; + [self.contentView layoutIfNeeded]; + } + !completion ?: completion(); + [self didChangeOrientation:toOrientation]; + }]; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window { + if (window == self.window) { + return 1 << self.currentOrientation; + } + return UIInterfaceOrientationMaskPortrait; +} + +- (CGAffineTransform)getRotationTransform:(UIInterfaceOrientation)orientation { + CGAffineTransform rotationTransform = CGAffineTransformIdentity; + if (orientation == UIInterfaceOrientationLandscapeLeft) { + rotationTransform = CGAffineTransformMakeRotation(-M_PI_2); + } else if (orientation == UIInterfaceOrientationLandscapeRight) { + rotationTransform = CGAffineTransformMakeRotation(M_PI_2); + } + return rotationTransform; +} + +@end diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.h b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.h new file mode 100755 index 0000000..1318fc8 --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.h @@ -0,0 +1,17 @@ +// +// GKRotationManager_iOS_9_15.h +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKRotationManager.h" + +NS_ASSUME_NONNULL_BEGIN + +API_DEPRECATED("deprecated!", ios(9.0, 16.0)) @interface GKRotationManager_iOS_9_15 : GKRotationManager + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.m b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.m new file mode 100755 index 0000000..ff600cc --- /dev/null +++ b/HiBit/Project/Player/Common/GKRotationManager/GKRotationManager_iOS_9_15.m @@ -0,0 +1,177 @@ +// +// GKRotationManager_iOS_9_15.m +// Example +// +// Created by QuintGao on 2023/3/31. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKRotationManager_iOS_9_15.h" +#import "GKLandscapeViewController.h" + +API_DEPRECATED("deprecated!", ios(9.0, 16.0)) @interface GKLandscapeViewController_iOS_9_15 : GKLandscapeViewController +@property (nonatomic, strong, readonly) UIView *playerSuperview; +@end + +@implementation GKLandscapeViewController_iOS_9_15 + +- (void)viewDidLoad { + [super viewDidLoad]; + _playerSuperview = [[UIView alloc] initWithFrame:CGRectZero]; + _playerSuperview.backgroundColor = UIColor.clearColor; + [self.view addSubview:_playerSuperview]; +} + +- (BOOL)shouldAutorotate { + if ([self.delegate respondsToSelector:@selector(viewControllerShouldAutorotate:)]) { + return [self.delegate viewControllerShouldAutorotate:self]; + } + return NO; +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskAllButUpsideDown; +} + +@end + +@interface GKRotationManager_iOS_9_15() { + void(^_rotateCompleted)(void); +} + +@property (nonatomic, strong, readonly) GKLandscapeViewController_iOS_9_15 *landscapeViewController; + +@property (nonatomic, assign) BOOL forceRotation; + +@end + +@implementation GKRotationManager_iOS_9_15 + +@synthesize landscapeViewController = _landscapeViewController; +- (GKLandscapeViewController *)landscapeViewController { + if (!_landscapeViewController) { + _landscapeViewController = [[GKLandscapeViewController_iOS_9_15 alloc] init]; + _landscapeViewController.delegate = self; + } + return _landscapeViewController; +} + +- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void (^)(void))completion { + [super interfaceOrientation:orientation completion:completion]; + _rotateCompleted = completion; + self.forceRotation = YES; + [UIDevice.currentDevice setValue:@(UIDeviceOrientationUnknown) forKey:@"orientation"]; + [UIDevice.currentDevice setValue:@(orientation) forKey:@"orientation"]; +} + +- (void)rotationBegin { + if (self.window.isHidden) { + self.window.hidden = NO; + [self.window makeKeyAndVisible]; + } + [UIView animateWithDuration:0.0 animations:^{} completion:^(BOOL finished) { + [self.window.rootViewController setNeedsStatusBarAppearanceUpdate]; + }]; +} + +- (void)rotationEnd { + if (!self.window.isHidden && !UIInterfaceOrientationIsLandscape(self.currentOrientation)) { + self.window.hidden = YES; + [self.containerView.window makeKeyAndVisible]; + } + self.disableAnimations = NO; + if (_rotateCompleted) { + _rotateCompleted(); + _rotateCompleted = nil; + } +} + +- (BOOL)allowsRotation { + if (UIDeviceOrientationIsValidInterfaceOrientation(UIDevice.currentDevice.orientation)) { + UIInterfaceOrientation toOrientation = self.currentDeviceOrientation; + if (![self isSupportInterfaceOrientation:toOrientation]) { + return NO; + } + } + if (self.forceRotation) return YES; + if (self.allowOrientationRotation) return YES; + return NO; +} + +#pragma mark - GKLandscapeViewControllerDelegate +- (BOOL)viewControllerShouldAutorotate:(GKLandscapeViewController *)viewController { + if ([self allowsRotation]) { + [self rotationBegin]; + return YES; + } + return NO; +} + +- (void)viewController:(GKLandscapeViewController *)viewController viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + UIInterfaceOrientation toOrientation = self.currentDeviceOrientation; + if (![self isSupportInterfaceOrientation:toOrientation]) return; + [self willChangeOrientation:toOrientation]; + self.currentOrientation = toOrientation; + if (self.currentOrientation != UIInterfaceOrientationPortrait) { + if (self.contentView.superview != self.landscapeViewController.playerSuperview) { + CGRect frame = [self.contentView convertRect:self.contentView.bounds toView:self.contentView.window]; + self.landscapeViewController.playerSuperview.frame = frame; + self.contentView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height); + self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.landscapeViewController.playerSuperview addSubview:self.contentView]; + [self.contentView layoutIfNeeded]; + } + if (self.disableAnimations) { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + } + [UIView animateWithDuration:0.0 animations:^{ /** preparing */} completion:^(BOOL finished) { + [UIView animateWithDuration:0.3 animations:^{ + self.landscapeViewController.playerSuperview.frame = (CGRect){CGPointZero, size}; + [self.contentView layoutIfNeeded]; + } completion:^(BOOL finished) { + if (self.disableAnimations) { + [CATransaction commit]; + } + self.forceRotation = NO; + [self rotationEnd]; + [self didChangeOrientation:toOrientation]; + }]; + }]; + }else { + if (self.disableAnimations) { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + } + [UIView animateWithDuration:0.0 animations:^{ /** preparing */ } completion:^(BOOL finished) { + [UIView animateWithDuration:0.3 animations:^{ + self.landscapeViewController.playerSuperview.frame = [self.containerView convertRect:self.containerView.bounds toView:self.containerView.window]; + [self.contentView layoutIfNeeded]; + } completion:^(BOOL finished) { + if (self.disableAnimations) { + [CATransaction commit]; + } + self.forceRotation = NO; + UIView *snapshot = [self.contentView snapshotViewAfterScreenUpdates:NO]; + snapshot.frame = self.containerView.bounds; + snapshot.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.containerView addSubview:snapshot]; + [UIView animateWithDuration:0.0 animations:^{} completion:^(BOOL finished) { + self.contentView.frame = self.containerView.bounds; + self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.containerView addSubview:self.contentView]; + [self.contentView layoutIfNeeded]; + [snapshot removeFromSuperview]; + [self rotationEnd]; + [self didChangeOrientation:toOrientation]; + }]; + }]; + }]; + } +} + +- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(UIWindow *)window { + return UIInterfaceOrientationMaskAllButUpsideDown; +} + +@end diff --git a/HiBit/Project/Player/Manager/GKDYPlayerManager.h b/HiBit/Project/Player/Manager/GKDYPlayerManager.h new file mode 100755 index 0000000..6077116 --- /dev/null +++ b/HiBit/Project/Player/Manager/GKDYPlayerManager.h @@ -0,0 +1,84 @@ +// +// GKDYPlayerManager.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import "GKDYVideoScrollView.h" +#import "GKDYVideoPortraitView.h" +#import "GKDYVideoLandscapeView.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GKDYVideoCell, GKDYVideoPortraitCell, GKDYVideoLandscapeCell; + +@protocol GKDYPlayerManagerDelegate + +- (void)scrollViewShouldLoadMore; + +- (void)scrollViewDidPanDistance:(CGFloat)distance isEnd:(BOOL)isEnd; + +- (void)celldidClickShare:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell; +- (void)celldidClickEpiscode:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell; +- (void)celldidClickFavorite:(GKDYVideoModel *)model cell:(GKDYVideoPortraitCell *)cell; +- (void)cellZoomBegan:(GKDYVideoModel *)model; +- (void)cellZoomEnded:(GKDYVideoModel *)model isFullscreen:(BOOL)isFullscreen; +- (void)cellSwitchWithModel:(GKDYVideoModel *)model; +@end + +@interface GKDYPlayerManager : NSObject + +@property (nonatomic, strong, readonly) ZFPlayerController *player; + +@property (nonatomic, weak) id delegate; + +// 竖屏滑动容器 +@property (nonatomic, strong) GKDYVideoScrollView *scrollView; + +// 横屏滑动容器 +@property (nonatomic, strong, nullable) GKDYVideoScrollView *landscapeScrollView; + +@property (nonatomic, weak) GKDYVideoPortraitCell *currentCell; + +@property (nonatomic, weak) GKDYVideoLandscapeCell *landscapeCell; + +// 竖屏控制层 +@property (nonatomic, weak) GKDYVideoPortraitView *portraitView; + +// 横屏控制层 +@property (nonatomic, strong) GKDYVideoLandscapeView *landscapeView; + +@property (nonatomic, assign) CGSize videoSize; + +/// 页码 +@property (nonatomic, assign) NSInteger page; + +/// 数据源 +@property (nonatomic, strong) NSMutableArray *dataSources; + +@property (nonatomic, assign) BOOL isPlaying; + +@property (nonatomic, assign) BOOL isAppeared; + +/// 请求播放地址 +- (void)requestPlayUrlWithModel:(GKDYVideoModel *)model completion:(nullable void(^)(void))completion; + +/// 播放视频 +- (void)playVideoWithCell:(GKDYVideoCell *)cell index:(NSInteger)index; + +/// 停止播放 +- (void)stopPlayWithCell:(GKDYVideoCell *)cell index:(NSInteger)index; + +/// 旋转 +- (void)rotate; + +- (void)play; +- (void)pause; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Manager/GKDYPlayerManager.m b/HiBit/Project/Player/Manager/GKDYPlayerManager.m new file mode 100755 index 0000000..09be748 --- /dev/null +++ b/HiBit/Project/Player/Manager/GKDYPlayerManager.m @@ -0,0 +1,504 @@ +// +// GKDYPlayerManager.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYPlayerManager.h" +#import +#import +#import +#import "GKDYVideoCell.h" +#import "GKRotationManager.h" +#import "GKDYVideoPortraitCell.h" +#import "GKDYVideoLandscapeCell.h" +#import "GKDYVideoFullscreenView.h" + +@interface GKDYPlayerManager() + +@property (nonatomic, strong) ZFPlayerController *player; + +@property (nonatomic, strong) GKRotationManager *rotationManager; + +@property (nonatomic, assign) BOOL isSeeking; + +@property (nonatomic, strong) GKDYVideoFullscreenView *fullscreenView; + +@end + +@implementation GKDYPlayerManager + +- (instancetype)init { + if (self = [super init]) { + [self initPlayer]; + } + return self; +} + +- (void)dealloc { + NSLog(@"GKDYPlayerManager dealloc"); + [self stop]; +} + +- (void)initPlayer { + // 初始化播放器 + ZFAVPlayerManager *manager = [[ZFAVPlayerManager alloc] init]; + + ZFPlayerController *player = [[ZFPlayerController alloc] init]; + player.shouldAutoPlay = YES; + player.currentPlayerManager = manager; + player.disableGestureTypes = ZFPlayerDisableGestureTypesPan | ZFPlayerDisableGestureTypesPinch; + player.allowOrentitaionRotation = NO; // 禁止自动旋转 + self.player = player; + + @weakify(self); + // 播放结束回调 + player.playerDidToEnd = ^(id _Nonnull asset) { + @strongify(self); + [self.scrollView scrollToNextPage]; + }; + + // 播放失败回调 + player.playerPlayFailed = ^(id _Nonnull asset, id _Nonnull error) { + @strongify(self); + self.portraitView.resumeButton.hidden = NO; + }; + + // 加载状态 + player.playerLoadStateChanged = ^(id _Nonnull asset, ZFPlayerLoadState loadState) { + @strongify(self); + if ((loadState == ZFPlayerLoadStatePrepare || loadState == ZFPlayerLoadStateStalled) && self.player.currentPlayerManager.isPlaying) { + [self.portraitView.slider showLoading]; + }else { + [self.portraitView.slider hideLoading]; +// [self.player.currentPlayerManager play]; + } + }; + + // 播放时间 + player.playerPlayTimeChanged = ^(id _Nonnull asset, NSTimeInterval currentTime, NSTimeInterval duration) { + @strongify(self); + [self.portraitView.slider updateCurrentTime:currentTime totalTime:duration]; + }; + + // 方向即将改变 + player.orientationWillChange = ^(ZFPlayerController * _Nonnull player, BOOL isFullScreen) { + @strongify(self); + self.player.controlView.hidden = YES; + if (player.isFullScreen) { + [self.landscapeView startTimer]; + }else { + [self.landscapeView destoryTimer]; + } + }; + + // 方向已经改变 + player.orientationDidChanged = ^(ZFPlayerController * _Nonnull player, BOOL isFullScreen) { + @strongify(self); + if (isFullScreen) { + self.landscapeView.hidden = NO; + self.player.controlView = self.landscapeView; + }else { + self.portraitView.hidden = NO; + self.player.controlView = self.portraitView; + } + }; + + self.rotationManager = [GKRotationManager rotationManager]; + self.rotationManager.contentView = self.player.currentPlayerManager.view; + self.landscapeView.rotationManager = self.rotationManager; + + // 即将旋转时调用 + self.rotationManager.orientationWillChange = ^(BOOL isFullscreen) { + @strongify(self); + self.player.controlView.hidden = YES; + if (isFullscreen) { + [self.landscapeView startTimer]; + }else { + self.player.currentPlayerManager.view.backgroundColor = UIColor.clearColor; + self.portraitView.hidden = NO; + [self.landscapeView destoryTimer]; + if (self.landscapeScrollView) { + UIView *superview = self.landscapeScrollView.superview; + [superview addSubview:self.rotationManager.contentView]; + [self.landscapeScrollView removeFromSuperview]; + self.landscapeScrollView = nil; + self.landscapeCell = nil; + } + } + }; + + // 旋转结束时调用 + self.rotationManager.orientationDidChanged = ^(BOOL isFullscreen) { + @strongify(self); + if (isFullscreen) { +// self.portraitView.hidden = YES; + self.landscapeView.hidden = NO; + [self.landscapeView hideContainerView:NO]; + if (!self.landscapeScrollView) { + [self initLandscapeScrollView]; + UIView *superview = self.rotationManager.contentView.superview; + self.landscapeScrollView.frame = superview.bounds; + [superview addSubview:self.landscapeScrollView]; + self.landscapeScrollView.defaultIndex = self.scrollView.currentIndex; + [self.landscapeScrollView reloadData]; + } + self.player.controlView = self.landscapeView; + [self.currentCell resetView]; + [self.landscapeCell hideTopView]; + }else { + self.portraitView.hidden = NO; + self.landscapeView.hidden = YES; + self.player.controlView = self.portraitView; + if (self.player.containerView != self.currentCell.coverImgView) { + self.player.containerView = self.currentCell.coverImgView; + } + self.player.currentPlayerManager.view.backgroundColor = UIColor.blackColor; + } + }; + + player.presentationSizeChanged = ^(id _Nonnull asset, CGSize size) { + @strongify(self); + self.videoSize = size; + }; +} + +- (void)initLandscapeScrollView { + self.landscapeScrollView = [[GKDYVideoScrollView alloc] init]; + self.landscapeScrollView.backgroundColor = UIColor.blackColor; + self.landscapeScrollView.dataSource = self; + self.landscapeScrollView.delegate = self; + [self.landscapeScrollView registerClass:GKDYVideoLandscapeCell.class forCellReuseIdentifier:@"GKDYVideoLandscapeCell"]; +} + +- (BOOL)isPlaying { + return self.player.currentPlayerManager.isPlaying; +} + +- (void)requestPlayUrlWithModel:(GKDYVideoModel *)model completion:(nullable void (^)(void))completion { + if (model.videoInfo.video_url.length > 0) return; + +// if (model.task) { +// [model.task cancel]; +// model.task = nil; +// } +// +// AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; +// +// NSString *url = [NSString stringWithFormat:@"https://haokan.baidu.com/v?vid=%@&_format=json&", model.video_id]; +// +// model.task = [manager GET:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { +// if ([responseObject[@"errno"] integerValue] == 0) { +// NSDictionary *videoMeta = responseObject[@"data"][@"apiData"][@"curVideoMeta"]; +// model.play_url = videoMeta[@"playurl"]; +// model.comment = videoMeta[@"comment"]; +// model.like = videoMeta[@"fmlike_num"]; +// +// __block NSInteger index = 0; +// __block BOOL exist = NO; +// [self.dataSources enumerateObjectsUsingBlock:^(GKDYVideoModel *obj, NSUInteger idx, BOOL * _Nonnull stop) { +// if ([obj.video_id isEqualToString:model.video_id]) { +// index = idx; +// exist = YES; +// *stop = YES; +// } +// }]; +// [self.dataSources replaceObjectAtIndex:index withObject:model]; +// model.task = nil; +// !completion ?: completion(); +// } +// } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { +// model.task = nil; +// NSLog(@"播放地址请求失败"); +// }]; +} + +- (void)playVideoWithCell:(GKDYVideoCell *)cell index:(NSInteger)index { + if (self.dataSources.count - index < 2) { + if ([self.delegate respondsToSelector:@selector(scrollViewShouldLoadMore)]) { + [self.delegate scrollViewShouldLoadMore]; + } + } + + GKDYVideoModel *model = self.dataSources[index]; + + self.landscapeView.model = model; + + if ([cell isKindOfClass:GKDYVideoPortraitCell.class]) { + self.currentCell = (GKDYVideoPortraitCell *)cell; + self.portraitView = self.currentCell.portraitView; + self.rotationManager.containerView = cell.coverImgView; + if (self.rotationManager.isFullscreen) return; + }else { + self.landscapeCell = (GKDYVideoLandscapeCell *)cell; + [self.landscapeCell autoHide]; + [self.scrollView scrollToPageWithIndex:index]; + } + + // 设置播放内容视图 + if (self.player.containerView != cell.coverImgView) { + self.player.containerView = cell.coverImgView; + } + + // 设置播放器控制层视图 + if ([cell isKindOfClass:GKDYVideoPortraitCell.class]) { + GKDYVideoPortraitCell *portraitCell = (GKDYVideoPortraitCell *)cell; + if (self.player.controlView != portraitCell.portraitView) { + self.player.controlView = portraitCell.portraitView; + self.portraitView = portraitCell.portraitView; + } + } + + // 设置封面图片 + id manager = self.player.currentPlayerManager; + [manager.view.coverImageView sd_setImageWithURL:[NSURL URLWithString:model.image_url]]; + + if (model.videoInfo.video_url.length > 0) { + // 播放内容一致,不做处理 + if ([self.player.assetURL.absoluteString isEqualToString:model.videoInfo.video_url]) return; + + // 设置播放地址 + self.player.assetURL = [NSURL URLWithString:model.videoInfo.video_url]; + self.portraitView.resumeButton.hidden = YES; + if (self.isAppeared) { + [self.player.currentPlayerManager play]; + } + }else { + @weakify(self); + [self requestPlayUrlWithModel:model completion:^{ + @strongify(self); + // 播放内容一致,不做处理 + if ([self.player.assetURL.absoluteString isEqualToString:model.videoInfo.video_url]) return; + + // 设置播放地址 + self.player.assetURL = [NSURL URLWithString:model.videoInfo.video_url]; + self.portraitView.resumeButton.hidden = YES; + if (self.isAppeared) { + [self.player.currentPlayerManager play]; + } + }]; + } +} + +- (void)stopPlayWithCell:(GKDYVideoCell *)cell index:(NSInteger)index { + GKDYVideoModel *model = self.dataSources[index]; + if (![self.player.assetURL.absoluteString isEqualToString:model.videoInfo.video_url]) return; + + [self.player stop]; + if ([self.player.controlView isKindOfClass:GKDYVideoPortraitView.class]) { + [self.player.controlView removeFromSuperview]; + self.player.controlView = nil; + } + [cell resetView]; +} + +- (void)rotate { + [self.rotationManager rotate]; +} + +- (void)play { + if (self.isPlaying) return; + [self.player.currentPlayerManager play]; +// [self.currentCell.portraitView handleSingleTapped]; +} + +- (void)pause { + if (!self.isPlaying) return; + [self.player.currentPlayerManager pause]; +} + +- (void)stop { + [self.player.currentPlayerManager stop]; + self.player = nil; +} + +#pragma mark - Private +- (void)likeVideoWithModel:(GKDYVideoModel *)model { + if (model == nil) { + model = self.currentCell.model; + } + model.is_collect = YES; + [self.scrollView reloadData]; +} + +#pragma mark - GKVideoScrollViewDataSource +- (NSInteger)numberOfRowsInScrollView:(GKVideoScrollView *)scrollView { + return self.dataSources.count; +} + +- (GKVideoViewCell *)scrollView:(GKVideoScrollView *)scrollView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + GKDYVideoModel *model = self.dataSources[indexPath.row]; + if (scrollView == self.scrollView) { + GKDYVideoPortraitCell *cell = [scrollView dequeueReusableCellWithIdentifier:@"GKDYVideoPortraitCell" forIndexPath:indexPath]; + cell.delegate = self; + cell.manager = self; + cell.portraitView.slider.player = self.player; + [cell loadData:model]; + return cell; + }else { + GKDYVideoLandscapeCell *cell = [scrollView dequeueReusableCellWithIdentifier:@"GKDYVideoLandscapeCell" forIndexPath:indexPath]; + [cell loadData:model]; + @weakify(self); + cell.backClickBlock = ^{ + @strongify(self); + [self rotate]; + }; + [cell showTopView]; + return cell; + } +} + +#pragma mark - GKDYVideoScrollViewDelegate +- (void)scrollView:(GKVideoScrollView *)scrollView didEndScrollingCell:(GKVideoViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + [self playVideoWithCell:(GKDYVideoCell *)cell index:indexPath.row]; + if ([self.delegate respondsToSelector:@selector(cellSwitchWithModel:)]) { + [self.delegate cellSwitchWithModel:self.dataSources[indexPath.row]]; + } +} + +- (void)scrollView:(GKVideoScrollView *)scrollView didEndDisplayingCell:(GKVideoViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { + [self stopPlayWithCell:(GKDYVideoCell *)cell index:indexPath.row]; +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + if (scrollView == self.scrollView) { + if (self.scrollView.currentIndex == 0 && scrollView.contentOffset.y < 0) { + self.scrollView.contentOffset = CGPointZero; + } + } +} + +- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + [self.portraitView willBeginDragging]; +} + +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { + [self.portraitView didEndDragging]; +} + +- (void)scrollView:(GKDYVideoScrollView *)scrollView didPanWithDistance:(CGFloat)distance isEnd:(BOOL)isEnd { + if ([self.delegate respondsToSelector:@selector(scrollViewDidPanDistance:isEnd:)]) { + [self.delegate scrollViewDidPanDistance:distance isEnd:isEnd]; + } +} + +#pragma mark - GKDYVideoPortraitCellDelegate + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickFavorite:(GKDYVideoModel *)model { + [self.scrollView reloadData]; + + if ([self.delegate respondsToSelector:@selector(celldidClickFavorite:cell:)]) { + [self.delegate celldidClickFavorite:model cell:cell]; + } +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickEpiscode:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(celldidClickEpiscode:cell:)]) { + [self.delegate celldidClickEpiscode:model cell:cell]; + } +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickShare:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(celldidClickShare:cell:)]) { + [self.delegate celldidClickShare:model cell:cell]; + } +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickDanmu:(GKDYVideoModel *)model { + +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickFullscreen:(GKDYVideoModel *)model { + [self rotate]; +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell zoomBegan:(GKDYVideoModel *)model { + self.player.controlView.hidden = YES; + if ([self.delegate respondsToSelector:@selector(cellZoomBegan:)]) { + [self.delegate cellZoomBegan:model]; + } +} + +- (void)videoCell:(GKDYVideoPortraitCell *)cell zoomEnded:(GKDYVideoModel *)model isFullscreen:(BOOL)isFullscreen { + if (isFullscreen) { + self.fullscreenView.hidden = NO; + if (self.player.controlView != self.fullscreenView) { + self.player.controlView = self.fullscreenView; + self.player.disableGestureTypes = ZFPlayerDisableGestureTypesPinch; + } + }else { + self.currentCell.portraitView.hidden = NO; + if (self.player.controlView != self.currentCell.portraitView) { + self.player.controlView = self.currentCell.portraitView; + self.player.disableGestureTypes = ZFPlayerDisableGestureTypesPan | ZFPlayerDisableGestureTypesPinch; + } + } + if ([self.delegate respondsToSelector:@selector(cellZoomEnded:isFullscreen:)]) { + [self.delegate cellZoomEnded:model isFullscreen:isFullscreen]; + } +} + +#pragma mark - Lazy +- (GKDYVideoScrollView *)scrollView { + if (!_scrollView) { + _scrollView = [[GKDYVideoScrollView alloc] init]; + _scrollView.dataSource = self; + _scrollView.delegate = self; + _scrollView.backgroundColor = UIColor.blackColor; + [_scrollView registerClass:GKDYVideoPortraitCell.class forCellReuseIdentifier:@"GKDYVideoPortraitCell"]; + [_scrollView addPanGesture]; + } + return _scrollView; +} + +- (GKDYVideoLandscapeView *)landscapeView { + if (!_landscapeView) { + _landscapeView = [[GKDYVideoLandscapeView alloc] initWithFrame:UIScreen.mainScreen.bounds]; + + @weakify(self); + _landscapeView.likeBlock = ^(GKDYVideoModel * _Nonnull model) { + @strongify(self); + [self likeVideoWithModel:model]; + }; + + _landscapeView.singleTapBlock = ^{ + @strongify(self); + if (self.landscapeCell.isShowTop) { + [self.landscapeCell hideTopView]; + [self.landscapeView hideContainerView:NO]; + }else { + [self.landscapeView autoHide]; + } + }; + } + return _landscapeView; +} + +- (GKDYVideoFullscreenView *)fullscreenView { + if (!_fullscreenView) { + _fullscreenView = [[GKDYVideoFullscreenView alloc] init]; + + @weakify(self); + _fullscreenView.closeFullscreenBlock = ^{ + @strongify(self); + [self.currentCell closeFullscreen]; + }; + + _fullscreenView.likeBlock = ^{ + @strongify(self); + [self likeVideoWithModel:nil]; + }; + } + return _fullscreenView; +} + +- (NSMutableArray *)dataSources { + if (!_dataSources) { + _dataSources = [NSMutableArray array]; + } + return _dataSources; +} + +@end diff --git a/HiBit/Project/Player/Model/GKDUVideoInfoModel.h b/HiBit/Project/Player/Model/GKDUVideoInfoModel.h new file mode 100644 index 0000000..a1431f0 --- /dev/null +++ b/HiBit/Project/Player/Model/GKDUVideoInfoModel.h @@ -0,0 +1,21 @@ +// +// GKDUVideoInfoModel.h +// QinJiuTV +// +// Created by HI_LOSER on 2024/5/28. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDUVideoInfoModel : NSObject +@property (assign, nonatomic) NSInteger status; +@property (assign, nonatomic) NSInteger skits_id; +@property (assign, nonatomic) NSInteger vid; +@property (copy, nonatomic) NSString * video_url; +@property (assign, nonatomic) NSInteger episode; +@property (assign, nonatomic) BOOL is_vip; +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/Model/GKDUVideoInfoModel.m b/HiBit/Project/Player/Model/GKDUVideoInfoModel.m new file mode 100644 index 0000000..0ce2e70 --- /dev/null +++ b/HiBit/Project/Player/Model/GKDUVideoInfoModel.m @@ -0,0 +1,14 @@ +// +// GKDUVideoInfoModel.m +// QinJiuTV +// +// Created by HI_LOSER on 2024/5/28. +// + +#import "GKDUVideoInfoModel.h" + +@implementation GKDUVideoInfoModel ++ (NSDictionary *)mj_replacedKeyFromPropertyName{ + return @{@"vid" : @"id"}; +} +@end diff --git a/HiBit/Project/Player/Model/GKDYVideoModel.h b/HiBit/Project/Player/Model/GKDYVideoModel.h new file mode 100755 index 0000000..c35435e --- /dev/null +++ b/HiBit/Project/Player/Model/GKDYVideoModel.h @@ -0,0 +1,88 @@ +// +// GKDYVideoModel.h +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// + +#import +#import "GKDUVideoInfoModel.h" + + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoModel : NSObject + +//@property (nonatomic, copy) NSString *video_id; +//@property (nonatomic, copy) NSString *poster_small; +//@property (nonatomic, copy) NSString *poster_big; +//@property (nonatomic, copy) NSString *poster_pc; +//@property (nonatomic, copy) NSString *source_name; +//@property (nonatomic, copy) NSString *play_url; +//@property (nonatomic, copy) NSString *duration; +//@property (nonatomic, copy) NSString *url; +//@property (nonatomic, copy) NSString *show_tag; +//@property (nonatomic, copy) NSString *publish_time; +//@property (nonatomic, copy) NSString *is_pay_column; +//@property (nonatomic, copy) NSString *like; +//@property (nonatomic, copy) NSString *comment; +//@property (nonatomic, copy) NSString *playcnt; +//@property (nonatomic, copy) NSString *fmplaycnt; +//@property (nonatomic, copy) NSString *fmplaycnt_2; +//@property (nonatomic, copy) NSString *outstand_tag; +//@property (nonatomic, copy) NSString *previewUrlHttp; +//@property (nonatomic, copy) NSString *third_id; +//@property (nonatomic, copy) NSString *vip; +//@property (nonatomic, copy) NSString *author_avatar; +// +//@property (nonatomic, assign) BOOL isLike; +@property (nonatomic, strong, nullable) NSURLSessionDataTask *task; + +@property (nonatomic, assign) BOOL isRequest; +@property (nonatomic, assign) BOOL requested; + + +/// 短剧id +@property (assign, nonatomic) NSInteger cid; + +/// 收藏数量 +@property (assign, nonatomic) NSInteger collect_total; + +/// 集数 +@property (assign, nonatomic) NSInteger episode_total; +@property (assign, nonatomic) NSInteger episode; + +/// 观看数量 +@property (assign, nonatomic) NSInteger watch_total; + +/// 是否购买 +@property (assign, nonatomic) BOOL buy_type; + +/// 是否收藏 +@property (assign, nonatomic) BOOL is_collect; + +@property (assign, nonatomic) NSInteger process; + +/// 价格 +@property (strong, nonatomic) NSNumber * all_price; + + +/// 标题 剧名 +@property (copy, nonatomic) NSString * title; // name + +/// 剧情描述 +@property (copy, nonatomic) NSString * detailText; + +/// 封面 海报 +@property (copy, nonatomic) NSString * image_url; + +@property (strong, nonatomic) GKDUVideoInfoModel * videoInfo; + + + +@end + +NS_ASSUME_NONNULL_END + + diff --git a/HiBit/Project/Player/Model/GKDYVideoModel.m b/HiBit/Project/Player/Model/GKDYVideoModel.m new file mode 100755 index 0000000..bb7c01e --- /dev/null +++ b/HiBit/Project/Player/Model/GKDYVideoModel.m @@ -0,0 +1,77 @@ +// +// GKDYVideoModel.m +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// + +#import "GKDYVideoModel.h" + +@implementation GKDYVideoModel + +/* + /// 短剧id + @property (assign, nonatomic) NSInteger ; + + /// 收藏数量 + @property (assign, nonatomic) NSInteger ; + + /// 集数 + @property (assign, nonatomic) NSInteger ; + + /// 是否观看 + @property (assign, nonatomic) BOOL ; + + /// 是否购买 + @property (assign, nonatomic) BOOL ; + + /// 是否收藏 + @property (assign, nonatomic) BOOL ; + + @property (assign, nonatomic) NSInteger ; + + /// 价格 + @property (strong, nonatomic) NSNumber * ; + + + /// 标题 剧名 + @property (copy, nonatomic) NSString * ; // name + + /// 剧情描述 + @property (copy, nonatomic) NSString * ; + + /// 封面 海报 + @property (copy, nonatomic) NSString * ; + + @property (strong, nonatomic) GKDUVideoInfoModel * ; + + */ + +- (id)copyWithZone:(NSZone *)zone{ + GKDYVideoModel * model = [self.class new]; + model.cid = self.cid; + model.collect_total = self.collect_total; + model.episode_total = self.episode_total; + model.episode = self.episode; + model.watch_total = self.watch_total; + model.buy_type = self.buy_type; + model.is_collect = self.is_collect; + model.process = self.process; + model.all_price = self.all_price; + model.title = self.title; + model.detailText = self.detailText; + model.image_url = self.image_url; + model.videoInfo = self.videoInfo; + + return model; +} + + ++ (NSDictionary *)mj_replacedKeyFromPropertyName { + return @{@"cid" : @"id", + @"detailText" : @"description", + @"videoInfo" : @"video_info", + @"title" : @"name"}; +} +@end diff --git a/HiBit/Project/Player/View/GKDYPanGestureRecognizer.h b/HiBit/Project/Player/View/GKDYPanGestureRecognizer.h new file mode 100755 index 0000000..e06e5af --- /dev/null +++ b/HiBit/Project/Player/View/GKDYPanGestureRecognizer.h @@ -0,0 +1,24 @@ +// +// GKDYPanGestureRecognizer.h +// GKDYVideo +// +// Created by gaokun on 2019/7/31. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, GKDYPanGestureRecognizerDirection) { + GKDYPanGestureRecognizerDirectionVertical, + GKDYPanGestureRecognizerDirectionHorizontal +}; + +@interface GKDYPanGestureRecognizer : UIPanGestureRecognizer + +@property (nonatomic, assign) GKDYPanGestureRecognizerDirection direction; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYPanGestureRecognizer.m b/HiBit/Project/Player/View/GKDYPanGestureRecognizer.m new file mode 100755 index 0000000..9ab9a4a --- /dev/null +++ b/HiBit/Project/Player/View/GKDYPanGestureRecognizer.m @@ -0,0 +1,54 @@ +// +// GKDYPanGestureRecognizer.h +// GKDYVideo +// +// Created by gaokun on 2019/7/31. +// Copyright © 2019 QuintGao. All rights reserved. +// + +#import "GKDYPanGestureRecognizer.h" + +int const static kDirectionPanThreshold = 5; + +@interface GKDYPanGestureRecognizer() + +@property (nonatomic, assign) BOOL drag; +@property (nonatomic, assign) int moveX; +@property (nonatomic, assign) int moveY; + +@end + +@implementation GKDYPanGestureRecognizer + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + [super touchesMoved:touches withEvent:event]; + if (self.state == UIGestureRecognizerStateFailed) return; + CGPoint nowPoint = [[touches anyObject] locationInView:self.view]; + CGPoint prevPoint = [[touches anyObject] previousLocationInView:self.view]; + _moveX += prevPoint.x - nowPoint.x; + _moveY += prevPoint.y - nowPoint.y; + if (!_drag) { + if (abs(_moveX) > kDirectionPanThreshold) { + if (_direction == GKDYPanGestureRecognizerDirectionVertical) { + self.state = UIGestureRecognizerStateFailed; + }else { + _drag = YES; + } + }else if (abs(_moveY) > kDirectionPanThreshold) { + if (_direction == GKDYPanGestureRecognizerDirectionHorizontal) { + self.state = UIGestureRecognizerStateFailed; + }else { + _drag = YES; + } + } + } +} + +- (void)reset { + [super reset]; + _drag = NO; + _moveX = 0; + _moveY = 0; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYScrollView.h b/HiBit/Project/Player/View/GKDYScrollView.h new file mode 100755 index 0000000..2069f5e --- /dev/null +++ b/HiBit/Project/Player/View/GKDYScrollView.h @@ -0,0 +1,17 @@ +// +// GKDYScrollView.h +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYScrollView : UIScrollView + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYScrollView.m b/HiBit/Project/Player/View/GKDYScrollView.m new file mode 100755 index 0000000..8638879 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYScrollView.m @@ -0,0 +1,58 @@ +// +// GKDYScrollView.m +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// + +#import "GKDYScrollView.h" + +@implementation GKDYScrollView + +#pragma mark - 解决全屏滑动时的手势冲突 与 左滑push手势冲突 +// 当UIScrollView在水平方向滑动到第一个时,默认是不能全屏滑动返回的,通过下面的方法可实现其滑动返回。 +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { + if ([self panBack:gestureRecognizer]) { + return NO; + } + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + if ([self panBack:gestureRecognizer]) { + return YES; + } + + return NO; +} + +- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer { + if (gestureRecognizer == self.panGestureRecognizer) { + CGPoint point = [self.panGestureRecognizer translationInView:self]; + UIGestureRecognizerState state = gestureRecognizer.state; + + // 设置手势滑动的位置距屏幕左边的区域 + CGFloat locationDistance = self.bounds.size.width; + + if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStatePossible) { + CGPoint location = [gestureRecognizer locationInView:self]; + if (point.x > 0 && location.x < locationDistance && self.contentOffset.x <= 0) { + return YES; + } + + // 临界点:scrollView滑动到最后一屏时的x轴位置,可根据需求改变 + CGFloat criticalPoint = self.frame.size.width; + + // point.x < 0 代表左滑即手指从屏幕右边向左移动 + // 当UIScrollview滑动到临界点时,则不再相应UIScrollview的滑动左滑手势,防止与左滑手势冲突 + if (point.x < 0 && self.contentOffset.x + criticalPoint >= self.contentSize.width) { + return YES; + } + } + } + return NO; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYTitleView.h b/HiBit/Project/Player/View/GKDYTitleView.h new file mode 100755 index 0000000..e74ed28 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYTitleView.h @@ -0,0 +1,26 @@ +// +// GKDYTitleView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/27. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYTitleView : UIView + +@property (nonatomic, strong) JXCategoryTitleView *categoryView; + +@property (nonatomic, copy) void(^loadingBlock)(void); + +- (void)changeAlphaWithDistance:(CGFloat)distance isEnd:(BOOL)isEnd; + +- (void)loadingEnd; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYTitleView.m b/HiBit/Project/Player/View/GKDYTitleView.m new file mode 100755 index 0000000..d7407db --- /dev/null +++ b/HiBit/Project/Player/View/GKDYTitleView.m @@ -0,0 +1,195 @@ +// +// GKDYTitleView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/27. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYTitleView.h" +#import "GKBallLoadingView.h" + +#define kTransitionCenter 20.0f + +@interface GKDYTitleView() + +@property (nonatomic, strong) UILabel *refreshLabel; + +@property (nonatomic, strong) UIButton *searchBtn; + +@property (nonatomic, strong) GKBallLoadingView *loadingView; + +@property (nonatomic, assign) BOOL isRefreshing; + +@end + +@implementation GKDYTitleView + +- (instancetype)init { + if (self = [super init]) { + [self initUI]; + } + return self; +} + +- (void)initUI { + [self addSubview:self.categoryView]; + [self addSubview:self.searchBtn]; + [self addSubview:self.refreshLabel]; + [self addSubview:self.loadingView]; + + [self.categoryView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.bottom.equalTo(self); + make.left.equalTo(self).offset(60); + make.right.equalTo(self).offset(-60); + }]; + + [self.searchBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self).offset(-15); + make.top.bottom.equalTo(self); + }]; + + [self.refreshLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.bottom.equalTo(self); + make.centerX.equalTo(self); + }]; + + [self.loadingView mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self).offset(-15); + make.centerY.equalTo(self); + make.width.height.mas_equalTo(44); + }]; +} + +- (void)changeAlphaWithDistance:(CGFloat)distance isEnd:(BOOL)isEnd { + if (isEnd) { + [UIView animateWithDuration:0.25 animations:^{ + [self changeFrameWithDistance:0]; + self.categoryView.alpha = 1; + self.refreshLabel.alpha = 0; + self.loadingView.alpha = 1; + }]; + + if (distance >= 2 * kTransitionCenter) { + self.searchBtn.alpha = 0; + self.isRefreshing = YES; + [self.loadingView startLoading]; + !self.loadingBlock ?: self.loadingBlock(); + }else { + self.searchBtn.alpha = 1; + self.loadingView.alpha = 0; + } + }else { + if (distance <= 0) { + self.categoryView.alpha = 1; + self.searchBtn.alpha = 1; + self.refreshLabel.alpha = 0; + self.loadingView.alpha = 0; + }else if (distance > 0 && distance < kTransitionCenter) { + CGFloat alpha = distance / kTransitionCenter; + self.categoryView.alpha = 1 - alpha; + self.searchBtn.alpha = 1 - alpha; + self.refreshLabel.alpha = 0; + self.loadingView.alpha = 0; + + // 改变位置 + [self changeFrameWithDistance:distance]; + }else if (distance >= kTransitionCenter && distance <= 2 * kTransitionCenter) { + CGFloat alpha = (2 * kTransitionCenter - distance) / kTransitionCenter; + self.categoryView.alpha = 0; + self.searchBtn.alpha = 0; + self.refreshLabel.alpha = 1 - alpha; + self.loadingView.alpha = 1 - alpha; + + // 改变位置 + [self changeFrameWithDistance:distance]; + + [self.loadingView startLoadingWithProgress:1 - alpha]; + }else { + self.categoryView.alpha = 0; + self.searchBtn.alpha = 0; + self.refreshLabel.alpha = 1; + self.loadingView.alpha = 1; + + [self.loadingView startLoadingWithProgress:1]; + } + } +} + +- (void)changeFrameWithDistance:(CGFloat)distance { + CGRect frame = self.categoryView.frame; + frame.origin.y = distance; + self.categoryView.frame = frame; + + frame = self.searchBtn.frame; + frame.origin.y = distance; + self.searchBtn.frame = frame; + + frame = self.refreshLabel.frame; + frame.origin.y = distance; + self.refreshLabel.frame = frame; + + frame = self.loadingView.frame; + frame.origin.y = distance; + self.loadingView.frame = frame; +} + +- (void)loadingEnd { + self.searchBtn.alpha = 1; + self.loadingView.alpha = 0; + [self.loadingView stopLoading]; + self.isRefreshing = NO; +} + +- (void)searchClick:(id)sender { + +} + +#pragma mark - Lazy +- (JXCategoryTitleView *)categoryView { + if (!_categoryView) { + _categoryView = [[JXCategoryTitleView alloc] init]; + _categoryView.backgroundColor = UIColor.clearColor; + _categoryView.titleColor = UIColor.lightGrayColor; + _categoryView.titleSelectedColor = UIColor.whiteColor; + _categoryView.titleFont = [UIFont systemFontOfSize:16]; + _categoryView.titleSelectedFont = [UIFont boldSystemFontOfSize:16]; + _categoryView.cellSpacing = 10; + + JXCategoryIndicatorLineView *lineView = [[JXCategoryIndicatorLineView alloc] init]; + lineView.indicatorColor = UIColor.whiteColor; + lineView.indicatorWidthIncrement = -4; + _categoryView.indicators = @[lineView]; + } + return _categoryView; +} + +- (UIButton *)searchBtn { + if (!_searchBtn) { + _searchBtn = [[UIButton alloc] init]; + [_searchBtn setImage:[UIImage imageNamed:@"ich_feed_search_Normal"] forState:UIControlStateNormal]; + [_searchBtn addTarget:self action:@selector(searchClick:) forControlEvents:UIControlEventTouchUpInside]; + } + return _searchBtn; +} + +- (UILabel *)refreshLabel { + if (!_refreshLabel) { + _refreshLabel = [[UILabel alloc] init]; + _refreshLabel.font = [UIFont systemFontOfSize:16]; + _refreshLabel.textColor = UIColor.whiteColor; + _refreshLabel.text = @"下拉刷新内容"; + _refreshLabel.alpha = 0; + } + return _refreshLabel; +} + +- (GKBallLoadingView *)loadingView { + if (!_loadingView) { + _loadingView = [[GKBallLoadingView alloc] init]; + _loadingView.alpha = 0; + } + return _loadingView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoCell.h b/HiBit/Project/Player/View/GKDYVideoCell.h new file mode 100755 index 0000000..1479165 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoCell.h @@ -0,0 +1,29 @@ +// +// GKDYVideoCell.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import +#import "GKDYVideoModel.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoCell : GKVideoViewCell + +@property (nonatomic, strong) GKDYVideoModel *model; + +@property (nonatomic, strong) UIImageView *coverImgView; + +- (void)initUI; + +- (void)loadData:(GKDYVideoModel *)model; + +- (void)resetView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoCell.m b/HiBit/Project/Player/View/GKDYVideoCell.m new file mode 100755 index 0000000..19dc322 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoCell.m @@ -0,0 +1,58 @@ +// +// GKDYVideoCell.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoCell.h" + +@interface GKDYVideoCell() + +@end + +@implementation GKDYVideoCell + +- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier { + if (self = [super initWithReuseIdentifier:reuseIdentifier]) { + [self initUI]; + } + return self; +} + +- (void)initUI { + [self addSubview:self.coverImgView]; + [self.coverImgView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; +} + +- (void)loadData:(GKDYVideoModel *)model { + self.model = model; + + [self.coverImgView sd_setImageWithURL:[NSURL URLWithString:model.image_url]]; +} + +- (void)setModel:(GKDYVideoModel *)model { + _model = model; + + [self.coverImgView sd_setImageWithURL:[NSURL URLWithString:model.image_url]]; + +} + +- (void)resetView { + +} + +#pragma mark - Lazy +- (UIImageView *)coverImgView { + if (!_coverImgView) { + _coverImgView = [[UIImageView alloc] init]; + _coverImgView.contentMode = UIViewContentModeScaleAspectFit; + _coverImgView.userInteractionEnabled = YES; + } + return _coverImgView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoControlView.h b/HiBit/Project/Player/View/GKDYVideoControlView.h new file mode 100755 index 0000000..f1df40a --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoControlView.h @@ -0,0 +1,55 @@ +// +// GKDYVideoControlView.h +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// 播放器视图控制层 + +#import +//#import "GKAWEModel.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GKDYVideoControlView; + +@protocol GKDYVideoControlViewDelegate + +- (void)controlViewDidClickSelf:(GKDYVideoControlView *)controlView; + +- (void)controlViewDidClickPriase:(GKDYVideoControlView *)controlView; + +- (void)controlViewdidClickEpiscode:(GKDYVideoControlView *)controlView; + +- (void)controlViewDidClickShare:(GKDYVideoControlView *)controlView; + +- (void)controlView:(GKDYVideoControlView *)controlView touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; + +@end + +@interface GKDYVideoControlView : UIView + +@property (nonatomic, weak) id delegate; + +// 视频封面图:显示封面并播放视频 +@property (nonatomic, strong) UIImageView *coverImgView; + +@property (nonatomic, strong) id model; + +@property (nonatomic, strong) GKSliderView *sliderView; + +- (void)setProgress:(float)progress; + +- (void)startLoading; +- (void)stopLoading; + +- (void)showPlayBtn; +- (void)hidePlayBtn; + +- (void)showLikeAnimation; +- (void)showUnLikeAnimation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoControlView.m b/HiBit/Project/Player/View/GKDYVideoControlView.m new file mode 100755 index 0000000..5219403 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoControlView.m @@ -0,0 +1,302 @@ +// +// GKDYVideoControlView.m +// GKDYVideo +// +// Created by QuintGao on 2018/9/23. +// Copyright © 2018 QuintGao. All rights reserved. +// + +#import "GKDYVideoControlView.h" +#import "GKLikeView.h" +//#import "NSString+GKCategory.h" +#import "GKDYVideoItemButton.h" + +@interface GKDYVideoControlView() + +@property (nonatomic, strong) UIImageView *iconView; +@property (nonatomic, strong) GKLikeView *likeView; +@property (nonatomic, strong) GKDYVideoItemButton *commentBtn; +@property (nonatomic, strong) GKDYVideoItemButton *shareBtn; + +@property (nonatomic, strong) UILabel *nameLabel; +@property (nonatomic, strong) UILabel *contentLabel; + +@property (nonatomic, strong) UIButton *playBtn; + +@property (nonatomic, strong) UILabel *label; + +@end + +@implementation GKDYVideoControlView + +- (instancetype)init { + if (self = [super init]) { + [self addSubview:self.coverImgView]; + [self addSubview:self.iconView]; + [self addSubview:self.likeView]; + [self addSubview:self.commentBtn]; + [self addSubview:self.shareBtn]; + [self addSubview:self.nameLabel]; + [self addSubview:self.contentLabel]; + [self addSubview:self.sliderView]; + + [self addSubview:self.playBtn]; + [self addSubview:self.label]; + + [self.coverImgView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + CGFloat bottomM = [UIScreen bottomSafeHeight]; + + self.sliderView.frame = CGRectMake(0, HBScreenSize.height - [UIScreen bottomSafeHeight] - 0.5, HBScreenSize.width, 1.0f); + + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(HBAdapt(30.0f)); + make.bottom.equalTo(self).offset(-(HBAdapt(30.0f) + bottomM)); + make.width.mas_equalTo(HBAdapt(504.0f)); + }]; + + [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.contentLabel); + make.bottom.equalTo(self.contentLabel.mas_top).offset(-HBAdapt(20.0f)); + }]; + + [self.shareBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self).offset(-HBAdapt(30.0f)); + make.bottom.equalTo(self.sliderView.mas_top).offset(-HBAdapt(100.0f)); + make.width.height.mas_equalTo(HBAdapt(110.0f)); + }]; + + [self.commentBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self.shareBtn); + make.bottom.equalTo(self.shareBtn.mas_top).offset(-HBAdapt(45.0f)); + make.width.height.mas_equalTo(HBAdapt(110.0f)); + }]; + + [self.likeView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self.shareBtn); + make.bottom.equalTo(self.commentBtn.mas_top).offset(-HBAdapt(45.0f)); + make.width.height.mas_equalTo(HBAdapt(110.0f)); + }]; + + [self.iconView mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self.shareBtn); + make.bottom.equalTo(self.likeView.mas_top).offset(-HBAdapt(70.0f)); + make.width.height.mas_equalTo(HBAdapt(100.0f)); + }]; + + [self.playBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.equalTo(self); + }]; + + [self.label mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.equalTo(self); + }]; + } + return self; +} + +//- (void)setModel:(GKAWEModel *)model { +// _model = model; +// +// self.sliderView.value = 0; +// +// if (model.video.width.floatValue > model.video.height.floatValue) { +// self.coverImgView.contentMode = UIViewContentModeScaleAspectFit; +// }else { +// self.coverImgView.contentMode = UIViewContentModeScaleAspectFill; +// } +// NSString *url = model.video.cover.url_list.firstObject; +// [self.coverImgView sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"img_video_loading"]]; +// self.nameLabel.text = [NSString stringWithFormat:@"@%@", model.author.nickname]; +// [self.iconView sd_setImageWithURL:[NSURL URLWithString:model.author.avatar_thumb.url_list.firstObject] placeholderImage:[UIImage imageNamed:@"placeholderimg"]]; +// self.contentLabel.text = model.desc; +// +// [self.likeView setupLikeState:model.is_like]; +// [self.likeView setupLikeCount:[model.statistics.digg_count gk_unitConvert]]; +// +// [self.commentBtn setTitle:[model.statistics.comment_count gk_unitConvert] forState:UIControlStateNormal]; +// [self.shareBtn setTitle:[model.statistics.share_count gk_unitConvert] forState:UIControlStateNormal]; +// +// self.label.text = [NSString stringWithFormat:@"第%zd个", model.index]; +//} + +#pragma mark - Public Methods +- (void)setProgress:(float)progress { + self.sliderView.value = progress; +} + +- (void)startLoading { + [self.sliderView showLineLoading]; +} + +- (void)stopLoading { + [self.sliderView hideLineLoading]; +} + +- (void)showPlayBtn { + self.playBtn.hidden = NO; +} + +- (void)hidePlayBtn { + self.playBtn.hidden = YES; +} + +- (void)showLikeAnimation { + [self.likeView startAnimationWithIsLike:YES]; +} + +- (void)showUnLikeAnimation { + [self.likeView startAnimationWithIsLike:NO]; +} + +#pragma mark - Action +- (void)controlViewDidClick { + if ([self.delegate respondsToSelector:@selector(controlViewDidClickSelf:)]) { + [self.delegate controlViewDidClickSelf:self]; + } +} + +- (void)praiseBtnClick:(id)sender { + if ([self.delegate respondsToSelector:@selector(controlViewDidClickPriase:)]) { + [self.delegate controlViewDidClickPriase:self]; + } +} + +- (void)commentBtnClick:(id)sender { + if ([self.delegate respondsToSelector:@selector(controlViewdidClickEpiscode:)]) { + [self.delegate controlViewdidClickEpiscode:self]; + } +} + +- (void)shareBtnClick:(id)sender { + if ([self.delegate respondsToSelector:@selector(controlViewDidClickShare:)]) { + [self.delegate controlViewDidClickShare:self]; + } +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [touches anyObject]; + + NSTimeInterval delayTime = 0.3f; + + if (touch.tapCount <= 1) { + [self performSelector:@selector(controlViewDidClick) withObject:nil afterDelay:delayTime]; + }else { + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(controlViewDidClick) object:nil]; + + if ([self.delegate respondsToSelector:@selector(controlView:touchesBegan:withEvent:)]) { + [self.delegate controlView:self touchesBegan:touches withEvent:event]; + } + } +} + +#pragma mark - 懒加载 +- (UIImageView *)coverImgView { + if (!_coverImgView) { + _coverImgView = [UIImageView new]; + _coverImgView.contentMode = UIViewContentModeScaleAspectFill; + _coverImgView.clipsToBounds = YES; + } + return _coverImgView; +} + +- (UIImageView *)iconView { + if (!_iconView) { + _iconView = [UIImageView new]; + _iconView.layer.cornerRadius = HBAdapt(50.0f); + _iconView.layer.masksToBounds = YES; + _iconView.layer.borderColor = [UIColor whiteColor].CGColor; + _iconView.layer.borderWidth = 1.0f; + _iconView.userInteractionEnabled = YES; + + UITapGestureRecognizer *iconTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(iconDidClick:)]; + [_iconView addGestureRecognizer:iconTap]; + } + return _iconView; +} + +- (GKLikeView *)likeView { + if (!_likeView) { + _likeView = [GKLikeView new]; + } + return _likeView; +} + +- (GKDYVideoItemButton *)commentBtn { + if (!_commentBtn) { + _commentBtn = [GKDYVideoItemButton new]; + [_commentBtn setImage:[UIImage imageNamed:@"icon_home_comment"] forState:UIControlStateNormal]; + _commentBtn.titleLabel.font = [UIFont systemFontOfSize:13.0f]; + [_commentBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [_commentBtn addTarget:self action:@selector(commentBtnClick:) forControlEvents:UIControlEventTouchUpInside]; + } + return _commentBtn; +} + +- (GKDYVideoItemButton *)shareBtn { + if (!_shareBtn) { + _shareBtn = [GKDYVideoItemButton new]; + [_shareBtn setImage:[UIImage imageNamed:@"icon_home_share"] forState:UIControlStateNormal]; + _shareBtn.titleLabel.font = [UIFont systemFontOfSize:13.0f]; + [_shareBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [_shareBtn addTarget:self action:@selector(shareBtnClick:) forControlEvents:UIControlEventTouchUpInside]; + } + return _shareBtn; +} + +- (UILabel *)nameLabel { + if (!_nameLabel) { + _nameLabel = [UILabel new]; + _nameLabel.textColor = [UIColor whiteColor]; + _nameLabel.font = [UIFont boldSystemFontOfSize:15.0f]; + _nameLabel.userInteractionEnabled = YES; + + UITapGestureRecognizer *nameTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(iconDidClick:)]; + [_nameLabel addGestureRecognizer:nameTap]; + } + return _nameLabel; +} + +- (UILabel *)contentLabel { + if (!_contentLabel) { + _contentLabel = [UILabel new]; + _contentLabel.numberOfLines = 0; + _contentLabel.textColor = [UIColor whiteColor]; + _contentLabel.font = [UIFont systemFontOfSize:14.0f]; + } + return _contentLabel; +} + +- (GKSliderView *)sliderView { + if (!_sliderView) { + _sliderView = [GKSliderView new]; + _sliderView.isHideSliderBlock = YES; + _sliderView.sliderHeight = 1.0f; + _sliderView.maximumTrackTintColor = [UIColor clearColor]; + _sliderView.minimumTrackTintColor = HBColor.color_FF0049; + } + return _sliderView; +} + +- (UIButton *)playBtn { + if (!_playBtn) { + _playBtn = [UIButton new]; + [_playBtn setImage:[UIImage imageNamed:@"player_play"] forState:UIControlStateNormal]; + _playBtn.hidden = YES; + } + return _playBtn; +} + +- (UILabel *)label { + if (!_label) { + _label = [[UILabel alloc] init]; + _label.font = [UIFont systemFontOfSize:30]; + _label.backgroundColor = UIColor.blackColor; + _label.textColor = UIColor.whiteColor; + } + return _label; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoFullscreenView.h b/HiBit/Project/Player/View/GKDYVideoFullscreenView.h new file mode 100755 index 0000000..ad9d224 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoFullscreenView.h @@ -0,0 +1,21 @@ +// +// GKDYVideoFullscreenView.h +// GKDYVideo +// +// Created by QuintGao on 2023/5/8. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoFullscreenView : UIView + +@property (nonatomic, copy) void(^closeFullscreenBlock)(void); +@property (nonatomic, copy) void(^likeBlock)(void); + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoFullscreenView.m b/HiBit/Project/Player/View/GKDYVideoFullscreenView.m new file mode 100755 index 0000000..8998482 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoFullscreenView.m @@ -0,0 +1,211 @@ +// +// GKDYVideoFullscreenView.m +// GKDYVideo +// +// Created by QuintGao on 2023/5/8. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoFullscreenView.h" +#import "GKDoubleLikeView.h" + +@interface GKDYVideoFullscreenView() + +@property (nonatomic, strong) UIView *bottomView; + +@property (nonatomic, strong) UIView *leftView; +@property (nonatomic, strong) UIButton *closeBtn; + +@property (nonatomic, strong) UIView *rightView; +@property (nonatomic, strong) UIButton *playBtn; +@property (nonatomic, strong) UIButton *speedBtn; + +@property (nonatomic, strong) NSArray *speeds; +@property (nonatomic, assign) NSInteger currentSpeed; + +@property (nonatomic, strong) GKDoubleLikeView *likeView; +@property (nonatomic, strong) NSDate *lastDoubleTapTime; + +@end + +@implementation GKDYVideoFullscreenView + +- (instancetype)init { + if (self = [super init]) { + [self initUI]; + self.speeds = @[@1, @1.5, @2, @0.5]; + self.currentSpeed = 0; + } + return self; +} + +- (void)initUI { + [self addSubview:self.bottomView]; + [self.bottomView addSubview:self.leftView]; + [self.leftView addSubview:self.closeBtn]; + [self.bottomView addSubview:self.rightView]; + [self.rightView addSubview:self.playBtn]; + [self.rightView addSubview:self.speedBtn]; + + [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.bottom.equalTo(self); + make.height.mas_equalTo(44); + }]; + + [self.leftView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.bottomView).offset(10); + make.top.bottom.equalTo(self.bottomView); + make.width.mas_equalTo(58); + }]; + + [self.closeBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self.leftView); + }]; + + [self.rightView mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.bottomView).offset(-10); + make.top.bottom.equalTo(self.bottomView); + make.width.mas_equalTo(100); + }]; + + [self.playBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.bottom.equalTo(self.rightView); + make.right.equalTo(self.rightView.mas_centerX); + }]; + + [self.speedBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.top.bottom.equalTo(self.rightView); + make.left.equalTo(self.rightView.mas_centerX); + }]; +} + +#pragma mark - ZFPlayerMediaControl +@synthesize player = _player; +- (void)setPlayer:(ZFPlayerController *)player { + _player = player; + + self.playBtn.selected = player.currentPlayerManager.isPlaying; +} + +- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl { + CGFloat diff = [NSDate date].timeIntervalSince1970 - self.lastDoubleTapTime.timeIntervalSince1970; + if (diff < 0.6) { + [self handleDoubleTapped:gestureControl.singleTap]; + self.lastDoubleTapTime = [NSDate date]; + }else { + [self handleSingleTapped]; + } +} + +- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl { + [self handleDoubleTapped:gestureControl.doubleTap]; + self.lastDoubleTapTime = [NSDate date]; +} + +- (void)gestureBeganPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location { + [self closeAction]; +} + +- (void)handleSingleTapped { + [self playAction]; +} + +- (void)handleDoubleTapped:(UITapGestureRecognizer *)gesture { + CGPoint point = [gesture locationInView:gesture.view]; + [self.likeView createAnimationWithPoint:point view:gesture.view completion:nil]; + !self.likeBlock ?: self.likeBlock(); +} + +#pragma mark - action +- (void)closeAction { + !self.closeFullscreenBlock ?: self.closeFullscreenBlock(); +} + +- (void)playAction { + id manager = self.player.currentPlayerManager; + if (manager.isPlaying) { + [manager pause]; + self.playBtn.selected = NO; + }else { + [manager play]; + self.playBtn.selected = YES; + } +} + +- (void)speedAction { + self.currentSpeed++; + if (self.currentSpeed == self.speeds.count) { + self.currentSpeed = 0; + } + float speed = [self.speeds[self.currentSpeed] floatValue]; + self.player.currentPlayerManager.rate = speed; + [self.speedBtn setTitle:[NSString stringWithFormat:@"%@x", self.speeds[self.currentSpeed]] forState:UIControlStateNormal]; +} + +#pragma mark - lazy +- (UIView *)bottomView { + if (!_bottomView) { + _bottomView = [[UIView alloc] init]; + } + return _bottomView; +} + +- (UIView *)leftView { + if (!_leftView) { + _leftView = [[UIView alloc] init]; + _leftView.backgroundColor = UIColor.darkGrayColor; + _leftView.layer.cornerRadius = 5; + _leftView.layer.masksToBounds = YES; + } + return _leftView; +} + +- (UIButton *)closeBtn { + if (!_closeBtn) { + _closeBtn = [[UIButton alloc] init]; + [_closeBtn setImage:[UIImage imageNamed:@"icon_feedback_close_Normal"] forState:UIControlStateNormal]; + [_closeBtn addTarget:self action:@selector(closeAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _closeBtn; +} + +- (UIView *)rightView { + if (!_rightView) { + _rightView = [[UIView alloc] init]; + _rightView.backgroundColor = UIColor.darkGrayColor; + _rightView.layer.cornerRadius = 5; + _rightView.layer.masksToBounds = YES; + } + return _rightView; +} + +- (UIButton *)playBtn { + if (!_playBtn) { + _playBtn = [[UIButton alloc] init]; + [_playBtn setImage:[UIImage imageNamed:@"icon_modern_feed_play_Normal"] forState:UIControlStateNormal]; + [_playBtn setImage:[UIImage imageNamed:@"icon_music_pause_new_Normal"] forState:UIControlStateSelected]; + [_playBtn addTarget:self action:@selector(playAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _playBtn; +} + +- (UIButton *)speedBtn { + if (!_speedBtn) { + _speedBtn = [[UIButton alloc] init]; + [_speedBtn setTitle:@"1x" forState:UIControlStateNormal]; + [_speedBtn setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + _speedBtn.titleLabel.font = [UIFont systemFontOfSize:14]; + [_speedBtn addTarget:self action:@selector(speedAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _speedBtn; +} + +- (GKDoubleLikeView *)likeView { + if (!_likeView) { + _likeView = [[GKDoubleLikeView alloc] init]; + } + return _likeView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoItemButton.h b/HiBit/Project/Player/View/GKDYVideoItemButton.h new file mode 100755 index 0000000..a90e9eb --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoItemButton.h @@ -0,0 +1,17 @@ +// +// GKDYVideoItemButton.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoItemButton : UIButton + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoItemButton.m b/HiBit/Project/Player/View/GKDYVideoItemButton.m new file mode 100755 index 0000000..6200cf7 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoItemButton.m @@ -0,0 +1,33 @@ +// +// GKDYVideoItemButton.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoItemButton.h" + +@implementation GKDYVideoItemButton + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self.imageView sizeToFit]; + [self.titleLabel sizeToFit]; + + CGFloat width = self.frame.size.width; + CGFloat height = self.frame.size.height; + + CGFloat imgW = self.imageView.frame.size.width; + CGFloat imgH = self.imageView.frame.size.height; + + self.imageView.frame = CGRectMake((width - imgH) / 2, 0, imgW, imgH); + + CGFloat titleW = self.titleLabel.frame.size.width; + CGFloat titleH = self.titleLabel.frame.size.height; + + self.titleLabel.frame = CGRectMake((width - titleW) / 2, height - titleH, titleW, titleH); +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoLandscapeCell.h b/HiBit/Project/Player/View/GKDYVideoLandscapeCell.h new file mode 100755 index 0000000..2af8c80 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoLandscapeCell.h @@ -0,0 +1,26 @@ +// +// GKDYVideoLandscapeCell.h +// GKDYVideo +// +// Created by QuintGao on 2023/5/5. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoCell.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoLandscapeCell : GKDYVideoCell + +@property (nonatomic, assign) BOOL isShowTop; + +@property (nonatomic, copy) void(^backClickBlock)(void); + +- (void)hideTopView; +- (void)showTopView; + +- (void)autoHide; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoLandscapeCell.m b/HiBit/Project/Player/View/GKDYVideoLandscapeCell.m new file mode 100755 index 0000000..7dcac89 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoLandscapeCell.m @@ -0,0 +1,110 @@ +// +// GKDYVideoLandscapeCell.m +// GKDYVideo +// +// Created by QuintGao on 2023/5/5. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoLandscapeCell.h" +#import "GKDYVideoMaskView.h" +#import "UIButton+GKEnlarge.h" + +@interface GKDYVideoLandscapeCell() + +@property (nonatomic, strong) GKDYVideoMaskView *topContainerView; + +@property (nonatomic, strong) UIButton *backBtn; + +@property (nonatomic, strong) UILabel *titleLabel; + +@end + +@implementation GKDYVideoLandscapeCell + +- (void)initUI { + [super initUI]; + + [self addSubview:self.topContainerView]; + [self.topContainerView addSubview:self.backBtn]; + [self.topContainerView addSubview:self.titleLabel]; + + [self.topContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.right.equalTo(self); + make.height.mas_equalTo(80); + }]; + + [self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self).offset(25); + make.left.equalTo(self.topContainerView.mas_safeAreaLayoutGuideLeft).offset(12); + }]; + + [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.backBtn).offset(3); + make.left.equalTo(self.backBtn.mas_right).offset(5); + make.right.equalTo(self.topContainerView.mas_safeAreaLayoutGuideRight).offset(-30); + }]; + + self.topContainerView.hidden = YES; + self.isShowTop = NO; +} + +- (void)loadData:(GKDYVideoModel *)model { + [super loadData:model]; + + self.titleLabel.text = model.title; +} + +- (void)hideTopView { + self.topContainerView.hidden = YES; + self.isShowTop = NO; +} + +- (void)showTopView { + self.topContainerView.hidden = NO; + self.isShowTop = YES; +} + +- (void)autoHide { + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideTopView) object:nil]; + [self performSelector:@selector(hideTopView) withObject:nil afterDelay:3.0f]; +} + +- (void)resetView { + [super resetView]; + [self showTopView]; +} + +- (void)backAction { + !self.backClickBlock ?: self.backClickBlock(); +} + +#pragma mark - Lazy +- (GKDYVideoMaskView *)topContainerView { + if (!_topContainerView) { + _topContainerView = [[GKDYVideoMaskView alloc] initWithStyle:GKDYVideoMaskViewStyle_Top]; + } + return _topContainerView; +} + +- (UIButton *)backBtn { + if (!_backBtn) { + _backBtn = [[UIButton alloc] init]; + [_backBtn setEnlargeEdge:10]; + [_backBtn setImage:[UIImage imageNamed:@"ic_back_white"] forState:UIControlStateNormal]; + [_backBtn addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _backBtn; +} + +- (UILabel *)titleLabel { + if (!_titleLabel) { + _titleLabel = [[UILabel alloc] init]; + _titleLabel.font = [UIFont boldSystemFontOfSize:15]; + _titleLabel.textColor = UIColor.whiteColor; + _titleLabel.numberOfLines = 0; + } + return _titleLabel; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoLandscapeView.h b/HiBit/Project/Player/View/GKDYVideoLandscapeView.h new file mode 100755 index 0000000..6cc96fe --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoLandscapeView.h @@ -0,0 +1,37 @@ +// +// GKDYVideoLandscapeView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import +#import "GKDYVideoModel.h" +#import "GKRotationManager.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoLandscapeView : UIView + +@property (nonatomic, strong) GKDYVideoModel *model; + +@property (nonatomic, weak) GKRotationManager *rotationManager; + +@property (nonatomic, copy) void(^likeBlock)(GKDYVideoModel *model); + +@property (nonatomic, copy) void(^singleTapBlock)(void); + +- (void)startTimer; +- (void)destoryTimer; + +@property (nonatomic, assign) BOOL isContainerShow; +- (void)showContainerView:(BOOL)animated; +- (void)hideContainerView:(BOOL)animated; + +- (void)autoHide; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoLandscapeView.m b/HiBit/Project/Player/View/GKDYVideoLandscapeView.m new file mode 100755 index 0000000..c902b17 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoLandscapeView.m @@ -0,0 +1,491 @@ +// +// GKDYVideoLandscapeView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoLandscapeView.h" +#import "GKDYVideoStatusBar.h" +#import "GKDYVideoMaskView.h" +#import "GKDoubleLikeView.h" +#import +#import "UIButton+GKEnlarge.h" +#import +#import "GKDYVideoPreviewView.h" + + +@interface GKDYVideoLandscapeView() + +// 顶部 +@property (nonatomic, strong) GKDYVideoMaskView *topContainerView; + +@property (nonatomic, strong) GKDYVideoStatusBar *statusBar; + +@property (nonatomic, strong) UIButton *backBtn; + +@property (nonatomic, strong) UILabel *nameLabel; + +@property (nonatomic, strong) UILabel *contentLabel; + +// 底部 +@property (nonatomic, strong) GKDYVideoMaskView *bottomContainerView; + +@property (nonatomic, strong) GKSliderView *sliderView; + +@property (nonatomic, strong) UIButton *playBtn; + +@property (nonatomic, strong) UILabel *timeLabel; + +@property (nonatomic, strong) UIButton *likeBtn; + +@property (nonatomic, strong) UIButton *exitBtn; + +@property (nonatomic, strong) GKDoubleLikeView *likeView; +@property (nonatomic, strong) NSDate *lastDoubleTapTime; + +@property (nonatomic, assign) BOOL isDragging; +@property (nonatomic ,assign) BOOL isSeeking; + +@end + +@implementation GKDYVideoLandscapeView + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self initUI]; + } + return self; +} + +- (void)initUI { + [self addSubview:self.topContainerView]; + [self.topContainerView addSubview:self.statusBar]; + [self.topContainerView addSubview:self.backBtn]; + [self.topContainerView addSubview:self.contentLabel]; + [self.topContainerView addSubview:self.nameLabel]; + + [self addSubview:self.bottomContainerView]; + [self.bottomContainerView addSubview:self.sliderView]; + [self.bottomContainerView addSubview:self.playBtn]; + [self.bottomContainerView addSubview:self.timeLabel]; + [self.bottomContainerView addSubview:self.likeBtn]; + [self.bottomContainerView addSubview:self.exitBtn]; + + [self.topContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.right.equalTo(self); + make.height.mas_equalTo(80); + }]; + + [self.statusBar mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.topContainerView.mas_safeAreaLayoutGuideTop); + make.left.equalTo(self.topContainerView.mas_safeAreaLayoutGuideLeft).offset(10); + make.right.equalTo(self.topContainerView.mas_safeAreaLayoutGuideRight).offset(-10); + make.height.mas_equalTo(20); + }]; + + [self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.statusBar.mas_bottom).offset(5); + make.left.equalTo(self.statusBar).offset(2); + }]; + + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.backBtn).offset(3); + make.left.equalTo(self.backBtn.mas_right).offset(5); + make.right.equalTo(self.statusBar.mas_right).offset(-20); + }]; + + [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.contentLabel); + make.top.equalTo(self.contentLabel.mas_bottom).offset(5); + }]; + + [self.bottomContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.bottom.left.right.equalTo(self); + make.height.mas_equalTo(80); + }]; + + [self.sliderView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.bottomContainerView.mas_safeAreaLayoutGuideLeft).offset(10); + make.right.equalTo(self.bottomContainerView.mas_safeAreaLayoutGuideRight).offset(-10); + make.bottom.equalTo(self.playBtn.mas_top).offset(-10); + make.height.mas_equalTo(10); + }]; + + [self.playBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.sliderView); + make.bottom.equalTo(self.bottomContainerView).offset(-10); + }]; + + [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.playBtn); + make.left.equalTo(self.playBtn.mas_right).offset(10); + }]; + + [self.likeBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.playBtn); + make.right.equalTo(self.exitBtn.mas_left).offset(-20); + }]; + + [self.exitBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.playBtn); + make.right.equalTo(self.sliderView.mas_right); + }]; +} + +- (void)setModel:(GKDYVideoModel *)model { + _model = model; + + self.contentLabel.text = model.detailText; + self.nameLabel.text = model.title; + self.likeBtn.selected = model.is_collect; +} + +- (void)startTimer { + [self.statusBar startTimer]; +} + +- (void)destoryTimer { + [self.statusBar destoryTimer]; +} + +#pragma mark - ZFPlayerMediaControl +@synthesize player = _player; +- (void)setPlayer:(ZFPlayerController *)player { + _player = player; + + GKDYVideoPreviewView *videoPreview = (GKDYVideoPreviewView *)self.sliderView.preview; + videoPreview.player = player; + + self.playBtn.selected = player.currentPlayerManager.isPlaying; + [self setNetworkState]; +} + +- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationDidChanged:(ZFOrientationObserver *)observer { + if (videoPlayer.isFullScreen) { + [self showContainerView:NO]; + [self cancelAutoHidden]; + [self performSelector:@selector(hideContainerView:) withObject:@(YES) afterDelay:5.0f]; + } +} + +- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl { + CGFloat diff = [NSDate date].timeIntervalSince1970 - self.lastDoubleTapTime.timeIntervalSince1970; + if (diff < 0.6) { + [self handleDoubleTapped:gestureControl.singleTap]; + self.lastDoubleTapTime = [NSDate date]; + }else { + [self handleSingleTapped]; + } +} + +- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl { + [self handleDoubleTapped:gestureControl.doubleTap]; + self.lastDoubleTapTime = [NSDate date]; +} + +- (void)videoPlayer:(ZFPlayerController *)videoPlayer reachabilityChanged:(ZFReachabilityStatus)status { + [self setNetworkState]; +} + +- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime { + if (self.isDragging) return; + if (self.isSeeking) return; + self.sliderView.value = self.player.progress; + self.timeLabel.text = [NSString stringWithFormat:@"%@ / %@", [NSString convertTimeSecond:currentTime], [NSString convertTimeSecond:totalTime]]; +} + +- (void)handleSingleTapped { + !self.singleTapBlock ?: self.singleTapBlock(); +} + +- (void)handleDoubleTapped:(UITapGestureRecognizer *)gesture { + [self cancelAutoHidden]; + + CGPoint point = [gesture locationInView:gesture.view]; + @weakify(self); + [self.likeView createAnimationWithPoint:point view:gesture.view completion:^{ + @strongify(self); + [self performSelector:@selector(hideContainerView) withObject:nil afterDelay:5.0f]; + }]; + self.model.is_collect = YES; + self.likeBtn.selected = self.model.is_collect; + !self.likeBlock ?: self.likeBlock(self.model); +} + +#pragma mark - Public +- (void)showContainerView:(BOOL)animated { + [self.topContainerView mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self); + }]; + + [self.bottomContainerView mas_updateConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(self); + }]; + + self.topContainerView.hidden = NO; + self.bottomContainerView.hidden = NO; + + NSTimeInterval duration = animated ? 0.2 : 0; + + [UIView animateWithDuration:duration animations:^{ + [self layoutIfNeeded]; + } completion:^(BOOL finished) { + self.isContainerShow = YES; + }]; +} + +- (void)hideContainerView { + [self hideContainerView:YES]; +} + +- (void)hideContainerView:(BOOL)animated { + [self.topContainerView mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self).offset(-80); + }]; + + [self.bottomContainerView mas_updateConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(self).offset(80); + }]; + + NSTimeInterval duration = animated ? 0.15 : 0; + + [UIView animateWithDuration:duration animations:^{ + [self layoutIfNeeded]; + } completion:^(BOOL finished) { + self.isContainerShow = NO; + self.topContainerView.hidden = YES; + self.bottomContainerView.hidden = YES; + }]; +} + +- (void)autoHide { + [self cancelAutoHidden]; + + if (self.isContainerShow) { + [self hideContainerView:YES]; + }else { + [self showContainerView:YES]; + [self performSelector:@selector(hideContainerView) withObject:nil afterDelay:5.0]; + } +} + +- (void)cancelAutoHidden { + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideContainerView) object:nil]; +} + +- (void)setNetworkState { + NSString *net = @"WIFI"; + switch (ZFReachabilityManager.sharedManager.networkReachabilityStatus) { + case ZFReachabilityStatusReachableViaWiFi: + net = @"WIFI"; + break; + case ZFReachabilityStatusNotReachable: + net = @"无网络"; + break; + case ZFReachabilityStatusReachableVia2G: + net = @"2G"; + break; + case ZFReachabilityStatusReachableVia3G: + net = @"3G"; + break; + case ZFReachabilityStatusReachableVia4G: + net = @"4G"; + break; + case ZFReachabilityStatusReachableVia5G: + net = @"5G"; + break; + default: + net = @"未知"; + break; + } + self.statusBar.network = net; +} + +#pragma mark - Action +- (void)backAction { + [self cancelAutoHidden]; + [self.rotationManager rotate]; +} + +- (void)playAction { + [self cancelAutoHidden]; + id manager = self.player.currentPlayerManager; + if (manager.isPlaying) { + [manager pause]; + }else { + [manager play]; + } + self.playBtn.selected = manager.isPlaying; + [self autoHide]; +} + +- (void)likeAction { + [self cancelAutoHidden]; + self.model.is_collect = !self.model.is_collect; + self.likeBtn.selected = self.model.is_collect; + !self.likeBlock ?: self.likeBlock(self.model); + [self autoHide]; +} + +- (void)exitAction { + [self backAction]; +} + +#pragma mark - GKSliderViewDelegate +- (void)sliderView:(GKSliderView *)sliderView touchBegan:(float)value { + self.isDragging = YES; + [self showLargeSlider]; + [self cancelAutoHidden]; +} + +- (void)sliderView:(GKSliderView *)sliderView touchEnded:(float)value { + self.isDragging = NO; + [self showSmallSlider]; + [self autoHide]; +} + +#pragma mark - GKSliderViewPreviewDelegate +- (UIView *)sliderViewSetupPreview:(GKSliderView *)sliderView { + GKDYVideoPreviewView *preview = [[GKDYVideoPreviewView alloc] init]; + preview.bounds = CGRectMake(0, 0, 120, 120); + return preview; +} + +- (CGFloat)sliderViewPreviewMargin:(GKSliderView *)sliderView { + return 40; +} + +- (void)sliderView:(GKSliderView *)sliderView preview:(UIView *)preview valueChanged:(float)value { + GKDYVideoPreviewView *videoPreview = (GKDYVideoPreviewView *)preview; + [videoPreview setPreviewValue:value]; +} + +- (void)showLargeSlider { + self.sliderView.sliderBtn.transform = CGAffineTransformMakeScale(1.5, 1.5); + self.sliderView.sliderHeight = 5; +} + +- (void)showSmallSlider { + self.sliderView.sliderBtn.transform = CGAffineTransformIdentity; + self.sliderView.sliderHeight = 2; +} + +#pragma mark - Lazy +- (GKDYVideoMaskView *)topContainerView { + if (!_topContainerView) { + _topContainerView = [[GKDYVideoMaskView alloc] initWithStyle:GKDYVideoMaskViewStyle_Top]; + } + return _topContainerView; +} + +- (GKDYVideoMaskView *)bottomContainerView { + if (!_bottomContainerView) { + _bottomContainerView = [[GKDYVideoMaskView alloc] initWithStyle:GKDYVideoMaskViewStyle_Bottom]; + } + return _bottomContainerView; +} + +- (GKDYVideoStatusBar *)statusBar { + if (!_statusBar) { + _statusBar = [[GKDYVideoStatusBar alloc] init]; + } + return _statusBar; +} + +- (UIButton *)backBtn { + if (!_backBtn) { + _backBtn = [[UIButton alloc] init]; + [_backBtn setImage:[UIImage imageNamed:@"ic_back_white"] forState:UIControlStateNormal]; + [_backBtn addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + [_backBtn setEnlargeEdge:10]; + } + return _backBtn; +} + +- (UILabel *)contentLabel { + if (!_contentLabel) { + _contentLabel = [[UILabel alloc] init]; + _contentLabel.font = [UIFont boldSystemFontOfSize:15]; + _contentLabel.textColor = UIColor.whiteColor; + _contentLabel.numberOfLines = 0; + } + return _contentLabel; +} + +- (UILabel *)nameLabel { + if (!_nameLabel) { + _nameLabel = [[UILabel alloc] init]; + _nameLabel.font = [UIFont systemFontOfSize:14]; + _nameLabel.textColor = UIColor.whiteColor; + } + return _nameLabel; +} + +- (GKSliderView *)sliderView { + if (!_sliderView) { + _sliderView = [[GKSliderView alloc] init]; +// [_sliderView setThumbImage:[UIImage imageNamed:@"icon_slider"] forState:UIControlStateNormal]; +// [_sliderView setThumbImage:[UIImage imageNamed:@"icon_slider"] forState:UIControlStateHighlighted]; + _sliderView.maximumTrackTintColor = UIColor.grayColor; + _sliderView.minimumTrackTintColor = HBColor.color_FF0049; + _sliderView.sliderHeight = 2; + _sliderView.delegate = self; + _sliderView.previewDelegate = self; + _sliderView.isPreviewChangePosition = NO; + _sliderView.isSliderAllowTapped = YES; + _sliderView.isSliderAllowDragged = YES; + } + return _sliderView; +} + +- (UIButton *)playBtn { + if (!_playBtn) { + _playBtn = [[UIButton alloc] init]; + [_playBtn setImage:[UIImage imageNamed:@"icon_play"] forState:UIControlStateNormal]; + [_playBtn setImage:[UIImage imageNamed:@"icon_pause"] forState:UIControlStateSelected]; + [_playBtn addTarget:self action:@selector(playAction) forControlEvents:UIControlEventTouchUpInside]; + [_playBtn setEnlargeEdge:10]; + } + return _playBtn; +} + +- (UILabel *)timeLabel { + if (!_timeLabel) { + _timeLabel = [[UILabel alloc] init]; + _timeLabel.font = [UIFont systemFontOfSize:13]; + _timeLabel.textColor = UIColor.whiteColor; + } + return _timeLabel; +} + +- (UIButton *)likeBtn { + if (!_likeBtn) { + _likeBtn = [[UIButton alloc] init]; + [_likeBtn setImage:[UIImage imageNamed:@"ss_icon_star_normal"] forState:UIControlStateNormal]; + [_likeBtn setImage:[UIImage imageNamed:@"ss_icon_star_selected"] forState:UIControlStateSelected]; + [_likeBtn addTarget:self action:@selector(likeAction) forControlEvents:UIControlEventTouchUpInside]; + [_likeBtn setEnlargeEdge:10]; + } + return _likeBtn; +} + +- (UIButton *)exitBtn { + if (!_exitBtn) { + _exitBtn = [[UIButton alloc] init]; + [_exitBtn setImage:[UIImage imageNamed:@"ss_icon_shrinkscreen"] forState:UIControlStateNormal]; + [_exitBtn addTarget:self action:@selector(exitAction) forControlEvents:UIControlEventTouchUpInside]; + [_exitBtn setEnlargeEdge:10]; + } + return _exitBtn; +} + +- (GKDoubleLikeView *)likeView { + if (!_likeView) { + _likeView = [[GKDoubleLikeView alloc] init]; + } + return _likeView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoMaskView.h b/HiBit/Project/Player/View/GKDYVideoMaskView.h new file mode 100755 index 0000000..ba18eac --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoMaskView.h @@ -0,0 +1,26 @@ +// +// GKDYVideoMaskView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, GKDYVideoMaskViewStyle) { + GKDYVideoMaskViewStyle_Top, // 顶部,(上->下)从深到浅 + GKDYVideoMaskViewStyle_Bottom // 底部,(上->下)从浅到深 +}; + +@interface GKDYVideoMaskView : UIView + +- (instancetype)initWithStyle:(GKDYVideoMaskViewStyle)style; + +- (void)clearColors; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoMaskView.m b/HiBit/Project/Player/View/GKDYVideoMaskView.m new file mode 100755 index 0000000..f218c39 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoMaskView.m @@ -0,0 +1,48 @@ +// +// GKDYVideoMaskView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoMaskView.h" + +@interface GKDYVideoMaskView() + +@property (nonatomic, assign) GKDYVideoMaskViewStyle style; + +@end + +@implementation GKDYVideoMaskView + ++ (Class)layerClass { + return CAGradientLayer.class; +} + +- (instancetype)initWithStyle:(GKDYVideoMaskViewStyle)style { + if (self = [super init]) { + self.style = style; + CAGradientLayer *maskGradientLayer = (id)self.layer; + switch (self.style) { + case GKDYVideoMaskViewStyle_Top: { + maskGradientLayer.colors = @[(__bridge id)[UIColor colorWithWhite:0 alpha:0.8].CGColor, + (__bridge id)[UIColor clearColor].CGColor]; + } + break; + case GKDYVideoMaskViewStyle_Bottom: { + maskGradientLayer.colors = @[(__bridge id)[UIColor clearColor].CGColor, + (__bridge id)[UIColor colorWithWhite:0 alpha:0.8].CGColor]; + } + break; + } + } + return self; +} + +- (void)clearColors { + CAGradientLayer *maskGradientLayer = (id)self.layer; + maskGradientLayer.colors = nil; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoPortraitCell.h b/HiBit/Project/Player/View/GKDYVideoPortraitCell.h new file mode 100755 index 0000000..aab5f6b --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPortraitCell.h @@ -0,0 +1,49 @@ +// +// GKDYVideoPortraitCell.h +// GKDYVideo +// +// Created by QuintGao on 2023/5/5. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoCell.h" +#import "GKDYPlayerManager.h" +#import "GKDYVideoPortraitView.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GKDYVideoPortraitCell; + +@protocol GKDYVideoPortraitCellDelegate + +@optional; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickFavorite:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickEpiscode:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickShare:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickDanmu:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell didClickFullscreen:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell zoomBegan:(GKDYVideoModel *)model; + +- (void)videoCell:(GKDYVideoPortraitCell *)cell zoomEnded:(GKDYVideoModel *)model isFullscreen:(BOOL)isFullscreen; + +@end + +@interface GKDYVideoPortraitCell : GKDYVideoCell + +@property (nonatomic, weak) id delegate; + +@property (nonatomic, strong) GKDYVideoPortraitView *portraitView; + +@property (nonatomic, weak) GKDYPlayerManager *manager; + +- (void)closeFullscreen; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoPortraitCell.m b/HiBit/Project/Player/View/GKDYVideoPortraitCell.m new file mode 100755 index 0000000..cd0efc1 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPortraitCell.m @@ -0,0 +1,174 @@ +// +// GKDYVideoPortraitCell.m +// GKDYVideo +// +// Created by QuintGao on 2023/5/5. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoPortraitCell.h" + +@interface GKDYVideoPortraitCell() + +@property (nonatomic, strong) UIScrollView *scrollView; + +@property (nonatomic, assign) BOOL isFullscreen; + +@property (nonatomic, assign) BOOL isCodeSet; + +@end + +@implementation GKDYVideoPortraitCell + +- (void)initUI { + [self addSubview:self.scrollView]; + [self.scrollView addSubview:self.coverImgView]; + +// [self addSubview:self.coverImgView]; + [self.coverImgView addSubview:self.portraitView]; + + [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + +// [self.coverImgView mas_makeConstraints:^(MASConstraintMaker *make) { +// make.edges.equalTo(self); +// }]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + self.coverImgView.frame = self.scrollView.bounds; + self.portraitView.frame = self.coverImgView.bounds; +} + +- (void)loadData:(GKDYVideoModel *)model { + [super loadData:model]; + + self.portraitView.model = model; + + if (self.manager) { + [self.manager requestPlayUrlWithModel:model completion:nil]; + } +} + +- (void)resetView { + [super resetView]; + + self.portraitView.slider.player = nil; + self.portraitView.slider.sliderView.value = 0; + self.portraitView.hidden = NO; + self.portraitView.frame = self.coverImgView.bounds; + [self.coverImgView addSubview:self.portraitView]; +} + +#pragma mark - UIScrollViewDelegate +- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { + return self.coverImgView; +} + +- (void)scrollViewDidZoom:(UIScrollView *)scrollView { + self.coverImgView.center = [self centerOfScrollViewContent:scrollView]; +} + +- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { + if (self.isCodeSet) return; + if ([self.delegate respondsToSelector:@selector(videoCell:zoomBegan:)]) { + [self.delegate videoCell:self zoomBegan:self.model]; + } +} + +- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { + if (self.isCodeSet) { + self.isCodeSet = NO; + return; + } + if ([self.delegate respondsToSelector:@selector(videoCell:zoomEnded:isFullscreen:)]) { + BOOL isFullscreen = NO; + if (scale > 1) { + isFullscreen = YES; + self.isFullscreen = isFullscreen; + }else { + self.isFullscreen = !self.isFullscreen; + isFullscreen = self.isFullscreen; + } + [self.delegate videoCell:self zoomEnded:self.model isFullscreen:isFullscreen]; + } + + if (scale != 1) { + self.isCodeSet = YES; + [scrollView setZoomScale:1.0f animated:YES]; + } +} + +- (CGPoint)centerOfScrollViewContent:(UIScrollView *)scrollView { + CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width) ? (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0; + CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height) ? (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0; + CGPoint actualCenter = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY); + return actualCenter; +} + +- (void)closeFullscreen { + self.isFullscreen = NO; + if ([self.delegate respondsToSelector:@selector(videoCell:zoomEnded:isFullscreen:)]) { + [self.delegate videoCell:self zoomEnded:self.model isFullscreen:self.isFullscreen]; + } +} + +#pragma mark - GKDYVideoPortraitViewDelegate + +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickFavorite:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(videoCell:didClickFavorite:)]) { + [self.delegate videoCell:self didClickFavorite:model]; + } +} + +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickEpiscode:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(videoCell:didClickEpiscode:)]) { + [self.delegate videoCell:self didClickEpiscode:model]; + } +} + +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickShare:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(videoCell:didClickShare:)]) { + [self.delegate videoCell:self didClickShare:model]; + } +} + +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickDanmu:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(videoCell:didClickDanmu:)]) { + [self.delegate videoCell:self didClickDanmu:model]; + } +} + +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickFullscreen:(GKDYVideoModel *)model { + if ([self.delegate respondsToSelector:@selector(videoCell:didClickFullscreen:)]) { + [self.delegate videoCell:self didClickFullscreen:model]; + } +} + +#pragma mark - Lazy +- (UIScrollView *)scrollView { + if (!_scrollView) { + _scrollView = [[UIScrollView alloc] init]; + _scrollView.delegate = self; + _scrollView.backgroundColor = UIColor.clearColor; + _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; + _scrollView.showsVerticalScrollIndicator = NO; + _scrollView.showsHorizontalScrollIndicator = NO; + _scrollView.minimumZoomScale = 1.0f; + _scrollView.maximumZoomScale = 10.0f; + } + return _scrollView; +} + +- (GKDYVideoPortraitView *)portraitView { + if (!_portraitView) { + _portraitView = [[GKDYVideoPortraitView alloc] initWithFrame:UIScreen.mainScreen.bounds]; + _portraitView.delegate = self; + } + return _portraitView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoPortraitView.h b/HiBit/Project/Player/View/GKDYVideoPortraitView.h new file mode 100755 index 0000000..d4e6aca --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPortraitView.h @@ -0,0 +1,64 @@ +// +// GKDYVideoPortraitView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import +#import "GKDYVideoModel.h" +#import "GKDYVideoSlider.h" +#import "GKLikeView.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GKDYVideoPortraitView; + +@protocol GKDYVideoPortraitViewDelegate + +/// 收藏点击事件代理 +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickFavorite:(GKDYVideoModel *)model; + +/// 剧集点击事件代理 +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickEpiscode:(GKDYVideoModel *)model; + +/// 分享点击事件代理 +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickShare:(GKDYVideoModel *)model; + +/// 弹幕点击事件代理 +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickDanmu:(GKDYVideoModel *)model; + +/// 全屏点击事件代理 +- (void)videoPortraitView:(GKDYVideoPortraitView *) view didClickFullscreen:(GKDYVideoModel *)model; + +@end + +@interface GKDYVideoPortraitView : UIView + +@property (nonatomic, weak) id delegate; + +/// 数据模型 +@property (nonatomic, strong) GKDYVideoModel * model; + +/// 视频介绍等 +@property (nonatomic, strong) UIView * bottomContainerView; + +/// 进度条 +@property (nonatomic, strong) GKDYVideoSlider * slider; + +/// 收藏按钮 带动画 +@property (nonatomic, strong) GKLikeView * favoriteButton; + +/// 继续播放按钮 +@property (nonatomic, strong) UIButton * resumeButton; + +- (void)handleSingleTapped; +- (void)willBeginDragging; +- (void)didEndDragging; + + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoPortraitView.m b/HiBit/Project/Player/View/GKDYVideoPortraitView.m new file mode 100755 index 0000000..e98cbd1 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPortraitView.m @@ -0,0 +1,393 @@ +// +// GKDYVideoPortraitView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoPortraitView.h" +#import "GKDYVideoItemButton.h" +#import "GKDoubleLikeView.h" +#import "UIButton+GKEnlarge.h" + +@interface GKDYVideoPortraitView() + +@property (nonatomic, strong) UIView * buttonContainerView; + +@property (nonatomic, strong) UILabel * titleLabel; + +@property (nonatomic, strong) UILabel * contentLabel; + +@property (nonatomic, strong) UILabel * episcodeLabel; + +@property (nonatomic, strong) UIButton * shareButton; + +@property (nonatomic, strong) RSButton * episcodeButton; + +@property (nonatomic, strong) UIButton * danmuButton; + +@property (nonatomic, strong) UIButton * fullscreenButton; + +@property (nonatomic, strong) GKDoubleLikeView * doubleLikeView; + +@property (nonatomic, strong) NSDate * lastDoubleTapTime; + +@end + +@implementation GKDYVideoPortraitView + +@synthesize player = _player; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self initUI]; + } + return self; +} +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)initUI { + + + [self addSubview:self.bottomContainerView]; + [self.bottomContainerView addSubview:self.contentLabel]; + [self.bottomContainerView addSubview:self.episcodeLabel]; + [self.bottomContainerView addSubview:self.titleLabel]; + + + [self.bottomContainerView addSubview:self.buttonContainerView]; + [self.buttonContainerView addSubview:self.shareButton]; + [self.buttonContainerView addSubview:self.episcodeButton]; + [self.buttonContainerView addSubview:self.favoriteButton]; + + + + [self addSubview:self.slider]; + [self addSubview:self.danmuButton]; + [self addSubview:self.fullscreenButton]; + [self addSubview:self.resumeButton]; + + [self.bottomContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.bottom.equalTo(self.mas_safeAreaLayoutGuideBottom); + }]; + + [self.slider mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(16.0); + make.right.equalTo(self).offset(-16.0); + make.bottom.equalTo(self.mas_safeAreaLayoutGuideBottom); + make.height.mas_equalTo(20.0); + }]; + + + [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.slider); + make.bottom.equalTo(self.slider.mas_top).offset(-10.0); + }]; + + [self.buttonContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.bottomContainerView); + make.right.equalTo(self.contentLabel); + make.bottom.equalTo(self.contentLabel.mas_top).offset(-30.0); + }]; + + [self.episcodeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.contentLabel); + make.bottom.equalTo(self.contentLabel.mas_top).offset(-12.0); + make.right.equalTo(self.buttonContainerView.mas_left).offset(-8.0); + }]; + + [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.episcodeLabel); + make.bottom.equalTo(self.episcodeLabel.mas_top).offset(-8.0); + }]; + + + [self.shareButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.bottom.left.right.equalTo(self.buttonContainerView); + }]; + + [self.episcodeButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.buttonContainerView); + make.bottom.equalTo(self.shareButton.mas_top).offset(-26.0); + }]; + + [self.favoriteButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(self.buttonContainerView); + make.bottom.equalTo(self.episcodeButton.mas_top).offset(-26.0); + }]; + + [self.danmuButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.bottomContainerView); + make.right.equalTo(self.mas_centerX).offset(-40); + make.width.height.mas_equalTo(30); + }]; + + [self.fullscreenButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.danmuButton); + make.left.equalTo(self.danmuButton.mas_right).offset(20); + make.width.mas_equalTo(80); + make.height.mas_equalTo(30); + }]; + + [self.resumeButton mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.equalTo(self); + }]; +} + +#pragma mark - ZFPlayerMediaControl +- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl { + CGFloat diff = [NSDate date].timeIntervalSince1970 - self.lastDoubleTapTime.timeIntervalSince1970; + if (diff < 0.6) { + [self handleDoubleTapped:gestureControl.singleTap]; + self.lastDoubleTapTime = [NSDate date]; + }else { + [self handleSingleTapped]; + } +} + +- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl { + [self handleDoubleTapped:gestureControl.doubleTap]; + self.lastDoubleTapTime = [NSDate date]; +} + +- (void)handleSingleTapped { + id manager = self.player.currentPlayerManager; + if (manager.isPlaying) { + + [manager pause]; + [self.slider showLargeSlider]; + self.resumeButton.hidden = NO; + self.resumeButton.transform = CGAffineTransformMakeScale(3, 3); + [UIView animateWithDuration:0.15 animations:^{ + self.resumeButton.alpha = 1; + self.resumeButton.transform = CGAffineTransformIdentity; + }]; + }else { + [manager play]; + [self.slider showSmallSlider]; + [UIView animateWithDuration:0.15 animations:^{ + self.resumeButton.alpha = 0; + } completion:^(BOOL finished) { + self.resumeButton.hidden = YES; + }]; + } +} + +- (void)handleDoubleTapped:(UITapGestureRecognizer *)gesture { + CGPoint point = [gesture locationInView:gesture.view]; + [self.doubleLikeView createAnimationWithPoint:point view:gesture.view completion:nil]; + [self.favoriteButton startAnimationWithIsLike:YES]; + self.model.is_collect = YES; + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickFavorite:)]) { + [self.delegate videoPortraitView:self didClickFavorite:self.model]; + } +} + +- (void)setModel:(GKDYVideoModel *)model { + _model = model; + + self.titleLabel.text = model.title; + + self.contentLabel.text = model.detailText; + + self.episcodeLabel.text = [NSString stringWithFormat:[@"player_text_episcode" language],model.videoInfo.episode,model.episode]; + + [self.favoriteButton setupLikeCount:[NSString stringWithFormat:@"%ld", model.collect_total]]; + [self.favoriteButton setupLikeState:model.is_collect]; + +} + +#pragma mark - Action + + +- (void)favoriteAction { + self.model.is_collect = !self.model.is_collect; + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickFavorite:)]) { + [self.delegate videoPortraitView:self didClickFavorite:self.model]; + } +} + +- (void)episcodeAction { + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickEpiscode:)]) { + [self.delegate videoPortraitView:self didClickEpiscode:self.model]; + } +} + +- (void)shareAction { + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickShare:)]) { + [self.delegate videoPortraitView:self didClickShare:self.model]; + } +} + +- (void)danmuAction { + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickDanmu:)]) { + [self.delegate videoPortraitView:self didClickDanmu:self.model]; + } +} + +- (void)fullscreenAction { + if ([self.delegate respondsToSelector:@selector(videoPortraitView:didClickFullscreen:)]) { + [self.delegate videoPortraitView:self didClickFullscreen:self.model]; + } +} + +- (void)sliderDragging:(BOOL)isDragging { + self.bottomContainerView.alpha = !isDragging; +} + +- (void)willBeginDragging { + self.bottomContainerView.alpha = 0.4; + self.danmuButton.alpha = 0.4; + self.fullscreenButton.alpha = 0.4; +} + +- (void)didEndDragging { + self.bottomContainerView.alpha = 1; + self.danmuButton.alpha = 1; + self.fullscreenButton.alpha = 1; +} + +#pragma mark - Lazy +- (UIView *)bottomContainerView { + if (!_bottomContainerView) { + _bottomContainerView = [[UIView alloc] init]; + } + return _bottomContainerView; +} +- (UIView *)buttonContainerView{ + if (!_buttonContainerView) { + _buttonContainerView = [[UIView alloc] init]; + } + return _buttonContainerView ; +} + +- (UILabel *)titleLabel { + if (!_titleLabel) { + _titleLabel = [[UILabel alloc] init]; + _titleLabel.font = [UIFont boldSystemFontOfSize:16]; + _titleLabel.textColor = UIColor.whiteColor; + _titleLabel.userInteractionEnabled = YES; + } + return _titleLabel; +} +- (UILabel *)episcodeLabel { + if (!_episcodeLabel) { + _episcodeLabel = [[UILabel alloc] init]; + _episcodeLabel.font = [UIFont systemFontOfSize:12.0 weight:UIFontWeightMedium]; + _episcodeLabel.textColor = UIColor.whiteColor; + _episcodeLabel.text = @"Episode 1 Complete set : 999"; + } + return _episcodeLabel; +} + +- (UILabel *)contentLabel { + if (!_contentLabel) { + _contentLabel = [[UILabel alloc] init]; + _contentLabel.font = [UIFont systemFontOfSize:12.0 weight:UIFontWeightLight]; + _contentLabel.textColor = UIColor.whiteColor; + _contentLabel.numberOfLines = 4; + } + return _contentLabel; +} + +- (GKDYVideoSlider *)slider { + if (!_slider) { + _slider = [[GKDYVideoSlider alloc] init]; + + @weakify(self); + _slider.slideBlock = ^(BOOL isDragging) { + @strongify(self); + [self sliderDragging:isDragging]; + }; + } + return _slider; +} + +- (GKLikeView *)favoriteButton { + if (!_favoriteButton) { + _favoriteButton = [[GKLikeView alloc] init]; + @weakify(self); + _favoriteButton.likeBlock = ^{ + @strongify(self); + [self favoriteAction]; + }; + } + return _favoriteButton; +} + +- (RSButton *)episcodeButton { + if (!_episcodeButton) { + _episcodeButton = [[RSButton alloc] initWithType:RSButtonTypeAbove]; + _episcodeButton.margin = 4.0; + [_episcodeButton setTitleFont:[UIFont systemFontOfSize:12.0f weight:UIFontWeightRegular]]; + [_episcodeButton setImage:[UIImage imageNamed:@"player_episode"] forState:UIControlStateNormal]; + [_episcodeButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + [_episcodeButton setTitle:[@"player_text_series" language] forState:UIControlStateNormal]; + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(episcodeAction)]; + [_episcodeButton addGestureRecognizer:tapGesture]; + } + return _episcodeButton; +} + +- (UIButton *)shareButton { + if (!_shareButton) { + _shareButton = [[UIButton alloc] init]; + [_shareButton setImage:[UIImage imageNamed:@"player_shared"] forState:UIControlStateNormal]; + [_shareButton addTarget:self action:@selector(shareAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _shareButton; +} + +- (UIButton *)danmuButton { + if (!_danmuButton) { + _danmuButton = [[UIButton alloc] init]; + _danmuButton.hidden = YES; + [_danmuButton setTitle:@"弹" forState:UIControlStateNormal]; + [_danmuButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + _danmuButton.titleLabel.font = [UIFont systemFontOfSize:15]; + _danmuButton.layer.cornerRadius = 15; + _danmuButton.layer.masksToBounds = YES; + _danmuButton.layer.borderColor = UIColor.whiteColor.CGColor; + _danmuButton.layer.borderWidth = 0.5; + [_danmuButton addTarget:self action:@selector(danmuAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _danmuButton; +} + +- (UIButton *)fullscreenButton { + if (!_fullscreenButton) { + _fullscreenButton = [[UIButton alloc] init]; + _fullscreenButton.hidden = YES; + [_fullscreenButton setTitle:@"全屏观看" forState:UIControlStateNormal]; + [_fullscreenButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + _fullscreenButton.titleLabel.font = [UIFont systemFontOfSize:15]; + _fullscreenButton.layer.cornerRadius = 15; + _fullscreenButton.layer.masksToBounds = YES; + _fullscreenButton.layer.borderColor = UIColor.whiteColor.CGColor; + _fullscreenButton.layer.borderWidth = 0.5; + [_fullscreenButton addTarget:self action:@selector(fullscreenAction) forControlEvents:UIControlEventTouchUpInside]; + } + return _fullscreenButton; +} + +- (UIButton *)resumeButton { + if (!_resumeButton) { + _resumeButton = [[UIButton alloc] init]; + [_resumeButton setImage:[UIImage imageNamed:@"player_play"] forState:UIControlStateNormal]; + _resumeButton.hidden = YES; + } + return _resumeButton; +} + +- (GKDoubleLikeView *)doubleLikeView { + if (!_doubleLikeView) { + _doubleLikeView = [[GKDoubleLikeView alloc] init]; + } + return _doubleLikeView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoPreviewView.h b/HiBit/Project/Player/View/GKDYVideoPreviewView.h new file mode 100755 index 0000000..4db18f6 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPreviewView.h @@ -0,0 +1,22 @@ +// +// GKDYVideoPreviewView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoPreviewView : UIView + +@property (nonatomic, weak) ZFPlayerController *player; + +- (void)setPreviewValue:(float)value; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoPreviewView.m b/HiBit/Project/Player/View/GKDYVideoPreviewView.m new file mode 100755 index 0000000..762cda6 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoPreviewView.m @@ -0,0 +1,108 @@ +// +// GKDYVideoPreviewView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoPreviewView.h" + +#import + +@interface ZFAVPlayerManager (GKCategory) + +- (void)thumbnailImageAtTime:(NSTimeInterval)time completion:(void(^)(UIImage *_Nullable image))completion; + +@end + +@implementation ZFAVPlayerManager (GKCategory) + +- (void)thumbnailImageAtTime:(NSTimeInterval)time completion:(void (^)(UIImage * _Nullable))completion { + CMTime expectedTime = CMTimeMakeWithSeconds(time, NSEC_PER_SEC); + + AVAssetImageGenerator *imageGenerator = [self valueForKey:@"imageGenerator"]; + + [imageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:expectedTime]] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) { + if (image) { + UIImage *finalImage = [UIImage imageWithCGImage:image]; + !completion ?: completion(finalImage); + }else { + !completion ?: completion(nil); + } + }]; +} + +@end + +@interface GKDYVideoPreviewView() + +@property (nonatomic, strong) UIImageView *imageView; + +@property (nonatomic, strong) UILabel *timeLabel; + +@end + +@implementation GKDYVideoPreviewView + +- (instancetype)init { + if (self = [super init]) { + [self initUI]; + } + return self; +} + +- (void)initUI { + [self addSubview:self.imageView]; + [self addSubview:self.timeLabel]; + + [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(self); + make.height.mas_equalTo(120*9/16); + }]; + + [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.imageView.mas_bottom).offset(20); + make.centerX.equalTo(self); + }]; +} + +- (void)setPreviewValue:(float)value { + NSString *currentTime = [NSString convertTimeSecond:self.player.totalTime * value]; + NSString *totalTime = [NSString convertTimeSecond:self.player.totalTime]; + self.timeLabel.text = [NSString stringWithFormat:@"%@ / %@", currentTime, totalTime]; + + ZFAVPlayerManager *manager = (ZFAVPlayerManager *)self.player.currentPlayerManager; + + @weakify(self); + [manager thumbnailImageAtTime:self.player.totalTime * value completion:^(UIImage * _Nullable image) { + if (image) { + @strongify(self); + dispatch_async(dispatch_get_main_queue(), ^{ + self.imageView.image = image; + }); + } + }]; +} + +#pragma mark - Lazy +- (UIImageView *)imageView { + if (!_imageView) { + _imageView = [[UIImageView alloc] init]; + _imageView.contentMode = UIViewContentModeScaleAspectFill; + _imageView.layer.cornerRadius = 5; + _imageView.layer.masksToBounds = YES; + } + return _imageView; +} + +- (UILabel *)timeLabel { + if (!_timeLabel) { + _timeLabel = [[UILabel alloc] init]; + _timeLabel.font = [UIFont systemFontOfSize:15]; + _timeLabel.textColor = UIColor.whiteColor; + } + return _timeLabel; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoScrollView.h b/HiBit/Project/Player/View/GKDYVideoScrollView.h new file mode 100755 index 0000000..2f1c4d4 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoScrollView.h @@ -0,0 +1,31 @@ +// +// GKDYVideoScrollView.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class GKDYVideoScrollView; + +@protocol GKDYVideoScrollViewDelegate + +@optional + +- (void)scrollView:(GKDYVideoScrollView *)scrollView didPanWithDistance:(CGFloat)distance isEnd:(BOOL)isEnd; + +@end + +@interface GKDYVideoScrollView : GKVideoScrollView + +@property (nonatomic, weak) id delegate; + +- (void)addPanGesture; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoScrollView.m b/HiBit/Project/Player/View/GKDYVideoScrollView.m new file mode 100755 index 0000000..9b7ee06 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoScrollView.m @@ -0,0 +1,126 @@ +// +// GKDYVideoScrollView.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/17. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoScrollView.h" +#import "GKDYPanGestureRecognizer.h" + +@interface GKDYVideoScrollView() + +@property (nonatomic, strong) GKDYPanGestureRecognizer *panGesture; + +// 开始移动时的位置 +@property (nonatomic, assign) CGFloat startLocationY; + +@property (nonatomic, weak) id userDelegate; + +@end + +@implementation GKDYVideoScrollView + +@dynamic delegate; + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + if (CGRectEqualToRect(frame, CGRectZero)) { + self.frame = CGRectMake(0, 0, HBScreenSize.width, HBScreenSize.height); + } + self.contentSize = CGSizeMake(0, self.frame.size.height); + } + return self; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + if (self.contentSize.height == 0) { + self.contentSize = CGSizeMake(self.bounds.size.width, self.bounds.size.height); + } +} + +- (void)addPanGesture { + [self addGestureRecognizer:self.panGesture]; +} + +- (void)setDelegate:(id)delegate { + [super setDelegate:delegate]; + + if (delegate) { + self.userDelegate = delegate; + }else { + self.userDelegate = nil; + } +} + +#pragma mark - Gesture +- (void)handlePanGesture:(GKDYPanGestureRecognizer *)panGesture { + if (self.currentIndex == 0) { + CGPoint location = [panGesture locationInView:panGesture.view]; + + switch (panGesture.state) { + case UIGestureRecognizerStateBegan: { + self.startLocationY = location.y; + } + break; + case UIGestureRecognizerStateChanged: { + if (panGesture.direction == GKDYPanGestureRecognizerDirectionVertical) { + // 这里取整是解决上滑时可能出现的distance > 0的情况 + CGFloat distance = ceil(location.y) - ceil(self.startLocationY); + if (distance > 0) { // 只要distance>0且没松手 就认为是下滑 + self.panGestureRecognizer.enabled = NO; + } + + if (self.panGestureRecognizer.enabled == NO) { + [self didPanWithDistance:distance isEnd:NO]; + } + } + } + break; + case UIGestureRecognizerStateFailed: + case UIGestureRecognizerStateCancelled: + case UIGestureRecognizerStateEnded: { + if (self.panGestureRecognizer.enabled == NO) { + CGFloat distance = location.y - self.startLocationY; + [self didPanWithDistance:distance isEnd:YES]; + self.panGestureRecognizer.enabled = YES; + } + } + break; + + default: + break; + } + + [panGesture setTranslation:CGPointZero inView:panGesture.view]; + } +} + +// 允许多个手势响应 +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { + if (otherGestureRecognizer.view == self) { + return YES; + } + return NO; +} + +- (void)didPanWithDistance:(CGFloat)distance isEnd:(BOOL)isEnd { + if ([self.userDelegate respondsToSelector:@selector(scrollView:didPanWithDistance:isEnd:)]) { + [self.userDelegate scrollView:self didPanWithDistance:distance isEnd:isEnd]; + } +} + +#pragma mark - Lazy +- (GKDYPanGestureRecognizer *)panGesture { + if (!_panGesture) { + _panGesture = [[GKDYPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; + _panGesture.delegate = self; + _panGesture.direction = GKDYPanGestureRecognizerDirectionVertical; + } + return _panGesture; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoSlider.h b/HiBit/Project/Player/View/GKDYVideoSlider.h new file mode 100755 index 0000000..fcb3fbc --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoSlider.h @@ -0,0 +1,33 @@ +// +// GKDYVideoSlider.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoSlider : UIView + +@property (nonatomic, strong) GKSliderView *sliderView; + +@property (nonatomic, copy) void(^slideBlock)(BOOL isDragging); + +@property (nonatomic, weak) ZFPlayerController *player; + +- (void)updateCurrentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime; + +- (void)showSmallSlider; +- (void)showLargeSlider; + +- (void)showLoading; +- (void)hideLoading; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoSlider.m b/HiBit/Project/Player/View/GKDYVideoSlider.m new file mode 100755 index 0000000..bb8ace7 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoSlider.m @@ -0,0 +1,212 @@ +// +// GKDYVideoSlider.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoSlider.h" +#import + +@interface GKDYVideoSlider() + +@property (nonatomic, assign) CGFloat startLocationX; + +@property (nonatomic, assign) float startValue; + +@property (nonatomic, assign) BOOL isDragging; + +@property (nonatomic, assign) BOOL isSeeking; + +@property (nonatomic, assign) NSTimeInterval currentTime; + +@property (nonatomic, assign) NSTimeInterval totalTime; + +@end + +@implementation GKDYVideoSlider + +- (instancetype)init { + if (self = [super init]) { + [self initUI]; + } + return self; +} + +- (void)initUI { + [self addSubview:self.sliderView]; + [self.sliderView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(self); + make.height.mas_offset(4); + }]; + + UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; + [self addGestureRecognizer:panGesture]; + + [self showSmallSlider]; +} + +- (void)updateCurrentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime { + self.currentTime = currentTime; + self.totalTime = totalTime; + if (self.isDragging) return; + if (self.isSeeking) return; + CGFloat value = totalTime == 0 ? 0 : currentTime / totalTime; + self.sliderView.value = value; +} + +- (void)showLoading { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.sliderView showLineLoading]; + }); +} + +- (void)hideLoading { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.sliderView hideLineLoading]; + }); + +} + +- (void)handlePan:(UIPanGestureRecognizer *)gesture { + CGPoint location = [gesture locationInView:gesture.view]; + switch (gesture.state) { + case UIGestureRecognizerStateBegan: { + self.startLocationX = location.x; + self.startValue = self.sliderView.value; + if (self.sliderView.preview) { + self.sliderView.preview.hidden = NO; + } + self.isDragging = YES; + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showSmallSlider) object:nil]; + [self showLargeSlider]; + !self.slideBlock ?: self.slideBlock(self.isDragging); + } + break; + case UIGestureRecognizerStateChanged: { + CGFloat diff = location.x - self.startLocationX; + CGFloat progress = self.startValue + diff / gesture.view.frame.size.width; + if (progress < 0) progress = 0; + if (progress > 1) progress = 1; + self.sliderView.value = progress; + if (self.sliderView.preview && [self.sliderView.previewDelegate respondsToSelector:@selector(sliderView:preview:valueChanged:)]) { + [self.sliderView.previewDelegate sliderView:self.sliderView preview:self.sliderView.preview valueChanged:self.sliderView.value]; + } + [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showSmallSlider) object:nil]; + [self showDragSlider]; + } + break; + case UIGestureRecognizerStateFailed: + case UIGestureRecognizerStateCancelled: + case UIGestureRecognizerStateEnded: { + self.isDragging = NO; + if (self.sliderView.preview) { + self.sliderView.preview.hidden = YES; + } + [self showLargeSlider]; + [self performSelector:@selector(showSmallSlider) withObject:nil afterDelay:3.0f]; + !self.slideBlock ?: self.slideBlock(self.isDragging); + [self seekTo:self.sliderView.value]; + } + break; + + default: + break; + } +} + +- (void)seekTo:(float)value { + NSTimeInterval time = self.totalTime * value; + + NSLog(@"seekTo: %f",time); + + self.isSeeking = YES; + @weakify(self); + [self.player seekToTime:time completionHandler:^(BOOL finished) { + @strongify(self); + weak_self.isSeeking = NO; + }]; +} + +#pragma mark - Slider +- (void)showSmallSlider { + CGRect frame = self.sliderView.sliderBtn.frame; + frame.size = CGSizeMake(4, 4); + self.sliderView.sliderBtn.frame = frame; + self.sliderView.sliderBtn.layer.cornerRadius = 2; + self.sliderView.sliderHeight = 1; + [self.sliderView mas_updateConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(4); + }]; + self.sliderView.bgCornerRadius = 0; +} + +- (void)showLargeSlider { + CGRect frame = self.sliderView.sliderBtn.frame; + frame.size = CGSizeMake(8, 8); + self.sliderView.sliderBtn.frame = frame; + self.sliderView.sliderBtn.layer.cornerRadius = 4; + self.sliderView.sliderHeight = 2; + [self.sliderView mas_updateConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(8); + }]; + self.sliderView.bgCornerRadius = 1; +} + +- (void)showDragSlider { + CGRect frame = self.sliderView.sliderBtn.frame; + frame.size = CGSizeMake(8, 16); + self.sliderView.sliderBtn.frame = frame; + self.sliderView.sliderBtn.layer.cornerRadius = 4; + self.sliderView.sliderHeight = 10; + [self.sliderView mas_updateConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(16); + }]; + self.sliderView.bgCornerRadius = 5; +} + +#pragma mark - GKSliderViewPreviewDelegate +- (UIView *)sliderViewSetupPreview:(GKSliderView *)sliderView { + GKSliderButton *preview = [[GKSliderButton alloc] init]; + NSString *currentTime = [NSString convertTimeSecond:self.currentTime]; + NSString *totalTime = [NSString convertTimeSecond:self.totalTime]; + [preview setTitle:[NSString stringWithFormat:@"%@ / %@", currentTime, totalTime] forState:UIControlStateNormal]; + [preview setTitleColor:UIColor.whiteColor forState:UIControlStateNormal]; + preview.titleLabel.font = [UIFont systemFontOfSize:15]; + [preview sizeToFit]; + CGRect frame = preview.frame; + frame.size.width += 10; + preview.frame = frame; + return preview; +} + +- (CGFloat)sliderViewPreviewMargin:(GKSliderView *)sliderView { + return 60; +} + +- (void)sliderView:(GKSliderView *)sliderView preview:(UIView *)preview valueChanged:(float)value { + GKSliderButton *button = (GKSliderButton *)preview; + NSString *currentTime = [NSString convertTimeSecond:self.totalTime * value]; + NSString *totalTime = [NSString convertTimeSecond:self.totalTime]; + [button setTitle:[NSString stringWithFormat:@"%@ / %@", currentTime, totalTime] forState:UIControlStateNormal]; +} + +#pragma mark - Lazy +- (GKSliderView *)sliderView { + if (!_sliderView) { + _sliderView = [[GKSliderView alloc] init]; + _sliderView.isSliderAllowTapped = NO; + _sliderView.sliderHeight = 2; + _sliderView.maximumTrackTintColor = [UIColor lightGrayColor]; + _sliderView.minimumTrackTintColor = HBColor.color_FF0049; + _sliderView.sliderBtn.layer.masksToBounds = YES; + _sliderView.sliderBtn.backgroundColor = HBColor.color_FF0049; + _sliderView.isPreviewChangePosition = NO; + _sliderView.userInteractionEnabled = NO; + _sliderView.previewDelegate = self; + } + return _sliderView; +} + +@end diff --git a/HiBit/Project/Player/View/GKDYVideoStatusBar.h b/HiBit/Project/Player/View/GKDYVideoStatusBar.h new file mode 100755 index 0000000..ffaa6fc --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoStatusBar.h @@ -0,0 +1,27 @@ +// +// GKDYVideoStatusBar.h +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GKDYVideoStatusBar : UIView + +// 刷新时间,默认3s +@property (nonatomic, assign) NSTimeInterval refreshTime; + +// 网络状态 +@property (nonatomic, copy) NSString *network; + +- (void)startTimer; + +- (void)destoryTimer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/HiBit/Project/Player/View/GKDYVideoStatusBar.m b/HiBit/Project/Player/View/GKDYVideoStatusBar.m new file mode 100755 index 0000000..4edf827 --- /dev/null +++ b/HiBit/Project/Player/View/GKDYVideoStatusBar.m @@ -0,0 +1,345 @@ +// +// GKDYVideoStatusBar.m +// GKDYVideo +// +// Created by QuintGao on 2023/3/22. +// Copyright © 2023 QuintGao. All rights reserved. +// + +#import "GKDYVideoStatusBar.h" + +#define UIColorFromHex(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] + +@interface GKDYVideoTimerTarget : NSProxy + +@property (nonatomic, weak) id target; + +@end + +@implementation GKDYVideoTimerTarget + ++ (instancetype)proxyWithTarget:(id)target { + GKDYVideoTimerTarget *proxy = [GKDYVideoTimerTarget alloc]; + proxy.target = target; + return proxy; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { + NSMethodSignature *signature = nil; + if ([self.target respondsToSelector:sel]) { + signature = [self.target methodSignatureForSelector:sel]; + }else { + /// 动态造一个 void object selector arg 函数签名 + /// 目的是返回有效signature,不要以为找不到而crash + signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"]; + } + return signature; +} + +- (void)forwardInvocation:(NSInvocation *)invocation { + if ([self.target respondsToSelector:invocation.selector]) { + [invocation invokeWithTarget:self.target]; + } +} + +@end + +@interface GKDYVideoStatusBar() + +/// 时间 +@property (nonatomic, strong) UILabel *dateLabel; +/// 电池 +@property (nonatomic, strong) UIView *batteryView; +/// 充电标识 +@property (nonatomic, strong) UIImageView *batteryImageView; +/// 充电层 +@property (nonatomic, strong) CAShapeLayer *batteryLayer; +/// 电池边框 +@property (nonatomic, strong) CAShapeLayer *batteryBoundLayer; +/// 电池正极 +@property (nonatomic, strong) CAShapeLayer *batteryPositiveLayer; +/// 电量百分比 +@property (nonatomic, strong) UILabel *batteryLabel; + +/// 网络状态 +@property (nonatomic, strong) UILabel *networkLabel; +@property (nonatomic, strong) NSTimer *timer; +@property (nonatomic, strong) NSDateFormatter *dateFormatter; + +@end + +@implementation GKDYVideoStatusBar + +- (instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + [self setup]; + } + return self; +} + +- (void)dealloc { + [self destoryTimer]; +} + +- (void)setup { + self.refreshTime = 3.0f; + /// 时间 + [self addSubview:self.dateLabel]; + /// 电池 + [self addSubview:self.batteryView]; + [self.batteryView.layer addSublayer:self.batteryBoundLayer]; + [self.batteryView.layer addSublayer:self.batteryPositiveLayer]; + [self.batteryView.layer addSublayer:self.batteryLayer]; + [self.batteryView addSubview:self.batteryImageView]; + [self addSubview:self.batteryLabel]; + [self addSubview:self.networkLabel]; + + [UIDevice currentDevice].batteryMonitoringEnabled = YES; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelDidChangeNotification:) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryStateDidChangeNotification:) name:UIDeviceBatteryStateDidChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(localeDidChangeNotification:) name:NSCurrentLocaleDidChangeNotification object:nil]; +} + +- (void)layoutSubviews { + [self.dateLabel sizeToFit]; + [self.networkLabel sizeToFit]; + [self.batteryLabel sizeToFit]; + + CGRect frame = self.dateLabel.frame; + CGPoint center = self.dateLabel.center; + + // dateLabel + frame.size.height = 16; + self.dateLabel.frame = frame; + center = self.center; + self.dateLabel.center = center; + + // batteryView + frame = self.batteryView.frame; + frame.origin.x = self.bounds.size.width - 35; + frame.size.width = 22; + frame.size.height = 10; + self.batteryView.frame = frame; + center = self.batteryView.center; + center.y = self.center.y; + self.batteryView.center = center; + + // batteryLabel + frame = self.batteryLabel.frame; + frame.origin.x = CGRectGetMinX(self.batteryView.frame) - 5 - frame.size.width; + frame.size.height = 16; + self.batteryLabel.frame = frame; + center = self.batteryLabel.center; + center.y = self.batteryView.center.y; + self.batteryLabel.center = center; + + // networkLabel + frame = self.networkLabel.frame; + frame.origin.x = 10; + frame.size.width = frame.size.width + 13; + frame.size.height = 14; + self.networkLabel.frame = frame; + center = self.networkLabel.center; + center.y = self.batteryView.center.y; + self.networkLabel.center = center; +} + +- (void)batteryLevelDidChangeNotification:(NSNotification *)noti { + [self updateUI]; +} + +- (void)batteryStateDidChangeNotification:(NSNotification *)noti { + [self updateUI]; +} + +- (void)localeDidChangeNotification:(NSNotification *)noti { + [self.dateFormatter setLocale:NSLocale.currentLocale]; + [self updateUI]; +} + +- (void)setNetwork:(NSString *)network { + _network = network; + + self.networkLabel.text = network; + [self setNeedsLayout]; + [self layoutIfNeeded]; +} + +- (void)startTimer { + if (self.timer) return; + self.timer = [NSTimer timerWithTimeInterval:self.refreshTime target:[GKDYVideoTimerTarget proxyWithTarget:self] selector:@selector(updateUI) userInfo:nil repeats:YES]; + [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; + [self.timer fire]; +} + +- (void)destoryTimer { + if (self.timer) { + [self.timer invalidate]; + self.timer = nil; + } +} + +#pragma mark - update UI +- (void)updateUI { + [self updateDate]; + [self updateBattery]; + [self setNeedsLayout]; + [self layoutIfNeeded]; +} + +- (void)updateDate { + NSMutableString *dateString = [[NSMutableString alloc] initWithString:[self.dateFormatter stringFromDate:[NSDate date]]]; + NSRange amRange = [dateString rangeOfString:[self.dateFormatter AMSymbol]]; + NSRange pmRange = [dateString rangeOfString:[self.dateFormatter PMSymbol]]; + if (amRange.location != NSNotFound) { + [dateString deleteCharactersInRange:amRange]; + }else if (pmRange.location != NSNotFound) { + [dateString deleteCharactersInRange:pmRange]; + } + self.dateLabel.text = dateString; +} + +- (void)updateBattery { + [UIDevice currentDevice].batteryMonitoringEnabled = YES; + CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel; + /// -1是模拟器 + if (batteryLevel < 0) { batteryLevel = 1.0; } + CGRect rect = CGRectMake(1.5, 1.5, (20-3)*batteryLevel, 10-3); + UIBezierPath *batteryPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:2]; + + UIColor *batteryColor; + UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState; + if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电 + self.batteryImageView.hidden = NO; + } else { + self.batteryImageView.hidden = YES; + } + if (@available(iOS 9.0, *)) { + if ([NSProcessInfo processInfo].lowPowerModeEnabled) { /// 低电量模式 + batteryColor = UIColorFromHex(0xF9CF0E); + } else { + if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电 + batteryColor = UIColorFromHex(0x37CB46); + } else if (batteryLevel <= 0.2) { /// 电量低 + batteryColor = UIColorFromHex(0xF02C2D); + } else { /// 电量正常 白色 + batteryColor = [UIColor whiteColor]; + } + } + } else { + if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电 + batteryColor = UIColorFromHex(0x37CB46); + } else if (batteryLevel <= 0.2) { /// 电量低 + batteryColor = UIColorFromHex(0xF02C2D); + } else { /// 电量正常 白色 + batteryColor = [UIColor whiteColor]; + } + } + + self.batteryLayer.strokeColor = [UIColor clearColor].CGColor; + self.batteryLayer.path = batteryPath.CGPath; + self.batteryLayer.fillColor = batteryColor.CGColor; + self.batteryLabel.text = [NSString stringWithFormat:@"%.0f%%", batteryLevel*100]; +} + +#pragma mark - getter +- (UILabel *)dateLabel { + if (!_dateLabel) { + _dateLabel = [[UILabel alloc] init]; + _dateLabel.bounds = CGRectMake(0, 0, 100, 16); + _dateLabel.textColor = UIColor.whiteColor; + _dateLabel.font = [UIFont systemFontOfSize:12]; + } + return _dateLabel; +} + +- (NSDateFormatter *)dateFormatter { + if (!_dateFormatter) { + _dateFormatter = [[NSDateFormatter alloc] init]; + [_dateFormatter setLocale:NSLocale.currentLocale]; + _dateFormatter.dateStyle = NSDateFormatterNoStyle; + _dateFormatter.timeStyle = NSDateFormatterShortStyle; + } + return _dateFormatter; +} + +- (UIView *)batteryView { + if (!_batteryView) { + _batteryView = [[UIView alloc] init]; + } + return _batteryView; +} + +- (UIImageView *)batteryImageView { + if (!_batteryImageView) { + _batteryImageView = [[UIImageView alloc] init]; + _batteryImageView.bounds = CGRectMake(0, 0, 8, 12); + _batteryImageView.center = CGPointMake(10, 5); + _batteryImageView.image = [UIImage imageNamed:@"icon_battery_lightning"]; + } + return _batteryImageView; +} + +- (CAShapeLayer *)batteryLayer { + if (!_batteryLayer) { + [UIDevice currentDevice].batteryMonitoringEnabled = YES; + CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel; + UIBezierPath *batteryPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(1.5, 1.5, (20-3)*batteryLevel, 10-3) cornerRadius:2]; + _batteryLayer = [CAShapeLayer layer]; + _batteryLayer.lineWidth = 1; + _batteryLayer.strokeColor = [UIColor clearColor].CGColor; + _batteryLayer.path = batteryPath.CGPath; + _batteryLayer.fillColor = [UIColor whiteColor].CGColor; + } + return _batteryLayer; +} + +- (CAShapeLayer *)batteryBoundLayer { + if (!_batteryBoundLayer) { + UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 20, 10) cornerRadius:2.5]; + _batteryBoundLayer = [CAShapeLayer layer]; + _batteryBoundLayer.lineWidth = 1; + _batteryBoundLayer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor; + _batteryBoundLayer.path = bezierPath.CGPath; + _batteryBoundLayer.fillColor = nil; + } + return _batteryBoundLayer; +} + +- (CAShapeLayer *)batteryPositiveLayer { + if (!_batteryPositiveLayer) { + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(22, 3, 1, 3) byRoundingCorners:(UIRectCornerTopRight|UIRectCornerBottomRight) cornerRadii:CGSizeMake(2, 2)]; + _batteryPositiveLayer = [CAShapeLayer layer]; + _batteryPositiveLayer.lineWidth = 0.5; + _batteryPositiveLayer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor; + _batteryPositiveLayer.path = path.CGPath; + _batteryPositiveLayer.fillColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor; + } + return _batteryPositiveLayer; +} + +- (UILabel *)batteryLabel { + if (!_batteryLabel) { + _batteryLabel = [[UILabel alloc] init]; + _batteryLabel.textColor = [UIColor whiteColor]; + _batteryLabel.font = [UIFont systemFontOfSize:11]; + _batteryLabel.textAlignment = NSTextAlignmentRight; + } + return _batteryLabel; +} + +- (UILabel *)networkLabel { + if (!_networkLabel) { + _networkLabel = [[UILabel alloc] init]; + _networkLabel.layer.cornerRadius = 7; + _networkLabel.layer.borderWidth = 1; + _networkLabel.layer.borderColor = [UIColor lightGrayColor].CGColor; + _networkLabel.textColor = [UIColor whiteColor]; + _networkLabel.font = [UIFont systemFontOfSize:9]; + _networkLabel.textAlignment = NSTextAlignmentCenter; + _networkLabel.text = @"WIFI"; + } + return _networkLabel; +} + +@end diff --git a/HiBit/Project/Publics/CommonKeys/HBCommonKeys.h b/HiBit/Project/Publics/CommonKeys/HBCommonKeys.h index 7d7cd23..d3d959c 100644 --- a/HiBit/Project/Publics/CommonKeys/HBCommonKeys.h +++ b/HiBit/Project/Publics/CommonKeys/HBCommonKeys.h @@ -8,32 +8,32 @@ #import /// 网络请求地址 -extern NSString *const HBBaseUrlString; +extern NSString * _Nonnull const HBBaseUrlString; /// 保存设备唯一值key -extern NSString *const HBIdentifierForVendorKey; +extern NSString * _Nonnull const HBIdentifierForVendorKey; /// 用来保存用户是不是主动登录成功了,可以用来判断是否登录 -extern NSString *const HBCustomerLoginSuccessKey; +extern NSString * _Nonnull const HBCustomerLoginSuccessKey; /// 保存网络请求的Token -extern NSString *const HBNetWorkingTokenKey; +extern NSString * _Nonnull const HBNetWorkingTokenKey; /// 保存网络请求的Token -extern NSString *const HBCustomerIdKey; +extern NSString * _Nonnull const HBCustomerIdKey; /// 搜索历史key -extern NSString *const HBSearchHistoryKey; +extern NSString * _Nonnull const HBSearchHistoryKey; /// 播放界面离开 通知播放器暂停 -extern NSString *const HBPlayerPuaseKey; +extern NSString * _Nonnull const HBPlayerPuaseKey; /// 推送详情使用 -extern NSString *const HBNotificationOpenActionIdentifier; -extern NSString *const HBNotificationOpenCategoryIdentifier; +extern NSString * _Nonnull const HBNotificationOpenActionIdentifier; +extern NSString * _Nonnull const HBNotificationOpenCategoryIdentifier; /// 第一次启动存储 -extern NSString *const HBNotFirstStartKey; +extern NSString * _Nonnull const HBNotFirstStartKey; /// 通知 FOUNDATION_EXPORT NSNotificationName _Nonnull const HBUpdateUserInfoNotification; diff --git a/HiBit/Project/Publics/CommonKeys/HBCommonKeys.m b/HiBit/Project/Publics/CommonKeys/HBCommonKeys.m index 4a92728..5fbd11d 100644 --- a/HiBit/Project/Publics/CommonKeys/HBCommonKeys.m +++ b/HiBit/Project/Publics/CommonKeys/HBCommonKeys.m @@ -8,7 +8,7 @@ #import "HBCommonKeys.h" /// 网络请求地址 -NSString *const HBBaseUrlString = @"https://hongkongapi.peonytv.com"; +NSString *const HBBaseUrlString = @"https://test-api.peonytv.com"; NSString *const HBIdentifierForVendorKey = @"HBIdentifierForVendorKey"; diff --git a/HiBit/Project/Publics/CommonKeys/HBThirdKeys.h b/HiBit/Project/Publics/CommonKeys/HBThirdKeys.h index 6de8d88..554768a 100644 --- a/HiBit/Project/Publics/CommonKeys/HBThirdKeys.h +++ b/HiBit/Project/Publics/CommonKeys/HBThirdKeys.h @@ -8,13 +8,13 @@ #import /// appsflyer dev key -extern NSString *const HBAppsFlyerDevKey; +extern NSString * _Nonnull const HBAppsFlyerDevKey; /// appsflyer app id -extern NSString *const HBAppsFlyerAppID; +extern NSString * _Nonnull const HBAppsFlyerAppID; /// applovin key -extern NSString *const HBAppLovinKey; +extern NSString * _Nonnull const HBAppLovinKey; /// Panlge app id -extern NSString *const HBPangleID; +extern NSString * _Nonnull const HBPangleID; diff --git a/HiBit/Project/Publics/MultiLanguage/Manager/HBMultiLanguageManager.h b/HiBit/Project/Publics/MultiLanguage/Manager/HBMultiLanguageManager.h index a766acd..84ce9d7 100644 --- a/HiBit/Project/Publics/MultiLanguage/Manager/HBMultiLanguageManager.h +++ b/HiBit/Project/Publics/MultiLanguage/Manager/HBMultiLanguageManager.h @@ -19,10 +19,10 @@ NS_ASSUME_NONNULL_BEGIN */ /// 多语言 userdefine key -extern NSString *const HBMultiLanguageKey; +extern NSString * _Nonnull const HBMultiLanguageKey; /// 多语言 查询系统首选语言 key -extern NSString *const HBLocaleLanguageKey; +extern NSString * _Nonnull const HBLocaleLanguageKey; /// 多语言发发现切换使用通知的key FOUNDATION_EXPORT NSNotificationName _Nonnull const HBMultiLanguageChangeNotification;