Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67eeef0447 | ||
|
|
4c250038e0 | ||
|
|
b7a0a86a1a | ||
|
|
41b7bc80c4 | ||
|
|
50d1cd9069 | ||
|
|
2c7cef9572 | ||
|
|
6d48234e48 | ||
|
|
5fb7a4d9bc | ||
|
|
2b3125d826 | ||
|
|
b21751e738 | ||
|
|
86b603c64f |
10
Podfile
10
Podfile
@ -20,7 +20,7 @@ target 'SynthReel' do
|
||||
pod 'YYCategories'
|
||||
pod 'YYText'
|
||||
pod 'Kingfisher'
|
||||
pod 'SmartCodable'
|
||||
pod 'SmartCodable','5.0.15'
|
||||
pod 'Moya'
|
||||
pod 'SVProgressHUD'
|
||||
pod 'Toast'
|
||||
@ -31,5 +31,13 @@ target 'SynthReel' do
|
||||
pod 'MJRefresh'
|
||||
pod 'collection-view-layouts/TagsLayout'
|
||||
pod 'HWPanModal'
|
||||
pod 'LYEmptyView'
|
||||
pod 'ZLPhotoBrowser'
|
||||
pod 'Adjust'
|
||||
|
||||
# # AdMob SDK
|
||||
pod 'Google-Mobile-Ads-SDK'
|
||||
#
|
||||
# # AppLovin SDK
|
||||
pod 'AppLovinSDK'
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,24 @@
|
||||
{
|
||||
"originHash" : "0e62262c59a183f44748a161870cc0f2b76e1b0e46f648559704e4be9de523b9",
|
||||
"originHash" : "deb3ea9bc9f7ea16d149d6025086ec795e4f5fc740540ae9e5e8308e4e3e8aec",
|
||||
"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",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -10,6 +28,114 @@
|
||||
"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",
|
||||
"kind" : "remoteSourceControl",
|
||||
@ -18,6 +144,15 @@
|
||||
"revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4",
|
||||
"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
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeApi.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -118,5 +118,4 @@ struct SRHomeApi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRShortApi.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// 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 {
|
||||
await withCheckedContinuation { continuation in
|
||||
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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
import UIKit
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRUserDefaultsKey.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -12,3 +12,12 @@ let kSRAccountTokenDefaultsKey = "kSRAccountTokenDefaultsKey"
|
||||
|
||||
///用户信息
|
||||
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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,17 +2,19 @@
|
||||
// String+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import YYCategories
|
||||
import SmartCodable
|
||||
|
||||
extension 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 {
|
||||
@ -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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UINavigationBar+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/25.
|
||||
// Created by 澜声世纪 on 2025/11/25.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UIScreen+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UIScrollView+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UIStackView+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UIView+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// UserDefaults+SRAdd.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// 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)?) {
|
||||
|
||||
if SRAccountManager.manager.token == nil {
|
||||
if SRLogin.manager.token == nil {
|
||||
print(SRLogin.manager.token ?? "123")
|
||||
self.requestToken(completer: nil)
|
||||
}
|
||||
|
||||
@ -48,12 +49,16 @@ class SRNetwork: NSObject {
|
||||
static func _request<T>(parameters: SRNetwork.Parameters, completion: ((_ response: SRNetwork.Response<T>) -> Void)?) -> Cancellable {
|
||||
|
||||
if parameters.isLoding {
|
||||
DispatchQueue.main.async {
|
||||
SRHud.show()
|
||||
}
|
||||
}
|
||||
return provider.request(.request(parameters: parameters)) { result in
|
||||
if parameters.isLoding {
|
||||
DispatchQueue.main.async {
|
||||
SRHud.dismiss()
|
||||
}
|
||||
}
|
||||
guard let completion = completion else {return}
|
||||
_resultDispose(parameters: parameters, result: result, completion: completion)
|
||||
}
|
||||
@ -81,7 +86,7 @@ class SRNetwork: NSObject {
|
||||
self.requestToken { token in
|
||||
if token != nil {
|
||||
_Concurrency.Task {
|
||||
await SRAccountManager.manager.updateUserInfo()
|
||||
await SRLogin.manager.requestUserToken(completer: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,7 +169,7 @@ class SRNetwork: NSObject {
|
||||
|
||||
extension SRNetwork {
|
||||
///获取token
|
||||
static func requestToken(completer: ((_ token: SRAccountToken?) -> Void)?) {
|
||||
static func requestToken(completer: ((_ token: SRTokenModel?) -> Void)?) {
|
||||
guard self.tokenOperation == nil else {
|
||||
completer?(nil)
|
||||
return
|
||||
@ -173,11 +178,11 @@ extension SRNetwork {
|
||||
self.tokenOperation = BlockOperation(block: {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let param = SRNetwork.Parameters(path: "/customer/register")
|
||||
|
||||
print("chongfu")
|
||||
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 {
|
||||
SRAccountManager.manager.setAccountToken(token)
|
||||
SRLogin.manager.loginSuccessSaveToken(token)
|
||||
}
|
||||
do { semaphore.signal() }
|
||||
self.tokenOperation = nil
|
||||
@ -189,5 +194,4 @@ extension SRNetwork {
|
||||
operationQueue.addOperation(self.tokenOperation!)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRNetworkModel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -30,7 +30,7 @@ extension SRNetwork {
|
||||
var data: T?
|
||||
var msg: String?
|
||||
|
||||
@SmartIgnored
|
||||
@IgnoredKey
|
||||
var rawData: Any?
|
||||
|
||||
var isSuccess: Bool {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRNetworkReachableManager.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRResponseCryptor.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRTargetType.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -56,7 +56,7 @@ extension SRTargetType: TargetType {
|
||||
"device-id" : SRDeviceId.shared.id, //设备id
|
||||
"system-type" : "ios",
|
||||
"model" : UIDevice.current.machineModelName ?? "",
|
||||
"authorization" : SRAccountManager.manager.token?.token ?? "",
|
||||
"authorization" : SRLogin.manager.token?.token ?? "",
|
||||
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
|
||||
"product-prefix" : "SynthReel"
|
||||
]
|
||||
|
||||
@ -2,16 +2,27 @@
|
||||
// SRUrlPath.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/12.
|
||||
// Created by 澜声世纪 on 2025/11/12.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
let SRBaseURL = "https://api-hbqinjiu.hbqinjiu.com"
|
||||
let SRUrlPathPrefix = "/eon"
|
||||
let SRWebBaseURL = "https://www.hbqinjiu.com"
|
||||
let SRCampaignWebURL = "https://campaign.hbqinjiu.com"
|
||||
let SRBaseURL = "https://api-synthreeltv.synthreeltv.com"
|
||||
let SRUrlPathPrefix = "/th"
|
||||
let SRWebBaseURL = "https://www.synthreeltv.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
|
||||
admin-api https://admin-api-synthreeltv.synthreeltv.com
|
||||
|
||||
@ -2,11 +2,12 @@
|
||||
// SRCollectionView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import LYEmptyView
|
||||
|
||||
class SRCollectionView: UICollectionView {
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRGradientView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRLabel.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRNavgationTitleView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by CSGY on 2025/11/25.
|
||||
// Created by 澜声世纪 on 2025/11/25.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -26,7 +26,7 @@ class SRNavgationTitleView: UIView {
|
||||
|
||||
private let titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .font(ofSize: 18, weight: .bold)
|
||||
label.font = .font(ofSize: 18, weight: .bold).withBoldItalic()
|
||||
label.textAlignment = .center
|
||||
label.textColor = .white
|
||||
return label
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRPanModalContentView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -12,16 +12,20 @@ import SnapKit
|
||||
|
||||
class SRPanModalContentView: HWPanModalContentView {
|
||||
|
||||
var mainScrollView: UIScrollView?
|
||||
|
||||
var contentHeight = UIScreen.height * (2 / 3)
|
||||
|
||||
var bgImage: UIImage? = UIImage(named: "pan_bg_image_01")
|
||||
|
||||
|
||||
///更新UI contentSize发生变化时调用
|
||||
func setNeedsLayoutUpdate() {
|
||||
self.panModalSetNeedsLayoutUpdate()
|
||||
}
|
||||
|
||||
lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "pan_bg_image_01"))
|
||||
let imageView = UIImageView(image: bgImage)
|
||||
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) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
//MARK: HWPanModalPresentable
|
||||
override func panScrollable() -> UIScrollView? {
|
||||
return nil
|
||||
return mainScrollView
|
||||
}
|
||||
|
||||
|
||||
override func longFormHeight() -> PanModalHeight {
|
||||
return PanModalHeightMake(.content, contentHeight)
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRScrollView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRTableView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRTableViewCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRTabBarController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -32,6 +32,9 @@ class SRTabBarController: ESTabBarController {
|
||||
self.tabBar.standardAppearance = appearance
|
||||
self.tabBar.scrollEdgeAppearance = appearance
|
||||
self.tabBar.isTranslucent = false
|
||||
|
||||
|
||||
// SRTool.checkUpdates()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRViewController.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/13.
|
||||
// Created by 澜声世纪 on 2025/11/13.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeModuleItem.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
@ -22,6 +22,7 @@ class SRHomeModuleItem: NSObject, SmartCodable {
|
||||
case bingeWorthy = "week_highest_recommend"
|
||||
case viralHits = "highest_payment_hot_video"
|
||||
case premiereNow = "new_recommand"
|
||||
case catetoryList = "category_navigation"
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeBannerCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeBannerMiniCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeBannerView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeBingeWorthyCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeBingeWorthyView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeChildCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// 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
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeMenuCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/14.
|
||||
// Created by 澜声世纪 on 2025/11/14.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeModuleView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomePremiereNowView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeTopChartsContentView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeTopChartsView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeViralHitsCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeViralHitsView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/17.
|
||||
// Created by 澜声世纪 on 2025/11/17.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeYouLikeCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHomeYouLikeView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/15.
|
||||
// Created by 澜声世纪 on 2025/11/15.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHotSearchCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRHotSearchView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRSearchHomeView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRSearchRecordCell.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// Copyright © 2025 SR. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SRSearchRecordView.swift
|
||||
// SynthReel
|
||||
//
|
||||
// Created by 湖北秦九 on 2025/11/18.
|
||||
// Created by 澜声世纪 on 2025/11/18.
|
||||
// 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