W2A开发,各种统计

This commit is contained in:
zeng 2025-05-08 18:51:12 +08:00
parent 2bbfb16139
commit 94e047a0e9
47 changed files with 602 additions and 168 deletions

View File

@ -45,9 +45,20 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
UIApplication.shared.applicationIconBadgeNumber = 0
}
let userInfo = response.notification.request.content.userInfo
guard let userInfo: [String : Any] = response.notification.request.content.userInfo as? [String : Any] else {
completionHandler()
return
}
guard let model = SPOpenAppModel.deserialize(from: userInfo) else {
completionHandler()
return
}
SPStatAPI.requestStatApns(messageId: model.message_id ?? "", title: response.notification.request.content.title)
if let shortPlayId = model.short_play_id {
if let shortPlayId = userInfo["short_play_id"] as? String {
let vc = SPPlayerDetailViewController()
vc.shortPlayId = shortPlayId
SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)

View File

@ -30,9 +30,61 @@ extension SceneDelegate {
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard let webpageURL = userActivity.webpageURL else { return }
guard let query = webpageURL.query else { return }
spLog(message: query)
handleOpenAppMessage(webpageURL: webpageURL)
}
}
extension SceneDelegate {
static var hasOpenMessage = false
func handleOpenAppMessage(webpageURL: URL?) {
//URL
var statUrlStr: String?
var data: [String : Any]?
if let pasteStr = UIPasteboard.general.string {
UIPasteboard.general.string = nil
let tempArr = pasteStr.components(separatedBy: "?")
let query = tempArr.last
let tempData = query?.urlQuryToDictionary()
if tempData?["short_play_id"] != nil {
data = tempData
statUrlStr = pasteStr
}
}
if Self.hasOpenMessage {
return
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
Self.hasOpenMessage = false
}
Self.hasOpenMessage = true
if data == nil {
data = webpageURL?.query?.urlQuryToDictionary()
statUrlStr = webpageURL?.absoluteString
}
if let urlStr = statUrlStr {//
SPStatAPI.requestStatW2a(data: urlStr)
}
guard let data = data else { return }
guard let model = SPOpenAppModel.deserialize(from: data) else { return }
guard let shortPlayId = model.short_play_id, shortPlayId.count > 0 else { return }
let vc = SPPlayerDetailViewController()
vc.shortPlayId = shortPlayId
SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)
}
}

View File

@ -24,7 +24,7 @@ extension AppDelegate {
private func registAdjust() {
let config = ADJConfig(appToken: "mtogye6pmha8", environment: ADJEnvironmentProduction)
let config = ADJConfig(appToken: "7z38v0rvceww", environment: ADJEnvironmentProduction)
Adjust.initSdk(config)
}

View File

@ -11,6 +11,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var timer: Timer?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
@ -20,6 +21,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window = UIWindow(windowScene: windowScene)
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
if let webpageURL = session.stateRestorationActivity?.webpageURL {
handleOpenAppMessage(webpageURL: webpageURL)
}
//线
timer = Timer.scheduledTimer(timeInterval: 60 * 10, target: self, selector: #selector(handleOnLine), userInfo: nil, repeats: true)
}
func sceneDidDisconnect(_ scene: UIScene) {
@ -32,6 +40,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
SPStatAPI.requestEnterApp()
handleOpenAppMessage(webpageURL: nil)
}
func sceneWillResignActive(_ scene: UIScene) {
@ -42,14 +52,23 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
SPStatAPI.requestLeaveApp()
}
}
extension SceneDelegate {
@objc private func handleOnLine() {
SPStatAPI.requestStatOnLine()
}
}

View File

@ -33,6 +33,25 @@ extension String: SmartCodable {
}
extension String {
///url
func urlQuryToDictionary() -> [String : Any] {
let array = self.components(separatedBy: "&")
var tempDic: [String : Any] = [:]
array.forEach {
if let strRange = $0.range(of: "=") {
var key: String = String($0.prefix(upTo: strRange.upperBound))
key.removeLast()
var value: String = String($0.suffix(from: strRange.upperBound))
value = value.removingPercentEncoding ?? value
tempDic[key] = value
}
}
return tempDic
}
}
extension String {
///Size
func size(font: UIFont, size: CGSize = CGSize(width: CGFloat(MAXFLOAT), height: CGFloat(MAXFLOAT))) -> CGSize{

View File

@ -388,5 +388,13 @@ extension UIColor {
static func color362020(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x362020, alpha: alpha)
}
static func color7A7F96(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x7A7F96, alpha: alpha)
}
static func color967A7A(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x967A7A, alpha: alpha)
}
}

View File

@ -0,0 +1,17 @@
//
// SPOpenAppModel.swift
// MoviaBox
//
// Created by on 2025/5/8.
//
import UIKit
import SmartCodable
class SPOpenAppModel: SPModel, SmartCodable {
var id: String?
var message_id: String?
var short_play_id: String?
}

View File

@ -0,0 +1,75 @@
//
// SPStatAPI.swift
// MoviaBox
//
// Created by on 2025/5/8.
//
import UIKit
///
class SPStatAPI: NSObject {
///APP
static func requestEnterApp() {
var param = SPNetworkParameters(path: "/customer/enterTheApp")
param.isToast = false
param.isLoding = false
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
///APP
static func requestLeaveApp() {
var param = SPNetworkParameters(path: "/customer/leaveApp")
param.isToast = false
param.isLoding = false
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
///线
static func requestStatOnLine() {
var param = SPNetworkParameters(path: "/customer/onLine")
param.isToast = false
param.isLoding = false
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
///w2a
static func requestStatW2a(data: String) {
var param = SPNetworkParameters(path: "/w2aSelfAttribution")
param.isToast = false
param.isLoding = false
param.parameters = [
"data" : data
]
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
///
static func requestStatApns(messageId: String, title: String) {
var param = SPNetworkParameters(path: "/message/sendReport")
param.isToast = false
param.isLoding = false
param.parameters = [
"message_id" : messageId,
"title" : title
]
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
}

View File

@ -54,16 +54,20 @@ class SPNetworkReachabilityManager {
if path.status == .satisfied {
if self.isReachable == false {
print("++++++有网")
self.isReachable = true
NotificationCenter.default.post(name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
} else {
self.isReachable = true
}
self.isReachable = true
} else {
if self.isReachable == true {
print("++++++无网")
self.isReachable = false
NotificationCenter.default.post(name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
} else {
self.isReachable = false
}
self.isReachable = false
}
// if path.usesInterfaceType(.wifi) {

View File

@ -12,8 +12,9 @@ class SPHomeViewController: SPHomeChildController {
private lazy var viewModel: SPHomeViewModel = SPHomeViewModel()
private lazy var page = 1
private lazy var dataArr: [SPShortModel] = []
private lazy var requestGroup = DispatchGroup()
//MARK: UI
private lazy var logoImageView: UIImageView = {
@ -64,6 +65,7 @@ class SPHomeViewController: SPHomeChildController {
updateAllData(completer: nil)
// updateEmptyState()
_setupUI()
@ -89,7 +91,7 @@ class SPHomeViewController: SPHomeChildController {
}
override func handleFooterRefresh(_ completer: (() -> Void)?) {
requestListDataArr(page: self.page + 1) { [weak self] in
requestListDataArr(page: self.viewModel.page + 1) { [weak self] in
self?.collectionView.sp_endFooterRefreshing()
}
}
@ -135,6 +137,18 @@ extension SPHomeViewController {
updateAllData(completer: nil)
}
}
///
private func updateEmptyState() {
if SPNetworkReachabilityManager.manager.isReachable != true, viewModel.isEmptyData {
self.collectionView.showNoNetworkEmpty { [weak self] in
self?.updateAllData(completer: nil)
}
} else {
self.collectionView.hiddenEmpty()
}
}
}
@ -143,13 +157,13 @@ extension SPHomeViewController: UICollectionViewDelegate, UICollectionViewDataSo
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = SPHomeShortCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
cell.model = dataArr[indexPath.row]
cell.model = viewModel.dataArr[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArr.count
return viewModel.dataArr.count
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
@ -161,7 +175,7 @@ extension SPHomeViewController: UICollectionViewDelegate, UICollectionViewDataSo
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = self.dataArr[indexPath.row]
let model = viewModel.dataArr[indexPath.row]
let vc = SPPlayerDetailViewController()
vc.shortPlayId = model.short_play_id
@ -174,14 +188,25 @@ extension SPHomeViewController: UICollectionViewDelegate, UICollectionViewDataSo
extension SPHomeViewController {
private func updateAllData(completer: (() -> Void)?) {
requestModuleData()
requestPlayHistory()
requestListDataArr(page: 1) {
self.requestGroup.enter()
requestModuleData { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.enter()
requestPlayHistory { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.enter()
requestListDataArr(page: 1) { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.notify(queue: DispatchQueue.main) {
completer?()
}
}
private func requestModuleData() {
private func requestModuleData(completer: (() -> Void)? = nil) {
SPHomeAPI.requestHomeModuleData { [weak self] model in
guard let self = self else { return }
if let model = model {
@ -190,11 +215,13 @@ extension SPHomeViewController {
self.layout.headerReferenceSize = CGSize(width: kSPScreenWidth, height: SPHomeHeaderView.contentHeight(viewModel: self.viewModel))
self.collectionView.reloadData()
}
self.updateEmptyState()
completer?()
}
}
///
private func requestPlayHistory() {
private func requestPlayHistory(completer: (() -> Void)? = nil) {
SPVideoAPI.requestPlayHistoryList(page: 1) { [weak self] listModel in
guard let self = self else { return }
if let list = listModel?.list {
@ -202,6 +229,8 @@ extension SPHomeViewController {
self.layout.headerReferenceSize = CGSize(width: kSPScreenWidth, height: SPHomeHeaderView.contentHeight(viewModel: self.viewModel))
self.collectionView.reloadData()
}
self.updateEmptyState()
completer?()
}
}
@ -212,13 +241,14 @@ extension SPHomeViewController {
if let list = listModel?.list {
if page == 1 {
self.dataArr.removeAll()
self.viewModel.dataArr.removeAll()
}
self.dataArr += list
self.viewModel.dataArr += list
self.collectionView.reloadData()
self.page = page
self.viewModel.page = page
}
self.updateEmptyState()
completer?()
}
}

View File

@ -18,8 +18,11 @@ class SPHomeHeaderView: UICollectionReusableView {
stackView.removeAllArrangedSubview()
stackView.addArrangedSubview(bannerView)
bannerView.reloadData()
if let bannerData = moduleModel?.bannerData, bannerData.count > 0 {
stackView.addArrangedSubview(bannerView)
bannerView.reloadData()
}
if let historyList = viewModel?.playHistoryArr, historyList.count > 0 {
stackView.addArrangedSubview(playHistoryView)
@ -200,18 +203,27 @@ extension SPHomeHeaderView: ZKCycleScrollViewDelegate, ZKCycleScrollViewDataSour
extension SPHomeHeaderView {
static func contentHeight(viewModel: SPHomeViewModel) -> CGFloat {
var height = bannerHeight()
var height: CGFloat = 0
let moduleModel = viewModel.moduleModel
if let bannerData = moduleModel?.bannerData, bannerData.count > 0 {
height = height + bannerHeight()
}
///
if let historyList = viewModel.playHistoryArr, historyList.count > 0 {
height = height + SPHomePlayHistoryView.contentHeight(dataArr: historyList) + 25
if height > 0 {
height = height + 25
}
height = height + SPHomePlayHistoryView.contentHeight(dataArr: historyList)
}
///
if let list = moduleModel?.nineSquare?.list, list.count > 0 {
height = height + SPHomeExploreView.contentHeight(dataArr: list) + 25
if height > 0 {
height = height + 25
}
height = height + SPHomeExploreView.contentHeight(dataArr: list)
}
// height = height + SPHomeTrendingView.contentHeight(dataArr: moduleModel?.bannerData ?? []) + 25

View File

@ -24,6 +24,7 @@ class SPSearchAssociativeView: UIView {
tableView.separatorInset = .init(top: 0, left: 16, bottom: 0, right: 16)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
tableView.keyboardDismissMode = .onDrag
tableView.showNormalEmpty(image: UIImage(named: "empty_image_03"))
SPSearchAssociativeCell.registerCell(tableView: tableView)
return tableView
}()

View File

@ -9,11 +9,20 @@ import UIKit
class SPHomeViewModel: NSObject {
lazy var page = 1
lazy var dataArr: [SPShortModel] = []
var moduleModel: SPHomeModuleModel?
///
var playHistoryArr: [SPShortModel]?
var isEmptyData: Bool {
if dataArr.count > 0 || (playHistoryArr?.count ?? 0) > 0 || moduleModel != nil {
return false
}
return true
}
}

View File

@ -34,6 +34,7 @@ class SPCollectListViewController: SPMyListChildViewController {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.contentInset = .init(top: 10, left: 0, bottom: 0, right: 0)
collectionView.showNormalEmpty()
collectionView.sp_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
self?.handleHeaderRefresh(nil)
}
@ -148,11 +149,6 @@ extension SPCollectListViewController: UICollectionViewDelegate, UICollectionVie
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.collectionView.addNormalEmpty()
} else {
self.collectionView.hiddenEmpty()
}
return count
}

View File

@ -65,6 +65,13 @@ class SPMyListViewController: SPViewController {
return pageView
}()
private(set) lazy var wmPageView: WMPageController = {
let pageView = WMPageController()
pageView.delegate = self
pageView.dataSource = self
return pageView
}()
private lazy var editButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "delete_icon_01"), for: .normal)
@ -145,9 +152,11 @@ class SPMyListViewController: SPViewController {
extension SPMyListViewController {
private func _setupUI() {
addChild(pageView)
// addChild(self.wmPageView)
view.addSubview(lineView)
view.addSubview(pageView.view)
// view.addSubview(wmPageView.view)
view.addSubview(editButton)
view.addSubview(cancelButton)
// view.addSubview(allSelectedButton)
@ -182,6 +191,40 @@ extension SPMyListViewController {
}
}
//MARK: -------------- WMPageControllerDelegate & WMPageControllerDataSource --------------
extension SPMyListViewController: WMPageControllerDelegate, WMPageControllerDataSource {
func pageController(_ pageController: WMPageController, preferredFrameForContentView contentView: WMScrollView) -> CGRect {
let y = kSPStatusbarHeight + 10 + 35
return .init(x: 0, y: kSPStatusbarHeight + 10 + 35, width: kSPScreenWidth, height: kSPScreenHeight - y - kSPTabBarHeight)
}
func pageController(_ pageController: WMPageController, preferredFrameFor menuView: WMMenuView) -> CGRect {
return .init(x: 0, y: kSPStatusbarHeight + 10, width: kSPScreenWidth, height: 35)
}
func numbersOfChildControllers(in pageController: WMPageController) -> Int {
return titles.count
}
func pageController(_ pageController: WMPageController, titleAt index: Int) -> String {
return titles[index]
}
func pageController(_ pageController: WMPageController, viewControllerAt index: Int) -> UIViewController {
self.viewControllers[index]
}
func pageController(_ pageController: WMPageController, didEnter viewController: UIViewController, withInfo info: [AnyHashable : Any]) {
if pageController.selectIndex == 0 {
self.editButton.isHidden = false
} else {
self.editButton.isHidden = true
}
}
}
//MARK: -------------- JYPageControllerDelegate & JYPageControllerDataSource --------------
extension SPMyListViewController: JYPageControllerDelegate, JYPageControllerDataSource {

View File

@ -32,6 +32,7 @@ class SPPlayHistoryViewController: SPMyListChildViewController {
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.showNormalEmpty()
collectionView.contentInset = .init(top: 10, left: 0, bottom: 0, right: 0)
collectionView.sp_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
self?.handleHeaderRefresh(nil)
@ -143,13 +144,6 @@ extension SPPlayHistoryViewController: UICollectionViewDelegate, UICollectionVie
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.collectionView.addNormalEmpty()
} else {
self.collectionView.hiddenEmpty()
}
return count
}

View File

@ -198,6 +198,8 @@ extension SPPlayerDetailViewController {
guard let self = self else { return }
self.play()
}
//
SPLoginManager.manager.updateUserInfo(completer: nil)
default:
break

View File

@ -19,6 +19,7 @@ class SPCoinOrderRecordViewController: SPViewController {
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 70
tableView.showNormalEmpty()
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
tableView.sp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
@ -76,11 +77,6 @@ extension SPCoinOrderRecordViewController: UITableViewDelegate, UITableViewDataS
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.tableView.addNormalEmpty()
} else {
self.tableView.hiddenEmpty()
}
return count
}

View File

@ -19,6 +19,7 @@ class SPConsumptionRecordsViewController: SPViewController {
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 72
tableView.showNormalEmpty()
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
tableView.sp_addRefreshHeader { [weak self] in
@ -82,11 +83,6 @@ extension SPConsumptionRecordsViewController: UITableViewDelegate, UITableViewDa
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.tableView.addNormalEmpty()
} else {
self.tableView.hiddenEmpty()
}
return count
}
}

View File

@ -19,6 +19,7 @@ class SPRewardCoinsViewController: SPViewController {
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 96
tableView.showNormalEmpty()
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
tableView.sp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
@ -84,11 +85,6 @@ extension SPRewardCoinsViewController: UITableViewDelegate, UITableViewDataSourc
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.tableView.addNormalEmpty()
} else {
self.tableView.hiddenEmpty()
}
return count
}
}

View File

@ -18,6 +18,7 @@ class SPVIPOrderRecordViewController: SPViewController {
tableView.delegate = self
tableView.dataSource = self
tableView.rowHeight = 74
tableView.showNormalEmpty()
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: kSPTabbarSafeBottomMargin, right: 0)
tableView.sp_addRefreshHeader { [weak self] in
self?.handleHeaderRefresh(nil)
@ -75,11 +76,6 @@ extension SPVIPOrderRecordViewController: UITableViewDelegate, UITableViewDataSo
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = self.dataArr.count
if count == 0 {
self.tableView.addNormalEmpty()
} else {
self.tableView.hiddenEmpty()
}
return count
}

View File

@ -1,92 +0,0 @@
//
// SPEmptyState.swift
// MoviaBox
//
// Created by Overseas on 2025/4/19.
//
import UIKit
import EmptyStateKit
struct SPEmptyParameters {
// var title: String = ""
// var titleFont: UIFont = UIFont.text_md
// var titleColor: UIColor = UIColor.system_text_secondary_300
var image: UIImage? = UIImage(named: "empty_image_01")
// var buttonTitle: String?
}
enum SPEmptyState {
case normail(parameters: SPEmptyParameters)
}
extension SPEmptyState: CustomState {
var image: UIImage? {
switch self {
case .normail(let parameters):
return parameters.image
}
}
var title: String? {
switch self {
case .normail(_):
return nil
}
}
// var titleButton: String? {
// switch self {
// case .normail(let parameters):
// return parameters.buttonTitle
// }
}
extension SPEmptyState {
var format: EmptyStateFormat {
var format = EmptyStateFormat()
format.backgroundColor = .clear
format.imageSize = self.image?.size ?? .zero
format.animation = nil
format.verticalMargin = -50
//
// format.buttonWidth = 107
// format.buttonTopMargin = 10
// format.buttonColor = .system_fill_primary_100
// format.buttonAttributes = [
// .font: UIFont.text_md,
// .foregroundColor: UIColor.system_text_secondary_500
// ]
//
// switch self {
// case .normail(let p):
// format.titleAttributes = [
// .font: p.titleFont,
// .foregroundColor: p.titleColor
// ]
//
//
// case .login(let p):
// format.titleAttributes = [
// .font: p.titleFont,
// .foregroundColor: p.titleColor
// ]
//
//
// }
return format
}
}

View File

@ -0,0 +1,90 @@
//
// SPNoNetworkEmptyView.swift
// MoviaBox
//
// Created by on 2025/5/8.
//
import UIKit
class SPNoNetworkEmptyView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: kSPScreenWidth, height: 100)
}
var clickButton: (() -> Void)?
//MARK: UI
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "empty_image_02"))
return imageView
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 16)
label.textColor = .color967A7A()
label.text = "kNoNetworkTip_01".localized
return label
}()
private lazy var button: UIButton = {
let button = JXButton(type: .custom)
button.layer.cornerRadius = 17
button.layer.masksToBounds = true
button.layer.borderWidth = 1
button.layer.borderColor = UIColor.colorFFFFFF().cgColor
button.jx_font = .fontRegular(ofSize: 18)
button.setTitleColor(.colorFFFFFF(), for: .normal)
button.setTitle("Retry".localized, for: .normal)
button.leftAndRightMargin = 33
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func handleButton() {
self.clickButton?()
}
}
extension SPNoNetworkEmptyView {
private func _setupUI() {
addSubview(iconImageView)
addSubview(titleLabel)
addSubview(button)
iconImageView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.centerX.equalToSuperview()
}
titleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(iconImageView.snp.bottom)
}
button.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(titleLabel.snp.bottom).offset(28)
make.height.equalTo(34)
make.bottom.equalToSuperview()
}
}
}

View File

@ -6,18 +6,47 @@
//
import UIKit
import EmptyDataSet_Swift
extension UIScrollView {
func addNormalEmpty() {
let parameters = SPEmptyParameters()
let emptyState = SPEmptyState.normail(parameters: parameters)
self.emptyState.format = emptyState.format
self.emptyState.show(emptyState)
///
func showNormalEmpty(image: UIImage? = UIImage(named: "empty_image_01"), title: String? = nil, titleColor: UIColor? = nil) {
self.emptyDataSetView { view in
view.image(image)
.isScrollAllowed(true)
.verticalOffset(-100)
}
}
///
func showNoNetworkEmpty(buttonHandle: (() -> Void)? = nil) {
let customView = SPNoNetworkEmptyView()
customView.clickButton = {
buttonHandle?()
}
self.emptyDataSetView { view in
view.isScrollAllowed(true)
.customView(customView)
.verticalOffset(-70)
}
self.reloadEmptyDataSet()
}
func hiddenEmpty() {
self.emptyState.hide()
self.emptyDataSetView { view in
view.customView(nil)
view.image(nil)
view.titleLabelString(nil)
}
self.reloadEmptyDataSet()
}
}

View File

@ -10,7 +10,7 @@
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:moviaboxapp.go.link</string>
<string>applinks:moviaapp.go.link</string>
<string>applinks:www.moviatv.com</string>
</array>
<key>keychain-access-groups</key>

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "image 38@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "image 38@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: 67 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -19,7 +19,7 @@
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>MoviaTV</string>
<string>moviaapp</string>
</array>
</dict>
<dict/>

View File

@ -92,6 +92,7 @@
"Unlock now for" = "Unlock now for";
"Unlock the previous episode" = "Unlock the previous episode";
"Purchase Single Episode" = "Purchase Single Episode";
"Retry" = "Retry";
///没有可恢复购买
"kToastMessage_01" = "There are no recoverable in-app purchases.";
@ -109,4 +110,5 @@
"kStoreTipTitle" = "Related terms and conditions:";
"kStoreTipText" = "1. Coins can only be used within this application.2. Payment: The purchase will be charged to your iTunes account. 3. Renewal: Your Apple iTunes account will be charged within 24 hours before the expiration and the subscription period will be extended for another subscription cycle upon successful deduction.4. Cancellation: To cancel the subscription renewal, please turn off the automatic renewal function in the iTunes/Apple ID settings at least 24 hours before the current subscription period expires. If canceled within the last 24 hours before expiration, a subscription fee will still be charged. 5. Payment successful but recharge not taking effect for an extended period? Click here to refresh or send an email to: cs.jiaer.developer@icloud.com. 6. Manage your subscriptions: You can view, change, or cancel your subscriptions. ";
"kDeleteAccountCheckText" = "I accept the deletion risk and agree to delete my account";
"kNoNetworkTip_01" = "Connection error. Please try again!";

View File

@ -7,7 +7,7 @@
import UIKit
public class JYScrollView: UITableView,UIGestureRecognizerDelegate {
public class JYScrollView: UITableView {
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return gestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder()) && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.classForCoder())

View File

@ -26,7 +26,7 @@ target 'MoviaBox' do
pod 'KTVHTTPCache' #视频缓存
pod 'HWPanModal' #底部弹出控制器
pod 'Kingfisher' #图片加载
pod 'EmptyStateKit' #空数据页面
pod 'EmptyDataSet-Swift' #空数据页面
pod 'ReachabilitySwift' #网络状态监控
pod 'WMZPageController' #分页控制器
pod 'SVProgressHUD' #HUD

View File

@ -6,7 +6,7 @@ PODS:
- AdjustSignature (3.35.2)
- Alamofire (5.10.2)
- CocoaAsyncSocket (7.6.5)
- EmptyStateKit (1.1.0)
- EmptyDataSet-Swift (5.0.0)
- HWPanModal (0.9.9)
- Kingfisher (8.3.2)
- KTVHTTPCache (3.0.2):
@ -38,7 +38,7 @@ PODS:
DEPENDENCIES:
- Adjust
- EmptyStateKit
- EmptyDataSet-Swift
- HWPanModal
- Kingfisher
- KTVHTTPCache
@ -58,12 +58,12 @@ SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- Adjust
- AdjustSignature
- EmptyDataSet-Swift
- Kingfisher
- ZFPlayer
trunk:
- Alamofire
- CocoaAsyncSocket
- EmptyStateKit
- HWPanModal
- KTVHTTPCache
- MJRefresh
@ -82,7 +82,7 @@ SPEC CHECKSUMS:
AdjustSignature: 23b9e5d4adcadffc303bb6b410fde617dd88504f
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
EmptyStateKit: dc41e9ce5c6089f67a49d063bce73ade9f2ba73f
EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
KTVHTTPCache: 5711692cdf9a5ecfe829b1e16577deb3ffe3dc86
@ -98,6 +98,6 @@ SPEC CHECKSUMS:
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
PODFILE CHECKSUM: 2a79f81260b8df4d6be58f4acb217732b1cd49ab
PODFILE CHECKSUM: 1e8174e48a7218cf3eed0a059ee987d0638ab131
COCOAPODS: 1.16.2

View File

@ -0,0 +1,27 @@
{
"buildCommand" : {
"command" : "build",
"skipDependencies" : false,
"style" : "buildOnly"
},
"configuredTargets" : [
],
"continueBuildingAfterErrors" : false,
"dependencyScope" : "workspace",
"enableIndexBuildArena" : false,
"hideShellScriptEnvironment" : false,
"parameters" : {
"action" : "build",
"overrides" : {
}
},
"qos" : "default",
"schemeCommand" : "launch",
"showNonLoggedProgress" : true,
"useDryRun" : false,
"useImplicitDependencies" : false,
"useLegacyBuildLocations" : false,
"useParallelTargets" : true
}

View File

@ -0,0 +1 @@
{"client":{"name":"basic","version":0,"file-system":"device-agnostic","perform-ownership-analysis":"no"},"targets":{"":["<all>"]},"commands":{"<all>":{"tool":"phony","inputs":["<WorkspaceHeaderMapVFSFilesWritten>"],"outputs":["<all>"]},"P0:::Gate WorkspaceHeaderMapVFSFilesWritten":{"tool":"phony","inputs":[],"outputs":["<WorkspaceHeaderMapVFSFilesWritten>"]}}}

View File

@ -0,0 +1 @@
Target dependency graph (0 target)

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgXR+Zedc3wF8TuJG6
oDKxJbcDqDLJDEx/ExfQKT5GMc+gCgYIKoZIzj0DAQehRANCAASNWCeIL6ELCoVo
igAm8yXBuraOuuQdbPBmJnFwauYq3pFZt3RiTKZxXLs3TAHXuuK6jlUMNZ0SsyIf
epUu2+ms
-----END PRIVATE KEY-----

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgIAZqlqn64s0g/cLK
HYv57T2s5WVllSrs6yyZeL0F1UegCgYIKoZIzj0DAQehRANCAATkoC81el02PBYY
0NtOiD6ZABY5yidgX7BLdfhIR4YABXRMHqgf5cC1wJeMFbuPimAhFyQUOjz4U3Pu
VYJ/uVUy
-----END PRIVATE KEY-----

View File

@ -0,0 +1,2 @@
Issuer ID5a4eda78-a1ec-4e14-b9e1-438e0c6b65e0
共享秘钥ef592c2f58e544f7b64c9e8e3fbdd918

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgcGOb1W3PIj7aFHCV
gklnxGt7MUXIwO8NGjxmYugvNqygCgYIKoZIzj0DAQehRANCAAT4GJv/flDfYucP
klNWB0Gbl4SC8g1aRQWsjlH5ZhTRCADsQMchLv1hfLluggscZ9/mjooXqxeIa9dA
kCEe5BH5
-----END PRIVATE KEY-----

View File

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgybyT4E9RcVHpanWn
rWHRf50TR8iio6SZ2s2oploN4JegCgYIKoZIzj0DAQehRANCAAQ4gRcELlsyQecH
Czr4kIVXbrD9oOk/ibNsSq7QpHSHgs8T+Ev08miNqPc9fMxP9KkIVgTxdKNdVkXg
g7cByXj5
-----END PRIVATE KEY-----

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyAT78NBZpoE2kazUeiWOBKuQNczOEtPPbU</string>
<key>GCM_SENDER_ID</key>
<string>157639867903</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.thimratv.app</string>
<key>PROJECT_ID</key>
<string>movia-c4ef0</string>
<key>STORAGE_BUCKET</key>
<string>movia-c4ef0.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:157639867903:ios:63bd57e22b7c906450fbca</string>
</dict>
</plist>