diff --git a/Veloria.xcodeproj/project.pbxproj b/Veloria.xcodeproj/project.pbxproj index c064303..b9a9be2 100644 --- a/Veloria.xcodeproj/project.pbxproj +++ b/Veloria.xcodeproj/project.pbxproj @@ -140,6 +140,9 @@ BF3339172E2624B800B10F76 /* VPAppOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339162E2624AF00B10F76 /* VPAppOpenAdManager.swift */; }; BF33391B2E26339300B10F76 /* VPAppOpenAdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33391A2E26339300B10F76 /* VPAppOpenAdViewController.swift */; }; BF33391F2E264BE200B10F76 /* VPBannerAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */; }; + BF3339212E28860A00B10F76 /* VPDiscountsVipAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339202E28860900B10F76 /* VPDiscountsVipAlertView.swift */; }; + BF3339232E289B9400B10F76 /* VPApplovinBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339222E289B9400B10F76 /* VPApplovinBannerAd.swift */; }; + BF3339252E28D60700B10F76 /* VPDiscountsVipCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3339242E28D60700B10F76 /* VPDiscountsVipCell.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 */; }; @@ -432,6 +435,9 @@ BF3339162E2624AF00B10F76 /* VPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAppOpenAdManager.swift; sourceTree = ""; }; BF33391A2E26339300B10F76 /* VPAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAppOpenAdViewController.swift; sourceTree = ""; }; BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPBannerAdManager.swift; sourceTree = ""; }; + BF3339202E28860900B10F76 /* VPDiscountsVipAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDiscountsVipAlertView.swift; sourceTree = ""; }; + BF3339222E289B9400B10F76 /* VPApplovinBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPApplovinBannerAd.swift; sourceTree = ""; }; + BF3339242E28D60700B10F76 /* VPDiscountsVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPDiscountsVipCell.swift; sourceTree = ""; }; BF5E75AE2DE4632200DE9DFE /* VPAboutUsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAboutUsViewController.swift; sourceTree = ""; }; BF5E75B02DE4656600DE9DFE /* VPCampaignWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCampaignWebViewController.swift; sourceTree = ""; }; BF5E75B22DE465EA00DE9DFE /* Dictionary+SPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+SPAdd.swift"; sourceTree = ""; }; @@ -1242,6 +1248,7 @@ isa = PBXGroup; children = ( BF33391E2E264BE200B10F76 /* VPBannerAdManager.swift */, + BF3339222E289B9400B10F76 /* VPApplovinBannerAd.swift */, ); path = Banner; sourceTree = ""; @@ -1407,6 +1414,8 @@ BFF5B2362DF013410044227A /* VPAlertWindowManager.swift */, BFCCE13F2E000ACE00EDE165 /* VPAnpsAlertView.swift */, BF692ABE2E06934D00A5C2DA /* VPVersionUpdateAlertView.swift */, + BF3339202E28860900B10F76 /* VPDiscountsVipAlertView.swift */, + BF3339242E28D60700B10F76 /* VPDiscountsVipCell.swift */, ); path = Alert; sourceTree = ""; @@ -1622,6 +1631,7 @@ BF0FA7B82DE44FCC00C9E5F2 /* VPWebViewController.swift in Sources */, BF0FA72A2DDC922F00C9E5F2 /* VPHomeRecommandCell.swift in Sources */, BF0FA7322DDEBD6400C9E5F2 /* AppDelegate+Config.swift in Sources */, + BF3339232E289B9400B10F76 /* VPApplovinBannerAd.swift in Sources */, BF5E75D52DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift in Sources */, BF3339042E249F4B00B10F76 /* VPAdManager.swift in Sources */, BF3339072E24A2DC00B10F76 /* VPRewardedAdManager.swift in Sources */, @@ -1663,6 +1673,7 @@ BF0FA7A32DE1AB1800C9E5F2 /* VPWatchHistoryCell.swift in Sources */, BFF5B24C2DF052E80044227A /* VPLoginManager+fb.swift in Sources */, BF0FA76D2DE053C100C9E5F2 /* VPScrollView.swift in Sources */, + BF3339212E28860A00B10F76 /* VPDiscountsVipAlertView.swift in Sources */, BFF5B2202DEEE2C50044227A /* VPLoginContentView.swift in Sources */, 1B056E5D2DDACD8E007EE38D /* UIFont+VPAdd.swift in Sources */, BF0FA7282DDC91F800C9E5F2 /* VPCollectionViewCell.swift in Sources */, @@ -1796,6 +1807,7 @@ BF0FA7772DE0735800C9E5F2 /* VPSearchInputView.swift in Sources */, BFF5AFB62DE803A30044227A /* VPVipPrivilegeItemView.swift in Sources */, BFC676C22E13EBED006659E5 /* VPAdPlayerControlView.swift in Sources */, + BF3339252E28D60700B10F76 /* VPDiscountsVipCell.swift in Sources */, BFF5B2542DF132540044227A /* VPConsumptionRecordsModel.swift in Sources */, BFF5AFB82DE832580044227A /* VPVipBuyCell.swift in Sources */, BFF5B22E2DEFEEAF0044227A /* VPDeleteAccountContentView.swift in Sources */, diff --git a/Veloria/Base/Extension/UIColor+VPAdd.swift b/Veloria/Base/Extension/UIColor+VPAdd.swift index 2320763..80e0d28 100644 --- a/Veloria/Base/Extension/UIColor+VPAdd.swift +++ b/Veloria/Base/Extension/UIColor+VPAdd.swift @@ -337,7 +337,32 @@ extension UIColor { static func colorA3F0DE(alpha: CGFloat = 1) -> UIColor { return UIColor(rgb: 0xA3F0DE, alpha: alpha) } + static func color101010(alpha: CGFloat = 1) -> UIColor { return UIColor(rgb: 0x101010, alpha: alpha) } + + static func color95ECD4(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x95ECD4, alpha: alpha) + } + + static func colorF2FFF6(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xF2FFF6, alpha: alpha) + } + + static func colorC5F8FB(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xC5F8FB, alpha: alpha) + } + + static func colorC9DEFF(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xC9DEFF, alpha: alpha) + } + + static func color78B3B3(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x78B3B3, alpha: alpha) + } + + static func color7698CF(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x7698CF, alpha: alpha) + } } diff --git a/Veloria/Base/Networking/API/VPWalletAPI.swift b/Veloria/Base/Networking/API/VPWalletAPI.swift index 06840a8..d561eb3 100644 --- a/Veloria/Base/Networking/API/VPWalletAPI.swift +++ b/Veloria/Base/Networking/API/VPWalletAPI.swift @@ -25,6 +25,21 @@ class VPWalletAPI { } } + ///获取优惠支付模版 + static func requestDiscountPayTemplate(shortPlayId: String, videoId: String, isLoding: Bool = false, completer: ((_ model: VPPayTemplateModel?) -> Void)?) { + var param = VPNetworkParameters(path: "/paySettingsDiscount") + param.method = .get + param.isLoding = isLoding + param.parameters = [ + "short_play_id" : shortPlayId, + "short_play_video_id" : videoId + ] + + VPNetwork.request(parameters: param) { (response: VPNetworkResponse) in + completer?(response.data) + } + } + ///金币解锁视频 static func requestCoinUnlockVideo(shortPlayId: String, videoId: String, completer: ((_ model: VPVideoUnlockModel?) -> Void)?) { diff --git a/Veloria/Class/Me/Controller/VPMeViewController.swift b/Veloria/Class/Me/Controller/VPMeViewController.swift index f2adb3e..44c9985 100644 --- a/Veloria/Class/Me/Controller/VPMeViewController.swift +++ b/Veloria/Class/Me/Controller/VPMeViewController.swift @@ -130,7 +130,9 @@ extension VPMeViewController { guard VPRewardedAdManager.manager.isReady else { return } needShowRewardedAd = false - VPRewardedAdManager.manager.showAd() + let manager = VPRewardedAdManager.manager + manager.statScene = .me + manager.showAd() } diff --git a/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift b/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift index ee67b20..30c4a84 100644 --- a/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift +++ b/Veloria/Class/Player/Controller/VPDetailPlayerViewController.swift @@ -151,10 +151,10 @@ class VPDetailPlayerViewController: VPVideoPlayerViewController { override func handleBack() { super.handleBack() - if VPLoginManager.manager.userInfo?.user_level == .ad { - if VPRewardedAdManager.manager.isReady { - VPRewardedAdManager.manager.showAd() - } + if VPLoginManager.manager.userInfo?.user_level == .ad, VPRewardedAdManager.manager.isReady { + VPRewardedAdManager.manager.videoInfo = self.viewModel.currentPlayer?.videoInfo + VPRewardedAdManager.manager.statScene = .detail + VPRewardedAdManager.manager.showAd() } } @@ -283,6 +283,7 @@ extension VPDetailPlayerViewController { private func onRecommandView() { let view = VPDetailRecommandView() + view.currentVideoInfo = self.viewModel.currentPlayer?.videoInfo view.dataArr = recommandList view.clickCloseButton = { [weak self] in self?.handleBack() diff --git a/Veloria/Class/Player/Model/VPVideoAdModel.swift b/Veloria/Class/Player/Model/VPVideoAdModel.swift index dbf7867..07de29e 100644 --- a/Veloria/Class/Player/Model/VPVideoAdModel.swift +++ b/Veloria/Class/Player/Model/VPVideoAdModel.swift @@ -21,6 +21,7 @@ class VPVideoAdModel: VPModel, SmartCodable { var shortPlayInfo: VPShortModel? var revolution: VPShortModel.VideoRevolution? + ///另一个APP信息 var site_info: VPVideoAdSiteInfoModel? } diff --git a/Veloria/Class/Player/View/VPDetailRecommandView.swift b/Veloria/Class/Player/View/VPDetailRecommandView.swift index 6f1f21a..18455f8 100644 --- a/Veloria/Class/Player/View/VPDetailRecommandView.swift +++ b/Veloria/Class/Player/View/VPDetailRecommandView.swift @@ -25,6 +25,14 @@ class VPDetailRecommandView: HWPanModalContentView { } } + var currentVideoInfo: VPVideoInfoModel? { + didSet { + if VPLoginManager.manager.userInfo?.user_level == .ad { + bannerAd.videoInfo = currentVideoInfo + } + } + } + var clickCloseButton: (() -> Void)? var clickLookButton: ((_ model: VPShortModel) -> Void)? diff --git a/Veloria/Class/Player/View/VPPlayerRechargeView.swift b/Veloria/Class/Player/View/VPPlayerRechargeView.swift index c5bf0d0..12a5b51 100644 --- a/Veloria/Class/Player/View/VPPlayerRechargeView.swift +++ b/Veloria/Class/Player/View/VPPlayerRechargeView.swift @@ -13,12 +13,14 @@ class VPPlayerRechargeView: HWPanModalContentView { didSet { vipView.shortPlayId = shortPlayId coinsView.shortPlayId = shortPlayId + requestDiscountRechargeData() } } var videoId: String? { didSet { vipView.videoId = videoId coinsView.videoId = videoId + requestDiscountRechargeData() } } @@ -77,6 +79,8 @@ class VPPlayerRechargeView: HWPanModalContentView { var buyFinishBlock: (() -> Void)? var vipBuyFinishBlock: (() -> Void)? + private var discountPayTemplateModel: VPPayTemplateModel? + //MARK: UI属性 private lazy var bgView: UIImageView = { let imageView = UIImageView(image: UIImage(named: "bg_image_01")) @@ -213,6 +217,7 @@ class VPPlayerRechargeView: HWPanModalContentView { updateCoin() + // requestRechargeData() } @@ -222,8 +227,13 @@ class VPPlayerRechargeView: HWPanModalContentView { @objc private func handleCloseButton() { +// let payTemplateModel = self.discountPayTemplateModel + self.dismiss(animated: true) { - +// if let payTemplateModel = payTemplateModel, payTemplateModel.list_sub_vip?.isEmpty == false { +// let alert = VPDiscountsVipAlertView(payTemplateModel: payTemplateModel) +// alert.show() +// } } } @@ -381,4 +391,19 @@ extension VPPlayerRechargeView { } + + ///获取优惠数据 + private func requestDiscountRechargeData() { +// guard let shortPlayId = self.shortPlayId else { return } +// guard let videoId = self.videoId else { return } +// +// VPWalletAPI.requestDiscountPayTemplate(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in +// guard let self = self else { return } +// if let model = model { +// self.discountPayTemplateModel = model +// } +// } + + } + } diff --git a/Veloria/Class/Player/ViewModel/VPVideoPlayViewModel.swift b/Veloria/Class/Player/ViewModel/VPVideoPlayViewModel.swift index 9167aea..13f4134 100644 --- a/Veloria/Class/Player/ViewModel/VPVideoPlayViewModel.swift +++ b/Veloria/Class/Player/ViewModel/VPVideoPlayViewModel.swift @@ -139,10 +139,10 @@ extension VPVideoPlayViewModel { break case .success: - videoInfo.is_lock = false - finish?() - - VPLoginManager.manager.updateUserInfo(completer: nil) + VPLoginManager.manager.updateUserInfo { + videoInfo.is_lock = false + finish?() + } default: break diff --git a/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift b/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift index cb8b9ed..5ad6435 100644 --- a/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift +++ b/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift @@ -31,6 +31,22 @@ class VPPayTemplateItem: VPModel, SmartCodable { return "year_short_type".localized } } + + func getTextV2() -> String { + switch self { + case .week: + return "veloria_week_text".localized + + case .month: + return "veloria_month_text".localized + + case .quarter: + return "veloria_quarter_text".localized + + case .year: + return "veloria_year_text".localized + } + } } enum SizeType: String, SmartCaseDefaultable { diff --git a/Veloria/Libs/AdManager/AppOpen/VPAppOpenAdManager.swift b/Veloria/Libs/AdManager/AppOpen/VPAppOpenAdManager.swift index 46737e5..d8b6336 100644 --- a/Veloria/Libs/AdManager/AppOpen/VPAppOpenAdManager.swift +++ b/Veloria/Libs/AdManager/AppOpen/VPAppOpenAdManager.swift @@ -79,6 +79,8 @@ class VPAppOpenAdManager: NSObject { private var timeOutTimer: Timer? + private var adsDate: Date? + deinit { NotificationCenter.default.removeObserver(self) } @@ -93,7 +95,7 @@ class VPAppOpenAdManager: NSObject { if self.appOpenAd?.isReady == true { self.showAd() } else { - self.timeOutTimer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false) + self.timeOutTimer = Timer.scheduledTimer(timeInterval: 30, target: YYWeakProxy(target: self), selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false) self.needAutoShow = true self.loadAd() @@ -122,6 +124,7 @@ class VPAppOpenAdManager: NSObject { cleanTimer() let error = NSError(domain: "time-out", code: -1) + requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) self.delegate?.appOpenAdManager?(adManager: self, didOtherFail: error) } @@ -134,6 +137,7 @@ class VPAppOpenAdManager: NSObject { appOpenAd = nil delegate = nil isShowing = false + self.adsDate = nil } } @@ -152,6 +156,7 @@ extension VPAppOpenAdManager: VPAppOpenAdDelegate { } ///广告加载成功 func appOpenAdDidLoadFinish(ad: VPAppOpenAd) { + cleanTimer() self.isLoading = false self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self) @@ -163,13 +168,13 @@ extension VPAppOpenAdManager: VPAppOpenAdDelegate { } ///广告展示失败 func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error) { - cleanTimer() requestStatAd(type: "show_failed", errorMsg: error.localizedDescription) self.delegate?.appOpenAdManager?(adManager: self, didDisplayFail: error) clean() } ///广告被展示 func appOpenAdDidShow(ad: VPAppOpenAd) { + adsDate = Date() requestStatAd(type: "start", errorMsg: nil) self.delegate?.appOpenAdManagerDidShow?(adManager: self) } @@ -192,8 +197,17 @@ extension VPAppOpenAdManager { private func requestStatAd(type: String, errorMsg: String?) { guard let appOpenAd = self.appOpenAd else { return } + var seconds = 0 + if let adsDate = self.adsDate { + if type == "click" || type == "close" { + seconds = Int(Date().timeIntervalSince(adsDate)) + } + } + + let model = VPStatAdModel() model.type = type + model.view_seconds = seconds model.ads_id = appOpenAd.adUnitID model.ad_platform_key = VPAdPlatformKey(rawValue: appOpenAd.adPlatformKey) model.error_msg = errorMsg diff --git a/Veloria/Libs/AdManager/Banner/VPApplovinBannerAd.swift b/Veloria/Libs/AdManager/Banner/VPApplovinBannerAd.swift new file mode 100644 index 0000000..f3d918b --- /dev/null +++ b/Veloria/Libs/AdManager/Banner/VPApplovinBannerAd.swift @@ -0,0 +1,88 @@ +// +// VPApplovinBannerAd.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/17. +// + +import UIKit +import AppLovinSDK + +class VPApplovinBannerAd: NSObject, VPBannerAd { + + let size = CGSize.init(width: UIScreen.width, height: 59) + + var delegate: (any VPBannerAdDelegate)? + + ///是否加载过 + private var isLoaded = false + + private(set) lazy var _adView: MAAdView = { + let view = MAAdView(adUnitIdentifier: adUnitID) + view.frame = .init(x: 0, y: 0, width: size.width, height: size.height) + view.delegate = self + return view + }() + + var adView: UIView { + return _adView + } + + var adPlatformKey: String { + return VPAdPlatformKey.applovin.rawValue + } + + var adUnitID: String { + return VPAdManager.applovin_bannerAdUnitID + } + + func loadAd() { + _adView.loadAd() + } +} + +//MARK: -------------- MAAdViewAdDelegate -------------- +extension VPApplovinBannerAd: MAAdViewAdDelegate { + func didExpand(_ ad: MAAd) { + + } + + func didCollapse(_ ad: MAAd) { + + } + + func didLoad(_ ad: MAAd) { + if !isLoaded { + isLoaded = true + self.delegate?.bannerAdDidLoadFinish?(bannerAd: self) + } + } + + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + if !isLoaded { + isLoaded = true + let nsError = NSError(domain: error.message, code: error.code.rawValue) + self.delegate?.bannerAd?(bannerAd: self, didLoadFail: nsError) + } + } + + func didDisplay(_ ad: MAAd) { + self.delegate?.bannerAdDidShow?(bannerAd: self) + } + + func didHide(_ ad: MAAd) { + self.delegate?.bannerAdDidDismiss?(bannerAd: self) + } + + func didClick(_ ad: MAAd) { + self.delegate?.bannerAdDidClick?(ad: self) + } + + func didFail(toDisplay ad: MAAd, withError error: MAError) { + + } + + + +} + diff --git a/Veloria/Libs/AdManager/Banner/VPBannerAdManager.swift b/Veloria/Libs/AdManager/Banner/VPBannerAdManager.swift index d748ba6..7a793bd 100644 --- a/Veloria/Libs/AdManager/Banner/VPBannerAdManager.swift +++ b/Veloria/Libs/AdManager/Banner/VPBannerAdManager.swift @@ -10,20 +10,52 @@ import UIKit import AppLovinSDK #endif -class VPBannerAdManager: NSObject { + +@objc protocol VPBannerAdDelegate: NSObjectProtocol { + ///广告加载失败 + @objc optional func bannerAd(bannerAd: VPBannerAd, didLoadFail error: Error) + ///广告加载成功 + @objc optional func bannerAdDidLoadFinish(bannerAd: VPBannerAd) + ///广告被展示 + @objc optional func bannerAdDidShow(bannerAd: VPBannerAd) + ///广告被关闭 + @objc optional func bannerAdDidDismiss(bannerAd: VPBannerAd) + ///广告被点击 + @objc optional func bannerAdDidClick(ad: VPBannerAd) +} + +@objc protocol VPBannerAd: NSObjectProtocol { - let adUnitID = VPAdManager.applovin_bannerAdUnitID + weak var delegate: VPBannerAdDelegate? { get set } + + var adView: UIView { get } + + var adPlatformKey: String { get } + + var adUnitID: String { get } + + func loadAd() + +} + +class VPBannerAdManager: NSObject { let size = CGSize.init(width: UIScreen.width, height: 59) + var videoInfo: VPVideoInfoModel? - private(set) lazy var adView: MAAdView = { - let view = MAAdView(adUnitIdentifier: adUnitID) - view.frame = .init(x: 0, y: 0, width: size.width, height: size.height) - view.delegate = self - return view + private var adsDate: Date? + + private(set) lazy var bannerAd: VPBannerAd = { + let ad = VPApplovinBannerAd() + ad.delegate = self + return ad }() + var adView: UIView { + return bannerAd.adView + } + deinit { NotificationCenter.default.removeObserver(self) } @@ -32,56 +64,61 @@ class VPBannerAdManager: NSObject { super.init() NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil) - self.adView.loadAd() + bannerAd.loadAd() } } -//MARK: -------------- MAAdViewAdDelegate -------------- -extension VPBannerAdManager: MAAdViewAdDelegate { - func didExpand(_ ad: MAAd) { - - } +//MARK: -------------- VPBannerAdDelegate -------------- +extension VPBannerAdManager: VPBannerAdDelegate { - func didCollapse(_ ad: MAAd) { - + ///广告加载失败 + func bannerAd(bannerAd: VPBannerAd, didLoadFail error: Error) { + requestStatAd(type: "load_failed", errorMsg: error.localizedDescription) } - - func didLoad(_ ad: MAAd) { + ///广告加载成功 + func bannerAdDidLoadFinish(bannerAd: VPBannerAd) { + adsDate = Date() requestStatAd(type: "start", errorMsg: nil) } - - func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { - requestStatAd(type: "load_failed", errorMsg: error.message) - } - - func didDisplay(_ ad: MAAd) { + ///广告被展示 + func bannerAdDidShow(bannerAd: VPBannerAd) { } - - func didHide(_ ad: MAAd) { + ///广告被关闭 + func bannerAdDidDismiss(bannerAd: VPBannerAd) { requestStatAd(type: "close", errorMsg: nil) } - - func didClick(_ ad: MAAd) { + ///广告被点击 + func bannerAdDidClick(ad: VPBannerAd) { requestStatAd(type: "click", errorMsg: nil) } - func didFail(toDisplay ad: MAAd, withError error: MAError) { - requestStatAd(type: "show_failed", errorMsg: error.message) - } } extension VPBannerAdManager { func requestStatAd(type: String, errorMsg: String?) { + + var seconds = 0 + if let adsDate = self.adsDate { + if type == "click" || type == "close" { + seconds = Int(Date().timeIntervalSince(adsDate)) + } + } + + if type == "close" && self.adsDate == nil { return } + let model = VPStatAdModel() + model.view_seconds = seconds model.type = type - model.ads_id = adUnitID - model.ad_platform_key = .applovin + model.ads_id = bannerAd.adUnitID + model.ad_platform_key = VPAdPlatformKey(rawValue: bannerAd.adPlatformKey) model.error_msg = errorMsg model.scene = .banner + model.short_play_id = self.videoInfo?.short_play_id + model.short_play_video_id = self.videoInfo?.short_play_video_id VPStatAPI.requestStatAd(model: model) } diff --git a/Veloria/Libs/AdManager/VPAdManager.swift b/Veloria/Libs/AdManager/VPAdManager.swift index fa124c7..9be29c6 100644 --- a/Veloria/Libs/AdManager/VPAdManager.swift +++ b/Veloria/Libs/AdManager/VPAdManager.swift @@ -36,9 +36,9 @@ class VPAdManager: NSObject { //初始化 let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in builder.mediationProvider = ALMediationProviderMAX -#if DEBUG - builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()] -#endif +//#if DEBUG +// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()] +//#endif } ALSdk.shared().initialize(with: initConfig) { sdkConfig in diff --git a/Veloria/Libs/Alert/VPDiscountsVipAlertView.swift b/Veloria/Libs/Alert/VPDiscountsVipAlertView.swift new file mode 100644 index 0000000..8890f6a --- /dev/null +++ b/Veloria/Libs/Alert/VPDiscountsVipAlertView.swift @@ -0,0 +1,300 @@ +// +// VPDiscountsVipAlertView.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/17. +// + +import UIKit + +class VPDiscountsVipAlertView: VPBaseAlertView { + + private var payTemplateModel: VPPayTemplateModel + + private var currentIndex = 0 + + //MARK: UI属性 + private lazy var bgView: UIView = { + let view = VPGradientView() + view.colors = [UIColor.color95ECD4().cgColor, UIColor.colorF2FFF6().cgColor, UIColor.colorF2FFF6().cgColor] + view.startPoint = .init(x: 0.5, y: 0) + view.endPoint = .init(x: 0.5, y: 1) + view.locations = [0, 0.5, 1] + view.layer.cornerRadius = 18 + view.layer.masksToBounds = true + return view + }() + + private lazy var closeButton: UIButton = { + let button = UIButton(type: .custom) + button.setImage(UIImage(named: "close_icon_02"), for: .normal) + button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside) + return button + }() + + private lazy var bgIconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "bg_icon_01")) + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = VPGradientLabel() + label.gradientLayer.colors = [UIColor.color126B4E().cgColor, UIColor.color1A2D22().cgColor] + label.gradientLayer.startPoint = .init(x: 0.5, y: 0) + label.gradientLayer.endPoint = .init(x: 0.5, y: 1) + label.text = "veloria_vip_unlimited_access".localized + label.font = .fontBold(ofSize: 20) + return label + }() + + private lazy var titleIconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "alert_title_icon_01")) + return imageView + }() + + private lazy var privilegeView1: VPDiscountsVipPrivilegeView = { + let view = VPDiscountsVipPrivilegeView() + view.iconImage = UIImage(named: "privilege_icon_07") + view.title = "veloria_ad_free_experience".localized + return view + }() + + private lazy var privilegeView2: VPDiscountsVipPrivilegeView = { + let view = VPDiscountsVipPrivilegeView() + view.iconImage = UIImage(named: "privilege_icon_08") + view.title = "veloria_unlimited_access_to_all_content".localized + return view + }() + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: 241, height: 64) + layout.minimumLineSpacing = 8 + layout.minimumInteritemSpacing = 8 + return layout + }() + + private lazy var collectionView: VPCollectionView = { + let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.isScrollEnabled = false + collectionView.register(VPDiscountsVipCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + private lazy var tipLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 10) + label.textColor = .colorB3B3B3() + label.text = "veloria_vip_tip_text_01".localized + return label + }() + + private lazy var openVipButton: UIButton = { + let button = UIButton(type: .custom) + button.setBackgroundImage(UIImage(named: "open_button_01"), for: .normal) + button.setTitle("veloria_activate_now".localized, for: .normal) + button.setTitleColor(.color005D48(), for: .normal) + button.titleLabel?.font = .fontMedium(ofSize: 15) + return button + }() + + + init(payTemplateModel: VPPayTemplateModel) { + self.payTemplateModel = payTemplateModel + super.init(frame: .zero) + vp_setupUI() + + UIView.performWithoutAnimation { + self.collectionView.reloadData() + } + + self.collectionView.performBatchUpdates(nil) { [weak self] _ in + guard let self = self else { return } + + let height = self.collectionView.contentSize.height + + self.collectionView.snp.updateConstraints { make in + make.height.equalTo(height) + } + } + + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @discardableResult + override func show(in view: UIView? = nil) -> Self { + VPVipAlertView.lastAlertDate = Date() + return super.show(in: VPAppTool.keyWindow) + } +} + +extension VPDiscountsVipAlertView { + @objc private func handleCloseButton() { + self.dismiss() + } + + +} + +extension VPDiscountsVipAlertView { + + private func vp_setupUI() { + contentView.addSubview(bgView) + contentView.addSubview(closeButton) + bgView.addSubview(bgIconImageView) + bgView.addSubview(titleIconImageView) + bgView.addSubview(titleLabel) + bgView.addSubview(privilegeView1) + bgView.addSubview(privilegeView2) + bgView.addSubview(collectionView) + bgView.addSubview(tipLabel) + bgView.addSubview(openVipButton) + + + bgView.snp.makeConstraints { make in + make.top.left.right.equalToSuperview() + make.width.equalTo(274) +// make.height.equalTo(355) + } + + closeButton.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(bgView.snp.bottom).offset(20) + make.bottom.equalToSuperview() + } + + bgIconImageView.snp.makeConstraints { make in + make.left.top.equalToSuperview() + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(21) + } + + titleIconImageView.snp.makeConstraints { make in + make.left.equalTo(titleLabel).offset(-15) + make.top.equalTo(titleLabel).offset(-7) + } + + privilegeView1.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(titleLabel.snp.bottom).offset(8) + } + + privilegeView2.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(privilegeView1.snp.bottom).offset(7) + } + + collectionView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(privilegeView2.snp.bottom).offset(14) + make.bottom.equalToSuperview().offset(-97) + make.width.equalTo(collectionViewLayout.itemSize.width) + make.height.equalTo(1) + } + + tipLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-9) + } + + openVipButton.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-30) + } + } + +} + +//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource -------------- +extension VPDiscountsVipAlertView: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPDiscountsVipCell + cell.item = payTemplateModel.list_sub_vip?[indexPath.row] + if (payTemplateModel.list_sub_vip?.count ?? 0) > 0 { + cell.vp_isSelected = indexPath.row == self.currentIndex + } + + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return payTemplateModel.list_sub_vip?.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + self.currentIndex = indexPath.row + + self.collectionView.reloadData() + } +} + + + +class VPDiscountsVipPrivilegeView: UIView { + + override var intrinsicContentSize: CGSize { + return .init(width: 100, height: 24) + } + + var iconImage: UIImage? { + didSet { + iconImageView.image = iconImage + } + } + + var title: String? { + didSet { + titleLabel.text = title + } + } + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + label.textColor = .color000000() + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .colorA3F0DE(alpha: 0.34) + layer.cornerRadius = 12 + layer.masksToBounds = true + + addSubview(iconImageView) + addSubview(titleLabel) + + iconImageView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(12) + } + + titleLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalTo(iconImageView.snp.right).offset(3) + make.right.equalToSuperview().offset(-12) + } + + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + +} diff --git a/Veloria/Libs/Alert/VPDiscountsVipCell.swift b/Veloria/Libs/Alert/VPDiscountsVipCell.swift new file mode 100644 index 0000000..3514494 --- /dev/null +++ b/Veloria/Libs/Alert/VPDiscountsVipCell.swift @@ -0,0 +1,171 @@ +// +// VPDiscountsVipCell.swift +// Veloria +// +// Created by 湖南秦九 on 2025/7/17. +// + +import UIKit + +class VPDiscountsVipCell: VPCollectionViewCell { + + var item: VPPayTemplateItem? { + didSet { + unitLabel.text = item?.currency + moneyLabel.text = item?.price + + let oldText = NSMutableAttributedString(string: "\(item?.currency ?? "")\(item?.origin_price ?? "")") + oldText.color = .colorFFFFFF(alpha: 0.7) + oldText.strikethroughColor = oldText.color + oldText.strikethroughStyle = .single + oldLabel.attributedText = oldText + + + tipLabel.text = "veloria_first_##_discount".localizedReplace(text: item?.vip_type_key?.getTextV2() ?? "") + + var colors: [CGColor] = [] + switch item?.vip_type_key { + case .week: + bgImageView.image = UIImage(named: "vip_alert_bg_week_v2") + colors = [UIColor.color64A3A7().cgColor, UIColor.color416767().cgColor] + tipBgView.colors = [UIColor.colorC5F8FB().cgColor, UIColor.colorC5F8FB(alpha: 0).cgColor] + tipLabel.textColor = .color78B3B3() + + default: + bgImageView.image = UIImage(named: "vip_alert_bg_month_v2") + colors = [UIColor.color647DA7().cgColor, UIColor.color414867().cgColor] + tipBgView.colors = [UIColor.colorC9DEFF().cgColor, UIColor.colorC9DEFF(alpha: 0).cgColor] + tipLabel.textColor = .color7698CF() + } + + unitLabel.gradientLayer.colors = colors + moneyLabel.gradientLayer.colors = colors + + } + } + + var vp_isSelected: Bool = false { + didSet { + selectedImageView.isHidden = !vp_isSelected + } + } + + private lazy var bgImageView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + + private lazy var unitLabel: VPGradientLabel = { + let label = VPGradientLabel() + label.font = .fontRegular(ofSize: 14) + return label + }() + + private lazy var moneyLabel: VPGradientLabel = { + let label = VPGradientLabel() + label.font = .fontAaHouDiHei(ofSize: 22) + return label + }() + + private lazy var tipBgView: VPGradientView = { + let view = VPGradientView() + view.locations = [0, 1] + view.startPoint = .init(x: 0, y: 0.5) + view.endPoint = .init(x: 1, y: 0.5) + view.addRadius(topLeft: 10, topRight: 0, bottomLeft: 0, bottomRight: 10) + return view + }() + + private lazy var tipLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 10) + return label + }() + + private lazy var oldBgView: UIView = { + let view = UIView() + view.backgroundColor = .colorBE0069() + view.addRadius(topLeft: 0, topRight: 10, bottomLeft: 10, bottomRight: 0) + return view + }() + + private lazy var oldLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + return label + }() + + private lazy var selectedImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "selected_icon_01")) + imageView.isHidden = true + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + vp_setupUI() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension VPDiscountsVipCell { + + private func vp_setupUI() { + contentView.addSubview(bgImageView) + bgImageView.addSubview(unitLabel) + bgImageView.addSubview(moneyLabel) + bgImageView.addSubview(tipBgView) + tipBgView.addSubview(tipLabel) + bgImageView.addSubview(oldBgView) + oldBgView.addSubview(oldLabel) + bgImageView.addSubview(selectedImageView) + + bgImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + unitLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(13) + make.top.equalToSuperview().offset(16) + } + + moneyLabel.snp.makeConstraints { make in + make.left.equalTo(unitLabel.snp.right) + make.bottom.equalTo(unitLabel).offset(4) + } + + tipBgView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(12) + make.bottom.equalToSuperview().offset(-8.5) + make.height.equalTo(15) + } + + tipLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(6) + make.right.equalToSuperview().offset(-7) + } + + oldBgView.snp.makeConstraints { make in + make.right.equalToSuperview() + make.top.equalToSuperview() + make.height.equalTo(18) + } + + oldLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(8) + make.right.equalToSuperview().offset(-8) + } + + selectedImageView.snp.makeConstraints { make in + make.right.bottom.equalToSuperview() + } + } + +} diff --git a/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c4d3b1 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Contents.json @@ -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 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@2x.png b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@2x.png new file mode 100644 index 0000000..002d05f Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@3x.png b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@3x.png new file mode 100644 index 0000000..99edc90 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/bg_icon_01.imageset/Frame@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/Contents.json new file mode 100644 index 0000000..379ba42 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/Contents.json @@ -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 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@2x.png b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@2x.png new file mode 100644 index 0000000..7683c3f Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@3x.png b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@3x.png new file mode 100644 index 0000000..c580778 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/open_button_01.imageset/按钮@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/Contents.json new file mode 100644 index 0000000..66d6a0b --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "No Ads@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "No Ads@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@2x.png b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@2x.png new file mode 100644 index 0000000..127eb92 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@3x.png b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@3x.png new file mode 100644 index 0000000..ffab348 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/privilege_icon_07.imageset/No Ads@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/Contents.json new file mode 100644 index 0000000..b0d4e2f --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "donate coins@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "donate coins@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@2x.png b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@2x.png new file mode 100644 index 0000000..f70f976 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@3x.png b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@3x.png new file mode 100644 index 0000000..34bd34b Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/privilege_icon_08.imageset/donate coins@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/Contents.json b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/Contents.json new file mode 100644 index 0000000..80ece22 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "月会员卡片bg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "月会员卡片bg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@2x.png b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@2x.png new file mode 100644 index 0000000..50c76ba Binary files /dev/null and b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@3x.png b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@3x.png new file mode 100644 index 0000000..848b10a Binary files /dev/null and b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_month_v2.imageset/月会员卡片bg@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/Contents.json b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/Contents.json new file mode 100644 index 0000000..e928568 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "周会员卡片bg@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "周会员卡片bg@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@2x.png b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@2x.png new file mode 100644 index 0000000..f626b3f Binary files /dev/null and b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@3x.png b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@3x.png new file mode 100644 index 0000000..22b4d01 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/image/vip_alert_bg_week_v2.imageset/周会员卡片bg@3x.png differ diff --git a/Veloria/Source/en.lproj/Localizable.strings b/Veloria/Source/en.lproj/Localizable.strings index 02790af..e5ac736 100644 --- a/Veloria/Source/en.lproj/Localizable.strings +++ b/Veloria/Source/en.lproj/Localizable.strings @@ -92,6 +92,10 @@ "veloria_month" = "1 month"; "veloria_quarter" = "1 quarter"; "veloria_year" = "1 year"; +"veloria_week_text" = "Week"; +"veloria_month_text" = "Month"; +"veloria_quarter_text" = "Quarter"; +"veloria_year_text" = "Year"; "veloria_days_count_text" = "## days"; "veloria_last_play_episode" = "Last time Episode ##"; "veloria_coin_buy_title" = "Top Up | Indefinitely use"; @@ -105,6 +109,11 @@ "veloria_no_short_found" = "No Short Found"; "veloria_no_ads_tip" = "Ad is on the way"; "veloria_watch_ads_to_unlock" = "Watch ads to unlock"; +"veloria_vip_unlimited_access" = "VIP Unlimited Access"; +"veloria_ad_free_experience" = "Ad-free experience"; +"veloria_unlimited_access_to_all_content" = "Unlimited access to all content"; +"veloria_activate_now" = "Activate Now"; +"veloria_first_##_discount" = "First ## Discount"; "veloria_bonus_count_text" = "+## Bonus"; @@ -143,7 +152,7 @@ "veloria_pay_error_3" = "No in-app purchases can be restored"; "veloria_pay_error_4" = "Payment has been cancelled"; - +"veloria_vip_tip_text_01" = "By subscribing, you agree to our Terms of Service."; "veloria_store_tips_ios" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
2. Gold coins will never expire, the reward coins will expire 24 hours a day.
3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.
4. The purchase has not been credited, click to refresh.
5. For other questions, contact us via Me>Feedback.";