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 {
if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
window?.rootViewController = current
window?.makeKeyAndVisible()
}
let battery = WidgetPublicModel.battery()
......@@ -37,7 +36,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private func setupDefault() {
HomePayModel.share.checkTrialStatus()
NetStatusManager.manager.startNet { status in
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{
@objc func submitAction(){
let compressingView : CompressingView = CompressingView(frame: self.view.bounds)
compressingView.data = self.model
self.view.addSubview(compressingView)
// 开始压缩
let manager : CompressViewModel = CompressViewModel()
var currentQulity = 0.2
if currentQulityType == 1 {
currentQulity = 0.5
}
if currentQulityType == 2 {
currentQulity = 0.8
}
var comDataSource : [Data] = []
if self.currentMediaType == 0 {
// 表示压缩图片
manager.compress(assets: self.model!, compressionQuality: currentQulity) {progress in
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
} completion: { compressedDataArray, errorArray in
var compressAllSize = 0.0
for (index, data) in compressedDataArray.enumerated() {
if let error = errorArray[index] {
print("第 \(index + 1) 个文件压缩出错: \(error.localizedDescription)")
} else if let data = data {
print("第 \(index + 1) 个文件压缩完成,压缩后大小: \(data.count) 字节")
compressAllSize = compressAllSize + Double(data.count)
comDataSource.append(data)
} else {
print("第 \(index + 1) 个文件压缩失败")
let actionBlock = { [weak self] in
guard let self = self else { return }
let compressingView : CompressingView = CompressingView(frame: self.view.bounds)
compressingView.data = self.model
self.view.addSubview(compressingView)
// 开始压缩
let manager : CompressViewModel = CompressViewModel()
var currentQulity = 0.2
if currentQulityType == 1 {
currentQulity = 0.5
}
if currentQulityType == 2 {
currentQulity = 0.8
}
var comDataSource : [Data] = []
if self.currentMediaType == 0 {
// 表示压缩图片
manager.compress(assets: self.model!, compressionQuality: currentQulity) {progress in
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
} completion: { compressedDataArray, errorArray in
var compressAllSize = 0.0
for (index, data) in compressedDataArray.enumerated() {
if let error = errorArray[index] {
print("第 \(index + 1) 个文件压缩出错: \(error.localizedDescription)")
} else if let data = data {
print("第 \(index + 1) 个文件压缩完成,压缩后大小: \(data.count) 字节")
compressAllSize = compressAllSize + Double(data.count)
comDataSource.append(data)
} else {
print("第 \(index + 1) 个文件压缩失败")
}
}
self.updateNextView(compressAllSize,compressingView,comDataSource,[])
}
self.updateNextView(compressAllSize,compressingView,comDataSource,[])
}
}else{
// 压缩视频
var compressAllSize : Double = 0.0
manager.compressVideos(models: self.model!, quality: Float(currentQulity)) { (identifier, progress) in
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
} completion: { (outputURLs, errors) in
for (index, outputURL) in outputURLs.enumerated() {
if let outputURL = outputURL {
do {
let attributes = try FileManager.default.attributesOfItem(atPath: outputURL.path)
if let fileSize = attributes[.size] as? Int64 {
compressAllSize = compressAllSize + Double(fileSize)
}else{
// 压缩视频
var compressAllSize : Double = 0.0
manager.compressVideos(models: self.model!, quality: Float(currentQulity)) { (identifier, progress) in
compressingView.animationView.setProgress(CGFloat(progress), animated: false, duration: 0.1)
} completion: { (outputURLs, errors) in
for (index, outputURL) in outputURLs.enumerated() {
if let outputURL = outputURL {
do {
let attributes = try FileManager.default.attributesOfItem(atPath: outputURL.path)
if let fileSize = attributes[.size] as? Int64 {
compressAllSize = compressAllSize + Double(fileSize)
}
} catch {
Print("获取视频文件大小失败")
}
} catch {
Print("获取视频文件大小失败")
print("Compressed video \(index) saved at: \(outputURL)")
} 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 {
}
@objc private func proBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let vc = HomePayViewController()
vc.modalPresentationStyle = .fullScreen
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc)
HomePayViewController.show {
}
}
......
......@@ -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] {
PhotoAndVideoMananger.deleteAssets(localIdentifiers: cA) {[weak self] in
guard let self else {return}
self.tablewView.deleteModel()
let deleteOp:((Any)->Void) = {[weak self] imgs in
if let cA = imgs as? [String] {
PhotoAndVideoMananger.deleteAssets(localIdentifiers: cA) {[weak self] in
guard let self else {return}
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 {
self.navigationController?.pushViewController(vc, animated: false)
}else {
let vc:HomePayViewController = HomePayViewController()
let nav:BaseNavViewController = BaseNavViewController(rootViewController: vc)
nav.modalPresentationStyle = .fullScreen
self.navigationController?.present(nav, animated: true)
if HomePayModel.share.isNoAd == false {
HomePayViewController.show {}
}
}
}
}
......
......@@ -85,10 +85,9 @@ class HomeNavView:UIView {
}
@objc private func proBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let vc = HomePayViewController()
vc.modalPresentationStyle = .fullScreen
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc)
HomePayViewController.show {
}
}
......
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 @@
import UIKit
import SnapKit
import Lottie
import StoreKit
class HomePayView:UIView {
......@@ -124,6 +125,7 @@ class HomePayView:UIView {
restoreBtn?.setTitle("Restore Purchase", for: .normal)
restoreBtn?.setTitleColor(UIColor.colorWithHex(hexStr: "#B3B3B3"), for: .normal)
restoreBtn?.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .regular)
restoreBtn?.addTarget(self, action: #selector(restoreTouch), for: .touchUpInside)
self.addSubview(restoreBtn!)
restoreBtn?.snp.makeConstraints { make in
......@@ -146,7 +148,7 @@ class HomePayView:UIView {
}
titleLabel1 = UILabel()
titleLabel1?.text = "Clean your Storage"
titleLabel1?.text = "Clean your storage space"
titleLabel1?.font = UIFont.systemFont(ofSize: 24, weight: .bold)
titleLabel1?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel1!)
......@@ -159,7 +161,7 @@ class HomePayView:UIView {
titleLabel1?.sizeToFit()
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?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.addSubview(titleLabel2!)
......@@ -285,7 +287,7 @@ class HomePayView:UIView {
}
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?.textColor = UIColor.colorWithHex(hexStr: black6Color)
contentView1Tip1?.numberOfLines = 2
......@@ -301,7 +303,6 @@ class HomePayView:UIView {
contentView1Tip1?.setlineSpacing(font: contentView1Tip1!.font, lineSpacing: 3, width: contentView1Tip1!.width, numberOfLines: contentView1Tip1!.numberOfLines, content: contentView1Tip1!.text ?? "")
contentView1Tip2 = UILabel()
contentView1Tip2?.text = "Free for 7 days, then $6.99/week"
contentView1Tip2?.font = UIFont.systemFont(ofSize: 12, weight: .regular)
contentView1Tip2?.textColor = UIColor.colorWithHex(hexStr: black6Color)
contentView1Tip2?.numberOfLines = 1
......@@ -328,7 +329,7 @@ class HomePayView:UIView {
contentView2?.layer.masksToBounds = true
contentView2Title = UILabel()
contentView2Title?.text = "Cleanup Pro"
contentView2Title?.text = "Free trial enabled"
contentView2Title?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
contentView2Title?.textColor = UIColor.colorWithHex(hexStr: black3Color)
self.contentView2?.addSubview(contentView2Title!)
......@@ -344,6 +345,8 @@ class HomePayView:UIView {
contentView2Switch?.onTintColor = UIColor.colorWithHex(hexStr: mColor)
contentView2Switch?.tintColor = .white
contentView2Switch?.backgroundColor = .clear
contentView2Switch?.isOn = true
contentView2Switch?.isUserInteractionEnabled = false
self.contentView2?.addSubview(contentView2Switch!)
contentView2Switch?.snp.makeConstraints { make in
......@@ -450,7 +453,7 @@ class HomePayView:UIView {
})
freeContentTip = UILabel()
freeContentTip?.text = "7 days free"
freeContentTip?.text = "3 days free"
freeContentTip?.font = UIFont.systemFont(ofSize: 12, weight: .bold)
freeContentTip?.textColor = UIColor.colorWithHex(hexStr: whiteColor)
freeContentTip?.backgroundColor = UIColor.colorWithHex(hexStr: "#52C776")
......@@ -478,10 +481,9 @@ class HomePayView:UIView {
make.width.equalToSuperview().offset(-45)
})
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?.textColor = UIColor.colorWithHex(hexStr: black6Color)
normalContent?.addSubview(normalContentTitle!)
......@@ -503,7 +505,6 @@ class HomePayView:UIView {
make.centerX.equalToSuperview()
make.right.equalToSuperview()
})
}
func playAnimationWithDelay() {
......@@ -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() {
callBack(OperStatus.close)
}
......@@ -530,18 +537,19 @@ class HomePayView:UIView {
}
@objc func touBtnClick(btn:UIButton) {
callBack(CommonPush.tou)
}
@objc func switchValueChanged(_ sender: UISwitch) {
callBack(CommonPush.swit)
}
@objc func restoreTouch() -> Void {
callBack(CommonPush.restore)
}
@objc func payButtonClick() {
callBack(CommonPush.pay)
}
}
......@@ -6,33 +6,42 @@
//
import UIKit
import StoreKit
class HomePayViewController:UIViewController {
private var homePayView:HomePayView?
private var disjunctor = false
private var doneBlock:(()->Void) = {}
var currentProduct:SKProduct? {
didSet {
setPrice()
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
addViews()
HomePayModel.share.fetchProducts()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
storeKeD()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
homePayView?.playAnimationWithDelay()
}
private func addViews() {
homePayView = HomePayView(frame: view.bounds)
view.addSubview(homePayView!)
homePayView?.callBack = {[weak self] status in
guard let self else {return}
......@@ -42,6 +51,7 @@ class HomePayViewController:UIViewController {
switch operstatus {
case .close:
self.dismiss(animated: true)
doneBlock()
default:
break
}
......@@ -54,18 +64,49 @@ class HomePayViewController:UIViewController {
self.ppClick()
case .tou:
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() {
DispatchQueue.main.async {[weak self] in
guard let self else {return}
let vc:PrivacyPolicyWebViewController = PrivacyPolicyWebViewController()
vc.hidesBottomBarWhenPushed = true
self.navigationController?.pushViewController(vc, animated: true)
......@@ -73,14 +114,25 @@ class HomePayViewController:UIViewController {
}
private func touClick() {
DispatchQueue.main.async {[weak self] in
guard let self else {return}
let vc:TermOfUseWebViewController = TermOfUseWebViewController()
vc.hidesBottomBarWhenPushed = 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 {
}
@objc func leanMoreBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let vc = HomePayViewController()
vc.modalPresentationStyle = .fullScreen
homeNavViewModel.presentToDetailController(currentView: self, destnationController: vc)
HomeNoAdsViewController.show {
}
}
}
......@@ -59,7 +59,6 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
let cell : SettingViewHeaderCell = tableView.dequeueReusableCell(withIdentifier: "SettingViewHeaderCell",for: indexPath) as! SettingViewHeaderCell
return cell
}else{
let model : SettingModel = modelData![indexPath.section]
let detailModel : RowInfoModel = model.rowInfo[indexPath.row]
......@@ -145,8 +144,48 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
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 {
case pp
case tou
case swit
case pay
case restore
}
enum tabbarType {
......
......@@ -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 {
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