Commit 8139f959 authored by CZ1004's avatar CZ1004

Merge branch 'develop' into charge

* develop:
  4-8-1
  4-8
  分享、评论和内购
  小组件

# Conflicts:
#	PhoneManager.xcodeproj/project.pbxproj
parents 112ce94a ce62ba6f
...@@ -25,7 +25,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -25,7 +25,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC { if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
window?.rootViewController = current window?.rootViewController = current
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
} }
let battery = WidgetPublicModel.battery() let battery = WidgetPublicModel.battery()
...@@ -37,7 +36,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -37,7 +36,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private func setupDefault() { private func setupDefault() {
HomePayModel.share.checkTrialStatus()
NetStatusManager.manager.startNet { status in NetStatusManager.manager.startNet { status in
switch status { switch status {
......
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_idsp_unlock.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_idsp_unlock@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_idsp_unlock@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_naal_unlock.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_naal_unlock@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_naal_unlock@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_sbst_unlock.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_sbst_unlock@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_sbst_unlock@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
...@@ -218,68 +218,76 @@ class CompressQualityController : BaseViewController{ ...@@ -218,68 +218,76 @@ class CompressQualityController : BaseViewController{
@objc func submitAction(){ @objc func submitAction(){
let compressingView : CompressingView = CompressingView(frame: self.view.bounds) let actionBlock = { [weak self] in
compressingView.data = self.model guard let self = self else { return }
let compressingView : CompressingView = CompressingView(frame: self.view.bounds)
self.view.addSubview(compressingView) compressingView.data = self.model
// 开始压缩 self.view.addSubview(compressingView)
let manager : CompressViewModel = CompressViewModel()
var currentQulity = 0.2 // 开始压缩
if currentQulityType == 1 { let manager : CompressViewModel = CompressViewModel()
currentQulity = 0.5 var currentQulity = 0.2
} if currentQulityType == 1 {
if currentQulityType == 2 { currentQulity = 0.5
currentQulity = 0.8 }
} if currentQulityType == 2 {
var comDataSource : [Data] = [] currentQulity = 0.8
}
if self.currentMediaType == 0 { var comDataSource : [Data] = []
// 表示压缩图片
manager.compress(assets: self.model!, compressionQuality: currentQulity) {progress in if self.currentMediaType == 0 {
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1) // 表示压缩图片
} completion: { compressedDataArray, errorArray in manager.compress(assets: self.model!, compressionQuality: currentQulity) {progress in
var compressAllSize = 0.0 compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
for (index, data) in compressedDataArray.enumerated() { } completion: { compressedDataArray, errorArray in
if let error = errorArray[index] { var compressAllSize = 0.0
print("第 \(index + 1) 个文件压缩出错: \(error.localizedDescription)") for (index, data) in compressedDataArray.enumerated() {
} else if let data = data { if let error = errorArray[index] {
print("第 \(index + 1) 个文件压缩完成,压缩后大小: \(data.count) 字节") print("第 \(index + 1) 个文件压缩出错: \(error.localizedDescription)")
compressAllSize = compressAllSize + Double(data.count) } else if let data = data {
comDataSource.append(data) print("第 \(index + 1) 个文件压缩完成,压缩后大小: \(data.count) 字节")
} else { compressAllSize = compressAllSize + Double(data.count)
print("第 \(index + 1) 个文件压缩失败") comDataSource.append(data)
} else {
print("第 \(index + 1) 个文件压缩失败")
}
} }
self.updateNextView(compressAllSize,compressingView,comDataSource,[])
} }
self.updateNextView(compressAllSize,compressingView,comDataSource,[]) }else{
} // 压缩视频
}else{ var compressAllSize : Double = 0.0
// 压缩视频 manager.compressVideos(models: self.model!, quality: Float(currentQulity)) { (identifier, progress) in
var compressAllSize : Double = 0.0 compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
manager.compressVideos(models: self.model!, quality: Float(currentQulity)) { (identifier, progress) in } completion: { (outputURLs, errors) in
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1) for (index, outputURL) in outputURLs.enumerated() {
} completion: { (outputURLs, errors) in if let outputURL = outputURL {
for (index, outputURL) in outputURLs.enumerated() { do {
if let outputURL = outputURL { let attributes = try FileManager.default.attributesOfItem(atPath: outputURL.path)
do { if let fileSize = attributes[.size] as? Int64 {
let attributes = try FileManager.default.attributesOfItem(atPath: outputURL.path) compressAllSize = compressAllSize + Double(fileSize)
if let fileSize = attributes[.size] as? Int64 { }
compressAllSize = compressAllSize + Double(fileSize) } catch {
Print("获取视频文件大小失败")
} }
} catch { print("Compressed video \(index) saved at: \(outputURL)")
Print("获取视频文件大小失败") } else if let error = errors[index] {
print("Error compressing video \(index): \(error.localizedDescription)")
} }
print("Compressed video \(index) saved at: \(outputURL)")
} else if let error = errors[index] {
print("Error compressing video \(index): \(error.localizedDescription)")
} }
self.updateNextView(compressAllSize,compressingView,[],outputURLs)
} }
self.updateNextView(compressAllSize,compressingView,[],outputURLs)
} }
}
}
if HomePayModel.share.isNoAd == false {
HomeNoAdsViewController.show {
actionBlock()
}
}
} }
} }
......
...@@ -58,10 +58,9 @@ class CompressNavView : UIView { ...@@ -58,10 +58,9 @@ class CompressNavView : UIView {
} }
@objc private func proBtnClick() { @objc private func proBtnClick() {
let homeNavViewModel = HomeNavViewModel() HomePayViewController.show {
let vc = HomePayViewController()
vc.modalPresentationStyle = .fullScreen }
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc)
} }
......
...@@ -56,16 +56,33 @@ class HomeInfoViewController:BaseViewController { ...@@ -56,16 +56,33 @@ class HomeInfoViewController:BaseViewController {
} }
} }
sview.deleteCallBack = {array in sview.deleteCallBack = { [weak self] array in
guard let self = self else { return }
if let cA = array as? [String] { let deleteOp:((Any)->Void) = {[weak self] imgs in
if let cA = imgs as? [String] {
PhotoAndVideoMananger.deleteAssets(localIdentifiers: cA) {[weak self] in PhotoAndVideoMananger.deleteAssets(localIdentifiers: cA) {[weak self] in
guard let self else {return}
guard let self else {return} self.tablewView.deleteModel()
}
self.tablewView.deleteModel() }
}
if HomePayModel.share.isNoAd == false {
if self.type == .duplicates { // 重复
HomePayViewController.show {
deleteOp(array)
}
}else if self.type == .similar { // 相似
HomeNoAdsViewController.show {
deleteOp(array)
}
}else{
HomeNoAdsViewController.show {
deleteOp(array)
}
} }
}else {
deleteOp(array)
} }
} }
......
...@@ -139,14 +139,9 @@ class HomeViewController:BaseViewController { ...@@ -139,14 +139,9 @@ class HomeViewController:BaseViewController {
self.navigationController?.pushViewController(vc, animated: false) self.navigationController?.pushViewController(vc, animated: false)
}else { }else {
if HomePayModel.share.isNoAd == false {
let vc:HomePayViewController = HomePayViewController() HomePayViewController.show {}
}
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
self.navigationController?.present(nav, animated: true)
} }
} }
} }
......
...@@ -85,10 +85,9 @@ class HomeNavView:UIView { ...@@ -85,10 +85,9 @@ class HomeNavView:UIView {
} }
@objc private func proBtnClick() { @objc private func proBtnClick() {
let homeNavViewModel = HomeNavViewModel() HomePayViewController.show {
let vc = HomePayViewController()
vc.modalPresentationStyle = .fullScreen }
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc)
} }
......
This diff is collapsed.
//
// NoAdsStackView.swift
// PhoneManager
//
// Created by edy on 2025/4/7.
//
import UIKit
protocol NoAdsStackDataSource: AnyObject {
func NoAdsStactChildView(_ content:NoAdsStackView, _ idx:Int) -> UIView
}
class NoAdsStackView: UIView {
var dataSource:(any NoAdsStackDataSource)?
var numbers:Int = 0 {
didSet{
self.loadUi()
}
}
private func loadUi() -> Void {
for i in 0..<self.numbers {
guard let child = dataSource?.NoAdsStactChildView(self , i) as? UIView else { return }
stack.addArrangedSubview(child)
}
}
var spacing:CGFloat = 0 {
didSet {
stack.spacing = spacing
}
}
var axis:NSLayoutConstraint.Axis = .vertical{
didSet{
stack.axis = axis
}
}
var alignment:UIStackView.Alignment = .fill {
didSet{
stack.alignment = alignment
}
}
var distribution:UIStackView.Distribution = .fill {
didSet{
stack.distribution = distribution
}
}
private lazy var stack: UIStackView = {
let stack = UIStackView()
stack.backgroundColor = .clear
stack.spacing = 8
stack.axis = .vertical
stack.alignment = .fill
stack.distribution = .equalSpacing
addSubview(stack)
return stack
}()
convenience init(_ numbers:Int) {
self.init(frame: CGRectZero)
self.numbers = numbers;
DispatchQueue.main.async {
self.loadUi()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
stack.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//
// HomePayModel.swift
// PhoneManager
//
// Created by edy on 2025/4/7.
//
import UIKit
import StoreKit
class HomePayModel: NSObject ,SKProductsRequestDelegate ,SKPaymentTransactionObserver {
static let share:HomePayModel = HomePayModel()
var isNoAd:Bool {
get {
guard let noabd = UserDefaults.standard.object(forKey: "noabd") as? Bool else { return false }
return noabd
}
set {
UserDefaults.standard.setValue((newValue), forKey: "noabd")
NotificationCenter.default.post(name: .HelperPurchaseNotification, object: nil)
UserDefaults.standard.synchronize()
}
}
var storeCall:((_ product:SKProduct) -> Void) = { prod in }
func checkTrialStatus() -> Void {
verifyReceiptWithApple { receipt in
self.alert.dismiss()
guard let json = receipt else {
self.refreshReceipt()
return
}
let sub = self.checkSubscriptionStatus(receiptInfo: json)
if sub.0 == true {
let extDate = sub.2
self.isNoAd = true
#if DEBUG
let s = DateFormatter()
s.dateFormat = "yyyyMMdd HHmmss"
Print("ext : %@", s.string(from: extDate ?? Date()))
#endif
}else{
self.isNoAd = false
}
}
}
func fetchProducts() {
let request = SKProductsRequest(productIdentifiers: ["com.app.phonemanager.year.member"])
request.delegate = self
request.start()
Print("获取商品信息")
}
var product:SKProduct?
/** 获取商品列表 */
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let products = response.products
guard let product = products.first else {
return
}
DispatchQueue.main.async {
self.product = product
self.storeCall(product)
}
}
/** 购买 */
func purchase() -> Void {
guard let prod = product,
SKPaymentQueue.canMakePayments()
else { return }
let payment = SKPayment(product: prod)
SKPaymentQueue.default().add(payment)
alert.show()
}
/** 恢复 */
func restore() -> Void {
SKPaymentQueue.default().restoreCompletedTransactions()
alert.show()
}
override init() {
super.init()
SKPaymentQueue.default().add(self)
}
let alert = PMAlertView()
}
extension HomePayModel {
/** 购买回调 */
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) -> Void {
guard let transaction = transactions.first else { return }
switch transaction.transactionState {
case .purchasing:
Print("购买中...")
break
case .purchased:
Print("购买成功")
self.handlePurchased(transaction)
break
case .failed:
Print("购买失败")
alert.dismiss()
SKPaymentQueue.default().finishTransaction(transaction)
break
case .restored:
Print("恢复购买")
self.restore()
break
default: break
}
}
/** 购买成功 */
private func handlePurchased(_ transaction: SKPaymentTransaction) {
checkTrialStatus()
SKPaymentQueue.default().finishTransaction(transaction)
}
func verifyReceiptWithApple(completion: @escaping (_ receipt:[String:Any]?) -> Void ) {
guard let receiptURL = Bundle.main.appStoreReceiptURL,
let receiptData = try? Data(contentsOf: receiptURL) else {
completion(nil)
return
}
let requestData: [String: Any] = [
"receipt-data": receiptData.base64EncodedString(),
"password": "3cbeb6f5ace84f5b98571263da74c192",
"exclude-old-transactions": true
]
// 2. 创建请求
let url = URL(string: "https://buy.itunes.apple.com/verifyReceipt")! // 生产环境
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: requestData)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if error != nil {
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
if let status = json["status"] as? Int, status == 21007 {
self.verifySandboxReceipt(receiptData: receiptData) { receipt in
completion(receipt)
}
} else {
completion(json)
}
} else {
completion(nil)
}
} catch {
completion(nil)
}
}
task.resume()
}
/** 验证收据 */
private func verifySandboxReceipt(receiptData: Data, completion: @escaping (_ receipt:[String:Any]?) -> Void) {
let base64Receipt = receiptData.base64EncodedString()
let requestData: [String: Any] = [
"receipt-data": base64Receipt,
"password": "3cbeb6f5ace84f5b98571263da74c192",
"exclude-old-transactions": true
]
let url = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")! // 沙盒环境
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: requestData)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(nil)
return
}
guard let data = data else {
completion(nil)
return
}
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
completion(json)
} else {
completion(nil)
}
} catch {
completion(nil)
}
}
task.resume()
}
/** 获取订阅状态 */
func checkSubscriptionStatus(receiptInfo: [String: Any]) -> (isActive: Bool, isTrial: Bool, expiresDate: Date?) {
guard let latestReceiptInfo = receiptInfo["latest_receipt_info"] as? [[String: Any]] else {
return (false, false, nil)
}
// 获取最新的订阅信息
guard let lastReceipt = latestReceiptInfo.first else {
return (false, false, nil)
}
// 解析试用期状态
let isTrial = (lastReceipt["is_trial_period"] as? String) == "true"
// 解析到期时间
var expiresDate: Date?
if let expiresDateMs = lastReceipt["expires_date_ms"] as? String,
let timeInterval = TimeInterval(expiresDateMs) {
expiresDate = Date(timeIntervalSince1970: timeInterval / 1000.0)
} else if let expiresDateString = lastReceipt["expires_date"] as? String {
let formatter = ISO8601DateFormatter()
expiresDate = formatter.date(from: expiresDateString)
}
// 检查订阅是否有效
let isActive: Bool
if let date = expiresDate {
isActive = date > Date()
} else {
isActive = false
}
return (isActive, isTrial, expiresDate)
}
/** 恢复购买 */
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) -> Void {
checkTrialStatus()
}
/** 刷新收据 */
func refreshReceipt() {
let request = SKReceiptRefreshRequest()
request.delegate = self
request.start()
}
}
extension Notification.Name {
static let HelperPurchaseNotification = Notification.Name("PhoneManagerisStore")
}
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import UIKit import UIKit
import SnapKit import SnapKit
import Lottie import Lottie
import StoreKit
class HomePayView:UIView { class HomePayView:UIView {
...@@ -124,6 +125,7 @@ class HomePayView:UIView { ...@@ -124,6 +125,7 @@ class HomePayView:UIView {
restoreBtn?.setTitle("Restore Purchase", for: .normal) restoreBtn?.setTitle("Restore Purchase", for: .normal)
restoreBtn?.setTitleColor(UIColor.colorWithHex(hexStr: "#B3B3B3"), for: .normal) restoreBtn?.setTitleColor(UIColor.colorWithHex(hexStr: "#B3B3B3"), for: .normal)
restoreBtn?.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular) restoreBtn?.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
restoreBtn?.addTarget(self, action: #selector(restoreTouch), for: .touchUpInside)
self.addSubview(restoreBtn!) self.addSubview(restoreBtn!)
restoreBtn?.snp.makeConstraints { make in restoreBtn?.snp.makeConstraints { make in
...@@ -146,7 +148,7 @@ class HomePayView:UIView { ...@@ -146,7 +148,7 @@ class HomePayView:UIView {
} }
titleLabel1 = UILabel() titleLabel1 = UILabel()
titleLabel1?.text = "Clean your Storage" titleLabel1?.text = "Clean your storage space"
titleLabel1?.font = UIFont.systemFont(ofSize: 24, weight: .bold) titleLabel1?.font = UIFont.systemFont(ofSize: 24, weight: .bold)
titleLabel1?.textColor = UIColor.colorWithHex(hexStr: black3Color) titleLabel1?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel1!) self.addSubview(titleLabel1!)
...@@ -159,7 +161,7 @@ class HomePayView:UIView { ...@@ -159,7 +161,7 @@ class HomePayView:UIView {
titleLabel1?.sizeToFit() titleLabel1?.sizeToFit()
titleLabel2 = UILabel() titleLabel2 = UILabel()
titleLabel2?.text = "Get rid of what you don't need" titleLabel2?.text = "Delete unnecessary content"
titleLabel2?.font = UIFont.systemFont(ofSize: 14, weight: .bold) titleLabel2?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
titleLabel2?.textColor = UIColor.colorWithHex(hexStr: black3Color) titleLabel2?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel2!) self.addSubview(titleLabel2!)
...@@ -285,7 +287,7 @@ class HomePayView:UIView { ...@@ -285,7 +287,7 @@ class HomePayView:UIView {
} }
contentView1Tip1 = UILabel() contentView1Tip1 = UILabel()
contentView1Tip1?.text = "Smart Cleaning, Video Compressor, Secret Storage, Manage Contacts, No Ads and Limits." contentView1Tip1?.text = "Smart Cleaning, Video Compressor, Secret Storage, No Ads and Limits."
contentView1Tip1?.font = UIFont.systemFont(ofSize: 12, weight: .regular) contentView1Tip1?.font = UIFont.systemFont(ofSize: 12, weight: .regular)
contentView1Tip1?.textColor = UIColor.colorWithHex(hexStr: black6Color) contentView1Tip1?.textColor = UIColor.colorWithHex(hexStr: black6Color)
contentView1Tip1?.numberOfLines = 2 contentView1Tip1?.numberOfLines = 2
...@@ -301,7 +303,6 @@ class HomePayView:UIView { ...@@ -301,7 +303,6 @@ class HomePayView:UIView {
contentView1Tip1?.setlineSpacing(font: contentView1Tip1!.font, lineSpacing: 3, width: contentView1Tip1!.width, numberOfLines: contentView1Tip1!.numberOfLines, content: contentView1Tip1!.text ?? "") contentView1Tip1?.setlineSpacing(font: contentView1Tip1!.font, lineSpacing: 3, width: contentView1Tip1!.width, numberOfLines: contentView1Tip1!.numberOfLines, content: contentView1Tip1!.text ?? "")
contentView1Tip2 = UILabel() contentView1Tip2 = UILabel()
contentView1Tip2?.text = "Free for 7 days, then $6.99/week"
contentView1Tip2?.font = UIFont.systemFont(ofSize: 12, weight: .regular) contentView1Tip2?.font = UIFont.systemFont(ofSize: 12, weight: .regular)
contentView1Tip2?.textColor = UIColor.colorWithHex(hexStr: black6Color) contentView1Tip2?.textColor = UIColor.colorWithHex(hexStr: black6Color)
contentView1Tip2?.numberOfLines = 1 contentView1Tip2?.numberOfLines = 1
...@@ -328,7 +329,7 @@ class HomePayView:UIView { ...@@ -328,7 +329,7 @@ class HomePayView:UIView {
contentView2?.layer.masksToBounds = true contentView2?.layer.masksToBounds = true
contentView2Title = UILabel() contentView2Title = UILabel()
contentView2Title?.text = "Cleanup Pro" contentView2Title?.text = "Free trial enabled"
contentView2Title?.font = UIFont.systemFont(ofSize: 16, weight: .bold) contentView2Title?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
contentView2Title?.textColor = UIColor.colorWithHex(hexStr: black3Color) contentView2Title?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.contentView2?.addSubview(contentView2Title!) self.contentView2?.addSubview(contentView2Title!)
...@@ -344,6 +345,8 @@ class HomePayView:UIView { ...@@ -344,6 +345,8 @@ class HomePayView:UIView {
contentView2Switch?.onTintColor = UIColor.colorWithHex(hexStr: mColor) contentView2Switch?.onTintColor = UIColor.colorWithHex(hexStr: mColor)
contentView2Switch?.tintColor = .white contentView2Switch?.tintColor = .white
contentView2Switch?.backgroundColor = .clear contentView2Switch?.backgroundColor = .clear
contentView2Switch?.isOn = true
contentView2Switch?.isUserInteractionEnabled = false
self.contentView2?.addSubview(contentView2Switch!) self.contentView2?.addSubview(contentView2Switch!)
contentView2Switch?.snp.makeConstraints { make in contentView2Switch?.snp.makeConstraints { make in
...@@ -450,7 +453,7 @@ class HomePayView:UIView { ...@@ -450,7 +453,7 @@ class HomePayView:UIView {
}) })
freeContentTip = UILabel() freeContentTip = UILabel()
freeContentTip?.text = "7 days free" freeContentTip?.text = "3 days free"
freeContentTip?.font = UIFont.systemFont(ofSize: 12, weight: .bold) freeContentTip?.font = UIFont.systemFont(ofSize: 12, weight: .bold)
freeContentTip?.textColor = UIColor.colorWithHex(hexStr: whiteColor) freeContentTip?.textColor = UIColor.colorWithHex(hexStr: whiteColor)
freeContentTip?.backgroundColor = UIColor.colorWithHex(hexStr: "#52C776") freeContentTip?.backgroundColor = UIColor.colorWithHex(hexStr: "#52C776")
...@@ -478,10 +481,9 @@ class HomePayView:UIView { ...@@ -478,10 +481,9 @@ class HomePayView:UIView {
make.width.equalToSuperview().offset(-45) make.width.equalToSuperview().offset(-45)
}) })
normalContentTitle = UILabel() normalContentTitle = UILabel()
normalContentTitle?.text = "Due today" let date:String = Date().operation(1)?.string("MMMM dd yyyy") ?? ""
normalContentTitle?.text = "Due \(date)"
normalContentTitle?.font = UIFont.systemFont(ofSize: 12, weight: .regular) normalContentTitle?.font = UIFont.systemFont(ofSize: 12, weight: .regular)
normalContentTitle?.textColor = UIColor.colorWithHex(hexStr: black6Color) normalContentTitle?.textColor = UIColor.colorWithHex(hexStr: black6Color)
normalContent?.addSubview(normalContentTitle!) normalContent?.addSubview(normalContentTitle!)
...@@ -503,7 +505,6 @@ class HomePayView:UIView { ...@@ -503,7 +505,6 @@ class HomePayView:UIView {
make.centerX.equalToSuperview() make.centerX.equalToSuperview()
make.right.equalToSuperview() make.right.equalToSuperview()
}) })
} }
func playAnimationWithDelay() { func playAnimationWithDelay() {
...@@ -518,9 +519,15 @@ class HomePayView:UIView { ...@@ -518,9 +519,15 @@ class HomePayView:UIView {
} }
} }
var product : SKProduct? {
didSet{
guard let prod = product else { return }
normalContentMoney?.text = "$\(prod.price)"
contentView1Tip2?.text = "Free trial for 3 days, $\(prod.price) per year thereafter"
}
}
@objc func closeBtnClick() { @objc func closeBtnClick() {
callBack(OperStatus.close) callBack(OperStatus.close)
} }
...@@ -530,18 +537,19 @@ class HomePayView:UIView { ...@@ -530,18 +537,19 @@ class HomePayView:UIView {
} }
@objc func touBtnClick(btn:UIButton) { @objc func touBtnClick(btn:UIButton) {
callBack(CommonPush.tou) callBack(CommonPush.tou)
} }
@objc func switchValueChanged(_ sender: UISwitch) { @objc func switchValueChanged(_ sender: UISwitch) {
callBack(CommonPush.swit)
}
@objc func restoreTouch() -> Void {
callBack(CommonPush.restore)
} }
@objc func payButtonClick() { @objc func payButtonClick() {
callBack(CommonPush.pay)
} }
} }
...@@ -6,33 +6,42 @@ ...@@ -6,33 +6,42 @@
// //
import UIKit import UIKit
import StoreKit
class HomePayViewController:UIViewController { class HomePayViewController:UIViewController {
private var homePayView:HomePayView? private var homePayView:HomePayView?
private var disjunctor = false
private var doneBlock:(()->Void) = {}
var currentProduct:SKProduct? {
didSet {
setPrice()
}
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.backgroundColor = .green view.backgroundColor = .green
addViews() addViews()
HomePayModel.share.fetchProducts()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
storeKeD()
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
homePayView?.playAnimationWithDelay() homePayView?.playAnimationWithDelay()
} }
private func addViews() { private func addViews() {
homePayView = HomePayView(frame: view.bounds) homePayView = HomePayView(frame: view.bounds)
view.addSubview(homePayView!) view.addSubview(homePayView!)
homePayView?.callBack = {[weak self] status in homePayView?.callBack = {[weak self] status in
guard let self else {return} guard let self else {return}
...@@ -42,6 +51,7 @@ class HomePayViewController:UIViewController { ...@@ -42,6 +51,7 @@ class HomePayViewController:UIViewController {
switch operstatus { switch operstatus {
case .close: case .close:
self.dismiss(animated: true) self.dismiss(animated: true)
doneBlock()
default: default:
break break
} }
...@@ -54,18 +64,49 @@ class HomePayViewController:UIViewController { ...@@ -54,18 +64,49 @@ class HomePayViewController:UIViewController {
self.ppClick() self.ppClick()
case .tou: case .tou:
self.touClick() self.touClick()
case .pay:
self.payTouch()
break
case .swit:
self.disjunctorTouch()
break
case .restore:
self.restoreClick()
break
} }
} }
} }
} }
}
extension HomePayViewController {
private func setPrice() -> Void {
guard currentProduct != nil else { return }
homePayView?.product = currentProduct
}
private func storeKeD() -> Void {
HomePayModel.share.storeCall = {[weak self] product in
guard let self = self else { return }
self.currentProduct = product
}
}
private func disjunctorTouch() -> Void {
self.disjunctor = !self.disjunctor
setPrice()
}
private func payTouch() -> Void {
HomePayModel.share.purchase()
}
private func ppClick() { private func ppClick() {
DispatchQueue.main.async {[weak self] in DispatchQueue.main.async {[weak self] in
guard let self else {return} guard let self else {return}
let vc:PrivacyPolicyWebViewController = PrivacyPolicyWebViewController() let vc:PrivacyPolicyWebViewController = PrivacyPolicyWebViewController()
vc.hidesBottomBarWhenPushed = true vc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
...@@ -73,14 +114,25 @@ class HomePayViewController:UIViewController { ...@@ -73,14 +114,25 @@ class HomePayViewController:UIViewController {
} }
private func touClick() { private func touClick() {
DispatchQueue.main.async {[weak self] in DispatchQueue.main.async {[weak self] in
guard let self else {return} guard let self else {return}
let vc:TermOfUseWebViewController = TermOfUseWebViewController() let vc:TermOfUseWebViewController = TermOfUseWebViewController()
vc.hidesBottomBarWhenPushed = true vc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(vc, animated: true) self.navigationController?.pushViewController(vc, animated: true)
} }
} }
private func restoreClick() {
HomePayModel.share.restore()
}
class func show( _ compate:@escaping(()->Void)) -> Void {
let vc:HomePayViewController = HomePayViewController()
vc.doneBlock = compate
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
guard let rt = UIViewController.topMostViewController() else { return }
rt.present(nav, animated: true)
}
} }
...@@ -112,10 +112,10 @@ class SettingViewHeaderCell : UITableViewCell { ...@@ -112,10 +112,10 @@ class SettingViewHeaderCell : UITableViewCell {
} }
@objc func leanMoreBtnClick() { @objc func leanMoreBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let vc = HomePayViewController() HomeNoAdsViewController.show {
vc.modalPresentationStyle = .fullScreen
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc) }
} }
} }
...@@ -59,7 +59,6 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV ...@@ -59,7 +59,6 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
let cell : SettingViewHeaderCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewHeaderCell",for: indexPath) as! SettingViewHeaderCell let cell : SettingViewHeaderCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewHeaderCell",for: indexPath) as! SettingViewHeaderCell
return cell return cell
}else{ }else{
let model : SettingModel = modelData![indexPath.section] let model : SettingModel = modelData![indexPath.section]
let detailModel : RowInfoModel = model.rowInfo[indexPath.row] let detailModel : RowInfoModel = model.rowInfo[indexPath.row]
...@@ -145,8 +144,48 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV ...@@ -145,8 +144,48 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
} }
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let signOutTipView = SignOutTipView(frame: self.view.frame)
self.view.addSubview(signOutTipView) switch indexPath.section {
case 0:
break
case 1:
break
case 2: // 小组件
let widget = WidgetViewController()
self.navigationController?.pushViewController(widget, animated: true)
break
case 3:
break
case 4:
if indexPath.row == 0 { // 评分
self.review()
}else if indexPath.row == 1 { // 分享
self.PhoneShare()
}
break
default:
break
}
}
private func review() -> Void {
let reviewURLString = "itms-apps://itunes.apple.com/app/id1530333201?action=write-review"
guard let url = URL(string: reviewURLString), UIApplication.shared.canOpenURL(url) else {
return
}
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:])
}
}
private func PhoneShare() -> Void {
let items: [Any] = [ URL(string: "itms-apps://itunes.apple.com/app/id1530333201")! ]
let shareVc = UIActivityViewController(
activityItems: items,
applicationActivities: nil
)
present(shareVc, animated: true)
} }
} }
//
// PMAlertView.swift
// PhoneManager
//
// Created by edy on 2025/4/8.
//
import UIKit
class PMAlertView: UIViewController {
private var pm_msg:String?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setUI()
}
private func setUI() -> Void {
pm_ActivityIndicator.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(13)
make.size.equalTo(CGSize(width: 24, height: 24))
}
massage.snp.makeConstraints { make in
make.top.equalTo(pm_ActivityIndicator.snp.bottom).offset(15)
make.width.lessThanOrEqualTo(140)
make.width.greaterThanOrEqualTo(50)
make.right.left.equalToSuperview()
make.bottom.equalTo(content.snp.bottom).offset(-5)
}
content.snp.makeConstraints { make in
make.centerX.centerY.equalToSuperview()
}
}
func show() -> Void {
DispatchQueue.main.async {
guard let rt = UIViewController.topMostViewController() else { return }
self.modalPresentationStyle = .overFullScreen
self.modalTransitionStyle = .crossDissolve
rt.present(self, animated: true)
}
}
func dismiss() -> Void {
DispatchQueue.main.async {
self.dismiss(animated: true)
}
}
convenience init( _ message:String?) {
self.init()
self.pm_msg = message
}
private lazy var pm_ActivityIndicator: UIActivityIndicatorView = {
let pmact = UIActivityIndicatorView()
pmact.style = .medium
pmact.startAnimating()
content.addSubview(pmact)
pmact.color = .black
pmact.transform = CGAffineTransformMakeScale(1.3, 1.3)
return pmact
}()
private lazy var content: UIView = {
let content = UIView()
content.backgroundColor = .clear
content.layer.cornerRadius = 14;
view.addSubview(content)
return content
}()
private lazy var massage: UILabel = {
let msg = UILabel()
msg.textAlignment = .center
msg.numberOfLines = 0
msg.font = UIFont.systemFont(ofSize: 15)
msg.textColor = .colorWithHex(hexStr: "#333333")
content.addSubview(msg)
return msg
}()
}
//
// PMPageControl.swift
// PhoneManager
//
// Created by edy on 2025/4/8.
//
import UIKit
class PMPageControl: UIPageControl {
private let activeWidth: CGFloat = 16.0
private let inactiveWidth: CGFloat = 8.0
private let dotSpacing: CGFloat = 8.0
override func layoutSubviews() {
super.layoutSubviews()
// for (index, dot) in subviews.enumerated() {
// let isCurrentPage = index == currentPage
// let targetWidth = isCurrentPage ? activeWidth : inactiveWidth
// let previousDotsWidth = CGFloat(index) * (inactiveWidth + dotSpacing)
// let adjustX = previousDotsWidth + (isCurrentPage ? 0 : activeWidth - inactiveWidth)
// dot.frame = CGRect(
// x: adjustX,
// y: dot.frame.origin.y,
// width: targetWidth,
// height: dot.frame.height
// )
// }
}
}
...@@ -22,6 +22,9 @@ enum CommonPush { ...@@ -22,6 +22,9 @@ enum CommonPush {
case pp case pp
case tou case tou
case swit
case pay
case restore
} }
enum tabbarType { enum tabbarType {
......
...@@ -214,3 +214,33 @@ enum GradientDirection { ...@@ -214,3 +214,33 @@ enum GradientDirection {
} }
} }
} }
extension Date {
func string(_ format:String = "") -> String {
let dateforametter = DateFormatter()
dateforametter.dateFormat = format
return dateforametter.string(from: self)
}
func operation(_ year:Int = 0,
_ month:Int = 0,
_ day:Int = 0,
_ houre:Int = 0,
_ minte:Int = 0,
_ sec:Int = 0,
_ week:Int = 0) -> Date? {
let calendar = Calendar.current
let currentDate = self
var dateComponent:DateComponents = calendar.dateComponents([.year,.month,.day,.hour,.minute,.second,.weekday], from: currentDate)
dateComponent.year! += year
dateComponent.month! += month
dateComponent.month! += day
dateComponent.hour! += houre
dateComponent.second! += sec
dateComponent.weekday! += week
guard let toDate = calendar.date(from: dateComponent) else { return self }
return toDate
}
}
...@@ -23,8 +23,40 @@ extension UIViewController { ...@@ -23,8 +23,40 @@ extension UIViewController {
nav.barHidden = isHidden nav.barHidden = isHidden
} }
class func topMostViewController() -> UIViewController? {
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
return nil
}
return self.topMostViewController(of: rootViewController)
}
private static func topMostViewController(of viewController: UIViewController) -> UIViewController {
// 处理模态弹出的视图控制器
if let presentedViewController = viewController.presentedViewController {
return self.topMostViewController(of: presentedViewController)
}
// 处理 UINavigationController
if let navigationController = viewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController {
return self.topMostViewController(of: visibleViewController)
}
// 处理 UITabBarController
if let tabBarController = viewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topMostViewController(of: selectedViewController)
}
// 处理子控制器
for subview in viewController.view?.subviews ?? [] {
if let childViewController = subview.next as? UIViewController {
return self.topMostViewController(of: childViewController)
}
}
return viewController
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment