Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67eeef0447 | ||
|
|
4c250038e0 | ||
|
|
b7a0a86a1a | ||
|
|
41b7bc80c4 | ||
|
|
50d1cd9069 | ||
|
|
2c7cef9572 | ||
|
|
6d48234e48 | ||
|
|
5fb7a4d9bc | ||
|
|
2b3125d826 | ||
|
|
b21751e738 | ||
|
|
86b603c64f |
12
Podfile
12
Podfile
@ -20,7 +20,7 @@ target 'SynthReel' do
|
|||||||
pod 'YYCategories'
|
pod 'YYCategories'
|
||||||
pod 'YYText'
|
pod 'YYText'
|
||||||
pod 'Kingfisher'
|
pod 'Kingfisher'
|
||||||
pod 'SmartCodable'
|
pod 'SmartCodable','5.0.15'
|
||||||
pod 'Moya'
|
pod 'Moya'
|
||||||
pod 'SVProgressHUD'
|
pod 'SVProgressHUD'
|
||||||
pod 'Toast'
|
pod 'Toast'
|
||||||
@ -31,5 +31,13 @@ target 'SynthReel' do
|
|||||||
pod 'MJRefresh'
|
pod 'MJRefresh'
|
||||||
pod 'collection-view-layouts/TagsLayout'
|
pod 'collection-view-layouts/TagsLayout'
|
||||||
pod 'HWPanModal'
|
pod 'HWPanModal'
|
||||||
|
pod 'LYEmptyView'
|
||||||
|
pod 'ZLPhotoBrowser'
|
||||||
|
pod 'Adjust'
|
||||||
|
|
||||||
|
# # AdMob SDK
|
||||||
|
pod 'Google-Mobile-Ads-SDK'
|
||||||
|
#
|
||||||
|
# # AppLovin SDK
|
||||||
|
pod 'AppLovinSDK'
|
||||||
end
|
end
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,24 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "0e62262c59a183f44748a161870cc0f2b76e1b0e46f648559704e4be9de523b9",
|
"originHash" : "deb3ea9bc9f7ea16d149d6025086ec795e4f5fc740540ae9e5e8308e4e3e8aec",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "abseil-cpp-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||||
|
"version" : "1.2024072200.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "app-check",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/app-check.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
|
||||||
|
"version" : "11.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "estabbarcontroller",
|
"identity" : "estabbarcontroller",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@ -10,6 +28,114 @@
|
|||||||
"version" : "2.9.0"
|
"version" : "2.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"identity" : "facebook-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/facebook/facebook-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c19607d535864533523d1f437c84035e5fb101cf",
|
||||||
|
"version" : "14.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "firebase-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "087bb95235f676c1a37e928769a5b6645dcbd325",
|
||||||
|
"version" : "12.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "35b601a60fbbea2de3ea461f604deaaa4d8bbd0c",
|
||||||
|
"version" : "3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleappmeasurement",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c2d59acf17a8ba7ed80a763593c67c9c7c006ad1",
|
||||||
|
"version" : "12.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googledatatransport",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
|
||||||
|
"version" : "10.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "googleutilities",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
|
||||||
|
"version" : "8.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "grpc-binary",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/grpc-binary.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "75b31c842f664a0f46a2e590a570e370249fd8f6",
|
||||||
|
"version" : "1.69.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "gtm-session-fetcher",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "fb7f2740b1570d2f7599c6bb9531bf4fad6974b7",
|
||||||
|
"version" : "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "interop-ios-for-google-sdks",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||||
|
"version" : "101.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "leveldb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/leveldb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||||
|
"version" : "1.22.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "nanopb",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/firebase/nanopb.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
|
||||||
|
"version" : "2.30910.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "promises",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/google/promises.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
|
||||||
|
"version" : "2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"identity" : "snapkit",
|
"identity" : "snapkit",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
@ -18,6 +144,15 @@
|
|||||||
"revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4",
|
"revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4",
|
||||||
"version" : "5.7.1"
|
"version" : "5.7.1"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swift-protobuf",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "c169a5744230951031770e27e475ff6eefe51f9d",
|
||||||
|
"version" : "1.33.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version" : 3
|
"version" : 3
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeApi.swift
|
// SRHomeApi.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -118,5 +118,4 @@ struct SRHomeApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRShortApi.swift
|
// SRShortApi.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -29,6 +29,20 @@ struct SRShortApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func requestRecommand() async -> ([SRShortModel]?, Int?, String?) {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/getDetailsRecommand")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRNetwork.List<SRShortModel>>) in
|
||||||
|
if response.isSuccess {
|
||||||
|
continuation.resume(returning:(response.data?.list, response.code, response.msg))
|
||||||
|
} else {
|
||||||
|
continuation.resume(returning:(nil, response.code, response.msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static func requestShortCollect(shortId: String, videoId: String?, isCollect: Bool) async -> Bool {
|
static func requestShortCollect(shortId: String, videoId: String?, isCollect: Bool) async -> Bool {
|
||||||
await withCheckedContinuation { continuation in
|
await withCheckedContinuation { continuation in
|
||||||
var path = ""
|
var path = ""
|
||||||
@ -75,6 +89,24 @@ struct SRShortApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func requestCoinUnlockVideo(shortId: String?, videoId: String?) async -> SRVideoUnlockResult? {
|
||||||
|
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/buy_video")
|
||||||
|
param.isToast = true
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"short_play_id": shortId ?? "",
|
||||||
|
"video_id": videoId ?? "0"
|
||||||
|
]
|
||||||
|
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRVideoUnlockResult>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
98
SynthReel/Base/API/SRStatAPI.swift
Normal file
98
SynthReel/Base/API/SRStatAPI.swift
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
//
|
||||||
|
// SRStatAPI.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/2.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRStatAPI: NSObject {
|
||||||
|
enum EventKey: String {
|
||||||
|
case payError = "pay_error" //支付过程中的其它错误
|
||||||
|
case payCallback = "pay_callback" //支付成功,但是后台接口失败
|
||||||
|
case payRestore = "pay_restore" //restore 失败
|
||||||
|
case forceUpdate = "force_update"//更新弹窗
|
||||||
|
case payCancel = "pay_cancel" //用户取消支付
|
||||||
|
case payTemplateDialog = "pay_template_dialog"//详情页面弹出支付模版事件
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func requestEventStat(orderCode: String?, shortPlayId: String?, videoId: String?, eventKey: EventKey, errorMsg: String?, otherParamenters: [String : Any]? = nil) async {
|
||||||
|
var eventName = ""
|
||||||
|
switch eventKey {
|
||||||
|
case .payRestore:
|
||||||
|
eventName = "pay restore"
|
||||||
|
|
||||||
|
case .payCallback:
|
||||||
|
eventName = "pay callback failed"
|
||||||
|
|
||||||
|
case .forceUpdate:
|
||||||
|
eventName = "force update"
|
||||||
|
|
||||||
|
case .payCancel:
|
||||||
|
eventName = "user pay canceled"
|
||||||
|
|
||||||
|
default:
|
||||||
|
eventName = "platform pay failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/createOrder")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"userId" : SRLogin.manager.userInfo?.customer_id ?? "",
|
||||||
|
"short_play_video_id" : videoId ?? "0",
|
||||||
|
"short_play_id" : shortPlayId ?? "0",
|
||||||
|
"event_key" : eventKey.rawValue,
|
||||||
|
"order_code": orderCode ?? "",
|
||||||
|
"event_name" : eventName,
|
||||||
|
]
|
||||||
|
if let errorMsg = errorMsg {
|
||||||
|
param.parameters?["error_msg"] = errorMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if let otherParamenters = otherParamenters {
|
||||||
|
otherParamenters.forEach {
|
||||||
|
param.parameters?[$0] = $1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestUploadApnsAuthorizationStatus(_ status: Bool) async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/uploadNoticeStatus")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"is_open_notice" : status ? 1 : 0
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRStatAPI {
|
||||||
|
///更新通知状态
|
||||||
|
static func uploadApnsAuthorizationStatus() {
|
||||||
|
UNUserNotificationCenter.current().getNotificationSettings { settings in
|
||||||
|
if settings.authorizationStatus == .authorized {
|
||||||
|
Task {
|
||||||
|
await requestUploadApnsAuthorizationStatus(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if settings.authorizationStatus == .denied {
|
||||||
|
Task {
|
||||||
|
await requestUploadApnsAuthorizationStatus(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
SynthReel/Base/API/SRStoreAPI.swift
Normal file
121
SynthReel/Base/API/SRStoreAPI.swift
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
//
|
||||||
|
// SRStoreAPI.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/2.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
|
||||||
|
class SRStoreAPI: NSObject {
|
||||||
|
enum BuyType: String, SmartCaseDefaultable {
|
||||||
|
case coins = "coins"
|
||||||
|
case subVip = "sub_vip"
|
||||||
|
case subCoins = "sub_coins"
|
||||||
|
case vip = "vip"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func requestPayTemplate() async -> SRPayDateModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/paySettingsV4")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"discount" : "1",
|
||||||
|
"purchases_token" : SRPayManger.manager.getAppStoreReceipt() ?? "",
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRPayDateModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, isDiscount: Bool = false, identifierDiscount: String? = nil) async -> SRIapOrderModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/createOrder")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"payment_channel" : "apple",
|
||||||
|
"short_play_id" : shortPlayId,
|
||||||
|
"video_id" : videoId,
|
||||||
|
"pay_setting_id" : payId,
|
||||||
|
"is_discount" : isDiscount ? 1 : 0,
|
||||||
|
"product_discount" : identifierDiscount ?? "",
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRIapOrderModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestVerifyOrder(parameters: [String : Any]) async -> SRIapVerifyModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/applePaid")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = parameters
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRIapVerifyModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestCoinsPackData() async -> SRCoinsPackModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/getReceiveDayCoinInfo")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRCoinsPackModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func requestCoinBagCanReceiveInfo() async -> SRCoinPackCanReceiveModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/getReceiveDayCoin")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRCoinPackCanReceiveModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static func requestReceiveCoinsPackCoins(id: String?) async -> Bool {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/receiveDayCoin")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"id" : id ?? ""
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<String>) in
|
||||||
|
if response.isSuccess {
|
||||||
|
continuation.resume(returning: true)
|
||||||
|
}else{
|
||||||
|
continuation.resume(returning: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestVipRetainPayInfo() async -> SRPayAlertModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/getRetainVipPaySetting")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRPayAlertModel>) in
|
||||||
|
if let model = response.data,
|
||||||
|
model.info != nil {
|
||||||
|
continuation.resume(returning: model)
|
||||||
|
} else {
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRUserApi.swift
|
// SRUserApi.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -22,4 +22,119 @@ struct SRUserApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func requestregister() async -> SRTokenModel? {
|
||||||
|
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/register")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestLeave() async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/leaveApp")
|
||||||
|
param.method = .post
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestEnterApp() async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/enterTheApp")
|
||||||
|
param.method = .post
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestStatOnLine() async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/onLine")
|
||||||
|
param.method = .post
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestStatApnsClick(id: String, title: String) async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/message/sendReport")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"message_id" : id,
|
||||||
|
"title" : title
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestUploadApnsDeviceToken(token: String) async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/firebaseToken")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"fcm_token": token
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestSignThirdLogin(model: SRThirdModel) async -> SRTokenModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/login")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = model.toDictionary()
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestLogout() async -> SRTokenModel? {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/signout")
|
||||||
|
param.method = .post
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestUploadW2a(data: String) async {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/w2aSelfAttribution")
|
||||||
|
param.method = .post
|
||||||
|
param.parameters = [
|
||||||
|
"data": data
|
||||||
|
]
|
||||||
|
SRNetwork.request(parameters: param) { (_: SRNetwork.Response<String>) in
|
||||||
|
continuation.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func requestVersionUpdateData() async -> SRVersionUpdateModel?{
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
var param = SRNetwork.Parameters(path: "/customer/versionControl")
|
||||||
|
param.method = .get
|
||||||
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRVersionUpdateModel>) in
|
||||||
|
continuation.resume(returning: response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
225
SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift
Normal file
225
SynthReel/Base/AdManager/AppOpen/VPAppOpenAdManager.swift
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
////
|
||||||
|
//// VPAppOpenAdManager.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/15.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//@objc protocol VPAppOpenAdManagerDelegate: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// ///广告加载成功
|
||||||
|
// @objc optional func appOpenAdManagerDidLoadFinish(adManager: VPAppOpenAdManager)
|
||||||
|
// ///广告加载失败
|
||||||
|
// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didLoadFail error: Error)
|
||||||
|
// ///广告展示失败
|
||||||
|
// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didDisplayFail error: Error)
|
||||||
|
// ///广告被展示
|
||||||
|
// @objc optional func appOpenAdManagerDidShow(adManager: VPAppOpenAdManager)
|
||||||
|
// ///广告被关闭
|
||||||
|
// @objc optional func appOpenAdManagerDidDismiss(adManager: VPAppOpenAdManager)
|
||||||
|
// ///广告被点击
|
||||||
|
// @objc optional func appOpenAdManagerDidClick(adManager: VPAppOpenAdManager)
|
||||||
|
// ///其它错误
|
||||||
|
// @objc optional func appOpenAdManager(adManager: VPAppOpenAdManager, didOtherFail error: Error)
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//@objc protocol VPAppOpenAdDelegate: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// ///广告加载失败
|
||||||
|
// @objc optional func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error)
|
||||||
|
// ///广告加载成功
|
||||||
|
// @objc optional func appOpenAdDidLoadFinish(ad: VPAppOpenAd)
|
||||||
|
// ///广告展示失败
|
||||||
|
// @objc optional func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error)
|
||||||
|
// ///广告被展示
|
||||||
|
// @objc optional func appOpenAdDidShow(ad: VPAppOpenAd)
|
||||||
|
// ///广告被关闭
|
||||||
|
// @objc optional func appOpenAdDidDismiss(ad: VPAppOpenAd)
|
||||||
|
// ///广告被点击
|
||||||
|
// @objc optional func appOpenAdDidClick(ad: VPAppOpenAd)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//@objc protocol VPAppOpenAd: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// weak var delegate: VPAppOpenAdDelegate? { get set }
|
||||||
|
//
|
||||||
|
// var adPlatformKey: String { get }
|
||||||
|
//
|
||||||
|
// var adUnitID: String { get }
|
||||||
|
//
|
||||||
|
// var isReady: Bool { get }
|
||||||
|
//
|
||||||
|
// func loadAd()
|
||||||
|
// func showAd()
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//class VPAppOpenAdManager: NSObject {
|
||||||
|
//
|
||||||
|
// static let manager = VPAppOpenAdManager()
|
||||||
|
//
|
||||||
|
// weak var delegate: VPAppOpenAdManagerDelegate?
|
||||||
|
//
|
||||||
|
// private(set) var appOpenAd: VPAppOpenAd? {
|
||||||
|
// didSet {
|
||||||
|
// oldValue?.delegate = nil
|
||||||
|
// appOpenAd?.delegate = self
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private var isLoading = false
|
||||||
|
// private var isShowing = false
|
||||||
|
// ///允许自动展示
|
||||||
|
// private var needAutoShow = false
|
||||||
|
//
|
||||||
|
// private var timeOutTimer: Timer?
|
||||||
|
//
|
||||||
|
// private var adsDate: Date?
|
||||||
|
//
|
||||||
|
// deinit {
|
||||||
|
// NotificationCenter.default.removeObserver(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override init() {
|
||||||
|
// super.init()
|
||||||
|
// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAdIfAvailable() {
|
||||||
|
//
|
||||||
|
// if self.appOpenAd?.isReady == true {
|
||||||
|
// self.showAd()
|
||||||
|
// } else {
|
||||||
|
// self.timeOutTimer = Timer.scheduledTimer(timeInterval: 5, target: (self), selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false)
|
||||||
|
//
|
||||||
|
// self.needAutoShow = true
|
||||||
|
// self.loadAd()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func loadAd() {
|
||||||
|
// guard !isLoading else { return }
|
||||||
|
//
|
||||||
|
// self.isLoading = true
|
||||||
|
// appOpenAd = VPApplovinAppOpenAd()
|
||||||
|
// appOpenAd?.loadAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAd() {
|
||||||
|
// guard self.appOpenAd?.isReady == true else { return }
|
||||||
|
// guard !self.isShowing else { return }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// self.isShowing = true
|
||||||
|
// self.appOpenAd?.showAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @objc private func handleTimeOutTimer() {
|
||||||
|
// self.needAutoShow = false
|
||||||
|
// cleanTimer()
|
||||||
|
//
|
||||||
|
// let error = NSError(domain: "time-out", code: -1)
|
||||||
|
// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
// self.delegate?.appOpenAdManager?(adManager: self, didOtherFail: error)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private func cleanTimer() {
|
||||||
|
// self.timeOutTimer?.invalidate()
|
||||||
|
// self.timeOutTimer = nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private func clean() {
|
||||||
|
// appOpenAd = nil
|
||||||
|
// delegate = nil
|
||||||
|
// isShowing = false
|
||||||
|
// self.adsDate = nil
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
////MARK: -------------- VPAppOpenAdDelegate --------------
|
||||||
|
//extension VPAppOpenAdManager: VPAppOpenAdDelegate {
|
||||||
|
//
|
||||||
|
// ///广告加载失败
|
||||||
|
// func appOpenAd(ad: VPAppOpenAd, didLoadFail error: Error) {
|
||||||
|
// cleanTimer()
|
||||||
|
// isLoading = false
|
||||||
|
// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
//
|
||||||
|
// self.delegate?.appOpenAdManager?(adManager: self, didLoadFail: error)
|
||||||
|
//
|
||||||
|
// clean()
|
||||||
|
// }
|
||||||
|
// ///广告加载成功
|
||||||
|
// func appOpenAdDidLoadFinish(ad: VPAppOpenAd) {
|
||||||
|
// cleanTimer()
|
||||||
|
// self.isLoading = false
|
||||||
|
// self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self)
|
||||||
|
//
|
||||||
|
// if needAutoShow {
|
||||||
|
// self.needAutoShow = false
|
||||||
|
// self.showAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// ///广告展示失败
|
||||||
|
// func appOpenAd(ad: VPAppOpenAd, didDisplayFail error: Error) {
|
||||||
|
// 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)
|
||||||
|
// }
|
||||||
|
// ///广告被关闭
|
||||||
|
// func appOpenAdDidDismiss(ad: VPAppOpenAd) {
|
||||||
|
// requestStatAd(type: "close", errorMsg: nil)
|
||||||
|
// self.delegate?.appOpenAdManagerDidDismiss?(adManager: self)
|
||||||
|
// clean()
|
||||||
|
// }
|
||||||
|
// ///广告被点击
|
||||||
|
// func appOpenAdDidClick(ad: VPAppOpenAd) {
|
||||||
|
// requestStatAd(type: "click", errorMsg: nil)
|
||||||
|
// self.delegate?.appOpenAdManagerDidClick?(adManager: self)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//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
|
||||||
|
// model.scene = .splash
|
||||||
|
//
|
||||||
|
//// VPStatAPI.requestStatAd(model: model)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @objc private func didEnterBackgroundNotification() {
|
||||||
|
// guard self.isShowing else { return }
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "Interrupt", errorMsg: nil)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
84
SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift
Normal file
84
SynthReel/Base/AdManager/AppOpen/VPApplovinAppOpenAd.swift
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
////
|
||||||
|
//// VPApplovinAppOpenAd.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/15.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
//import AppLovinSDK
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
//class VPApplovinAppOpenAd: NSObject, VPAppOpenAd {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private lazy var appOpenAd = MAAppOpenAd(adUnitIdentifier: adUnitID)
|
||||||
|
//
|
||||||
|
// weak var delegate: (any VPAppOpenAdDelegate)?
|
||||||
|
//
|
||||||
|
// var adPlatformKey: String {
|
||||||
|
// return VPAdPlatformKey.applovin.rawValue
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var adUnitID: String {
|
||||||
|
// return VPAdManager.applovin_appOpenAdUnitID
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var isReady: Bool {
|
||||||
|
// if ALSdk.shared().isInitialized && appOpenAd.isReady {
|
||||||
|
// return true
|
||||||
|
// } else {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func loadAd() {
|
||||||
|
//
|
||||||
|
// VPAdManager.initialize_applovinSdk { [weak self] in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// appOpenAd.delegate = self
|
||||||
|
// appOpenAd.load()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAd() {
|
||||||
|
// guard isReady else { return }
|
||||||
|
//
|
||||||
|
// appOpenAd.show()
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//extension VPApplovinAppOpenAd: MAAdDelegate {
|
||||||
|
// func didLoad(_ ad: MAAd) {
|
||||||
|
// self.delegate?.appOpenAdDidLoadFinish?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
|
||||||
|
// let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||||
|
// self.delegate?.appOpenAd?(ad: self, didLoadFail: nsError)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didDisplay(_ ad: MAAd) {
|
||||||
|
// self.delegate?.appOpenAdDidShow?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didHide(_ ad: MAAd) {
|
||||||
|
// self.delegate?.appOpenAdDidDismiss?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didClick(_ ad: MAAd) {
|
||||||
|
// self.delegate?.appOpenAdDidClick?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didFail(toDisplay ad: MAAd, withError error: MAError) {
|
||||||
|
// let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||||
|
// self.delegate?.appOpenAd?(ad: self, didDisplayFail: nsError)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
88
SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift
Normal file
88
SynthReel/Base/AdManager/Banner/VPApplovinBannerAd.swift
Normal file
@ -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) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
131
SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift
Normal file
131
SynthReel/Base/AdManager/Banner/VPBannerAdManager.swift
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
////
|
||||||
|
//// VPBannerAdManager.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/15.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
//import AppLovinSDK
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//@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 {
|
||||||
|
//
|
||||||
|
// 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 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)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override init() {
|
||||||
|
// super.init()
|
||||||
|
// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||||
|
//
|
||||||
|
// bannerAd.loadAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
////MARK: -------------- VPBannerAdDelegate --------------
|
||||||
|
//extension VPBannerAdManager: VPBannerAdDelegate {
|
||||||
|
//
|
||||||
|
// ///广告加载失败
|
||||||
|
// func bannerAd(bannerAd: VPBannerAd, didLoadFail error: Error) {
|
||||||
|
// requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
// }
|
||||||
|
// ///广告加载成功
|
||||||
|
// func bannerAdDidLoadFinish(bannerAd: VPBannerAd) {
|
||||||
|
// adsDate = Date()
|
||||||
|
// requestStatAd(type: "start", errorMsg: nil)
|
||||||
|
// }
|
||||||
|
// ///广告被展示
|
||||||
|
// func bannerAdDidShow(bannerAd: VPBannerAd) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// ///广告被关闭
|
||||||
|
// func bannerAdDidDismiss(bannerAd: VPBannerAd) {
|
||||||
|
// requestStatAd(type: "close", errorMsg: nil)
|
||||||
|
// }
|
||||||
|
// ///广告被点击
|
||||||
|
// func bannerAdDidClick(ad: VPBannerAd) {
|
||||||
|
// requestStatAd(type: "click", errorMsg: nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//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 = 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)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// @objc private func didEnterBackgroundNotification() {
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "Interrupt", errorMsg: nil)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
91
SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift
Normal file
91
SynthReel/Base/AdManager/Rewarded/VPApplovinRewardedAd.swift
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
////
|
||||||
|
//// VPApplovinRewardedAd.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/15.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
//import AppLovinSDK
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
//class VPApplovinRewardedAd: NSObject, VPRewardedAd {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
// private var rewardedAd: MARewardedAd?
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
// weak var delegate: (any VPRewardedAdDelegate)?
|
||||||
|
//
|
||||||
|
// var adInfo: VPAdInfo? = nil
|
||||||
|
//
|
||||||
|
// var isReady: Bool {
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
// return rewardedAd?.isReady ?? false
|
||||||
|
//#else
|
||||||
|
// return false
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func loadAd(adInfo: VPAdInfo) {
|
||||||
|
// self.adInfo = adInfo
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
// rewardedAd = MARewardedAd.shared(withAdUnitIdentifier: adInfo.ads_id ?? "")
|
||||||
|
// rewardedAd?.delegate = self
|
||||||
|
// rewardedAd?.load()
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAd() {
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
// if isReady {
|
||||||
|
// rewardedAd?.show()
|
||||||
|
// }
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//#if canImport(AppLovinSDK)
|
||||||
|
////MARK: -------------- MARewardedAdDelegate --------------
|
||||||
|
//extension VPApplovinRewardedAd: MARewardedAdDelegate {
|
||||||
|
//
|
||||||
|
// func didLoad(_ ad: MAAd) {
|
||||||
|
// self.delegate?.rewardedAdDidLoadFinish?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
|
||||||
|
//
|
||||||
|
// let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, didLoadFail: nsError)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didDisplay(_ ad: MAAd) {
|
||||||
|
// self.delegate?.rewardedAdDidShow?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didHide(_ ad: MAAd) {
|
||||||
|
// self.delegate?.rewardedAdDidDismiss?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didClick(_ ad: MAAd) {
|
||||||
|
// self.delegate?.rewardedAdDidClick?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didFail(toDisplay ad: MAAd, withError error: MAError) {
|
||||||
|
// let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, didDisplayFail: nsError)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func didRewardUser(for ad: MAAd, with reward: MAReward) {
|
||||||
|
// if let adInfo = self.adInfo {
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, userDidEarnReward: adInfo)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
//
|
||||||
101
SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift
Normal file
101
SynthReel/Base/AdManager/Rewarded/VPGoogleRewardedAd.swift
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
////
|
||||||
|
//// VPGoogleRewardedAd.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/14.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
//import GoogleMobileAds
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
//class VPGoogleRewardedAd: NSObject, VPRewardedAd {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
// private var rewardedAd: RewardedAd?
|
||||||
|
//#endif
|
||||||
|
//
|
||||||
|
// weak var delegate: VPRewardedAdDelegate?
|
||||||
|
//
|
||||||
|
// var adInfo: VPAdInfo?
|
||||||
|
//
|
||||||
|
// var isReady: Bool {
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
// if rewardedAd != nil {
|
||||||
|
// return true
|
||||||
|
// } else {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
//#else
|
||||||
|
// return false
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func loadAd(adInfo: VPAdInfo) {
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
// self.adInfo = adInfo
|
||||||
|
//#if DEBUG
|
||||||
|
// adInfo.ads_id = VPAdManager.google_rewardedAdUnitID
|
||||||
|
//#endif
|
||||||
|
// let adUnitID = adInfo.ads_id ?? ""
|
||||||
|
// let request = Request()
|
||||||
|
//
|
||||||
|
// RewardedAd.load(with: adUnitID, request: request) { [weak self] rewardedAd, error in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// if let error = error {
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, didLoadFail: error)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// self.rewardedAd = rewardedAd
|
||||||
|
// self.rewardedAd?.fullScreenContentDelegate = self
|
||||||
|
// self.delegate?.rewardedAdDidLoadFinish?(ad: self)
|
||||||
|
// }
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAd() {
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
// guard let rewardedAd = rewardedAd else { return }
|
||||||
|
//
|
||||||
|
// rewardedAd.present(from: nil) { [weak self] in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// guard let adInfo = self.adInfo else { return }
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, userDidEarnReward: adInfo)
|
||||||
|
// }
|
||||||
|
//#endif
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
////MARK: -------------- FullScreenContentDelegate --------------
|
||||||
|
//#if canImport(GoogleMobileAds)
|
||||||
|
//extension VPGoogleRewardedAd: FullScreenContentDelegate {
|
||||||
|
//
|
||||||
|
// /// Tells the delegate that the ad failed to present full screen content.
|
||||||
|
// func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||||
|
// self.delegate?.rewardedAd?(ad: self, didDisplayFail: error)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// Tells the delegate that the ad will present full screen content.
|
||||||
|
// func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||||
|
// print("====Ad will present full screen content.")
|
||||||
|
// self.delegate?.rewardedAdDidShow?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// Tells the delegate that the ad dismissed full screen content.
|
||||||
|
// func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||||
|
// print("====Ad did dismiss full screen content.")
|
||||||
|
// self.delegate?.rewardedAdDidDismiss?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func adDidRecordClick(_ ad: any FullScreenPresentingAd) {
|
||||||
|
// self.delegate?.rewardedAdDidClick?(ad: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//#endif
|
||||||
292
SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift
Normal file
292
SynthReel/Base/AdManager/Rewarded/VPRewardedAdManager.swift
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
////
|
||||||
|
//// VPRewardedAdManager.swift
|
||||||
|
//// Veloria
|
||||||
|
////
|
||||||
|
//// Created by 湖南秦九 on 2025/7/14.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
//import UIKit
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//@objc protocol VPRewardedAdManagerDelegate: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// ///发放奖励
|
||||||
|
// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, userDidEarnReward adInfo: VPAdInfo)
|
||||||
|
// ///广告加载成功
|
||||||
|
// @objc optional func rewardedAdManagerDidLoadFinish(adManager: VPRewardedAdManager)
|
||||||
|
// ///广告加载失败
|
||||||
|
// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didLoadFail error: Error)
|
||||||
|
// ///广告展示失败
|
||||||
|
// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDisplayFail error: Error)
|
||||||
|
// ///广告被展示
|
||||||
|
// @objc optional func rewardedAdManagerDidShow(adManager: VPRewardedAdManager)
|
||||||
|
// ///广告被关闭
|
||||||
|
// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didDismiss adInfo: VPAdInfo)
|
||||||
|
// ///广告被点击
|
||||||
|
// @objc optional func rewardedAdManagerDidClick(adManager: VPRewardedAdManager)
|
||||||
|
// ///其它错误
|
||||||
|
// @objc optional func rewardedAdManager(adManager: VPRewardedAdManager, didOtherFail error: Error)
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//@objc protocol VPRewardedAdDelegate: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// ///发放奖励
|
||||||
|
// @objc optional func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo)
|
||||||
|
// ///广告加载失败
|
||||||
|
// @objc optional func rewardedAd(ad: VPRewardedAd, didLoadFail error: Error)
|
||||||
|
// ///广告加载成功
|
||||||
|
// @objc optional func rewardedAdDidLoadFinish(ad: VPRewardedAd)
|
||||||
|
// ///广告展示失败
|
||||||
|
// @objc optional func rewardedAd(ad: VPRewardedAd, didDisplayFail error: Error)
|
||||||
|
// ///广告被展示
|
||||||
|
// @objc optional func rewardedAdDidShow(ad: VPRewardedAd)
|
||||||
|
// ///广告被关闭
|
||||||
|
// @objc optional func rewardedAdDidDismiss(ad: VPRewardedAd)
|
||||||
|
// ///广告被点击
|
||||||
|
// @objc optional func rewardedAdDidClick(ad: VPRewardedAd)
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//@objc protocol VPRewardedAd: NSObjectProtocol {
|
||||||
|
//
|
||||||
|
// weak var delegate: VPRewardedAdDelegate? { get set }
|
||||||
|
// var adInfo: VPAdInfo? { get set }
|
||||||
|
// var isReady: Bool { get }
|
||||||
|
//
|
||||||
|
// func loadAd(adInfo: VPAdInfo)
|
||||||
|
// func showAd()
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//class VPRewardedAdManager: NSObject {
|
||||||
|
//
|
||||||
|
// static let manager = VPRewardedAdManager()
|
||||||
|
//
|
||||||
|
// private weak var delegate: VPRewardedAdManagerDelegate?
|
||||||
|
//
|
||||||
|
// ///广告在加载中
|
||||||
|
// private var isLoadingAd = false
|
||||||
|
// ///广告激活状态
|
||||||
|
// private(set) var isEnable = true
|
||||||
|
//
|
||||||
|
// private var adInfo: VPAdInfo?
|
||||||
|
//
|
||||||
|
// private var adsDate: Date?
|
||||||
|
// ///统计场景
|
||||||
|
// var statScene: VPStatAdModel.AdScene?
|
||||||
|
// var videoInfo: VPVideoInfoModel?
|
||||||
|
//
|
||||||
|
// var rewardedAd: VPRewardedAd? {
|
||||||
|
// didSet {
|
||||||
|
// rewardedAd?.delegate = self
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var isReady: Bool {
|
||||||
|
// return rewardedAd?.isReady ?? false
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// deinit {
|
||||||
|
// NotificationCenter.default.removeObserver(self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override init() {
|
||||||
|
// super.init()
|
||||||
|
// NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func loadAd() {
|
||||||
|
// if isReady || isLoadingAd { return }
|
||||||
|
//
|
||||||
|
// self.isLoadingAd = true
|
||||||
|
//
|
||||||
|
// self.getAdInfo { [weak self] adInfo in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
//
|
||||||
|
// switch adInfo.platform_key {
|
||||||
|
// case .google:
|
||||||
|
// let ad = VPGoogleRewardedAd()
|
||||||
|
// self.rewardedAd = ad
|
||||||
|
// ad.loadAd(adInfo: adInfo)
|
||||||
|
//
|
||||||
|
// case .applovin:
|
||||||
|
// let ad = VPApplovinRewardedAd()
|
||||||
|
// self.rewardedAd = ad
|
||||||
|
// ad.loadAd(adInfo: adInfo)
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// self.adInfo = nil
|
||||||
|
// break
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func showAd(delegate: VPRewardedAdManagerDelegate? = nil) {
|
||||||
|
// if isEnable && !isLoadingAd && !isReady {//没有任何广告,并且没有正在加载的广告,需要出发加载广告
|
||||||
|
// loadAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !isEnable || !isReady {
|
||||||
|
// VPToast.show(text: "veloria_no_ads_tip".localized)
|
||||||
|
// let error = NSError(domain: "veloria_no_ads_tip".localized, code: -1)
|
||||||
|
// self.delegate?.rewardedAdManager?(adManager: self, didOtherFail: error)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// guard let rewardedAd = self.rewardedAd else { return }
|
||||||
|
// self.delegate = delegate
|
||||||
|
//
|
||||||
|
// rewardedAd.showAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private func clean() {
|
||||||
|
// self.rewardedAd = nil
|
||||||
|
// self.statScene = nil
|
||||||
|
// self.videoInfo = nil
|
||||||
|
// self.delegate = nil
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
////MARK: -------------- VPRewardedAdDelegate --------------
|
||||||
|
//extension VPRewardedAdManager: VPRewardedAdDelegate {
|
||||||
|
//
|
||||||
|
// ///发放奖励
|
||||||
|
// func rewardedAd(ad: VPRewardedAd, userDidEarnReward adInfo: VPAdInfo) {
|
||||||
|
// self.requestStatAd(type: "reward", errorMsg: nil)
|
||||||
|
// self.delegate?.rewardedAdManager?(adManager: self, userDidEarnReward: adInfo)
|
||||||
|
// }
|
||||||
|
// ///广告加载失败
|
||||||
|
// func rewardedAd(ad: VPRewardedAd, didLoadFail error: Error) {
|
||||||
|
// isEnable = false
|
||||||
|
// isLoadingAd = false
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
// self.delegate?.rewardedAdManager?(adManager: self, didLoadFail: error)
|
||||||
|
//
|
||||||
|
// self.clean()
|
||||||
|
// }
|
||||||
|
// ///广告加载成功
|
||||||
|
// func rewardedAdDidLoadFinish(ad: VPRewardedAd) {
|
||||||
|
// isLoadingAd = false
|
||||||
|
//
|
||||||
|
// self.delegate?.rewardedAdManagerDidLoadFinish?(adManager: self)
|
||||||
|
// }
|
||||||
|
// ///广告展示失败
|
||||||
|
// func rewardedAd(ad: VPRewardedAd, didDisplayFail error: Error) {
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
|
||||||
|
// self.delegate?.rewardedAdManager?(adManager: self, didDisplayFail: error)
|
||||||
|
//
|
||||||
|
// self.isEnable = false
|
||||||
|
// self.clean()
|
||||||
|
//
|
||||||
|
// /*
|
||||||
|
// if self.adInfo?.platform_key != .google {
|
||||||
|
// let adInfo = VPAdInfo()
|
||||||
|
// adInfo.platform_key = .google
|
||||||
|
// adInfo.ads_id = VPAdManager.google_rewardedAdUnitID
|
||||||
|
//
|
||||||
|
// let ad = VPGoogleRewardedAd()
|
||||||
|
// self.rewardedAd = ad
|
||||||
|
// ad.loadAd(adInfo: adInfo)
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// self.isEnable = false
|
||||||
|
// }
|
||||||
|
// */
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// ///广告被展示
|
||||||
|
// func rewardedAdDidShow(ad: VPRewardedAd) {
|
||||||
|
// self.adsDate = Date()
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "start", errorMsg: nil)
|
||||||
|
// self.delegate?.rewardedAdManagerDidShow?(adManager: self)
|
||||||
|
// }
|
||||||
|
// ///广告被关闭
|
||||||
|
// func rewardedAdDidDismiss(ad: VPRewardedAd) {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// var seconds = 0
|
||||||
|
// if let adsDate = self.adsDate {
|
||||||
|
// seconds = Int(Date().timeIntervalSince(adsDate))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "close", seconds: seconds, errorMsg: nil) { [weak self] in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// if let adInfo = ad.adInfo {
|
||||||
|
// self.delegate?.rewardedAdManager?(adManager: self, didDismiss: adInfo)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// self.clean()
|
||||||
|
// //加载新的广告
|
||||||
|
// self.loadAd()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ///广告被点击
|
||||||
|
// func rewardedAdDidClick(ad: VPRewardedAd) {
|
||||||
|
//
|
||||||
|
// var seconds = 0
|
||||||
|
// if let adsDate = self.adsDate {
|
||||||
|
// seconds = Int(Date().timeIntervalSince(adsDate))
|
||||||
|
// }
|
||||||
|
// self.requestStatAd(type: "click", seconds: seconds, errorMsg: nil)
|
||||||
|
//
|
||||||
|
// self.delegate?.rewardedAdManagerDidClick?(adManager: self)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//extension VPRewardedAdManager {
|
||||||
|
// private func requestStatAd(type: String, seconds: Int = 0, errorMsg: String?, completer: (() -> Void)? = nil) {
|
||||||
|
// guard let adInfo = adInfo else { return }
|
||||||
|
//
|
||||||
|
// let model = VPStatAdModel()
|
||||||
|
// model.type = type
|
||||||
|
// model.ads_id = adInfo.ads_id
|
||||||
|
// model.view_seconds = seconds
|
||||||
|
// model.ad_platform_key = adInfo.platform_key
|
||||||
|
// model.error_msg = errorMsg
|
||||||
|
// model.scene = self.statScene
|
||||||
|
// model.short_play_id = self.videoInfo?.short_play_id
|
||||||
|
// model.short_play_video_id = self.videoInfo?.short_play_video_id
|
||||||
|
//
|
||||||
|
// VPStatAPI.requestStatAd(model: model) { finish in
|
||||||
|
// completer?()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @objc private func didEnterBackgroundNotification() {
|
||||||
|
// if self.statScene == nil { return }
|
||||||
|
//
|
||||||
|
// self.requestStatAd(type: "Interrupt", seconds: 0, errorMsg: nil)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private func getAdInfo(completer: ((_ adInfo: VPAdInfo) -> Void)?) {
|
||||||
|
//
|
||||||
|
// if let adInfo = self.adInfo {
|
||||||
|
// completer?(adInfo)
|
||||||
|
// }
|
||||||
|
// VPAdAPI.requestShowAdInfo { [weak self] adInfo in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
//
|
||||||
|
// if let adInfo = adInfo {
|
||||||
|
// self.adInfo = adInfo
|
||||||
|
// completer?(adInfo)
|
||||||
|
// } else {
|
||||||
|
// let adInfo = VPAdInfo.createNormalAdInfo()
|
||||||
|
// self.adInfo = adInfo
|
||||||
|
// completer?(adInfo)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//
|
||||||
40
SynthReel/Base/AdManager/VPAdInfo.swift
Normal file
40
SynthReel/Base/AdManager/VPAdInfo.swift
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// VPAdInfo.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/7/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
enum VPAdPlatformKey: String, SmartCaseDefaultable {
|
||||||
|
case google = "google"
|
||||||
|
case applovin = "applovin"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct VPAdDataModel: SmartCodable {
|
||||||
|
var ad: VPAdInfo?
|
||||||
|
}
|
||||||
|
|
||||||
|
class VPAdInfo:NSObject, SmartCodable {
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var platform_name: String?
|
||||||
|
var ads_id: String?
|
||||||
|
var status: String?
|
||||||
|
var platform_key: VPAdPlatformKey?
|
||||||
|
|
||||||
|
|
||||||
|
static func createNormalAdInfo() -> VPAdInfo {
|
||||||
|
var adInfo = VPAdInfo()
|
||||||
|
adInfo.platform_key = .applovin
|
||||||
|
adInfo.ads_id = VPAdManager.applovin_rewardedAdUnitID
|
||||||
|
return adInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
100
SynthReel/Base/AdManager/VPAdManager.swift
Normal file
100
SynthReel/Base/AdManager/VPAdManager.swift
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// VPAdManager.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/7/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
import GoogleMobileAds
|
||||||
|
#endif
|
||||||
|
#if canImport(AppLovinSDK)
|
||||||
|
import AppLovinSDK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class VPAdManager: NSObject {
|
||||||
|
|
||||||
|
|
||||||
|
static var completer: (() -> Void)?
|
||||||
|
|
||||||
|
static func start() {
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
MobileAds.shared.start()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
initialize_applovinSdk()
|
||||||
|
}
|
||||||
|
|
||||||
|
///初始化AppLovinSDK
|
||||||
|
static func initialize_applovinSdk(completer: (() -> Void)? = nil) {
|
||||||
|
if completer != nil {
|
||||||
|
self.completer = completer
|
||||||
|
}
|
||||||
|
#if canImport(AppLovinSDK)
|
||||||
|
if !ALSdk.shared().isInitialized {
|
||||||
|
//初始化
|
||||||
|
let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in
|
||||||
|
builder.mediationProvider = ALMediationProviderMAX
|
||||||
|
//#if DEBUG
|
||||||
|
// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()]
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSdk.shared().initialize(with: initConfig) { sdkConfig in
|
||||||
|
// Start loading ads
|
||||||
|
self.completer?()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.completer?()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- 单元ID --------------
|
||||||
|
extension VPAdManager {
|
||||||
|
|
||||||
|
///谷歌激励广告单元ID
|
||||||
|
static var google_rewardedAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/1712485313"
|
||||||
|
#else
|
||||||
|
return ""
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///开屏广告的单元ID
|
||||||
|
static var google_appOpenAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/5575463023"
|
||||||
|
#else
|
||||||
|
return ""
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
///横幅广告单元ID
|
||||||
|
static var google_bannerAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/2435281174"
|
||||||
|
#else
|
||||||
|
return ""
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///激励广告的单元ID
|
||||||
|
static var applovin_rewardedAdUnitID: String {
|
||||||
|
return "39bf981e27728eae"
|
||||||
|
}
|
||||||
|
|
||||||
|
///开屏广告的单元ID
|
||||||
|
static var applovin_appOpenAdUnitID: String {
|
||||||
|
return "d587df0fd75ff03b"
|
||||||
|
}
|
||||||
|
///横幅广告单元ID
|
||||||
|
static var applovin_bannerAdUnitID: String {
|
||||||
|
return "1eb6278843149711"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
33
SynthReel/Base/AdManager/VPStatAdModel.swift
Normal file
33
SynthReel/Base/AdManager/VPStatAdModel.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// VPStatAdModel.swift
|
||||||
|
// Veloria
|
||||||
|
//
|
||||||
|
// Created by 湖南秦九 on 2025/7/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
class VPStatAdModel: NSObject, SmartCodable {
|
||||||
|
|
||||||
|
required override init() {
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AdScene: String, SmartCaseDefaultable {
|
||||||
|
case detail = "detail"
|
||||||
|
case me = "me"
|
||||||
|
case reward = "reward"
|
||||||
|
case splash = "splash"
|
||||||
|
case banner = "banner"
|
||||||
|
}
|
||||||
|
|
||||||
|
var type: String? //start click error click show_failed load_failed Interrupt(退到后台) close
|
||||||
|
var ads_id: String?
|
||||||
|
var view_seconds: Int?
|
||||||
|
var ad_platform_key: VPAdPlatformKey?
|
||||||
|
var scene: AdScene? // splash reward banner detail me turntable
|
||||||
|
var short_play_id: String?
|
||||||
|
var short_play_video_id: String?
|
||||||
|
var error_msg: String?
|
||||||
|
}
|
||||||
137
SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift
Normal file
137
SynthReel/Base/Admanger/BannerAd/SRAdmobOpenAd.swift
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
//
|
||||||
|
// SRAdmobOpenAd.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/11.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
import GoogleMobileAds
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SRAdmobOpenAd: NSObject, SRAppOpenAd {
|
||||||
|
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
private var appOpenAd: AppOpenAd?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
weak var delegate: SRAppOpenAdDelegate?
|
||||||
|
|
||||||
|
var adInfo: VPAdInfo?
|
||||||
|
var isShowingAd: Bool = false
|
||||||
|
|
||||||
|
// 实现 SRAppOpenAd 协议中的 adPlatformKey 属性
|
||||||
|
var adPlatformKey: String {
|
||||||
|
return "AdMob" // 这里可以改成适合你应用的广告平台标识
|
||||||
|
}
|
||||||
|
|
||||||
|
var isReady: Bool {
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
return appOpenAd != nil
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 实现 SRAppOpenAd 协议中的 adUnitID 属性
|
||||||
|
var adUnitID: String {
|
||||||
|
return adInfo?.ads_id ?? ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载广告
|
||||||
|
func loadAd() {
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
guard let adInfo = self.adInfo else { return }
|
||||||
|
|
||||||
|
let adUnitID = adInfo.ads_id ?? ""
|
||||||
|
let request = Request()
|
||||||
|
|
||||||
|
AppOpenAd.load(with: adUnitID, request: request) { [weak self] appOpenAd, error in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
if let error = error {
|
||||||
|
self.delegate?.appOpenAd?(ad: self, didLoadFail: error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.appOpenAd = appOpenAd
|
||||||
|
appOpenAd?.fullScreenContentDelegate = self
|
||||||
|
if let error = error {
|
||||||
|
self.delegate?.appOpenAd?(ad: self, didLoadFail: error)
|
||||||
|
} else {
|
||||||
|
// 如果没有错误,调用加载成功的回调
|
||||||
|
self.delegate?.appOpenAdDidLoadFinish?(ad: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示广告
|
||||||
|
func showAd() {
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
guard let appOpenAd = appOpenAd else {
|
||||||
|
print("App open ad is not ready yet.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isShowingAd {
|
||||||
|
return print("App open ad is already showing.")
|
||||||
|
}
|
||||||
|
|
||||||
|
appOpenAd.present(from: nil)
|
||||||
|
isShowingAd = true
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - FullScreenContentDelegate
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
extension SRAdmobOpenAd: FullScreenContentDelegate {
|
||||||
|
|
||||||
|
func adDidRecordImpression(_ ad: FullScreenPresentingAd) {
|
||||||
|
print("App open ad recorded an impression.")
|
||||||
|
delegate?.appOpenAdDidShow?(ad: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adDidRecordClick(_ ad: FullScreenPresentingAd) {
|
||||||
|
print("App open ad recorded a click.")
|
||||||
|
delegate?.appOpenAdDidClick?(ad: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adWillDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||||
|
print("App open ad will be dismissed.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||||
|
print("App open ad will be presented.")
|
||||||
|
delegate?.appOpenAdDidShow?(ad: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||||
|
print("App open ad was dismissed.")
|
||||||
|
|
||||||
|
// 确保调用正确的委托方法
|
||||||
|
delegate?.appOpenAdDidDismiss?(ad: self)
|
||||||
|
|
||||||
|
appOpenAd = nil
|
||||||
|
isShowingAd = false
|
||||||
|
|
||||||
|
// 重新加载广告
|
||||||
|
|
||||||
|
loadAd()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||||
|
print("App open ad failed to present with error: \(error.localizedDescription)")
|
||||||
|
appOpenAd = nil
|
||||||
|
isShowingAd = false
|
||||||
|
delegate?.appOpenAd?(ad: self, didDisplayFail: error)
|
||||||
|
// 重新加载广告
|
||||||
|
loadAd()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
227
SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift
Normal file
227
SynthReel/Base/Admanger/OpenAd/SROpenAdManager.swift
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
////
|
||||||
|
//// SROpenAdManager.swift
|
||||||
|
//// SynthReel
|
||||||
|
////
|
||||||
|
//// Created by 澜声世纪 on 2025/12/10.
|
||||||
|
//// Copyright © 2025 SR. All rights reserved.
|
||||||
|
////
|
||||||
|
//
|
||||||
|
import UIKit
|
||||||
|
import Foundation
|
||||||
|
import GoogleMobileAds
|
||||||
|
|
||||||
|
@objc protocol SRAppOpenAdManagerDelegate: NSObjectProtocol {
|
||||||
|
|
||||||
|
///广告加载成功
|
||||||
|
@objc optional func appOpenAdManagerDidLoadFinish(adManager: SRAppOpenAdDelegate)
|
||||||
|
///广告加载失败
|
||||||
|
@objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didLoadFail error: Error)
|
||||||
|
///广告展示失败
|
||||||
|
@objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didDisplayFail error: Error)
|
||||||
|
///广告被展示
|
||||||
|
@objc optional func appOpenAdManagerDidShow(adManager: SRAppOpenAdDelegate)
|
||||||
|
///广告被关闭
|
||||||
|
@objc optional func appOpenAdManagerDidDismiss(adManager: SRAppOpenAdDelegate)
|
||||||
|
///广告被点击
|
||||||
|
@objc optional func appOpenAdManagerDidClick(adManager: SRAppOpenAdDelegate)
|
||||||
|
///其它错误
|
||||||
|
@objc optional func appOpenAdManager(adManager: SRAppOpenAdDelegate, didOtherFail error: Error)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objc protocol SRAppOpenAdDelegate: NSObjectProtocol {
|
||||||
|
|
||||||
|
///广告加载失败
|
||||||
|
@objc optional func appOpenAd(ad: SRAppOpenAd, didLoadFail error: Error)
|
||||||
|
///广告加载成功
|
||||||
|
@objc optional func appOpenAdDidLoadFinish(ad: SRAppOpenAd)
|
||||||
|
///广告展示失败
|
||||||
|
@objc optional func appOpenAd(ad: SRAppOpenAd, didDisplayFail error: Error)
|
||||||
|
///广告被展示
|
||||||
|
@objc optional func appOpenAdDidShow(ad: SRAppOpenAd)
|
||||||
|
///广告被关闭
|
||||||
|
@objc optional func appOpenAdDidDismiss(ad: SRAppOpenAd)
|
||||||
|
///广告被点击
|
||||||
|
@objc optional func appOpenAdDidClick(ad: SRAppOpenAd)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc protocol SRAppOpenAd: NSObjectProtocol {
|
||||||
|
|
||||||
|
weak var delegate: SRAppOpenAdDelegate? { get set }
|
||||||
|
|
||||||
|
var adPlatformKey: String { get }
|
||||||
|
|
||||||
|
var adUnitID: String { get }
|
||||||
|
|
||||||
|
var isReady: Bool { get }
|
||||||
|
|
||||||
|
func loadAd()
|
||||||
|
func showAd()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SRAppOpenAdManager: NSObject {
|
||||||
|
|
||||||
|
static let manager = SRAppOpenAdManager()
|
||||||
|
|
||||||
|
weak var delegate: SRAppOpenAdManagerDelegate?
|
||||||
|
|
||||||
|
private(set) var appOpenAd: SRAppOpenAd? {
|
||||||
|
didSet {
|
||||||
|
oldValue?.delegate = nil
|
||||||
|
appOpenAd?.delegate = self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isLoading = false
|
||||||
|
private var isShowing = false
|
||||||
|
///允许自动展示
|
||||||
|
private var needAutoShow = false
|
||||||
|
|
||||||
|
private var timeOutTimer: Timer?
|
||||||
|
|
||||||
|
private var adsDate: Date?
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showAdIfAvailable() {
|
||||||
|
|
||||||
|
if self.appOpenAd?.isReady == true {
|
||||||
|
self.showAd()
|
||||||
|
} else {
|
||||||
|
self.timeOutTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false)
|
||||||
|
|
||||||
|
self.needAutoShow = true
|
||||||
|
self.loadAd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadAd() {
|
||||||
|
guard !isLoading else { return }
|
||||||
|
|
||||||
|
self.isLoading = true
|
||||||
|
appOpenAd = SRAdmobOpenAd()
|
||||||
|
appOpenAd?.loadAd()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showAd() {
|
||||||
|
guard self.appOpenAd?.isReady == true else { return }
|
||||||
|
guard !self.isShowing else { return }
|
||||||
|
|
||||||
|
|
||||||
|
self.isShowing = true
|
||||||
|
self.appOpenAd?.showAd()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func handleTimeOutTimer() {
|
||||||
|
self.needAutoShow = false
|
||||||
|
cleanTimer()
|
||||||
|
|
||||||
|
let error = NSError(domain: "time-out", code: -1)
|
||||||
|
requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
self.delegate?.appOpenAdManager?(adManager: self, didOtherFail: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func cleanTimer() {
|
||||||
|
self.timeOutTimer?.invalidate()
|
||||||
|
self.timeOutTimer = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func clean() {
|
||||||
|
appOpenAd = nil
|
||||||
|
delegate = nil
|
||||||
|
isShowing = false
|
||||||
|
self.adsDate = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- VPAppOpenAdDelegate --------------
|
||||||
|
extension SRAppOpenAdManager: SRAppOpenAdDelegate {
|
||||||
|
|
||||||
|
///广告加载失败
|
||||||
|
func appOpenAd(ad: SRAppOpenAd, didLoadFail error: Error) {
|
||||||
|
cleanTimer()
|
||||||
|
isLoading = false
|
||||||
|
requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||||
|
|
||||||
|
self.delegate?.appOpenAdManager?(adManager: self, didLoadFail: error)
|
||||||
|
|
||||||
|
clean()
|
||||||
|
}
|
||||||
|
///广告加载成功
|
||||||
|
func appOpenAdDidLoadFinish(ad: SRAppOpenAd) {
|
||||||
|
cleanTimer()
|
||||||
|
self.isLoading = false
|
||||||
|
self.delegate?.appOpenAdManagerDidLoadFinish?(adManager: self)
|
||||||
|
|
||||||
|
if needAutoShow {
|
||||||
|
self.needAutoShow = false
|
||||||
|
self.showAd()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
///广告展示失败
|
||||||
|
func appOpenAd(ad: SRAppOpenAd, didDisplayFail error: Error) {
|
||||||
|
requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
|
||||||
|
self.delegate?.appOpenAdManager?(adManager: self, didDisplayFail: error)
|
||||||
|
clean()
|
||||||
|
}
|
||||||
|
///广告被展示
|
||||||
|
func appOpenAdDidShow(ad: SRAppOpenAd) {
|
||||||
|
adsDate = Date()
|
||||||
|
requestStatAd(type: "start", errorMsg: nil)
|
||||||
|
self.delegate?.appOpenAdManagerDidShow?(adManager: self)
|
||||||
|
}
|
||||||
|
///广告被关闭
|
||||||
|
func appOpenAdDidDismiss(ad: SRAppOpenAd) {
|
||||||
|
requestStatAd(type: "close", errorMsg: nil)
|
||||||
|
self.delegate?.appOpenAdManagerDidDismiss?(adManager: self)
|
||||||
|
clean()
|
||||||
|
}
|
||||||
|
///广告被点击
|
||||||
|
func appOpenAdDidClick(ad: SRAppOpenAd) {
|
||||||
|
requestStatAd(type: "click", errorMsg: nil)
|
||||||
|
self.delegate?.appOpenAdManagerDidClick?(adManager: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SRAppOpenAdManager {
|
||||||
|
|
||||||
|
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
|
||||||
|
model.scene = .splash
|
||||||
|
|
||||||
|
// VPStatAPI.requestStatAd(model: model)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objc private func didEnterBackgroundNotification() {
|
||||||
|
guard self.isShowing else { return }
|
||||||
|
|
||||||
|
self.requestStatAd(type: "Interrupt", errorMsg: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
101
SynthReel/Base/Admanger/SRAdManger.swift
Normal file
101
SynthReel/Base/Admanger/SRAdManger.swift
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
//
|
||||||
|
// SRAdManger.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/11.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
import GoogleMobileAds
|
||||||
|
#endif
|
||||||
|
#if canImport(AppLovinSDK)
|
||||||
|
import AppLovinSDK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SRAdManger: NSObject {
|
||||||
|
|
||||||
|
|
||||||
|
static var completer: (() -> Void)?
|
||||||
|
|
||||||
|
static func start() {
|
||||||
|
#if canImport(GoogleMobileAds)
|
||||||
|
MobileAds.shared.start()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
initialize_applovinSdk()
|
||||||
|
}
|
||||||
|
|
||||||
|
///初始化AppLovinSDK
|
||||||
|
static func initialize_applovinSdk(completer: (() -> Void)? = nil) {
|
||||||
|
if completer != nil {
|
||||||
|
self.completer = completer
|
||||||
|
}
|
||||||
|
#if canImport(AppLovinSDK)
|
||||||
|
if !ALSdk.shared().isInitialized {
|
||||||
|
//初始化
|
||||||
|
let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in
|
||||||
|
builder.mediationProvider = ALMediationProviderMAX
|
||||||
|
//#if DEBUG
|
||||||
|
// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()]
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ALSdk.shared().initialize(with: initConfig) { sdkConfig in
|
||||||
|
// Start loading ads
|
||||||
|
self.completer?()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.completer?()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- 单元ID --------------
|
||||||
|
extension SRAdManger {
|
||||||
|
|
||||||
|
///谷歌激励广告单元ID
|
||||||
|
static var google_rewardedAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/1712485313"
|
||||||
|
#else
|
||||||
|
return "ca-app-pub-6275401933109862/2121481439"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///开屏广告的单元ID
|
||||||
|
static var google_appOpenAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/5575463023"
|
||||||
|
#else
|
||||||
|
return "ca-app-pub-6275401933109862/7130265535"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
///横幅广告单元ID
|
||||||
|
static var google_bannerAdUnitID: String {
|
||||||
|
#if DEBUG
|
||||||
|
return "ca-app-pub-3940256099942544/2435281174"
|
||||||
|
#else
|
||||||
|
return "ca-app-pub-6275401933109862/7971191024"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
///激励广告的单元ID
|
||||||
|
static var applovin_rewardedAdUnitID: String {
|
||||||
|
return "3708ac6b6026e375"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ///开屏广告的单元ID
|
||||||
|
// static var applovin_appOpenAdUnitID: String {
|
||||||
|
// return "d587df0fd75ff03b"
|
||||||
|
// }
|
||||||
|
// ///横幅广告单元ID
|
||||||
|
// static var applovin_bannerAdUnitID: String {
|
||||||
|
// return "1eb6278843149711"
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRDefine.swift
|
// SRDefine.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRUserDefaultsKey.swift
|
// SRUserDefaultsKey.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -12,3 +12,12 @@ let kSRAccountTokenDefaultsKey = "kSRAccountTokenDefaultsKey"
|
|||||||
|
|
||||||
///用户信息
|
///用户信息
|
||||||
let kSRUserInfoDefaultsKey = "kSRUserInfoDefaultsKey"
|
let kSRUserInfoDefaultsKey = "kSRUserInfoDefaultsKey"
|
||||||
|
|
||||||
|
|
||||||
|
let kSRWaitRestoreIAPDefaultsKey = "kSRWaitRestoreIAPDefaultsKey"
|
||||||
|
|
||||||
|
let kSRApnsAlertDefaultsKey = "kSRApnsAlertDefaultsKey"
|
||||||
|
|
||||||
|
let kSRVersionUpdateAlertDefaultsKey = "kSRVersionUpdateAlertDefaultsKey"
|
||||||
|
|
||||||
|
let kSRHasBeenOpenedAPPDefaultsKey = "kSRHasBeenOpenedAPPDefaultsKey"
|
||||||
|
|||||||
24
SynthReel/Base/Extension/Dictionary+SRAdd.swift
Normal file
24
SynthReel/Base/Extension/Dictionary+SRAdd.swift
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Dictionary+SRAdd.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// NSNumber+SRAdd.swift
|
// NSNumber+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,17 +2,19 @@
|
|||||||
// String+SRAdd.swift
|
// String+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import YYCategories
|
import YYCategories
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
|
|
||||||
var localized: String {
|
var localized: String {
|
||||||
return String(localized: LocalizationValue(self))
|
let value = String(localized: LocalizationValue(self))
|
||||||
|
return value.replacingOccurrences(of: "<br>", with: "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func localizedReplace(text: String) -> String {
|
func localizedReplace(text: String) -> String {
|
||||||
@ -24,3 +26,32 @@ extension String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension String: SmartCodable {
|
||||||
|
|
||||||
|
static func timeZone() -> String {
|
||||||
|
let timeZone = NSTimeZone.local as NSTimeZone
|
||||||
|
let timeZoneSecondsFromGMT = timeZone.secondsFromGMT / 3600
|
||||||
|
return String(format: "GMT+0%d:00", timeZoneSecondsFromGMT)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UIFont+SRAdd.swift
|
// UIFont+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UINavigationBar+SRAdd.swift
|
// UINavigationBar+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by CSGY on 2025/11/25.
|
// Created by 澜声世纪 on 2025/11/25.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UIScreen+SRAdd.swift
|
// UIScreen+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UIScrollView+SRAdd.swift
|
// UIScrollView+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UIStackView+SRAdd.swift
|
// UIStackView+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UIView+SRAdd.swift
|
// UIView+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// UserDefaults+SRAdd.swift
|
// UserDefaults+SRAdd.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
26
SynthReel/Base/Model/SROpenAppModel.swift
Normal file
26
SynthReel/Base/Model/SROpenAppModel.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// SROpenAppModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/9.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct SROpenAppModel: SmartCodable {
|
||||||
|
|
||||||
|
enum Path: String, SmartCaseDefaultable {
|
||||||
|
case videoDetail = "detail"
|
||||||
|
///反馈列表
|
||||||
|
case feedback = "feedback"
|
||||||
|
///活动
|
||||||
|
case promotion = "promotion"
|
||||||
|
}
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var message_id: String?
|
||||||
|
var short_play_id: String?
|
||||||
|
var path: Path?
|
||||||
|
}
|
||||||
39
SynthReel/Base/Model/SRVersionUpdateModel.swift
Normal file
39
SynthReel/Base/Model/SRVersionUpdateModel.swift
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// SRVersionUpdateModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/10.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct SRVersionUpdateModel: SmartCodable {
|
||||||
|
|
||||||
|
var version_code: String?
|
||||||
|
var des: String?
|
||||||
|
var version_name: String?
|
||||||
|
|
||||||
|
var force: Bool?
|
||||||
|
|
||||||
|
|
||||||
|
func canUpdate() -> Bool {
|
||||||
|
guard let version = version_code else { return false }
|
||||||
|
|
||||||
|
let result = kSRAPPVersion.compare(version, options: .numeric)
|
||||||
|
if result == .orderedAscending {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||||
|
return [
|
||||||
|
CodingKeys.des <--- ["description"]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRNetwork.swift
|
// SRNetwork.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -20,7 +20,8 @@ class SRNetwork: NSObject {
|
|||||||
|
|
||||||
static func request<T>(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response<T>) -> Void)?) {
|
static func request<T>(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response<T>) -> Void)?) {
|
||||||
|
|
||||||
if SRAccountManager.manager.token == nil {
|
if SRLogin.manager.token == nil {
|
||||||
|
print(SRLogin.manager.token ?? "123")
|
||||||
self.requestToken(completer: nil)
|
self.requestToken(completer: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,11 +49,15 @@ class SRNetwork: NSObject {
|
|||||||
static func _request<T>(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response<T>) -> Void)?) -> Cancellable {
|
static func _request<T>(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response<T>) -> Void)?) -> Cancellable {
|
||||||
|
|
||||||
if parameters.isLoding {
|
if parameters.isLoding {
|
||||||
SRHud.show()
|
DispatchQueue.main.async {
|
||||||
|
SRHud.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return provider.request(.request(parameters: parameters)) { result in
|
return provider.request(.request(parameters: parameters)) { result in
|
||||||
if parameters.isLoding {
|
if parameters.isLoding {
|
||||||
SRHud.dismiss()
|
DispatchQueue.main.async {
|
||||||
|
SRHud.dismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
guard let completion = completion else {return}
|
guard let completion = completion else {return}
|
||||||
_resultDispose(parameters: parameters, result: result, completion: completion)
|
_resultDispose(parameters: parameters, result: result, completion: completion)
|
||||||
@ -81,7 +86,7 @@ class SRNetwork: NSObject {
|
|||||||
self.requestToken { token in
|
self.requestToken { token in
|
||||||
if token != nil {
|
if token != nil {
|
||||||
_Concurrency.Task {
|
_Concurrency.Task {
|
||||||
await SRAccountManager.manager.updateUserInfo()
|
await SRLogin.manager.requestUserToken(completer: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +169,7 @@ class SRNetwork: NSObject {
|
|||||||
|
|
||||||
extension SRNetwork {
|
extension SRNetwork {
|
||||||
///获取token
|
///获取token
|
||||||
static func requestToken(completer: ((_ token: SRAccountToken?) -> Void)?) {
|
static func requestToken(completer: ((_ token: SRTokenModel?) -> Void)?) {
|
||||||
guard self.tokenOperation == nil else {
|
guard self.tokenOperation == nil else {
|
||||||
completer?(nil)
|
completer?(nil)
|
||||||
return
|
return
|
||||||
@ -173,11 +178,11 @@ extension SRNetwork {
|
|||||||
self.tokenOperation = BlockOperation(block: {
|
self.tokenOperation = BlockOperation(block: {
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
let semaphore = DispatchSemaphore(value: 0)
|
||||||
let param = SRNetwork.Parameters(path: "/customer/register")
|
let param = SRNetwork.Parameters(path: "/customer/register")
|
||||||
|
print("chongfu")
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRAccountToken>) in
|
SRNetwork.request(parameters: param) { (response: SRNetwork.Response<SRTokenModel>) in
|
||||||
if let token = response.data {
|
if let token = response.data {
|
||||||
SRAccountManager.manager.setAccountToken(token)
|
SRLogin.manager.loginSuccessSaveToken(token)
|
||||||
}
|
}
|
||||||
do { semaphore.signal() }
|
do { semaphore.signal() }
|
||||||
self.tokenOperation = nil
|
self.tokenOperation = nil
|
||||||
@ -189,5 +194,4 @@ extension SRNetwork {
|
|||||||
operationQueue.addOperation(self.tokenOperation!)
|
operationQueue.addOperation(self.tokenOperation!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRNetworkModel.swift
|
// SRNetworkModel.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ extension SRNetwork {
|
|||||||
var data: T?
|
var data: T?
|
||||||
var msg: String?
|
var msg: String?
|
||||||
|
|
||||||
@SmartIgnored
|
@IgnoredKey
|
||||||
var rawData: Any?
|
var rawData: Any?
|
||||||
|
|
||||||
var isSuccess: Bool {
|
var isSuccess: Bool {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRNetworkReachableManager.swift
|
// SRNetworkReachableManager.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRResponseCryptor.swift
|
// SRResponseCryptor.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRTargetType.swift
|
// SRTargetType.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ extension SRTargetType: TargetType {
|
|||||||
"device-id" : SRDeviceId.shared.id, //设备id
|
"device-id" : SRDeviceId.shared.id, //设备id
|
||||||
"system-type" : "ios",
|
"system-type" : "ios",
|
||||||
"model" : UIDevice.current.machineModelName ?? "",
|
"model" : UIDevice.current.machineModelName ?? "",
|
||||||
"authorization" : SRAccountManager.manager.token?.token ?? "",
|
"authorization" : SRLogin.manager.token?.token ?? "",
|
||||||
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
|
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
|
||||||
"product-prefix" : "SynthReel"
|
"product-prefix" : "SynthReel"
|
||||||
]
|
]
|
||||||
|
|||||||
@ -2,16 +2,27 @@
|
|||||||
// SRUrlPath.swift
|
// SRUrlPath.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/12.
|
// Created by 澜声世纪 on 2025/11/12.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
let SRBaseURL = "https://api-hbqinjiu.hbqinjiu.com"
|
let SRBaseURL = "https://api-synthreeltv.synthreeltv.com"
|
||||||
let SRUrlPathPrefix = "/eon"
|
let SRUrlPathPrefix = "/th"
|
||||||
let SRWebBaseURL = "https://www.hbqinjiu.com"
|
let SRWebBaseURL = "https://www.synthreeltv.com"
|
||||||
let SRCampaignWebURL = "https://campaign.hbqinjiu.com"
|
let SRCampaignWebURL = "https://campaign.synthreeltv.com"
|
||||||
|
|
||||||
|
//@"https://api-univicos.univicos.com/uni";
|
||||||
|
|
||||||
|
///反馈首页
|
||||||
|
let kSRFeedBackHomeWebUrl = SRCampaignWebURL + "/pages/leave/index"
|
||||||
|
///反馈列表
|
||||||
|
let kSRFeedBackListWebUrl = SRCampaignWebURL + "/pages/leave/list"
|
||||||
|
///反馈详情
|
||||||
|
let kSRFeedBackDetailWebUrl = SRCampaignWebURL + "/pages/leave/detail"
|
||||||
|
///注销账号
|
||||||
|
let kSRLogoutWebUrl = SRCampaignWebURL + "/pages/setting/logout"
|
||||||
|
|
||||||
|
let kSRRewardWebUrl = SRCampaignWebURL + "/pages/reward/theme4"
|
||||||
/*
|
/*
|
||||||
SynthReel
|
SynthReel
|
||||||
admin-api https://admin-api-synthreeltv.synthreeltv.com
|
admin-api https://admin-api-synthreeltv.synthreeltv.com
|
||||||
|
|||||||
@ -2,11 +2,12 @@
|
|||||||
// SRCollectionView.swift
|
// SRCollectionView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import LYEmptyView
|
||||||
|
|
||||||
class SRCollectionView: UICollectionView {
|
class SRCollectionView: UICollectionView {
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRGradientView.swift
|
// SRGradientView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
45
SynthReel/Base/View/SRGradientbutton.swift
Normal file
45
SynthReel/Base/View/SRGradientbutton.swift
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// SRGradientbutton.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/27.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRGradientbutton: UIButton {
|
||||||
|
|
||||||
|
override class var layerClass: AnyClass {
|
||||||
|
return CAGradientLayer.self
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa_gradientLayer: CAGradientLayer {
|
||||||
|
return self.layer as! CAGradientLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa_colors: [CGColor]? {
|
||||||
|
didSet {
|
||||||
|
fa_gradientLayer.colors = fa_colors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa_startPoint: CGPoint = .zero {
|
||||||
|
didSet {
|
||||||
|
fa_gradientLayer.startPoint = fa_startPoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa_endPoint: CGPoint = .zero {
|
||||||
|
didSet {
|
||||||
|
fa_gradientLayer.endPoint = fa_endPoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fa_locations: [NSNumber] = [] {
|
||||||
|
didSet {
|
||||||
|
fa_gradientLayer.locations = fa_locations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRImageView.swift
|
// SRImageView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRLabel.swift
|
// SRLabel.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRNavgationTitleView.swift
|
// SRNavgationTitleView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by CSGY on 2025/11/25.
|
// Created by 澜声世纪 on 2025/11/25.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class SRNavgationTitleView: UIView {
|
|||||||
|
|
||||||
private let titleLabel: UILabel = {
|
private let titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 18, weight: .bold)
|
label.font = .font(ofSize: 18, weight: .bold).withBoldItalic()
|
||||||
label.textAlignment = .center
|
label.textAlignment = .center
|
||||||
label.textColor = .white
|
label.textColor = .white
|
||||||
return label
|
return label
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRPanModalContentView.swift
|
// SRPanModalContentView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -12,16 +12,20 @@ import SnapKit
|
|||||||
|
|
||||||
class SRPanModalContentView: HWPanModalContentView {
|
class SRPanModalContentView: HWPanModalContentView {
|
||||||
|
|
||||||
|
var mainScrollView: UIScrollView?
|
||||||
|
|
||||||
var contentHeight = UIScreen.height * (2 / 3)
|
var contentHeight = UIScreen.height * (2 / 3)
|
||||||
|
|
||||||
|
var bgImage: UIImage? = UIImage(named: "pan_bg_image_01")
|
||||||
|
|
||||||
|
|
||||||
///更新UI contentSize发生变化时调用
|
///更新UI contentSize发生变化时调用
|
||||||
func setNeedsLayoutUpdate() {
|
func setNeedsLayoutUpdate() {
|
||||||
self.panModalSetNeedsLayoutUpdate()
|
self.panModalSetNeedsLayoutUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy var bgImageView: UIImageView = {
|
lazy var bgImageView: UIImageView = {
|
||||||
let imageView = UIImageView(image: UIImage(named: "pan_bg_image_01"))
|
let imageView = UIImageView(image: bgImage)
|
||||||
return imageView
|
return imageView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -35,15 +39,28 @@ class SRPanModalContentView: HWPanModalContentView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 子类更新背景图
|
||||||
|
func updateBackgroundImage(_ img: UIImage?) {
|
||||||
|
self.bgImage = img
|
||||||
|
self.bgImageView.image = img
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子类更新高度
|
||||||
|
func updateContentHeight(_ height: CGFloat) {
|
||||||
|
self.contentHeight = height
|
||||||
|
self.panModalSetNeedsLayoutUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: HWPanModalPresentable
|
//MARK: HWPanModalPresentable
|
||||||
override func panScrollable() -> UIScrollView? {
|
override func panScrollable() -> UIScrollView? {
|
||||||
return nil
|
return mainScrollView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override func longFormHeight() -> PanModalHeight {
|
override func longFormHeight() -> PanModalHeight {
|
||||||
return PanModalHeightMake(.content, contentHeight)
|
return PanModalHeightMake(.content, contentHeight)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRScrollView.swift
|
// SRScrollView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRTableView.swift
|
// SRTableView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRTableViewCell.swift
|
// SRTableViewCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
//
|
||||||
|
// SRAppOpenAdViewController.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/11.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRAppOpenAdViewController: SRViewController {
|
||||||
|
|
||||||
|
var didEndBlock: (() -> Void)?
|
||||||
|
|
||||||
|
private(set) lazy var lanuchVC: UIViewController? = {
|
||||||
|
let vc = SRTool.lanuchViewController
|
||||||
|
return vc
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
if let vc = lanuchVC {
|
||||||
|
addChild(vc)
|
||||||
|
view.addSubview(vc.view)
|
||||||
|
}
|
||||||
|
let manager = SRAppOpenAdManager.manager
|
||||||
|
manager.delegate = self
|
||||||
|
manager.showAdIfAvailable()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- VPAppOpenAdManagerDelegate --------------
|
||||||
|
extension SRAppOpenAdViewController: SRAppOpenAdManagerDelegate {
|
||||||
|
|
||||||
|
func appOpenAdManagerDidDismiss(adManager: SRAppOpenAdDelegate) {
|
||||||
|
self.didEndBlock?()
|
||||||
|
}
|
||||||
|
|
||||||
|
func appOpenAdManager(adManager: SRAppOpenAdDelegate, didLoadFail error: any Error) {
|
||||||
|
self.didEndBlock?()
|
||||||
|
}
|
||||||
|
|
||||||
|
func appOpenAdManager(adManager: SRAppOpenAdDelegate, didDisplayFail error: any Error) {
|
||||||
|
self.didEndBlock?()
|
||||||
|
}
|
||||||
|
|
||||||
|
func appOpenAdManager(adManager: SRAppOpenAdDelegate, didOtherFail error: any Error) {
|
||||||
|
self.didEndBlock?()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
52
SynthReel/Base/ViewController/SRAppStartViewController.swift
Normal file
52
SynthReel/Base/ViewController/SRAppStartViewController.swift
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// SRAppStartViewController.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/9.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRAppStartViewController: SRViewController {
|
||||||
|
|
||||||
|
var openAppBlock: (() -> Void)?
|
||||||
|
|
||||||
|
private lazy var lanuchVC: UIViewController? = {
|
||||||
|
let vc = SRTool.lanuchViewController
|
||||||
|
return vc
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var startButton: UIButton = {
|
||||||
|
let button = SRGradientbutton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.openAppBlock?()
|
||||||
|
}))
|
||||||
|
button.setBackgroundImage(.startButton, for: .normal)
|
||||||
|
button.setTitle("start", for: .normal)
|
||||||
|
button.setTitleColor(.white, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize:16, weight: .semibold)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
if let vc = lanuchVC {
|
||||||
|
addChild(vc)
|
||||||
|
view.addSubview(vc.view)
|
||||||
|
}
|
||||||
|
|
||||||
|
view.addSubview(startButton)
|
||||||
|
|
||||||
|
startButton.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview().inset(48)
|
||||||
|
make.height.equalTo(50)
|
||||||
|
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 110))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRNavigationController.swift
|
// SRNavigationController.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRTabBarController.swift
|
// SRTabBarController.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -32,6 +32,9 @@ class SRTabBarController: ESTabBarController {
|
|||||||
self.tabBar.standardAppearance = appearance
|
self.tabBar.standardAppearance = appearance
|
||||||
self.tabBar.scrollEdgeAppearance = appearance
|
self.tabBar.scrollEdgeAppearance = appearance
|
||||||
self.tabBar.isTranslucent = false
|
self.tabBar.isTranslucent = false
|
||||||
|
|
||||||
|
|
||||||
|
// SRTool.checkUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRViewController.swift
|
// SRViewController.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/13.
|
// Created by 澜声世纪 on 2025/11/13.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
83
SynthReel/Base/webview/SRAppWebViewController.swift
Normal file
83
SynthReel/Base/webview/SRAppWebViewController.swift
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
//
|
||||||
|
// SRAppWebViewController.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRAppWebViewController: SRBaseWebViewController {
|
||||||
|
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
|
||||||
|
private var receiveDataCount = 0
|
||||||
|
|
||||||
|
var theme: String? = "theme_16"
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
self.autoTitle = false
|
||||||
|
|
||||||
|
if webUrl == kSRFeedBackListWebUrl {
|
||||||
|
self.title = "synthreel_feedback_history".localized
|
||||||
|
} else if webUrl == kSRFeedBackHomeWebUrl {
|
||||||
|
self.title = "synthreel_feedback".localized
|
||||||
|
} else if webUrl == kSRFeedBackDetailWebUrl {
|
||||||
|
self.title = "synthreel_feedback_detail".localized
|
||||||
|
} else if webUrl == kSRLogoutWebUrl {
|
||||||
|
self.title = "synthreel_account_deletion".localized
|
||||||
|
}else if webUrl == kSRRewardWebUrl {
|
||||||
|
self.title = "Rewards".localized
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func fa_webViewDidFinishLoad(_ webView: SRWebView) {
|
||||||
|
super.fa_webViewDidFinishLoad(webView)
|
||||||
|
receiveDataCount = 0
|
||||||
|
receiveDataFromNative()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRAppWebViewController {
|
||||||
|
|
||||||
|
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" : SRLogin.manager.token?.token ?? "",
|
||||||
|
"time_zone" : String.timeZone(),
|
||||||
|
// "lang" : FALanguageManager.manager.currentLanguageKey,
|
||||||
|
"lang" : "en",
|
||||||
|
"type" : "ios",
|
||||||
|
"device-id" : SRDeviceId.shared.id
|
||||||
|
]
|
||||||
|
|
||||||
|
if let theme = theme {
|
||||||
|
dic["theme"] = theme
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
112
SynthReel/Base/webview/SRBaseWebViewController + Script.swift
Normal file
112
SynthReel/Base/webview/SRBaseWebViewController + Script.swift
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
//
|
||||||
|
// SRBaseWebViewController + Script.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
import ZLPhotoBrowser
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
///APP交互
|
||||||
|
let kSRWebMessageAPP = "js2app"
|
||||||
|
///打开反馈列表
|
||||||
|
let kSRWebMessageOpenFeedbackList = "openFeedbackList"
|
||||||
|
///打开反馈详情
|
||||||
|
let kSRWebMessageOpenFeedbackDetail = "openFeedbackDetail"
|
||||||
|
///打开相册
|
||||||
|
let kSRWebMessageOpenPhotoPicker = "openPhotoPicker"
|
||||||
|
///删除账号成功
|
||||||
|
let kSRWebMessageAccountDeletionFinish = "accountLogout"
|
||||||
|
|
||||||
|
extension SRBaseWebViewController {
|
||||||
|
|
||||||
|
func fa_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||||
|
let name = message.name
|
||||||
|
let body = message.body
|
||||||
|
|
||||||
|
switch name {
|
||||||
|
case kSRWebMessageOpenFeedbackList:
|
||||||
|
let vc = SRAppWebViewController()
|
||||||
|
vc.webUrl = kSRFeedBackListWebUrl
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case kSRWebMessageOpenFeedbackDetail:
|
||||||
|
guard let body = body as? [String : Any] else { return }
|
||||||
|
guard let id = body["id"] as? Int else { return }
|
||||||
|
|
||||||
|
let vc = SRAppWebViewController()
|
||||||
|
vc.id = "\(id)"
|
||||||
|
vc.webUrl = kSRFeedBackDetailWebUrl
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
|
||||||
|
case kSRWebMessageOpenPhotoPicker:
|
||||||
|
openPhotoPicker()
|
||||||
|
|
||||||
|
case kSRWebMessageAPP:
|
||||||
|
guard let body = message.body as? [String : Any] else { return }
|
||||||
|
guard let model = SRWebMessageModel.deserialize(from: body) else { return }
|
||||||
|
let type = model.type
|
||||||
|
let data = model.data
|
||||||
|
|
||||||
|
if type == "login" {
|
||||||
|
// let view = FALoginView()
|
||||||
|
// view.present(in: nil)
|
||||||
|
|
||||||
|
} else if type == "open_notify" {
|
||||||
|
// openNotify()
|
||||||
|
|
||||||
|
} else if type == "watch_video" {
|
||||||
|
let vc = SRDetailPlayerViewController()
|
||||||
|
vc.shortId = data?.short_play_id
|
||||||
|
// vc.activityId = data?.activity_id
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
guard let urlStr = data?.link else { return }
|
||||||
|
guard let url = URL(string: urlStr) else { return }
|
||||||
|
if UIApplication.shared.canOpenURL(url) {
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case kSRWebMessageAccountDeletionFinish:
|
||||||
|
self.navigationController?.popToRootViewController(animated: true)
|
||||||
|
NotificationCenter.default.post(name: SRLogin.loginStatusChangeNotification, object: nil)
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///打开相册
|
||||||
|
private func openPhotoPicker() {
|
||||||
|
|
||||||
|
ZLPhotoConfiguration.default().allowSelectOriginal = false
|
||||||
|
ZLPhotoConfiguration.default().maxSelectCount = 1
|
||||||
|
ZLPhotoConfiguration.default().allowEditImage = false
|
||||||
|
ZLPhotoConfiguration.default().allowSelectVideo = false
|
||||||
|
ZLPhotoConfiguration.default().allowSelectGif = false
|
||||||
|
ZLPhotoConfiguration.default().allowTakePhotoInLibrary = false
|
||||||
|
|
||||||
|
let picker = ZLPhotoPicker()
|
||||||
|
picker.selectImageBlock = { [weak self] (results, _) in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let image = results.first?.image else { return }
|
||||||
|
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
|
||||||
|
let imageDataStr = imageData.base64EncodedString(options: .endLineWithCarriageReturn)
|
||||||
|
|
||||||
|
let js = "uploadConvertImage('\(imageDataStr)')"
|
||||||
|
self.webView.evaluateJavaScript(js)
|
||||||
|
}
|
||||||
|
|
||||||
|
picker.showPhotoLibrary(sender: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
114
SynthReel/Base/webview/SRBaseWebViewController.swift
Normal file
114
SynthReel/Base/webview/SRBaseWebViewController.swift
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// SRBaseWebViewController.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
|
||||||
|
class SRBaseWebViewController: SRViewController {
|
||||||
|
|
||||||
|
var webUrl: String?
|
||||||
|
|
||||||
|
///自动设置标题
|
||||||
|
var autoTitle = true
|
||||||
|
|
||||||
|
var needAutoRefresh = true
|
||||||
|
|
||||||
|
private(set) lazy var webView: SRWebView = {
|
||||||
|
let controller = WKUserContentController()
|
||||||
|
|
||||||
|
let config = WKWebViewConfiguration()
|
||||||
|
config.userContentController = controller
|
||||||
|
config.preferences.javaScriptEnabled = true
|
||||||
|
/** 默认是不能通过JS自动打开窗口的,必须通过用户交互才能打开 */
|
||||||
|
config.preferences.javaScriptCanOpenWindowsAutomatically = true
|
||||||
|
let webView = SRWebView(frame: self.view.bounds, configuration: config)
|
||||||
|
webView.delegate = self
|
||||||
|
return webView
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
// self.edgesForExtendedLayout = []
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
|
||||||
|
if let url = webUrl {
|
||||||
|
self.load(webUrl: url)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
|
// self.fa_setNavigationStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(webUrl: String) {
|
||||||
|
let str: String = webUrl
|
||||||
|
|
||||||
|
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 SRBaseWebViewController {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
self.view.addSubview(webView)
|
||||||
|
|
||||||
|
self.webView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(0)
|
||||||
|
make.right.equalToSuperview().offset(0)
|
||||||
|
make.bottom.equalToSuperview().offset(0)
|
||||||
|
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: -------------- VPWebViewDelegate --------------
|
||||||
|
extension SRBaseWebViewController: SRWebViewDelegate {
|
||||||
|
|
||||||
|
func fa_webView(_ webView: SRWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool {
|
||||||
|
self.webView.isHidden = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func fa_webViewDidStartLoad(_ webView: SRWebView) {
|
||||||
|
SRHud.show(containerView: self.view)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fa_webView(webView: SRWebView, didChangeTitle title: String) {
|
||||||
|
if autoTitle {
|
||||||
|
self.title = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fa_webViewDidFinishLoad(_ webView: SRWebView) {
|
||||||
|
self.webView.isHidden = false
|
||||||
|
SRHud.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
func fa_webView(_ webView: SRWebView, didFailLoadWithError error: any Error) {
|
||||||
|
SRHud.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
func fa_userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||||
|
self.fa_webViewUserContentController(didReceive: message)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
SynthReel/Base/webview/SRWebMessageModel.swift
Normal file
26
SynthReel/Base/webview/SRWebMessageModel.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// SRWebMessageModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
|
||||||
|
struct SRWebMessageModel: SmartCodable {
|
||||||
|
var type: String?
|
||||||
|
|
||||||
|
var data: SRWebMessageData?
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SRWebMessageData: SmartCodable {
|
||||||
|
|
||||||
|
var activity_id: String?
|
||||||
|
var short_play_id: String?
|
||||||
|
var link: String?
|
||||||
|
|
||||||
|
}
|
||||||
153
SynthReel/Base/webview/SRWebView.swift
Normal file
153
SynthReel/Base/webview/SRWebView.swift
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
//
|
||||||
|
// SRWebView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
@preconcurrency import WebKit
|
||||||
|
import YYText
|
||||||
|
|
||||||
|
@objc protocol SRWebViewDelegate: NSObjectProtocol {
|
||||||
|
|
||||||
|
@objc optional func fa_webView(_ webView: SRWebView, shouldStartLoadWith navigationAction: WKNavigationAction) -> Bool
|
||||||
|
|
||||||
|
@objc optional func fa_webViewDidStartLoad(_ webView: SRWebView)
|
||||||
|
|
||||||
|
@objc optional func fa_webViewDidFinishLoad(_ webView: SRWebView)
|
||||||
|
|
||||||
|
@objc optional func fa_webView(_ webView: SRWebView, didFailLoadWithError error: Error)
|
||||||
|
|
||||||
|
///进度
|
||||||
|
@objc optional func fa_webView(webView: SRWebView, didChangeProgress progress: CGFloat)
|
||||||
|
///标题
|
||||||
|
@objc optional func fa_webView(webView: SRWebView, didChangeTitle title: String)
|
||||||
|
|
||||||
|
///web交互用
|
||||||
|
@objc optional func fa_userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SRWebView: WKWebView {
|
||||||
|
|
||||||
|
weak var delegate: SRWebViewDelegate?
|
||||||
|
|
||||||
|
private(set) var scriptMessageHandlerArray: [String] = [
|
||||||
|
kSRWebMessageAPP,
|
||||||
|
kSRWebMessageOpenFeedbackList,
|
||||||
|
kSRWebMessageOpenFeedbackDetail,
|
||||||
|
kSRWebMessageOpenPhotoPicker,
|
||||||
|
kSRWebMessageAccountDeletionFinish,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
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.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? SRWebView == self {
|
||||||
|
if keyPath == "estimatedProgress", let progress = change?[NSKeyValueChangeKey.newKey] as? CGFloat {
|
||||||
|
self.delegate?.fa_webView?(webView: self, didChangeProgress: progress)
|
||||||
|
} else if keyPath == "title", let title = change?[NSKeyValueChangeKey.newKey] as? String {
|
||||||
|
self.delegate?.fa_webView?(webView: self, didChangeTitle: title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func load(urlStr: String) {
|
||||||
|
guard let url = URL(string: urlStr) else { return }
|
||||||
|
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 30)
|
||||||
|
self.load(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeScriptMessageHandler() {
|
||||||
|
self.scriptMessageHandlerArray.forEach{
|
||||||
|
configuration.userContentController.removeScriptMessageHandler(forName: $0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func addScriptMessageHandler() {
|
||||||
|
self.scriptMessageHandlerArray.forEach{
|
||||||
|
configuration.userContentController.add(YYTextWeakProxy(target: self) as! WKScriptMessageHandler, name: $0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK:-------------- WKNavigationDelegate --------------
|
||||||
|
extension SRWebView: 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) {
|
||||||
|
|
||||||
|
if let url = navigationAction.request.url,
|
||||||
|
url.scheme != "http",
|
||||||
|
url.scheme != "https"
|
||||||
|
{
|
||||||
|
UIApplication.shared.open(url)
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let result = self.delegate?.fa_webView?(self, shouldStartLoadWith: navigationAction) {
|
||||||
|
if result {
|
||||||
|
decisionHandler(.allow)
|
||||||
|
} else {
|
||||||
|
decisionHandler(.cancel)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
decisionHandler(.allow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||||||
|
self.delegate?.fa_webViewDidStartLoad?(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||||
|
self.delegate?.fa_webViewDidFinishLoad?(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
||||||
|
self.delegate?.fa_webView?(self, didFailLoadWithError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
||||||
|
self.delegate?.fa_webView?(self, didFailLoadWithError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK:-------------- WKScriptMessageHandler --------------
|
||||||
|
extension SRWebView: WKScriptMessageHandler {
|
||||||
|
|
||||||
|
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
||||||
|
self.delegate?.fa_userContentController?(userContentController, didReceive: message)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
SynthReel/Class/Coinpack/M/SRCoinPackCanReceiveModel.swift
Normal file
14
SynthReel/Class/Coinpack/M/SRCoinPackCanReceiveModel.swift
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackCanReceiveModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/9.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct SRCoinPackCanReceiveModel: SmartCodable {
|
||||||
|
var coins: Int?
|
||||||
|
}
|
||||||
26
SynthReel/Class/Coinpack/M/SRCoinsPackModel.swift
Normal file
26
SynthReel/Class/Coinpack/M/SRCoinsPackModel.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct SRCoinsPackModel: SmartCodable {
|
||||||
|
|
||||||
|
//当前可领取订阅数
|
||||||
|
var receive_count: Int?
|
||||||
|
//已领取累计金币总数
|
||||||
|
var week_total: Int?
|
||||||
|
//剩余可领取金币数
|
||||||
|
var week_remaining_total: Int?
|
||||||
|
//订阅可领取累计金币总数
|
||||||
|
var week_max_total: Int?
|
||||||
|
//当前可领取金币总数
|
||||||
|
var receive_coins: Int?
|
||||||
|
|
||||||
|
var receive_list: [SRCoinsPackReceiveModel]?
|
||||||
|
}
|
||||||
26
SynthReel/Class/Coinpack/M/SRCoinsPackReceiveModel.swift
Normal file
26
SynthReel/Class/Coinpack/M/SRCoinsPackReceiveModel.swift
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackReceiveModel.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct SRCoinsPackReceiveModel: SmartCodable {
|
||||||
|
|
||||||
|
var id: String?
|
||||||
|
var title: String?
|
||||||
|
//剩余可领取金币数
|
||||||
|
var week_remaining_total: Int?
|
||||||
|
//当前可领取金币数
|
||||||
|
var receive_coins: Int?
|
||||||
|
//已领取累计金币总数
|
||||||
|
var week_total: Int?
|
||||||
|
//可领取累计金币总数
|
||||||
|
var week_max_total: Int?
|
||||||
|
//领取天数文本
|
||||||
|
var day_text: String?
|
||||||
|
}
|
||||||
246
SynthReel/Class/Coinpack/VC/SRCoinPackController.swift
Normal file
246
SynthReel/Class/Coinpack/VC/SRCoinPackController.swift
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackController.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinPackController: SRViewController {
|
||||||
|
|
||||||
|
private var model: SRCoinsPackModel? {
|
||||||
|
didSet {
|
||||||
|
headerView.model = model
|
||||||
|
claimView.dataArr = model?.receive_list ?? []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var payDataModel : SRPayDateModel? {
|
||||||
|
didSet {
|
||||||
|
var arr: [SRPayItem] = []
|
||||||
|
|
||||||
|
payDataModel?.list_coins?.forEach {
|
||||||
|
if $0.buy_type == .subCoins {
|
||||||
|
arr.append($0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.buyView.dataArr = arr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var payDataRequest: SRPayDataRequest?
|
||||||
|
|
||||||
|
lazy var topImageview = UIImageView.init(image: .topCoinPack)
|
||||||
|
|
||||||
|
private lazy var bgIconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "查看图片 25"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var scrollView: SRScrollView = {
|
||||||
|
let scrollView = SRScrollView()
|
||||||
|
return scrollView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var headerView: SRCoinPackHeaderView = {
|
||||||
|
let view = SRCoinPackHeaderView()
|
||||||
|
view.clickClaimButton = { [weak self] in
|
||||||
|
self?.requestReceiveCoins(nil)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let stackView = UIStackView()
|
||||||
|
stackView.axis = .vertical
|
||||||
|
stackView.spacing = 19
|
||||||
|
return stackView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var claimView: SRCoinsPackClaimListView = {
|
||||||
|
let view = SRCoinsPackClaimListView()
|
||||||
|
view.clickClaimButton = { [weak self] id in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.requestReceiveCoins(id)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var buyView: SRCoinsPackBuyView = {
|
||||||
|
let view = SRCoinsPackBuyView()
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
self?.requestCoinsPackData()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tipView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.addSubview(tipTitleLabel)
|
||||||
|
view.addSubview(tipTextLabel)
|
||||||
|
|
||||||
|
tipTitleLabel.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
tipTextLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||||
|
make.top.equalTo(tipTitleLabel.snp.bottom).offset(4)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var tipTitleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .white.withAlphaComponent(0.5)
|
||||||
|
label.text = "coins_pack_tips_title".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private weak var recommandView: UIView?
|
||||||
|
|
||||||
|
private lazy var tipTextLabel: UILabel = {
|
||||||
|
let att = NSMutableAttributedString(string: "coins_pack_tips".localized)
|
||||||
|
att.yy_lineSpacing = 3
|
||||||
|
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
|
label.textColor = .white.withAlphaComponent(0.5)
|
||||||
|
label.attributedText = att
|
||||||
|
label.numberOfLines = 0
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
()
|
||||||
|
self.navigationItem.title = "My Refills".localized
|
||||||
|
|
||||||
|
payDataModel = SRIapManager.manager.payDateModel
|
||||||
|
|
||||||
|
sr_setui()
|
||||||
|
|
||||||
|
requestCoinsPackData()
|
||||||
|
|
||||||
|
updateLayout()
|
||||||
|
// Do any additional setup after loading the view.
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateLayout() {
|
||||||
|
stackView.sr_removeAllArrangedSubview()
|
||||||
|
|
||||||
|
if self.claimView.dataArr.count > 0 {
|
||||||
|
stackView.addArrangedSubview(self.claimView)
|
||||||
|
} else if self.buyView.dataArr.count > 0 {
|
||||||
|
stackView.addArrangedSubview(self.buyView)
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.addArrangedSubview(tipView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackController {
|
||||||
|
func sr_setui() {
|
||||||
|
view.addSubview(topImageview)
|
||||||
|
|
||||||
|
topImageview.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.addSubview(bgIconImageView)
|
||||||
|
view.addSubview(scrollView)
|
||||||
|
scrollView.addSubview(headerView)
|
||||||
|
scrollView.addSubview(stackView)
|
||||||
|
|
||||||
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(UIScreen.navBarHeight)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
headerView.snp.makeConstraints { make in
|
||||||
|
make.left.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(headerView.snp.bottom).offset(16)
|
||||||
|
make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackController {
|
||||||
|
|
||||||
|
private func requestCoinsPackData() {
|
||||||
|
Task {
|
||||||
|
let model = await SRStoreAPI.requestCoinsPackData()
|
||||||
|
guard let model = model else { return }
|
||||||
|
self.model = model
|
||||||
|
if (model.receive_list?.count ?? 0) == 0 {
|
||||||
|
self.requestPayData()
|
||||||
|
}
|
||||||
|
self.updateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requestPayData() {
|
||||||
|
self.payDataRequest = SRPayDataRequest()
|
||||||
|
self.payDataRequest?.requestProducts { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = model else { return }
|
||||||
|
self.payDataModel = model
|
||||||
|
|
||||||
|
self.updateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func requestReceiveCoins(_ id: String?) {
|
||||||
|
Task {
|
||||||
|
let sucess = await SRStoreAPI.requestReceiveCoinsPackCoins(id: id)
|
||||||
|
self.requestCoinsPackData()
|
||||||
|
if sucess {
|
||||||
|
self.showVideoRecommand()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///展示视频推荐
|
||||||
|
private func showVideoRecommand() {
|
||||||
|
guard self.recommandView == nil else { return }
|
||||||
|
Task {
|
||||||
|
let (model, _, _) = await SRShortApi.requestRecommand()
|
||||||
|
guard let model = model else { return }
|
||||||
|
guard self.recommandView == nil else { return }
|
||||||
|
let view = SRDetailRecommendview()
|
||||||
|
view.dataArr = model
|
||||||
|
view.didSelectedVideo = { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let vc = SRDetailPlayerViewController()
|
||||||
|
vc.shortId = model.short_play_id
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
view.show(in: SRTool.keyWindow)
|
||||||
|
self.recommandView = view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackConfirmItem1View.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinPackConfirmItem1View: SRCoinPackConfirmItemView {
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
lazy var bgIconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "getBg"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
titleLabel.text = "synthreel_bonus_you_get".localized
|
||||||
|
|
||||||
|
let view1 = getItemView(image: UIImage(named: "dailyIocn"), text: "synthreel_weekly_refill_package".localized)
|
||||||
|
let view2 = getItemView(image: UIImage(named: "rewardicon"), text: "synthreel_dailu_bonuses".localized)
|
||||||
|
|
||||||
|
addSubview(bgIconImageView)
|
||||||
|
addSubview(view1)
|
||||||
|
addSubview(view2)
|
||||||
|
|
||||||
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
view1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||||
|
make.height.equalTo(83)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
view2.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(view1.snp.right).offset(12)
|
||||||
|
make.right.equalToSuperview().offset(-12)
|
||||||
|
make.width.height.top.equalTo(view1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getItemView(image: UIImage?, text: String) -> UIView {
|
||||||
|
let view = UIImageView()
|
||||||
|
view.image = .itemBg
|
||||||
|
|
||||||
|
let imageView = UIImageView(image: image)
|
||||||
|
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
|
||||||
|
let label = UILabel()
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.font = .font(ofSize: 12, weight: .init(800))
|
||||||
|
label.textColor = .white
|
||||||
|
label.text = text
|
||||||
|
label.textAlignment = .center
|
||||||
|
|
||||||
|
|
||||||
|
view.addSubview(imageView)
|
||||||
|
view.addSubview(label)
|
||||||
|
|
||||||
|
imageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
label.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview().inset(10)
|
||||||
|
make.top.equalTo(imageView.snp.bottom).offset(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
}
|
||||||
134
SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift
Normal file
134
SynthReel/Class/Coinpack/view/SRCoinPackConfirmItem2View.swift
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackConfirmItem2View.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinPackConfirmItem2View: SRCoinPackConfirmItemView {
|
||||||
|
|
||||||
|
var list: [String]? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
self.stackView.sr_removeAllArrangedSubview()
|
||||||
|
|
||||||
|
list?.forEach {
|
||||||
|
let view = SRCoinPackConfirmItem2View.ItemView()
|
||||||
|
view.text = $0
|
||||||
|
self.stackView.addArrangedSubview(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgIconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "receiveBg"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var lineView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .white.withAlphaComponent(0.1)
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var stackView: UIStackView = {
|
||||||
|
let view = UIStackView()
|
||||||
|
view.axis = .vertical
|
||||||
|
view.spacing = 24
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.titleLabel.text = "synthreel_coin_bag_buy_tip_title".localized
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackConfirmItem2View {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(bgIconImageView)
|
||||||
|
addSubview(lineView)
|
||||||
|
addSubview(stackView)
|
||||||
|
|
||||||
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
lineView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(16)
|
||||||
|
make.height.equalTo(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
stackView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(lineView.snp.bottom).offset(16)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackConfirmItem2View {
|
||||||
|
|
||||||
|
class ItemView: UIView {
|
||||||
|
var text: String? {
|
||||||
|
didSet {
|
||||||
|
textLabel.text = text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "coins_icon_06"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var textLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
label.textColor = .white
|
||||||
|
label.numberOfLines = 0
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
addSubview(iconImageView)
|
||||||
|
addSubview(textLabel)
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
textLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(iconImageView.snp.right).offset(12)
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackConfirmItemView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinPackConfirmItemView: UIView {
|
||||||
|
|
||||||
|
lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColor = .white
|
||||||
|
label.textAlignment = .center
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
backgroundColor = .black
|
||||||
|
layer.cornerRadius = 8
|
||||||
|
layer.masksToBounds = true
|
||||||
|
|
||||||
|
addSubview(titleLabel)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-16)
|
||||||
|
make.top.equalToSuperview().offset(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
207
SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift
Normal file
207
SynthReel/Class/Coinpack/view/SRCoinPackConfirmView.swift
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackConfirmView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import HWPanModal
|
||||||
|
|
||||||
|
class SRCoinPackConfirmView: SRPanModalContentView {
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
var shortPlayId: String?
|
||||||
|
var videoId: String?
|
||||||
|
|
||||||
|
var model: SRPayItem? {
|
||||||
|
didSet {
|
||||||
|
item2View.list = model?.ext_info?.sub_coins_txt_list
|
||||||
|
|
||||||
|
var price = model?.price ?? ""
|
||||||
|
if model?.discount_type == 1, let introductoryPrice = model?.introductionaryOffer {
|
||||||
|
price = introductoryPrice.price.stringValue
|
||||||
|
} else if model?.discount_type == 2, let discount = model?.promotionalOffers?.first {
|
||||||
|
price = discount.price.stringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.text = "\(model?.currency ?? "")\(price)/\(model?.getTimeString() ?? "")"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private lazy var bgImageView: UIImageView = {
|
||||||
|
// let imageView = UIImageView(image: UIImage(named: "弹窗背景色"))
|
||||||
|
// return imageView
|
||||||
|
// }()
|
||||||
|
|
||||||
|
private lazy var bgIconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: ""))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: SRLabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.font = .font(ofSize: 24, weight: .init(700))
|
||||||
|
label.textColors = [UIColor._4_CFFD_4.cgColor, UIColor._51_D_4_FF.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0.5, y: 0)
|
||||||
|
label.textEndPoint = .init(x: 0.5, y: 1)
|
||||||
|
label.text = "synthreel_what_you_get".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var closeButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
Task {
|
||||||
|
await self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
button.setImage(UIImage(named: "Close"), for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var scrollView: SRScrollView = {
|
||||||
|
let scrollView = SRScrollView()
|
||||||
|
scrollView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
return scrollView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var item1View: SRCoinPackConfirmItem1View = {
|
||||||
|
let view = SRCoinPackConfirmItem1View()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var item2View: SRCoinPackConfirmItem2View = {
|
||||||
|
let view = SRCoinPackConfirmItem2View()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var priceLabel: SRLabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColors = [UIColor.srBlue.cgColor, UIColor.srBlue.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var continueButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let model = self.model else { return }
|
||||||
|
SRIapManager.manager.start(model: model, shortPlayId: self.shortPlayId, videoId: self.videoId) { [weak self] finish in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if finish {
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
Task {
|
||||||
|
await self.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
button.setTitle("synthreel_continue".localized, for: .normal)
|
||||||
|
button.setTitleColor(.black, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize: 14, weight: .bold)
|
||||||
|
button.setBackgroundImage(.continueBG, for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.backgroundColor = .clear
|
||||||
|
sr_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
self.panModalSetNeedsLayoutUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func allowsTapBackgroundToDismiss() -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override func cornerRadius() -> CGFloat {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override func longFormHeight() -> PanModalHeight {
|
||||||
|
let height = 96 + scrollView.contentSize.height + 92 + 10
|
||||||
|
return PanModalHeightMake(.content, height + UIScreen.safeBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackConfirmView {
|
||||||
|
|
||||||
|
private func sr_setupLayout() {
|
||||||
|
addSubview(bgImageView)
|
||||||
|
bgImageView.addSubview(bgIconImageView)
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(closeButton)
|
||||||
|
addSubview(scrollView)
|
||||||
|
scrollView.addSubview(item1View)
|
||||||
|
scrollView.addSubview(item2View)
|
||||||
|
addSubview(priceLabel)
|
||||||
|
addSubview(continueButton)
|
||||||
|
|
||||||
|
bgImageView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(55)
|
||||||
|
}
|
||||||
|
|
||||||
|
closeButton.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
make.top.equalToSuperview().offset(24)
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollView.snp.makeConstraints { make in
|
||||||
|
make.left.right.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(96)
|
||||||
|
make.bottom.equalToSuperview().offset(-(92 + UIScreen.safeBottom + 10))
|
||||||
|
}
|
||||||
|
|
||||||
|
item1View.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
item2View.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(item1View.snp.bottom).offset(12)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
priceLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.centerY.equalTo(scrollView.snp.bottom).offset(22)
|
||||||
|
}
|
||||||
|
|
||||||
|
continueButton.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.top.equalTo(scrollView.snp.bottom).offset(44)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
328
SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift
Normal file
328
SynthReel/Class/Coinpack/view/SRCoinPackHeaderView.swift
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
//
|
||||||
|
// SRCoinPackHeaderView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/28.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinPackHeaderView: UIView {
|
||||||
|
|
||||||
|
var clickClaimButton: (() -> Void)?
|
||||||
|
|
||||||
|
var model: SRCoinsPackModel? {
|
||||||
|
didSet {
|
||||||
|
coinsView1.coins = model?.week_max_total
|
||||||
|
coinsView2.coins = model?.week_total
|
||||||
|
|
||||||
|
activeCountLabel.text = "\(model?.receive_count ?? 0)"
|
||||||
|
|
||||||
|
if let coin = model?.receive_coins, coin > 0 {
|
||||||
|
claimButton.isEnabled = true
|
||||||
|
} else {
|
||||||
|
claimButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
claimButton.setNeedsUpdateConfiguration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleView: UILabel = {
|
||||||
|
let view = UILabel()
|
||||||
|
view.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
view.textColor = .white
|
||||||
|
view.text = "synthreel_rewards_overview".localized.uppercased()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsView1: CoinsView = {
|
||||||
|
let view = CoinsView()
|
||||||
|
view.title = "synthreel_weekly_total".localized
|
||||||
|
view.coins = 0
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsView2: CoinsView = {
|
||||||
|
let view = CoinsView()
|
||||||
|
view.title = "synthreel_claimable_coins".localized
|
||||||
|
view.coins = 0
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var lineView1: UIView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "间隔线"))
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var lineView2: UIView = {
|
||||||
|
let view = UIImageView(image: UIImage(named: "横间隔虚线"))
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var activeCountTitleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .regular)
|
||||||
|
label.textColor = .white.withAlphaComponent(0.5)
|
||||||
|
label.text = "synthreel_active_refills".localized + ": "
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var activeCountLabel: SRLabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColors = [UIColor._4_CFFD_4.cgColor, UIColor._51_D_4_FF.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0.5, y: 0)
|
||||||
|
label.textEndPoint = .init(x: 0.5, y: 1)
|
||||||
|
label.text = "0"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var claimButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom)
|
||||||
|
|
||||||
|
// 使用闭包创建配置更新处理器
|
||||||
|
let updateHandler: UIButton.ConfigurationUpdateHandler = { [weak self] button in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
var config = UIButton.Configuration.plain()
|
||||||
|
|
||||||
|
if button.isEnabled {
|
||||||
|
// 启用状态
|
||||||
|
config.background.image = .claimAllHiglit
|
||||||
|
config.background.imageContentMode = .scaleToFill
|
||||||
|
|
||||||
|
// 创建富文本标题
|
||||||
|
let coinImage = UIImage(named: "smallCoins")!
|
||||||
|
let coinText = NSTextAttachment(image: coinImage)
|
||||||
|
coinText.bounds = CGRect(x: 0, y: -2.5, width: 13, height: 13)
|
||||||
|
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||||
|
|
||||||
|
let textAtt = AttributedString("synthreel_claim_all".localized + " ", attributes: AttributeContainer([
|
||||||
|
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
.foregroundColor: UIColor.white
|
||||||
|
]))
|
||||||
|
|
||||||
|
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([
|
||||||
|
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
.foregroundColor: UIColor.white
|
||||||
|
]))
|
||||||
|
|
||||||
|
config.attributedTitle = textAtt + coinAtt + countAtt
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 禁用状态
|
||||||
|
config.background.image = .claimAllNomarl
|
||||||
|
config.background.imageContentMode = .scaleToFill
|
||||||
|
|
||||||
|
config.attributedTitle = AttributedString("synthreel_get_refill_button_text".localized, attributes: AttributeContainer([
|
||||||
|
.font: UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
.foregroundColor: UIColor.white.withAlphaComponent(0.5)
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置内边距
|
||||||
|
config.contentInsets = NSDirectionalEdgeInsets(top: 12, leading: 20, bottom: 12, trailing: 20)
|
||||||
|
|
||||||
|
// 应用配置
|
||||||
|
button.configuration = config
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化配置
|
||||||
|
button.configurationUpdateHandler = updateHandler
|
||||||
|
|
||||||
|
// 设置点击事件
|
||||||
|
button.addAction(UIAction(handler: { [weak self] _ in
|
||||||
|
self?.clickClaimButton?()
|
||||||
|
}), for: .touchUpInside)
|
||||||
|
|
||||||
|
// 初始状态
|
||||||
|
button.isEnabled = false
|
||||||
|
button.configurationUpdateHandler?(button) // 手动触发一次更新
|
||||||
|
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
// private lazy var claimButton: UIButton = {
|
||||||
|
// let config = UIButton.Configuration.plain()
|
||||||
|
// let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
// self?.clickClaimButton?()
|
||||||
|
// }))
|
||||||
|
// button.isEnabled = false
|
||||||
|
// button.configurationUpdateHandler = { [weak self] button in
|
||||||
|
// guard let self = self else { return }
|
||||||
|
// guard let button = button as? UIButton else { return }
|
||||||
|
// if button.isEnabled {
|
||||||
|
//// button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor]
|
||||||
|
// button.setBackgroundImage(.claimAllHiglit, for: .normal)
|
||||||
|
// let coinImage = UIImage(named: "smallCoins")!
|
||||||
|
// let coinText = NSTextAttachment(image: coinImage)
|
||||||
|
// coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height)
|
||||||
|
// let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||||
|
//
|
||||||
|
// let textAtt = AttributedString("synthreel_claim_all".localized + " ", attributes: AttributeContainer([
|
||||||
|
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
// .foregroundColor : UIColor.white
|
||||||
|
// ]))
|
||||||
|
//
|
||||||
|
// let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)".localized, attributes: AttributeContainer([
|
||||||
|
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
// .foregroundColor : UIColor.white
|
||||||
|
// ]))
|
||||||
|
//
|
||||||
|
// button.configuration?.attributedTitle = textAtt + coinAtt + countAtt
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
//// button.fa_colors = [UIColor._6_D_6_D_6_D.cgColor, UIColor._6_D_6_D_6_D.cgColor]
|
||||||
|
// button.setBackgroundImage(.claimAllNomarl, for: .normal)
|
||||||
|
// button.configuration?.attributedTitle = AttributedString("synthreel_get_refill_button_text".localized, attributes: AttributeContainer([
|
||||||
|
// .font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
// .foregroundColor : UIColor.white.withAlphaComponent(0.5)
|
||||||
|
// ]))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// return button
|
||||||
|
// }()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinPackHeaderView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(titleView)
|
||||||
|
addSubview(coinsView1)
|
||||||
|
addSubview(coinsView2)
|
||||||
|
addSubview(lineView1)
|
||||||
|
addSubview(activeCountTitleLabel)
|
||||||
|
addSubview(activeCountLabel)
|
||||||
|
addSubview(claimButton)
|
||||||
|
addSubview(lineView2)
|
||||||
|
|
||||||
|
titleView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(16)
|
||||||
|
make.top.equalToSuperview().offset(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsView1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(28)
|
||||||
|
make.top.equalTo(titleView.snp.bottom).offset(23)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineView1.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinsView1)
|
||||||
|
make.left.equalTo(coinsView1.snp.right).offset(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsView2.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(lineView1)
|
||||||
|
make.left.equalTo(lineView1.snp.right).offset(18)
|
||||||
|
}
|
||||||
|
|
||||||
|
activeCountTitleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coinsView1)
|
||||||
|
make.top.equalTo(coinsView1.snp.bottom).offset(23)
|
||||||
|
}
|
||||||
|
|
||||||
|
activeCountLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(activeCountTitleLabel.snp.right)
|
||||||
|
make.centerY.equalTo(activeCountTitleLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
claimButton.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(23)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(activeCountTitleLabel.snp.bottom).offset(12)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
make.bottom.equalToSuperview().offset(-16)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineView2.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(claimButton)
|
||||||
|
make.right.equalTo(claimButton)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SRCoinPackHeaderView {
|
||||||
|
|
||||||
|
class CoinsView: UIView {
|
||||||
|
var title: String? {
|
||||||
|
didSet {
|
||||||
|
titleLabel.text = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var coins: Int? {
|
||||||
|
didSet {
|
||||||
|
coinsLabel.text = "\(coins ?? 0)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .bold)
|
||||||
|
label.textColor = .white.withAlphaComponent(0.5)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: UIImage(named: "smallCoins"))
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsLabel: SRLabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColors = [UIColor.srBlue.cgColor, UIColor.srBlue.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(iconImageView)
|
||||||
|
addSubview(coinsLabel)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(4)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(iconImageView)
|
||||||
|
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
124
SynthReel/Class/Coinpack/view/SRCoinsPackAlert.swift
Normal file
124
SynthReel/Class/Coinpack/view/SRCoinsPackAlert.swift
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackAlert.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/9.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinsPackAlert: SRBaseAlert {
|
||||||
|
|
||||||
|
var claimButtonClick: (() -> Void)?
|
||||||
|
var coinsCount: Int? {
|
||||||
|
didSet {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var imageView = UIImageView(image: UIImage(named: "coinalertBg"))
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 18, weight: .bold)
|
||||||
|
label.textColor = .white
|
||||||
|
label.textAlignment = .center
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.text = "coins_pack_alert_title".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var moreCoinimageView = UIImageView(image: UIImage(named: "moreCoins"))
|
||||||
|
|
||||||
|
private lazy var coinLabel: SRLabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.textColors = [UIColor.F_1_FF_2_F.cgColor, UIColor.srBlue.cgColor]
|
||||||
|
label.textStartPoint = .init(x: 0, y: 0.5)
|
||||||
|
label.textEndPoint = .init(x: 1, y: 0.5)
|
||||||
|
label.font = .font(ofSize: 20, weight: .semibold)
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var claimButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom)
|
||||||
|
button.setTitle("synthreel_claim_now".localized, for: .normal)
|
||||||
|
button.setTitleColor(.black, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize: 16, weight: .semibold)
|
||||||
|
button.setBackgroundImage(.cliamNowBg, for: .normal)
|
||||||
|
button.addTarget(self, action: #selector(claimButtonAciton), for: .touchUpInside)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var laterButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom)
|
||||||
|
button.setTitle("synthreel_open_notification_later".localized, for: .normal)
|
||||||
|
button.setTitleColor(.FFFFFF_40, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
button.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func claimButtonAciton () {
|
||||||
|
self.claimButtonClick?()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinsPackAlert {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(imageView)
|
||||||
|
imageView.addSubview(titleLabel)
|
||||||
|
imageView.addSubview(moreCoinimageView)
|
||||||
|
imageView.addSubview(coinLabel)
|
||||||
|
imageView.addSubview(claimButton)
|
||||||
|
imageView.addSubview(laterButton)
|
||||||
|
|
||||||
|
imageView.isUserInteractionEnabled = true
|
||||||
|
imageView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(17)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-110)
|
||||||
|
make.top.equalTo(15)
|
||||||
|
}
|
||||||
|
|
||||||
|
moreCoinimageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(35)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinLabel.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(moreCoinimageView.snp.bottom).offset(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
claimButton.snp.makeConstraints { make in
|
||||||
|
make.top.equalTo(coinLabel.snp.bottom).offset(35)
|
||||||
|
make.left.right.equalToSuperview().inset(17)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
}
|
||||||
|
|
||||||
|
laterButton.snp.makeConstraints { make in
|
||||||
|
make.left.right.height.equalTo(claimButton)
|
||||||
|
make.top.equalTo(claimButton.snp.bottom).offset(1)
|
||||||
|
make.bottom.equalToSuperview().offset(-13)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
114
SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift
Normal file
114
SynthReel/Class/Coinpack/view/SRCoinsPackBuyView.swift
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackBuyView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinsPackBuyView: UIView {
|
||||||
|
|
||||||
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
var dataArr: [SRPayItem] = []
|
||||||
|
|
||||||
|
private lazy var titleView: UILabel = {
|
||||||
|
let view = UILabel()
|
||||||
|
view.textColor = .white
|
||||||
|
view.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
view.text = "synthreel_weekly_refill".localized.uppercased()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.itemSize = .init(width: UIScreen.width - 32, height: 84)
|
||||||
|
layout.minimumLineSpacing = 12
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: SRCollectionView = {
|
||||||
|
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
collectionView.register(SRPackCoinViewCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.collectionView.contentSize.height + 1
|
||||||
|
collectionView.snp.updateConstraints { make in
|
||||||
|
make.height.equalTo(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinsPackBuyView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(titleView)
|
||||||
|
addSubview(collectionView)
|
||||||
|
|
||||||
|
titleView.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(30)
|
||||||
|
make.height.equalTo(1)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||||
|
extension SRCoinsPackBuyView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRPackCoinViewCell
|
||||||
|
cell.model = self.dataArr[indexPath.row]
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||||
|
let model = self.dataArr[indexPath.row]
|
||||||
|
|
||||||
|
let view = SRCoinPackConfirmView()
|
||||||
|
view.model = model
|
||||||
|
view.buyFinishHandle = { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
Task {
|
||||||
|
await SRLogin.manager.requestUserInfo(completer: nil)
|
||||||
|
self.buyFinishHandle?()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view.present(in: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
264
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift
Normal file
264
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListCell.swift
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackClaimListCell.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinsPackClaimListCell: UICollectionViewCell {
|
||||||
|
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||||
|
|
||||||
|
var model: SRCoinsPackReceiveModel? {
|
||||||
|
didSet {
|
||||||
|
coinsView1.coins = model?.week_max_total
|
||||||
|
coinsView2.coins = model?.week_remaining_total
|
||||||
|
|
||||||
|
claimButton.isEnabled = (model?.receive_coins ?? 0) > 0
|
||||||
|
claimButton.setNeedsUpdateConfiguration()
|
||||||
|
|
||||||
|
let titleAtt = NSMutableAttributedString(string: "\(model?.title ?? "")")
|
||||||
|
titleAtt.yy_color = .white
|
||||||
|
titleAtt.yy_font = .font(ofSize: 14, weight: .bold)
|
||||||
|
|
||||||
|
let day = "synthreel_d".localized
|
||||||
|
let dayAtt = NSMutableAttributedString(string: " (\(day) \(model?.day_text ?? ""))")
|
||||||
|
dayAtt.yy_color = .white
|
||||||
|
dayAtt.yy_font = .font(ofSize: 14, weight: .regular)
|
||||||
|
titleAtt.append(dayAtt)
|
||||||
|
|
||||||
|
titleLabel.attributedText = titleAtt
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var bgView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
view.image = .claimCellbg
|
||||||
|
view.contentMode = .scaleToFill
|
||||||
|
view.isUserInteractionEnabled = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgIconImageView1 = UIImageView(image: UIImage(named: "coin_attachment_01"))
|
||||||
|
private lazy var bgIconImageView2 = UIImageView(image: UIImage(named: "coin_attachment_03"))
|
||||||
|
private lazy var bgIconImageView4 = UIImageView(image: UIImage(named: "coin_attachment_04"))
|
||||||
|
private lazy var bgIconImageView5 = UIImageView(image: UIImage(named: "coin_attachment_05"))
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.numberOfLines = 0
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var lineView1 = UIImageView(image: UIImage(named: "横间隔虚线"))
|
||||||
|
private lazy var lineView2 = UIImageView(image: UIImage(named: "间隔线"))
|
||||||
|
|
||||||
|
private lazy var coinsView1: CoinsView = {
|
||||||
|
let view = CoinsView()
|
||||||
|
view.title = "synthreel_total_reward".localized
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var coinsView2: CoinsView = {
|
||||||
|
let view = CoinsView()
|
||||||
|
view.title = "synthreel_remaining".localized
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var claimButton: UIButton = {
|
||||||
|
var config = UIButton.Configuration.plain()
|
||||||
|
config.titleAlignment = .center
|
||||||
|
config.background.image = .coinStackBg
|
||||||
|
let button = UIButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.clickClaimButton?(self.model?.id)
|
||||||
|
}))
|
||||||
|
button.configurationUpdateHandler = { [weak self] button in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if button.isEnabled {
|
||||||
|
button.configuration?.background.image = UIImage(named: "coinStackBg")
|
||||||
|
let coinImage = UIImage(named: "bigCoins")!
|
||||||
|
let coinText = NSTextAttachment(image: coinImage)
|
||||||
|
coinText.bounds = .init(x: 0, y: -2.5, width: 13, height: 13)
|
||||||
|
let coinAtt = AttributedString(NSAttributedString(attachment: coinText))
|
||||||
|
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 12, weight: .bold),
|
||||||
|
.foregroundColor : UIColor._000000.withAlphaComponent(0.5)
|
||||||
|
]))
|
||||||
|
|
||||||
|
|
||||||
|
button.configuration?.attributedTitle = AttributedString("synthreel_claim".localized, attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
.foregroundColor : UIColor.white
|
||||||
|
]))
|
||||||
|
|
||||||
|
button.configuration?.attributedSubtitle = coinAtt + countAtt
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
button.configuration?.background.image = UIImage(named: "claimd_button_bg")
|
||||||
|
button.configuration?.attributedTitle = AttributedString("synthreel_claimd".localized, attributes: AttributeContainer([
|
||||||
|
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
|
.foregroundColor : UIColor.FFFFFF_40
|
||||||
|
]))
|
||||||
|
|
||||||
|
button.configuration?.attributedSubtitle = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinsPackClaimListCell {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
contentView.addSubview(bgView)
|
||||||
|
bgView.addSubview(bgIconImageView5)
|
||||||
|
bgView.addSubview(bgIconImageView4)
|
||||||
|
bgView.addSubview(bgIconImageView1)
|
||||||
|
bgView.addSubview(bgIconImageView2)
|
||||||
|
bgView.addSubview(titleLabel)
|
||||||
|
bgView.addSubview(lineView1)
|
||||||
|
bgView.addSubview(lineView2)
|
||||||
|
bgView.addSubview(coinsView1)
|
||||||
|
bgView.addSubview(coinsView2)
|
||||||
|
bgView.addSubview(claimButton)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.edges.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView1.snp.makeConstraints { make in
|
||||||
|
make.left.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView2.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.equalToSuperview().offset(-8)
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView4.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.centerX.equalTo(bgIconImageView2)
|
||||||
|
}
|
||||||
|
|
||||||
|
bgIconImageView5.snp.makeConstraints { make in
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.centerY.equalTo(self.bgView.snp.top).offset(25)
|
||||||
|
make.right.lessThanOrEqualToSuperview().offset(-12)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineView1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(48)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsView1.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview().offset(12)
|
||||||
|
make.bottom.equalToSuperview().offset(-14)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineView2.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinsView1)
|
||||||
|
make.left.equalTo(coinsView1.snp.right).offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsView2.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinsView1)
|
||||||
|
make.left.equalTo(lineView2.snp.right).offset(12)
|
||||||
|
}
|
||||||
|
|
||||||
|
claimButton.snp.makeConstraints { make in
|
||||||
|
make.right.equalToSuperview().offset(-12)
|
||||||
|
make.bottom.equalTo(-14)
|
||||||
|
make.height.equalTo(48)
|
||||||
|
make.width.equalTo(120)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinsPackClaimListCell {
|
||||||
|
|
||||||
|
class CoinsView: UIView {
|
||||||
|
|
||||||
|
var title: String? {
|
||||||
|
didSet {
|
||||||
|
titleLabel.text = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var coins: Int? {
|
||||||
|
didSet {
|
||||||
|
coinsLabel.text = "\(coins ?? 0)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .bold)
|
||||||
|
label.textColor = .white
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var iconImageView = UIImageView(image: UIImage(named: "bigCoins"))
|
||||||
|
|
||||||
|
private lazy var coinsLabel: UILabel = {
|
||||||
|
let label = SRLabel()
|
||||||
|
label.font = .font(ofSize: 14, weight: .bold)
|
||||||
|
label.textColor = .white
|
||||||
|
label.text = "0"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
addSubview(titleLabel)
|
||||||
|
addSubview(iconImageView)
|
||||||
|
addSubview(coinsLabel)
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
iconImageView.snp.makeConstraints { make in
|
||||||
|
make.left.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
make.top.equalTo(titleLabel.snp.bottom).offset(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
coinsLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(iconImageView)
|
||||||
|
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||||
|
make.right.lessThanOrEqualToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
106
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift
Normal file
106
SynthReel/Class/Coinpack/view/SRCoinsPackClaimListView.swift
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
//
|
||||||
|
// SRCoinsPackClaimListView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/4.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRCoinsPackClaimListView: UIView {
|
||||||
|
|
||||||
|
var clickClaimButton: ((_ id: String?) -> Void)?
|
||||||
|
|
||||||
|
var dataArr: [SRCoinsPackReceiveModel] = [] {
|
||||||
|
didSet {
|
||||||
|
collectionView.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var titleView: UILabel = {
|
||||||
|
let view = UILabel()
|
||||||
|
view.textColor = .white
|
||||||
|
view.font = .font(ofSize: 14, weight: .regular)
|
||||||
|
view.text = "synthreel_refills".localized.uppercased()
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
|
let layout = UICollectionViewFlowLayout()
|
||||||
|
layout.itemSize = .init(width: UIScreen.width - 32, height: 122)
|
||||||
|
layout.minimumLineSpacing = 12
|
||||||
|
return layout
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var collectionView: SRCollectionView = {
|
||||||
|
let collectionView = SRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
|
collectionView.delegate = self
|
||||||
|
collectionView.dataSource = self
|
||||||
|
collectionView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
||||||
|
collectionView.register(SRCoinsPackClaimListCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
|
return collectionView
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
collectionView.removeObserver(self, forKeyPath: "contentSize")
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
|
if keyPath == "contentSize" {
|
||||||
|
let height = self.collectionView.contentSize.height + 1
|
||||||
|
collectionView.snp.updateConstraints { make in
|
||||||
|
make.height.equalTo(height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SRCoinsPackClaimListView {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(titleView)
|
||||||
|
addSubview(collectionView)
|
||||||
|
|
||||||
|
titleView.snp.makeConstraints { make in
|
||||||
|
make.top.equalToSuperview()
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(30)
|
||||||
|
make.height.equalTo(1)
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: UICollectionViewDelegate UICollectionViewDataSource
|
||||||
|
extension SRCoinsPackClaimListView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SRCoinsPackClaimListCell
|
||||||
|
cell.model = self.dataArr[indexPath.row]
|
||||||
|
cell.clickClaimButton = { [weak self] id in
|
||||||
|
self?.clickClaimButton?(id)
|
||||||
|
}
|
||||||
|
return cell
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return dataArr.count
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRCategoryModel.swift
|
// SRCategoryModel.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeModuleItem.swift
|
// SRHomeModuleItem.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ class SRHomeModuleItem: NSObject, SmartCodable {
|
|||||||
case bingeWorthy = "week_highest_recommend"
|
case bingeWorthy = "week_highest_recommend"
|
||||||
case viralHits = "highest_payment_hot_video"
|
case viralHits = "highest_payment_hot_video"
|
||||||
case premiereNow = "new_recommand"
|
case premiereNow = "new_recommand"
|
||||||
|
case catetoryList = "category_navigation"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeBannerCell.swift
|
// SRHomeBannerCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeBannerMiniCell.swift
|
// SRHomeBannerMiniCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeBannerView.swift
|
// SRHomeBannerView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeBingeWorthyCell.swift
|
// SRHomeBingeWorthyCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeBingeWorthyView.swift
|
// SRHomeBingeWorthyView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeChildCell.swift
|
// SRHomeChildCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
50
SynthReel/Class/Home/V/SRHomeCoinsPackButton.swift
Normal file
50
SynthReel/Class/Home/V/SRHomeCoinsPackButton.swift
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// SRHomeCoinsPackButton.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/12/9.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRHomeCoinsPackButton: UIControl {
|
||||||
|
|
||||||
|
private lazy var bgImageView = UIImageView(image: UIImage(named: "浮窗"))
|
||||||
|
private lazy var textBgImageView = UIImageView(image: UIImage(named: "Rectangle 1098"))
|
||||||
|
|
||||||
|
private lazy var textLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .init(900)).withBoldItalic()
|
||||||
|
label.textColor = .white
|
||||||
|
label.text = "synthreel_daily_coins".localized
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
addSubview(bgImageView)
|
||||||
|
addSubview(textBgImageView)
|
||||||
|
textBgImageView.addSubview(textLabel)
|
||||||
|
|
||||||
|
bgImageView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.equalToSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
|
textBgImageView.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(50)
|
||||||
|
}
|
||||||
|
|
||||||
|
textLabel.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeHeaderView.swift
|
// SRHomeHeaderView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
143
SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift
Normal file
143
SynthReel/Class/Home/V/SRHomeHistoryBottomView.swift
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
//
|
||||||
|
// SRHomeHistoryBottomView.swift
|
||||||
|
// SynthReel
|
||||||
|
//
|
||||||
|
// Created by 澜声世纪 on 2025/11/27.
|
||||||
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SRHomeHistoryBottomView: UIView {
|
||||||
|
|
||||||
|
var model: SRShortModel? {
|
||||||
|
didSet {
|
||||||
|
coverImageView.sr_setImage(model?.image_url)
|
||||||
|
titleLabel.text = model?.name
|
||||||
|
let text = String(format: "EP. %@ / EP. %d", model?.current_episode ?? "0", model?.episode_total ?? 0)
|
||||||
|
setEpisodeText(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy var coverImageView: SRImageView = {
|
||||||
|
let imageView = SRImageView()
|
||||||
|
imageView.layer.cornerRadius = 21
|
||||||
|
imageView.layer.masksToBounds = true
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var bgView: UIImageView = {
|
||||||
|
let view = UIImageView()
|
||||||
|
view.image = .recordBottomBg
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var playView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: .recordBottomArrow)
|
||||||
|
imageView.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
|
label.textColor = .white
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var epLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 10, weight: .regular)
|
||||||
|
label.textColor = .white
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
|
|
||||||
|
let tap = UITapGestureRecognizer(target: self, action: #selector(handleBg))
|
||||||
|
addGestureRecognizer(tap)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func handleBg() {
|
||||||
|
let vc = SRDetailPlayerViewController()
|
||||||
|
vc.shortId = self.model?.short_play_id
|
||||||
|
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setEpisodeText(_ text: String) {
|
||||||
|
let full = text as NSString
|
||||||
|
|
||||||
|
let parts = text.components(separatedBy: " / ")
|
||||||
|
guard parts.count == 2 else {
|
||||||
|
epLabel.text = text
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let front = parts[0] + " "
|
||||||
|
let frontLen = (front as NSString).length
|
||||||
|
let fullLen = full.length
|
||||||
|
|
||||||
|
let attr = NSMutableAttributedString(string: text)
|
||||||
|
|
||||||
|
// 前段(白色)
|
||||||
|
attr.yy_setColor(.srBlue, range: NSRange(location: 0, length: frontLen))
|
||||||
|
attr.yy_setFont(.systemFont(ofSize: 12), range: NSRange(location: 0, length: frontLen))
|
||||||
|
|
||||||
|
// 后段(灰色)
|
||||||
|
attr.yy_setColor(UIColor.white, range: NSRange(location: frontLen, length: fullLen - frontLen))
|
||||||
|
attr.yy_setFont(.systemFont(ofSize: 12), range: NSRange(location: frontLen, length: fullLen - frontLen))
|
||||||
|
|
||||||
|
epLabel.attributedText = attr
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension SRHomeHistoryBottomView {
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
addSubview(bgView)
|
||||||
|
addSubview(coverImageView)
|
||||||
|
bgView.addSubview(playView)
|
||||||
|
bgView.addSubview(titleLabel)
|
||||||
|
bgView.addSubview(epLabel)
|
||||||
|
|
||||||
|
bgView.snp.makeConstraints { make in
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(1)
|
||||||
|
make.height.equalTo(57)
|
||||||
|
}
|
||||||
|
|
||||||
|
coverImageView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.left.equalToSuperview().offset(25)
|
||||||
|
make.width.equalTo(42)
|
||||||
|
make.height.equalTo(42)
|
||||||
|
}
|
||||||
|
|
||||||
|
playView.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalToSuperview()
|
||||||
|
make.right.equalToSuperview().offset(-28)
|
||||||
|
}
|
||||||
|
|
||||||
|
titleLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(coverImageView.snp.right).offset(10)
|
||||||
|
make.top.equalToSuperview().offset(12)
|
||||||
|
make.right.lessThanOrEqualTo(playView.snp.left).offset(-10)
|
||||||
|
}
|
||||||
|
|
||||||
|
epLabel.snp.makeConstraints { make in
|
||||||
|
make.left.equalTo(titleLabel)
|
||||||
|
make.bottom.equalToSuperview().offset(-12)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeHotView.swift
|
// SRHomeHotView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeMenuCell.swift
|
// SRHomeMenuCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/14.
|
// Created by 澜声世纪 on 2025/11/14.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeModuleView.swift
|
// SRHomeModuleView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomePremiereNowView.swift
|
// SRHomePremiereNowView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeTopChartsContentView.swift
|
// SRHomeTopChartsContentView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeTopChartsView.swift
|
// SRHomeTopChartsView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeViralHitsCell.swift
|
// SRHomeViralHitsCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeViralHitsView.swift
|
// SRHomeViralHitsView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/17.
|
// Created by 澜声世纪 on 2025/11/17.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeYouLikeCell.swift
|
// SRHomeYouLikeCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHomeYouLikeView.swift
|
// SRHomeYouLikeView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/15.
|
// Created by 澜声世纪 on 2025/11/15.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHotSearchCell.swift
|
// SRHotSearchCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRHotSearchView.swift
|
// SRHotSearchView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRSearchHomeView.swift
|
// SRSearchHomeView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRSearchRecordCell.swift
|
// SRSearchRecordCell.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
// SRSearchRecordView.swift
|
// SRSearchRecordView.swift
|
||||||
// SynthReel
|
// SynthReel
|
||||||
//
|
//
|
||||||
// Created by 湖北秦九 on 2025/11/18.
|
// Created by 澜声世纪 on 2025/11/18.
|
||||||
// Copyright © 2025 SR. All rights reserved.
|
// Copyright © 2025 SR. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user