我的页面

This commit is contained in:
zjx 2025-05-26 18:28:51 +08:00
parent 75306178e1
commit 26a5f7bd1a
61 changed files with 1561 additions and 60 deletions

11
Podfile
View File

@ -16,17 +16,20 @@ target 'Veloria' do
use_frameworks!
pod 'SVProgressHUD' #HUD
pod 'Moya' #网络框架
pod 'SnapKit' #布局
pod 'SmartCodable' #数据解析
pod 'YYKit' #工具类
pod 'MJRefresh' #刷新控件
pod 'SnapKit' #布局
pod 'Toast' #吐司提示
pod 'ZFPlayer/AVPlayer' #播放器
pod 'KTVHTTPCache' #视频缓存
pod 'HWPanModal' #底部弹出控制器
pod 'Kingfisher' #图片加载
pod 'HWPanModal' #底部弹出控制器
pod "ESTabBarController-swift"
pod 'WMZPageController' #分页控制器
pod 'ZFPlayer/AVPlayer' #播放器
pod 'EmptyDataSet-Swift' #空数据页面
end

View File

@ -1,6 +1,7 @@
PODS:
- Alamofire (5.10.2)
- CocoaAsyncSocket (7.6.5)
- EmptyDataSet-Swift (5.0.0)
- ESTabBarController-swift (2.8.0)
- HWPanModal (0.9.9)
- Kingfisher (8.3.2)
@ -15,6 +16,9 @@ PODS:
- SmartCodable/Core (= 5.0.9)
- SmartCodable/Core (5.0.9)
- SnapKit (5.7.1)
- SVProgressHUD (2.3.1):
- SVProgressHUD/Core (= 2.3.1)
- SVProgressHUD/Core (2.3.1)
- Toast (4.1.1)
- WMZPageController (1.5.5)
- YYKit (1.0.9):
@ -25,6 +29,7 @@ PODS:
- ZFPlayer/Core (4.1.4)
DEPENDENCIES:
- EmptyDataSet-Swift
- ESTabBarController-swift
- HWPanModal
- Kingfisher
@ -33,6 +38,7 @@ DEPENDENCIES:
- Moya
- SmartCodable
- SnapKit
- SVProgressHUD
- Toast
- WMZPageController
- YYKit
@ -42,6 +48,7 @@ SPEC REPOS:
trunk:
- Alamofire
- CocoaAsyncSocket
- EmptyDataSet-Swift
- ESTabBarController-swift
- HWPanModal
- Kingfisher
@ -50,6 +57,7 @@ SPEC REPOS:
- Moya
- SmartCodable
- SnapKit
- SVProgressHUD
- Toast
- WMZPageController
- YYKit
@ -58,6 +66,7 @@ SPEC REPOS:
SPEC CHECKSUMS:
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
ESTabBarController-swift: 05593a6ad64700b03c0eb60ff625916370aa4136
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
@ -66,11 +75,12 @@ SPEC CHECKSUMS:
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
SmartCodable: 68b3598438181a938eed8ee5623e58ef3e3ea443
SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
WMZPageController: 87dd82d1e3528cd362de19b9a74fd6890d6e1906
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
PODFILE CHECKSUM: e5cac55fd92698becba7d142dc17ec724cd6313f
PODFILE CHECKSUM: 5a8b71939b2bf65623c166084b1e01d877b2979d
COCOAPODS: 1.16.2

View File

@ -119,6 +119,21 @@
BF0FA7A12DE1AA5100C9E5F2 /* VPTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */; };
BF0FA7A32DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */; };
BF0FA7A52DE4384100C9E5F2 /* AttributedString+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */; };
BF0FA7AF2DE443E000C9E5F2 /* VPMeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7AE2DE443E000C9E5F2 /* VPMeViewController.swift */; };
BF0FA7B12DE447EB00C9E5F2 /* VPMeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7B02DE447EB00C9E5F2 /* VPMeItem.swift */; };
BF0FA7B32DE447FE00C9E5F2 /* VPMeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7B22DE447FE00C9E5F2 /* VPMeCell.swift */; };
BF0FA7B62DE44E8000C9E5F2 /* VPWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7B52DE44E8000C9E5F2 /* VPWebView.swift */; };
BF0FA7B82DE44FCC00C9E5F2 /* VPWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7B72DE44FCC00C9E5F2 /* VPWebViewController.swift */; };
BF0FA7BA2DE451B900C9E5F2 /* UINavigationBar+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7B92DE451B000C9E5F2 /* UINavigationBar+VPAdd.swift */; };
BF0FA7BC2DE4563300C9E5F2 /* VPMeUserInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7BB2DE4563300C9E5F2 /* VPMeUserInfoCell.swift */; };
BF0FA7BE2DE4592A00C9E5F2 /* UserDefaults+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7BD2DE4591B00C9E5F2 /* UserDefaults+VPAdd.swift */; };
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7C02DE45D5D00C9E5F2 /* VPUserInfo.swift */; };
BF0FA7C32DE45DE300C9E5F2 /* VPUserAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7C22DE45DE300C9E5F2 /* VPUserAPI.swift */; };
BF5E75AF2DE4632200DE9DFE /* VPAboutUsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */; };
BF5E75B12DE4656600DE9DFE /* VPCampaignWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */; };
BF5E75B32DE465EC00DE9DFE /* Dictionary+SPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */; };
BF5E75B62DE46DB600DE9DFE /* UIScrollView+Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B52DE46DB600DE9DFE /* UIScrollView+Empty.swift */; };
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B72DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift */; };
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
/* End PBXBuildFile section */
@ -244,6 +259,21 @@
BF0FA7A02DE1AA5100C9E5F2 /* VPTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPTableView.swift; sourceTree = "<group>"; };
BF0FA7A22DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWatchHistoryCell.swift; sourceTree = "<group>"; };
BF0FA7A42DE4384100C9E5F2 /* AttributedString+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+VPAdd.swift"; sourceTree = "<group>"; };
BF0FA7AE2DE443E000C9E5F2 /* VPMeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeViewController.swift; sourceTree = "<group>"; };
BF0FA7B02DE447EB00C9E5F2 /* VPMeItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeItem.swift; sourceTree = "<group>"; };
BF0FA7B22DE447FE00C9E5F2 /* VPMeCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeCell.swift; sourceTree = "<group>"; };
BF0FA7B52DE44E8000C9E5F2 /* VPWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWebView.swift; sourceTree = "<group>"; };
BF0FA7B72DE44FCC00C9E5F2 /* VPWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPWebViewController.swift; sourceTree = "<group>"; };
BF0FA7B92DE451B000C9E5F2 /* UINavigationBar+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+VPAdd.swift"; sourceTree = "<group>"; };
BF0FA7BB2DE4563300C9E5F2 /* VPMeUserInfoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMeUserInfoCell.swift; sourceTree = "<group>"; };
BF0FA7BD2DE4591B00C9E5F2 /* UserDefaults+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+VPAdd.swift"; sourceTree = "<group>"; };
BF0FA7C02DE45D5D00C9E5F2 /* VPUserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPUserInfo.swift; sourceTree = "<group>"; };
BF0FA7C22DE45DE300C9E5F2 /* VPUserAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPUserAPI.swift; sourceTree = "<group>"; };
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAboutUsViewController.swift; sourceTree = "<group>"; };
BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCampaignWebViewController.swift; sourceTree = "<group>"; };
BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SPAdd.swift"; sourceTree = "<group>"; };
BF5E75B52DE46DB600DE9DFE /* UIScrollView+Empty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+Empty.swift"; sourceTree = "<group>"; };
BF5E75B72DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNetworkReachabilityManager.swift; sourceTree = "<group>"; };
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -316,6 +346,8 @@
1B056E352DDAC1DE007EE38D /* Libs */ = {
isa = PBXGroup;
children = (
BF5E75B42DE46D9500DE9DFE /* Empty */,
BF0FA7BF2DE45D4500C9E5F2 /* User */,
BF0FA7432DDF025A00C9E5F2 /* Player */,
BF0FA6F22DDC603200C9E5F2 /* HUD */,
BF0FA6D82DDC5C8200C9E5F2 /* Login */,
@ -328,6 +360,7 @@
1B056E362DDAC1E8007EE38D /* Class */ = {
isa = PBXGroup;
children = (
BF0FA7A62DE4437F00C9E5F2 /* Me */,
BF0FA7952DE1948A00C9E5F2 /* MyList */,
1B056E522DDACBF4007EE38D /* Home */,
BF0FA7422DDF024400C9E5F2 /* Explore */,
@ -344,6 +377,7 @@
1B056E3A2DDAC21E007EE38D /* Model */,
1B056E422DDAC32C007EE38D /* Extension */,
1B056E3C2DDAC23D007EE38D /* Define */,
BF0FA7B42DE44E5100C9E5F2 /* WebView */,
1B056E3B2DDAC22D007EE38D /* Networking */,
);
path = Base;
@ -410,6 +444,7 @@
BF0FA6D42DDC5B5D00C9E5F2 /* VPApi.swift */,
BF0FA6D62DDC5BE100C9E5F2 /* VPURLPath.swift */,
BF0FA6F02DDC600200C9E5F2 /* VPNetwork.swift */,
BF5E75B72DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift */,
);
path = Base;
sourceTree = "<group>";
@ -417,6 +452,9 @@
1B056E422DDAC32C007EE38D /* Extension */ = {
isa = PBXGroup;
children = (
BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */,
BF0FA7BD2DE4591B00C9E5F2 /* UserDefaults+VPAdd.swift */,
BF0FA7B92DE451B000C9E5F2 /* UINavigationBar+VPAdd.swift */,
1B056E432DDAC355007EE38D /* UIDevice+VPAdd.swift */,
1B056E452DDAC370007EE38D /* UIScreen+VPAdd.swift */,
1B056E5A2DDACD80007EE38D /* UIColor+VPAdd.swift */,
@ -547,6 +585,7 @@
children = (
BF0FA6F82DDC64E700C9E5F2 /* VPHomeAPI.swift */,
BF0FA73C2DDED2D000C9E5F2 /* VPVideoAPI.swift */,
BF0FA7C22DE45DE300C9E5F2 /* VPUserAPI.swift */,
);
path = API;
sourceTree = "<group>";
@ -755,6 +794,68 @@
path = View;
sourceTree = "<group>";
};
BF0FA7A62DE4437F00C9E5F2 /* Me */ = {
isa = PBXGroup;
children = (
BF0FA7A72DE4438600C9E5F2 /* Controller */,
BF0FA7AC2DE443AE00C9E5F2 /* View */,
BF0FA7AD2DE443B700C9E5F2 /* Model */,
);
path = Me;
sourceTree = "<group>";
};
BF0FA7A72DE4438600C9E5F2 /* Controller */ = {
isa = PBXGroup;
children = (
BF0FA7AE2DE443E000C9E5F2 /* VPMeViewController.swift */,
BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */,
BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
};
BF0FA7AC2DE443AE00C9E5F2 /* View */ = {
isa = PBXGroup;
children = (
BF0FA7B22DE447FE00C9E5F2 /* VPMeCell.swift */,
BF0FA7BB2DE4563300C9E5F2 /* VPMeUserInfoCell.swift */,
);
path = View;
sourceTree = "<group>";
};
BF0FA7AD2DE443B700C9E5F2 /* Model */ = {
isa = PBXGroup;
children = (
BF0FA7B02DE447EB00C9E5F2 /* VPMeItem.swift */,
);
path = Model;
sourceTree = "<group>";
};
BF0FA7B42DE44E5100C9E5F2 /* WebView */ = {
isa = PBXGroup;
children = (
BF0FA7B52DE44E8000C9E5F2 /* VPWebView.swift */,
BF0FA7B72DE44FCC00C9E5F2 /* VPWebViewController.swift */,
);
path = WebView;
sourceTree = "<group>";
};
BF0FA7BF2DE45D4500C9E5F2 /* User */ = {
isa = PBXGroup;
children = (
BF0FA7C02DE45D5D00C9E5F2 /* VPUserInfo.swift */,
);
path = User;
sourceTree = "<group>";
};
BF5E75B42DE46D9500DE9DFE /* Empty */ = {
isa = PBXGroup;
children = (
BF5E75B52DE46DB600DE9DFE /* UIScrollView+Empty.swift */,
);
path = Empty;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -877,13 +978,18 @@
1B056E742DDB2DD7007EE38D /* UIView+VPAdd.swift in Sources */,
BF0FA6F12DDC600200C9E5F2 /* VPNetwork.swift in Sources */,
BF0FA7502DDF0A9900C9E5F2 /* VPVideoPlayerCell.swift in Sources */,
BF5E75B62DE46DB600DE9DFE /* UIScrollView+Empty.swift in Sources */,
1B056E572DDACC6B007EE38D /* VPHomePageViewController.swift in Sources */,
BF0FA7BC2DE4563300C9E5F2 /* VPMeUserInfoCell.swift in Sources */,
BF0FA7B82DE44FCC00C9E5F2 /* VPWebViewController.swift in Sources */,
BF0FA72A2DDC922F00C9E5F2 /* VPHomeRecommandCell.swift in Sources */,
BF0FA7322DDEBD6400C9E5F2 /* AppDelegate+Config.swift in Sources */,
BF0FA7B32DE447FE00C9E5F2 /* VPMeCell.swift in Sources */,
BF0FA6DF2DDC5E4D00C9E5F2 /* String+VPAdd.swift in Sources */,
BF0FA7002DDC665300C9E5F2 /* VPShortModel.swift in Sources */,
1B056E7B2DDB37BA007EE38D /* VPGradientView.swift in Sources */,
BF0FA7262DDC8F7600C9E5F2 /* VPCollectionView.swift in Sources */,
BF0FA7C32DE45DE300C9E5F2 /* VPUserAPI.swift in Sources */,
BF0FA78B2DE164C100C9E5F2 /* VPSearchResultCell.swift in Sources */,
BF0FA71D2DDC807200C9E5F2 /* UIImageView+VPAdd.swift in Sources */,
BF0FA6DC2DDC5CD700C9E5F2 /* VPTokenModel.swift in Sources */,
@ -916,12 +1022,15 @@
BF0FA7522DDF134700C9E5F2 /* VPVideoPlayerControlView.swift in Sources */,
BF0FA7852DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift in Sources */,
BF0FA7832DE1533E00C9E5F2 /* VPGradientLabel.swift in Sources */,
BF0FA7B12DE447EB00C9E5F2 /* VPMeItem.swift in Sources */,
1B056E2C2DDAC0FD007EE38D /* SceneDelegate.swift in Sources */,
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
1B056E462DDAC370007EE38D /* UIScreen+VPAdd.swift in Sources */,
BF0FA7692DE0502900C9E5F2 /* VPEpisodeCell.swift in Sources */,
BF0FA73D2DDED2D000C9E5F2 /* VPVideoAPI.swift in Sources */,
BF0FA6EE2DDC5F8700C9E5F2 /* JXUUID.m in Sources */,
BF5E75B12DE4656600DE9DFE /* VPCampaignWebViewController.swift in Sources */,
BF0FA7BA2DE451B900C9E5F2 /* UINavigationBar+VPAdd.swift in Sources */,
BF0FA77D2DE078D400C9E5F2 /* VPSearchRecommendedView.swift in Sources */,
BF0FA7812DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift in Sources */,
BF0FA7872DE1601200C9E5F2 /* VPTextField.swift in Sources */,
@ -933,6 +1042,7 @@
BF0FA6DA2DDC5CB600C9E5F2 /* VPLoginManager.swift in Sources */,
BF0FA74A2DDF04E200C9E5F2 /* VPPlayerProtocol.swift in Sources */,
BF0FA72C2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift in Sources */,
BF0FA7AF2DE443E000C9E5F2 /* VPMeViewController.swift in Sources */,
BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */,
BF0FA7A52DE4384100C9E5F2 /* AttributedString+VPAdd.swift in Sources */,
BF0FA7652DE00A0E00C9E5F2 /* VPDetailPlayerControlView.swift in Sources */,
@ -951,11 +1061,13 @@
BF0FA79D2DE198C600C9E5F2 /* VPWatchHistoryViewController.swift in Sources */,
1B056E6A2DDAD0BF007EE38D /* VPLocalizedManager.swift in Sources */,
BF0FA7242DDC888F00C9E5F2 /* VPHomeRecommandContentCell.swift in Sources */,
BF5E75AF2DE4632200DE9DFE /* VPAboutUsViewController.swift in Sources */,
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */,
BF0FA7192DDC7F4900C9E5F2 /* VPHomeBannerCell.swift in Sources */,
BF0FA7712DE062EB00C9E5F2 /* VPVideoRateModel.swift in Sources */,
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */,
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */,
BF0FA7BE2DE4592A00C9E5F2 /* UserDefaults+VPAdd.swift in Sources */,
BF0FA76F2DE062A700C9E5F2 /* VPRateSelectedView.swift in Sources */,
BF0FA7772DE0735800C9E5F2 /* VPSearchInputView.swift in Sources */,
BF0FA7892DE161F200C9E5F2 /* VPSearchResultView.swift in Sources */,
@ -969,13 +1081,17 @@
BF0FA73F2DDEF26E00C9E5F2 /* VPHomeSearchButton.swift in Sources */,
1B056E512DDACBE5007EE38D /* VPViewController.swift in Sources */,
BF0FA7122DDC6D2C00C9E5F2 /* VPHomeModuleItem.swift in Sources */,
BF5E75B32DE465EC00DE9DFE /* Dictionary+SPAdd.swift in Sources */,
BF0FA7162DDC78FF00C9E5F2 /* ZKCycleScrollViewFlowLayout.swift in Sources */,
BF0FA7172DDC78FF00C9E5F2 /* ZKCycleScrollView.swift in Sources */,
BF0FA7612DDFFE7100C9E5F2 /* VPVideoDetailModel.swift in Sources */,
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */,
BF0FA6D52DDC5B5D00C9E5F2 /* VPApi.swift in Sources */,
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */,
BF0FA6FC2DDC657500C9E5F2 /* VPHomeDataModel.swift in Sources */,
BF0FA7392DDECF8900C9E5F2 /* VPHomeListViewController.swift in Sources */,
BF0FA6F62DDC616300C9E5F2 /* VPToast.swift in Sources */,
BF0FA7B62DE44E8000C9E5F2 /* VPWebView.swift in Sources */,
1B056E492DDAC3DF007EE38D /* VPAppTool.swift in Sources */,
BF0FA74E2DDF067E00C9E5F2 /* VPVideoPlayViewModel.swift in Sources */,
BF0FA75B2DDF206000C9E5F2 /* VPExplorePlayerCell.swift in Sources */,

View File

@ -12,6 +12,8 @@ extension AppDelegate {
func appConfig() {
UIButton.vp_bt_Awake()
UIView.vp_Awake()
VPToast.config()
}
}

View File

@ -15,6 +15,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
appConfig()
///
VPNetworkReachabilityManager.manager.startMonitoring()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
VPLoginManager.manager.updateUserInfo(completer: nil)
return true
}
@ -36,3 +41,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
extension AppDelegate {
@objc private func reachabilityDidChangeNotification() {
if VPNetworkReachabilityManager.manager.isReachable == true {
VPLoginManager.manager.updateUserInfo(completer: nil)
}
}
}

View File

@ -6,7 +6,6 @@
//
import UIKit
import ESTabBarController_swift
class VPTabBarController: UITabBarController {
@ -53,7 +52,6 @@ class VPTabBarController: UITabBarController {
view.backgroundColor = .color000000()
// ESTabBarController
vp_setup()
self.tabBar.isTranslucent = true
@ -89,7 +87,7 @@ extension VPTabBarController {
let nav1 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
let nav2 = createNavigationController(viewController: VPExploreViewController(), title: "Explore".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
let nav3 = createNavigationController(viewController: VPMyListViewController(), title: "My List".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
let nav4 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
let nav4 = createNavigationController(viewController: VPMeViewController(), title: "Me".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
viewControllers = [nav1, nav2, nav3, nav4]
@ -97,13 +95,6 @@ extension VPTabBarController {
private func createNavigationController(viewController: UIViewController, title: String?, image: UIImage?, selectedImage: UIImage?) -> UINavigationController {
// let tabBarContentView = VPTabBarItemContentView()
// let tabBarItem = ESTabBarItem(tabBarContentView, title: title, image: image, selectedImage: selectedImage)
//
// tabBarItem.contentView?.renderingMode = .alwaysOriginal
// tabBarItem.contentView?.textColor = .colorFFFFFF()
// tabBarItem.contentView?.highlightTextColor = .colorFFFFFF()
// tabBarItem.contentView?.titleLabel.font = .fontRegular(ofSize: 13)
let tabBarItem = VPTabBarItem()
tabBarItem.title = title
@ -111,7 +102,6 @@ extension VPTabBarController {
tabBarItem.selectedImage = selectedImage
let nav = VPNavigationController(rootViewController: viewController)
// nav.tabBarItem.title = title
nav.tabBarItem = tabBarItem
return nav
}
@ -124,11 +114,6 @@ extension VPTabBarController {
guard let idx = tabBar.items?.firstIndex(of: item) else {
return;
}
// if idx == tabBar.items!.count - 1, ESTabBarController.isShowingMore(self) {
// ignoreNextSelection = true
// selectedViewController = moreNavigationController
// return;
// }
if let vc = viewControllers?[idx] {
ignoreNextSelection = true
selectedIndex = idx
@ -149,3 +134,24 @@ extension VPTabBarController {
}
}
extension VPTabBarController {
func openHistoryPage() {
var index: Int?
var viewController: VPMyListViewController?
self.viewControllers?.enumerated().forEach({
guard let nav = $1 as? UINavigationController else { return }
if let vc = nav.viewControllers.first as? VPMyListViewController {
index = $0
viewController = vc
}
})
if let index = index {
self.selectedIndex = index
viewController?.showHistoryPage()
}
}
}

View File

@ -92,3 +92,40 @@ extension VPViewController {
}
}
}
extension UIViewController {
///
func setNavigationNormalStyle(backgroundColor: UIColor = .clear,
isTranslucent: Bool = true,
prefersLargeTitles: Bool = false)
{
self.setNavigationBackgroundColor(color: backgroundColor, isTranslucent: isTranslucent)
self.setNavigationTitleStyle()
self.navigationController?.navigationBar.prefersLargeTitles = prefersLargeTitles
}
///
func setNavigationBackgroundColor(color: UIColor?, isTranslucent: Bool = false) {
guard let nav = navigationController else { return }
if nav.visibleViewController == self {
nav.navigationBar.vp_setBackgroundColor(backgroundColor: color)
nav.navigationBar.vp_setTranslucent(isTranslucent: isTranslucent)
}
}
///
func setNavigationTitleStyle(color: UIColor? = nil, font: UIFont? = nil) {
guard let nav = navigationController else { return }
if nav.visibleViewController == self {
//
var titleTextAttributes = UINavigationBar.vp_normalTitleTextAttributes
if let color = color {
titleTextAttributes[NSAttributedString.Key.foregroundColor] = color
}
if let font = font {
titleTextAttributes[NSAttributedString.Key.font] = font
}
nav.navigationBar.vp_setTitleTextAttributes(titleTextAttributes: titleTextAttributes)
}
}
}

View File

@ -9,3 +9,9 @@ import UIKit
///
let kVPSearchHistoryDefaultsKey = "kVPSearchHistoryDefaultsKey"
///token
let kVPLoginTokenDefaultsKey = "kVPLoginTokenDefaultsKey"
///
let kVPLoginUserInfoDefaultsKey = "kSPLoginUserInfoDefaultsKey"

View File

@ -0,0 +1,23 @@
//
// Dictionary+SPAdd.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
extension Dictionary {
func toJsonString() -> String? {
do {
let data = try JSONSerialization.data(withJSONObject: self)
let jsonStr = String(data: data, encoding: .utf8)
return jsonStr
} catch {
}
return nil
}
}

View File

@ -97,4 +97,8 @@ extension UIColor {
static func colorD87675(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xD87675, alpha: alpha)
}
static func colorB5B5B5(alpha: CGFloat = 1) -> UIColor {
return UIColor(rgb: 0xB5B5B5, alpha: alpha)
}
}

View File

@ -0,0 +1,88 @@
//
// UINavigationBar+VPAdd.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
extension UINavigationBar {
static let vp_normalTitleFont = UIFont.fontBold(ofSize: 16)
static var vp_normalTitleColor: UIColor {
get {
return .colorFFFFFF()
}
}
/**
*/
static var vp_normalTitleTextAttributes: [NSAttributedString.Key : Any] {
get {
return [
NSAttributedString.Key.font : vp_normalTitleFont,
NSAttributedString.Key.foregroundColor : vp_normalTitleColor
]
}
}
/**
*/
static var vp_normalBackgroundColor: UIColor {
get {
return .black
}
}
@available(iOS 13.0, *)
static let navBarAppearance: UINavigationBarAppearance = {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
//
navBarAppearance.backgroundColor = vp_normalBackgroundColor
//
navBarAppearance.backgroundEffect = nil
// clear线
navBarAppearance.shadowColor = UIColor.clear
//
navBarAppearance.titleTextAttributes = vp_normalTitleTextAttributes
return navBarAppearance
}()
func vp_setTranslucent(isTranslucent: Bool) {
self.isTranslucent = isTranslucent
}
func vp_setBackgroundColor(backgroundColor: UIColor?) {
if #available(iOS 15.0, *) {
UINavigationBar.navBarAppearance.backgroundColor = backgroundColor
self.standardAppearance = UINavigationBar.navBarAppearance
self.scrollEdgeAppearance = UINavigationBar.navBarAppearance
}
if let backgroundColor = backgroundColor {
self.setBackgroundImage(UIImage(color: backgroundColor), for: .default)
} else {
self.setBackgroundImage(UIImage(), for: .default)
}
}
func vp_setTitleTextAttributes(titleTextAttributes: [NSAttributedString.Key : Any]?) {
if #available(iOS 15.0, *) {
if let titleTextAttributes = titleTextAttributes {
UINavigationBar.navBarAppearance.titleTextAttributes = titleTextAttributes
}
self.scrollEdgeAppearance = UINavigationBar.navBarAppearance
self.standardAppearance = UINavigationBar.navBarAppearance
} else {
self.titleTextAttributes = titleTextAttributes
}
}
}

View File

@ -0,0 +1,45 @@
//
// UserDefaults+VPAdd.swift
// Veloria
//
// Created by on 2025/5/26.
//
import Foundation
extension UserDefaults {
static func vp_setObject(_ obj: NSSecureCoding?, forKey key: String) {
let defaults = UserDefaults.standard
guard let obj = obj else {
defaults.removeObject(forKey: key)
return
}
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: obj, requiringSecureCoding: true)
defaults.set(data, forKey: key)
} catch {
print("Error archiving object: \(error)")
}
}
static func vp_object<T: NSObject & NSSecureCoding>(forKey key: String, as type: T.Type) -> T? {
let defaults = UserDefaults.standard
guard let data = defaults.data(forKey: key) else {
return nil
}
do {
let object = try NSKeyedUnarchiver.unarchivedObject(ofClass: type, from: data)
return object
} catch {
print("Error unarchiving object: \(error)")
return nil
}
}
}

View File

@ -13,7 +13,7 @@ class VPHomeAPI: NSObject {
static func requestHomeData(completer: ((_ list: [VPHomeModuleItem]?) -> Void)?) {
var param = VPNetworkParameters(path: "/home/all-modules")
param.method = .get
param.isToast = true
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPHomeModuleItem>>) in
completer?(response.data?.list)

View File

@ -0,0 +1,22 @@
//
// VPUserAPI.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPUserAPI: NSObject {
///
static func requestUserInfo(completer: ((_ userInfo: VPUserInfo?) -> Void)?) {
var param = VPNetworkParameters(path: "/customer/info")
param.method = .get
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPUserInfo>) in
completer?(response.data)
}
}
}

View File

@ -0,0 +1,60 @@
//
// VPNetworkReachabilityManager.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
import Network
class VPNetworkReachabilityManager {
static let manager = VPNetworkReachabilityManager()
///
var isReachable: Bool?
private let monitor = NWPathMonitor()
private let queue = DispatchQueue(label: "NetworkMonitorQueue")
func startMonitoring() {
monitor.pathUpdateHandler = { [weak self] path in
guard let self = self else { return }
if path.status == .satisfied {
if self.isReachable == false {
self.isReachable = true
DispatchQueue.main.async {
NotificationCenter.default.post(name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
}
} else {
self.isReachable = true
}
} else {
if self.isReachable == true {
self.isReachable = false
DispatchQueue.main.async {
NotificationCenter.default.post(name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
}
} else {
self.isReachable = false
}
}
}
monitor.start(queue: queue)
}
func stopMonitoring() {
monitor.cancel()
}
}
extension VPNetworkReachabilityManager {
///
@objc static let reachabilityDidChangeNotification = NSNotification.Name(rawValue: "VPNetworkReachabilityManager.reachabilityDidChangeNotification")
}

View File

@ -22,25 +22,25 @@ let VPCampaignWebURL = "https://campaign.moviatv.com"
#endif
///
let VPUserAgreementWebUrl = VPWebBaseURL + "/user_policy"
let kVPUserAgreementWebUrl = VPWebBaseURL + "/user_policy"
///
let VPPrivacyPolicyWebUrl = VPWebBaseURL + "/private"
let kVPPrivacyPolicyWebUrl = VPWebBaseURL + "/private"
///
let VPInformationProtectionWebUrl = VPWebBaseURL + "/information_protection"
let kVPInformationProtectionWebUrl = VPWebBaseURL + "/information_protection"
///
let VPInformationSharingWebUrl = VPWebBaseURL + "/information_sharing"
let kVPInformationSharingWebUrl = VPWebBaseURL + "/information_sharing"
///
let VPPersoInforDisclosureWebUrl = VPWebBaseURL + "/persoInfor_disclosure"
let kVPPersoInforDisclosureWebUrl = VPWebBaseURL + "/persoInfor_disclosure"
///
let VPCivizatioConventionWebUrl = VPWebBaseURL + "/civizatio_convention"
let kVPCivizatioConventionWebUrl = VPWebBaseURL + "/civizatio_convention"
///
let VPMemberShipAgreement = VPWebBaseURL + "/member_ship_agreement"
let kVPMemberShipAgreement = VPWebBaseURL + "/member_ship_agreement"
///
let VPFeedBackHomeWebUrl = VPCampaignWebURL + "/pages/leave/index"
let kVPFeedBackHomeWebUrl = VPCampaignWebURL + "/pages/leave/index"
///
let VPFeedBackListWebUrl = VPCampaignWebURL + "/pages/leave/list"
let kVPFeedBackListWebUrl = VPCampaignWebURL + "/pages/leave/list"
///
let VPFeedBackDetailWebUrl = VPCampaignWebURL + "/pages/leave/detail"
let kVPFeedBackDetailWebUrl = VPCampaignWebURL + "/pages/leave/detail"
///
let VPRewardsWebUrl = VPCampaignWebURL
let kVPRewardsWebUrl = VPCampaignWebURL

View File

@ -39,11 +39,9 @@ class VPTableView: UITableView {
}
get {
var margins = super.layoutMargins
if #available(iOS 13.0, *) {
if self.style == .insetGrouped {
margins.left = self.safeAreaInsets.left + insetGroupedMargins
margins.right = self.safeAreaInsets.right + insetGroupedMargins
}
if self.style == .insetGrouped {
margins.left = self.safeAreaInsets.left + insetGroupedMargins
margins.right = self.safeAreaInsets.right + insetGroupedMargins
}
return margins
}

View File

@ -9,6 +9,11 @@ import UIKit
class VPTableViewCell: UITableViewCell {
private(set) lazy var indicatorImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "arrow_right_icon_02"))
return imageView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)

View File

@ -0,0 +1,197 @@
//
// VPWebView.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
@preconcurrency import WebKit
//MARK:-------------- VPWebViewDelegate --------------
@objc protocol VPWebViewDelegate: NSObjectProtocol {
@objc optional func webView(_ webView: VPWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool
@objc optional func webViewDidStartLoad(_ webView: VPWebView)
@objc optional func webViewDidFinishLoad(_ webView: VPWebView)
@objc optional func webView(_ webView: VPWebView, didFailLoadWithError error: Error)
///
@objc optional func webView(webView: VPWebView, didChangeProgress progress: CGFloat)
///
@objc optional func webView(webView: VPWebView, didChangeTitle title: String)
///web
@objc optional func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
}
class VPWebView: WKWebView {
weak var delegate: VPWebViewDelegate?
// private(set) var scriptMessageHandlerArray: [SPWebViewMessageName] = [
// WebMessageAPP,
// WebMessageOpenFeedbackList,
// WebMessageOpenFeedbackDetail,
// WebMessageOpenPhotoPicker,
// ]
deinit {
self.removeObserver(self, forKeyPath: "estimatedProgress")
self.removeObserver(self, forKeyPath: "title")
}
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
super.init(frame: frame, configuration: configuration)
// addScriptMessageHandler()
_setupInit()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func _setupInit() {
self.isOpaque = false
self.uiDelegate = self
self.navigationDelegate = self
self.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)
self.addObserver(self, forKeyPath: "title", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if object as? VPWebView == self {
if keyPath == "estimatedProgress", let progress = change?[NSKeyValueChangeKey.newKey] as? CGFloat {
self.delegate?.webView?(webView: self, didChangeProgress: progress)
} else if keyPath == "title", let title = change?[NSKeyValueChangeKey.newKey] as? String {
self.delegate?.webView?(webView: self, didChangeTitle: title)
}
}
}
func load(urlStr: String) {
guard let url = URL(string: urlStr) else { return }
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
self.load(request)
}
// func removeScriptMessageHandler() {
// self.scriptMessageHandlerArray.forEach{
// configuration.userContentController.removeScriptMessageHandler(forName: $0)
// }
// }
// func addScriptMessageHandler() {
// self.scriptMessageHandlerArray.forEach{
// configuration.userContentController.add(YYWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
// }
// }
}
//MARK:-------------- WKUIDelegate --------------
extension VPWebView: WKUIDelegate {
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "确认", style: .default, handler: { (action) in
completionHandler()
}))
self.viewController?.present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (action) in
completionHandler(false)
}))
alertController.addAction(UIAlertAction(title: "确认", style: .default, handler: { (action) in
completionHandler(true)
}))
self.viewController?.present(alertController, animated: true, completion: nil)
}
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {
let alertController = UIAlertController(title: prompt, message: "", preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.text = defaultText
}
alertController.addAction(UIAlertAction(title: "完成", style: .default, handler: { (action) in
completionHandler(alertController.textFields?.first?.text)
}))
self.viewController?.present(alertController, animated: true, completion: nil)
}
}
//MARK:-------------- WKNavigationDelegate --------------
extension VPWebView: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
decisionHandler(.allow);
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
vpLog(message: navigationAction.request.url)
if let url = navigationAction.request.url,
url.scheme != "http",
url.scheme != "https"
{
UIApplication.shared.open(url)
decisionHandler(.cancel)
return
}
//
// if JXRequestHttpProxy.isIntercept() {
// decisionHandler(.cancel)
// return
// }
if let result = self.delegate?.webView?(self, shouldStartLoadWith: navigationAction) {
if result {
decisionHandler(.allow)
} else {
decisionHandler(.cancel)
}
} else {
decisionHandler(.allow)
}
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
self.delegate?.webViewDidStartLoad?(self)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.delegate?.webViewDidFinishLoad?(self)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
self.delegate?.webView?(self, didFailLoadWithError: error)
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
self.delegate?.webView?(self, didFailLoadWithError: error)
}
}
//MARK:-------------- WKScriptMessageHandler --------------
extension VPWebView: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
self.delegate?.userContentController?(userContentController, didReceive: message)
}
}

View File

@ -0,0 +1,99 @@
//
// VPWebViewController.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
import WebKit
class VPWebViewController: VPViewController {
var urlStr: String?
///
var autoTitle = true
private(set) lazy var webView: VPWebView = {
let controller = WKUserContentController()
let config = WKWebViewConfiguration()
config.userContentController = controller
config.preferences.javaScriptEnabled = true
/** JS */
config.preferences.javaScriptCanOpenWindowsAutomatically = true
let webView = VPWebView(frame: self.view.bounds, configuration: config)
webView.delegate = self
return webView
}()
override func viewDidLoad() {
super.viewDidLoad()
_setupUI()
if let url = urlStr {
self.load(urlString: url)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.setNavigationNormalStyle()
}
func load(urlString: String) {
let str: String = urlString
guard let url = URL(string: str) else { return }
let request = URLRequest(url: url, timeoutInterval: 30)
self.webView.load(request)
}
func reload() {
self.webView.reload()
}
}
extension VPWebViewController {
private func _setupUI() {
self.view.addSubview(webView)
self.webView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(0)
make.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
make.bottom.equalToSuperview().offset(0)
}
}
}
//MARK: -------------- VPWebViewDelegate --------------
extension VPWebViewController: VPWebViewDelegate {
func webView(webView: VPWebView, didChangeTitle title: String) {
if autoTitle {
self.title = title
}
}
func webView(_ webView: VPWebView, didFailLoadWithError error: any Error) {
vpLog(message: error)
}
func webViewDidFinishLoad(_ webView: VPWebView) {
vpLog(message: "网页加载完成")
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
// _webViewUserContentController(didReceive: message)
}
}

View File

@ -118,17 +118,19 @@ class VPHomePageViewController: VPViewController {
private lazy var historyButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "history_icon_01"), for: .normal)
button.addTarget(self, action: #selector(handleHistoryButton), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: VPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
requestHomeData()
setupPageView()
vp_setupUI()
}
override func viewWillAppear(_ animated: Bool) {
@ -172,6 +174,21 @@ class VPHomePageViewController: VPViewController {
self.navigationController?.pushViewController(vc, animated: true)
}
@objc private func handleHistoryButton() {
(VPAppTool.rootViewController as? VPTabBarController)?.openHistoryPage()
}
}
extension VPHomePageViewController {
@objc private func reachabilityDidChangeNotification() {
if VPNetworkReachabilityManager.manager.isReachable == true {
if self.viewModel.oldModuleList == nil {
requestHomeData()
}
}
}
}
extension VPHomePageViewController {
@ -199,8 +216,6 @@ extension VPHomePageViewController {
make.width.height.equalTo(40)
make.centerY.equalTo(searchButton)
}
}
}

View File

@ -35,8 +35,19 @@ class VPHomeModuleItem: VPModel, SmartCodable {
self.list = [VPShortModel].deserialize(from: data)
}
} else if let data = data as? [String : Any] {
title = data["title"] as? String
list = [VPShortModel].deserialize(from: data["list"] as? [[String : Any]])
var dataList: [[String : Any]]?
if let list = data["list"] as? [[String : Any]] {
self.title = data["title"] as? String
dataList = list
} else if let list = data["shortPlayList"] as? [[String : Any]] {
dataList = list
}
if let dataList = dataList {
self.list = [VPShortModel].deserialize(from: dataList)
}
}
}

View File

@ -0,0 +1,25 @@
//
// VPAboutUsViewController.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPAboutUsViewController: VPViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "About Us".localized
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(false, animated: true)
setNavigationNormalStyle()
}
}

View File

@ -0,0 +1,83 @@
//
// VPCampaignWebViewController.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPCampaignWebViewController: VPWebViewController {
var id: String?
///
private var receiveDataCount = 0
override func viewDidLoad() {
super.viewDidLoad()
autoTitle = false
if urlStr == kVPFeedBackListWebUrl {
self.title = "Feedback History".localized
} else if urlStr == kVPFeedBackHomeWebUrl {
self.title = "Feedback".localized
} else if urlStr == kVPFeedBackDetailWebUrl {
self.title = "Feedback Details".localized
} else if urlStr == kVPRewardsWebUrl {
self.title = "Rewards".localized
}
self.webView.scrollView.vp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
}
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
self.reload()
self.webView.scrollView.vp_endHeaderRefreshing()
}
override func webViewDidFinishLoad(_ webView: VPWebView) {
super.webViewDidFinishLoad(webView)
receiveDataCount = 0
receiveDataFromNative()
}
}
extension VPCampaignWebViewController {
///
func receiveDataFromNative() {
receiveDataCount += 1
if receiveDataCount > 10 { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
guard let self = self else { return }
var dic = [
"token" : VPLoginManager.manager.token?.token ?? "",
"time_zone" : String.timeZone(),
"lang" : VPLocalizedManager.shared.currentLocalizedKey,
"type" : "ios",
"theme" : "theme_1",
]
if let id = id {
dic["id"] = id
}
if let json = dic.toJsonString() {
let js = "receiveDataFromNative(\(json))"
self.webView.evaluateJavaScript(js) { [weak self] _, error in
guard let self = self else { return }
if error != nil {
self.receiveDataFromNative()
}
}
}
}
}
}

View File

@ -0,0 +1,152 @@
//
// VPMeViewController.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPMeViewController: VPViewController {
private lazy var dataArr: [[VPMeItem]] = {
let arr = [
[
VPMeItem(cellKey: .userInfo),
],
[
VPMeItem(icon: UIImage(named: "me_item_icon_01"), title: "Privacy Policy".localized, type: .privacyPolicy, cellKey: .normal),
VPMeItem(icon: UIImage(named: "me_item_icon_02"), title: "User Agreement".localized, type: .userAgreement, cellKey: .normal),
// VPMeItem(icon: UIImage(named: "me_item_icon_04"), title: "Help Center".localized, type: .feedback, cellKey: .normal),
VPMeItem(icon: UIImage(named: "me_item_icon_03"), title: "About Us".localized, type: .aboutUs, cellKey: .normal),
]
]
return arr
}()
private lazy var tableView: VPTableView = {
let tableView = VPTableView(frame: .zero, style: .insetGrouped)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.vp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
}
tableView.register(VPMeCell.self, forCellReuseIdentifier: VPMeItem.CellKey.normal.rawValue)
tableView.register(VPMeUserInfoCell.self, forCellReuseIdentifier: VPMeItem.CellKey.userInfo.rawValue)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
vp_setupUI()
requestUserInfo()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
if hasViewDidAppear {
requestUserInfo()
}
super.viewDidAppear(animated)
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
self.requestUserInfo()
}
}
extension VPMeViewController {
private func vp_setupUI() {
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(UIScreen.statusBarHeight)
}
}
}
//MARK: -------------- UITableViewDelegate UITableViewDataSource --------------
extension VPMeViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = self.dataArr[indexPath.section][indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: item.cellKey?.rawValue ?? VPMeItem.CellKey.normal.rawValue, for: indexPath)
if let cell = cell as? VPMeCell {
cell.item = item
} else if let cell = cell as? VPMeUserInfoCell {
cell.userInfo = VPLoginManager.manager.userInfo
}
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArr[section].count
}
func numberOfSections(in tableView: UITableView) -> Int {
return self.dataArr.count
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
if section == 0 {
return 0.1
} else {
return 14
}
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 0.1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = dataArr[indexPath.section][indexPath.row]
switch item.type {
case .privacyPolicy:
let vc = VPWebViewController()
vc.urlStr = kVPPrivacyPolicyWebUrl
self.navigationController?.pushViewController(vc, animated: true)
case .userAgreement:
let vc = VPWebViewController()
vc.urlStr = kVPUserAgreementWebUrl
self.navigationController?.pushViewController(vc, animated: true)
case .aboutUs:
let vc = VPAboutUsViewController()
self.navigationController?.pushViewController(vc, animated: true)
default:
break
}
}
}
extension VPMeViewController {
///
private func requestUserInfo() {
VPLoginManager.manager.updateUserInfo { [weak self] in
self?.tableView.reloadData()
}
}
}

View File

@ -0,0 +1,27 @@
//
// VPMeItem.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
struct VPMeItem {
enum ItemType {
case privacyPolicy
case userAgreement
case aboutUs
case feedback
}
enum CellKey: String {
case normal
case userInfo
}
var icon: UIImage?
var title: String?
var type: ItemType?
var cellKey: CellKey?
}

View File

@ -0,0 +1,69 @@
//
// VPMeCell.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPMeCell: VPTableViewCell {
var item: VPMeItem? {
didSet {
titleLabel.text = item?.title
iconImageView.image = item?.icon
}
}
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView()
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorFFFFFF()
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.backgroundColor = .colorFFFFFF(alpha: 0.1)
vp_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPMeCell {
private func vp_setupUI() {
contentView.addSubview(iconImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(indicatorImageView)
iconImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(10)
make.width.height.equalTo(20)
make.top.equalToSuperview().offset(18)
}
titleLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(39)
}
indicatorImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().offset(-10)
}
}
}

View File

@ -0,0 +1,89 @@
//
// VPMeUserInfoCell.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
class VPMeUserInfoCell: VPTableViewCell {
var userInfo: VPUserInfo? {
didSet {
avatarImageView.vp_setImage(url: userInfo?.avator, placeholder: UIImage(named: "avatar_placeholder_icon_01"))
if let name = userInfo?.family_name, name.count > 0 {
nicknameLabel.text = name
} else {
nicknameLabel.text = "Visitor".localized
}
idLabel.text = "ID \(userInfo?.customer_id ?? "")"
}
}
private lazy var avatarImageView: VPImageView = {
let imageView = VPImageView()
imageView.layer.cornerRadius = 22
imageView.layer.masksToBounds = true
imageView.layer.borderWidth = 1
imageView.layer.borderColor = UIColor.colorFFFFFF().cgColor
return imageView
}()
private lazy var nicknameLabel: UILabel = {
let label = UILabel()
label.font = .fontBold(ofSize: 16)
label.textColor = .colorFFFFFF()
return label
}()
private lazy var idLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .colorB5B5B5()
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
bc_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension VPMeUserInfoCell {
private func bc_setupUI() {
contentView.addSubview(avatarImageView)
contentView.addSubview(nicknameLabel)
contentView.addSubview(idLabel)
avatarImageView.snp.makeConstraints { make in
make.left.equalToSuperview()
make.bottom.equalToSuperview()
make.width.height.equalTo(44)
make.top.equalToSuperview().offset(36)
}
nicknameLabel.snp.makeConstraints { make in
make.top.equalTo(avatarImageView).offset(3)
make.left.equalTo(avatarImageView.snp.right).offset(10)
make.right.lessThanOrEqualToSuperview().offset(-170)
}
idLabel.snp.makeConstraints { make in
make.left.equalTo(nicknameLabel)
make.bottom.equalTo(avatarImageView).offset(-3)
}
}
}

View File

@ -14,14 +14,18 @@ class VPCollectListViewController: VPViewController {
didSet {
allSelectedButton.isHidden = editState == .normal
if editState == .normal {
collectionView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(0)
if collectionView.superview != nil {
collectionView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(0)
}
}
isAllSelected = false
allSelectedButton.isSelected = false
} else {
collectionView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(30)
if collectionView.superview != nil {
collectionView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(30)
}
}
}
@ -101,6 +105,7 @@ class VPCollectListViewController: VPViewController {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.contentInset = .init(top: 5, left: 0, bottom: 0, right: 0)
collectionView.vp_addNormalEmpty()
collectionView.vp_addRefreshHeader(insetTop: collectionView.top) { [weak self] in
self?.handleHeaderRefresh(nil)
}
@ -146,7 +151,7 @@ class VPCollectListViewController: VPViewController {
if count > 0 {
requestCancelCollect()
} else {
VPToast.show(text: "kToastText1")
VPToast.show(text: "kToastText1".localized)
}
}
}

View File

@ -76,7 +76,7 @@ class VPMyListViewController: VPViewController {
return param
}()
private lazy var pageView: WMZPageView = {
private(set) lazy var pageView: WMZPageView = {
let y = UIScreen.statusBarHeight + 10
let height = UIScreen.height - y - UIScreen.customTabBarHeight
@ -120,6 +120,7 @@ class VPMyListViewController: VPViewController {
super.viewDidLoad()
vp_setupUI()
// pageView.selectMenu(with: 1)
}
override func viewWillAppear(_ animated: Bool) {
@ -131,6 +132,12 @@ class VPMyListViewController: VPViewController {
super.viewDidDisappear(animated)
self.editState = .normal
}
func showHistoryPage() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.pageView.selectMenu(with: 1)
}
}
}

View File

@ -20,6 +20,7 @@ class VPWatchHistoryViewController: VPViewController {
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.rowHeight = 118
tableView.vp_addNormalEmpty()
tableView.vp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
}

View File

@ -194,9 +194,7 @@ extension VPVideoPlayerCell: VPPlayerDelegate {
}
func vp_player(_ player: VPPlayer, playStateDidChanged state: VPPlayer.PlayState) {
if state == .playing {
self.coverImageView.isHidden = true
}
updateCoverShowState()
}
func vp_player(_ player: VPPlayer, loadStateDidChange state: VPPlayer.LoadState) {
@ -205,10 +203,19 @@ extension VPVideoPlayerCell: VPPlayerDelegate {
} else {
self.controlView.isLoading = false
}
updateCoverShowState()
}
func vp_playerReadyToPlay(_ player: VPPlayer) {
self.seekToTime(toTime: (videoInfo?.play_seconds ?? 0) / 1000)
}
private func updateCoverShowState() {
let loadState = self.player.loadState
let playState = self.player.playState
if isCurrent && (loadState == .playable || loadState == .playthroughOK) && (playState == .playing) {
self.coverImageView.isHidden = true
}
}
}

View File

@ -0,0 +1,20 @@
//
// UIScrollView+Empty.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
import EmptyDataSet_Swift
extension UIScrollView {
func vp_addNormalEmpty(image: UIImage? = UIImage(named: "empty_image_01"), title: String? = nil, titleColor: UIColor? = nil) {
self.emptyDataSetView { view in
view.image(image)
.isScrollAllowed(true)
.verticalOffset(-100)
}
}
}

View File

@ -8,16 +8,13 @@
import UIKit
class VPHUD: NSObject {
static func config() {
// SVProgressHUD.setDefaultMaskType(.clear)
}
static func show() {
// SVProgressHUD.setDefaultMaskType(.clear)
// SVProgressHUD.show()
SVProgressHUD.setDefaultMaskType(.clear)
SVProgressHUD.show()
}
static func dismiss() {
// SVProgressHUD.dismiss()
SVProgressHUD.dismiss()
}
}

View File

@ -17,6 +17,6 @@ class VPToast: NSObject {
static func show(text: String?) {
guard let text = text else { return }
// SPAPPTool.getKeyWindow()?.makeToast(text)
VPAppTool.keyWindow?.makeToast(text)
}
}

View File

@ -13,13 +13,35 @@ class VPLoginManager: NSObject {
static let manager = VPLoginManager()
private(set) var token: VPTokenModel?
private(set) var userInfo: VPUserInfo?
///token
private(set) var isRefreshingToken = false
override init() {
super.init()
token = UserDefaults.vp_object(forKey: kVPLoginTokenDefaultsKey, as: VPTokenModel.self)
userInfo = UserDefaults.vp_object(forKey: kVPLoginUserInfoDefaultsKey, as: VPUserInfo.self)
}
func setLoginToken(token: VPTokenModel?) {
self.token = token
// UserDefaults.jx_setObject(token, forKey: kSPLoginTokenDefaultsKey)
UserDefaults.vp_setObject(token, forKey: kVPLoginTokenDefaultsKey)
}
///
func updateUserInfo(completer: (() -> Void)?) {
VPUserAPI.requestUserInfo { [weak self] userInfo in
guard let self = self else { return }
if let userInfo = userInfo {
self.userInfo = userInfo
UserDefaults.vp_setObject(userInfo, forKey: kVPLoginUserInfoDefaultsKey)
}
completer?()
}
}
}

View File

@ -0,0 +1,67 @@
//
// VPUserInfo.swift
// Veloria
//
// Created by on 2025/5/26.
//
import UIKit
import SmartCodable
class VPUserInfo: VPModel, SmartCodable, NSSecureCoding {
var id: String?
var customer_id: String?
var is_guide_vip: String?
///
var is_tourist: Bool?
var family_name: String?
var giving_name: String?
var vip_end_time: TimeInterval?
var third_access_id: String?
var is_vip: Bool?
var coin_left_total: Int?
var send_coin_left_total: Int?
var vip_type: String?
var email: String?
var third_access_platform: String?
var ip_address: String?
var country_code: String?
var user_level: String?
var avator: String?
var sign_in_status: String?
var registered_days: String?
var ln: String?
var country: String?
required init() { }
static var supportsSecureCoding: Bool {
get {
return true
}
}
func encode(with coder: NSCoder) {
// coder.encode(id, forKey: "id")
// coder.encode(phone, forKey: "phone")
// coder.encode(userToken, forKey: "userToken")
// coder.encode(ipAddress, forKey: "ipAddress")
// coder.encode(audioNum, forKey: "audioNum")
// coder.encode(audioSeconds, forKey: "audioSeconds")
}
required init?(coder: NSCoder) {
super.init()
// id = coder.decodeObject(of: NSString.self, forKey: "id") as? String
// phone = coder.decodeObject(of: NSString.self, forKey: "phone") as? String
// userToken = coder.decodeObject(of: NSString.self, forKey: "userToken") as? String
// ipAddress = coder.decodeObject(of: NSString.self, forKey: "ipAddress") as? String
// audioNum = coder.decodeObject(of: NSNumber.self, forKey: "audioNum")?.intValue
// audioSeconds = coder.decodeObject(of: NSNumber.self, forKey: "audioSeconds")?.intValue
}
}

View File

@ -18,5 +18,8 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "original"
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "头像@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "头像@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "缺省页-内容为空-切图图层@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "缺省页-内容为空-切图图层@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@ -10,3 +10,4 @@
#import <ZFPlayer.h>
#import <KTVHTTPCache/KTVHTTPCache.h>
#import <HWPanModal/HWPanModal.h>
#import <SVProgressHUD/SVProgressHUD.h>

View File

@ -7,6 +7,7 @@
*/
"Home" = "Home";
"Me" = "Me";
"All" = "All";
"Drama Champions" = "Drama Champions";
"Explore" = "Explore";
@ -20,6 +21,15 @@
"My List" = "My List";
"History" = "History";
"Select All" = "Select All";
"Privacy Policy" = "Privacy Policy";
"User Agreement" = "User Agreement";
"About Us" = "About Us";
"Visitor" = "Visitor";
"Help Center" = "Help Center";
"Feedback History" = "Feedback History";
"Feedback" = "Feedback";
"Feedback Details" = "Feedback Details";
"Rewards" = "Rewards";
"kHomeTitleText" = "10,000+ addictive shorts await!";