Commit 855a80da authored by shenyong's avatar shenyong

年费会员界面,启动引导页结构更改

parent 5e825e99
......@@ -27,13 +27,19 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
window?.backgroundColor = .white
window?.overrideUserInterfaceStyle = .light
let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
window?.rootViewController = current
window?.makeKeyAndVisible()
}
let rootNav = BaseNavViewController(rootViewController: HomeViewController())
window?.rootViewController = rootNav
window?.makeKeyAndVisible()
// let Ssoryboard = UIStoryboard(name: "LauchVC", bundle: nil)
//
// if let current = Ssoryboard.instantiateViewController(identifier: "LauchVCID") as? LauchVC {
//
// window?.rootViewController = current
// window?.makeKeyAndVisible()
// }
let battery = WidgetPublicModel.battery()
let storage = WidgetPublicModel.UseDiskSpace() * 100
widgetAppgourp.share.PushWidgetData(battery: Int(battery), storage: Int(storage))
......@@ -51,6 +57,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// 相册基本资源加载
PhotoManager.shared.config()
// 设置app动态按钮
setupDynamicShortcuts()
return true
}
......
//
// AppDelegateEx.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import Foundation
import UIKit
extension AppDelegate{
func setupDynamicShortcuts() {
let shortcutItem = UIApplicationShortcutItem(
type: "com.app.phonemanager.iap.distance",
localizedTitle: "Unlock Exclusive Discounts",
localizedSubtitle: "Your special offer is awaiting—don't miss this limited-time second chance benefit!",
icon: UIApplicationShortcutIcon(systemImageName: "star.fill"),
userInfo: nil
)
UIApplication.shared.shortcutItems = [shortcutItem]
}
// 处理快捷方式点击
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
// 处理快捷方式点击事件
switch shortcutItem.type {
case "com.app.phonemanager.iap.distance":
// 执行相应操作
let vc = PayDistanceViewController()
vc.modalPresentationStyle = .fullScreen
GETCURRENTNAV()?.present(vc, animated: false)
completionHandler(true)
default:
completionHandler(false)
}
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame_1171276222@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame_1171276222@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -48,7 +48,8 @@ class IAPManager: NSObject {
private let alert = PMLoadingHUD.share
enum PayState {
case subscribe
case weekSubscribe
case yearSubscribe
case nonConsumable
}
......@@ -56,9 +57,10 @@ class IAPManager: NSObject {
private struct ProductID {
static let weekMember = "com.app.phonemanager.week.member"
static let lifetimeMember = "com.app.phonemanager.lifetime.member"
static let yearMember = "com.app.phonemanager.year.member"
static var all: [String] {
return [weekMember, lifetimeMember]
return [weekMember, lifetimeMember,yearMember]
}
}
......@@ -66,14 +68,16 @@ class IAPManager: NSObject {
private var weekProduct: SKProduct?
// 永久订阅
private var lifetimeProduct: SKProduct?
// 年费订阅
private var yearProduct: SKProduct?
private var state: PayState = .subscribe
private var state: PayState = .weekSubscribe
//购买操作的完成回调
private var purchaseCompletion: ((Result<Bool, IAPError>) -> Void)?
//恢复购买的完成回调
private var restoreCompletion: ((Result<Bool, IAPError>) -> Void)?
//获取商品信息的完成回调
private var productRequestCompletion: (((SKProduct?,SKProduct?)?) -> Void)?
private var productRequestCompletion: (((SKProduct?,SKProduct?,SKProduct?)?) -> Void)?
var isSubscribed = false {
didSet {
......@@ -98,15 +102,16 @@ class IAPManager: NSObject {
extension IAPManager {
// 获取订阅内购商品信息
func fetchProducts(completion: @escaping ((SKProduct?,SKProduct?)?) -> Void) {
func fetchProducts(completion: @escaping ((SKProduct?,SKProduct?,SKProduct?)?) -> Void) {
// 先检查缓存
if let cachedProducts = getCachedProducts() {
// 后台更新最新数据
self.weekProduct = cachedProducts.filter{$0.productIdentifier == ProductID.weekMember}.first
self.lifetimeProduct = cachedProducts.filter{$0.productIdentifier == ProductID.lifetimeMember}.first
completion((self.weekProduct,self.lifetimeProduct))
self.yearProduct = cachedProducts.filter{$0.productIdentifier == ProductID.yearMember}.first
completion((self.weekProduct,self.lifetimeProduct,self.yearProduct))
refreshProducts()
return
}
productRequestCompletion = completion
......@@ -157,9 +162,14 @@ extension IAPManager {
}
}
func purchase(_ state: PayState = .subscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) {
func purchase(_ state: PayState = .weekSubscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) {
if state == .subscribe,weekProduct == nil{
if state == .weekSubscribe,weekProduct == nil{
completion(.failure(.noProductsFound))
return
}
if state == .yearSubscribe,yearProduct == nil{
completion(.failure(.noProductsFound))
return
}
......@@ -175,12 +185,23 @@ extension IAPManager {
self.state = state
self.purchaseCompletion = completion
let payment = SKPayment(product: state == .subscribe ? weekProduct! : lifetimeProduct!)
var payment:SKPayment = SKPayment()
switch state{
case .weekSubscribe:
payment = SKPayment(product: weekProduct!)
case .yearSubscribe:
payment = SKPayment(product: yearProduct!)
case .nonConsumable:
payment = SKPayment(product: lifetimeProduct!)
}
SKPaymentQueue.default().add(payment)
alert.show("Processing the purchase request...", "")
}
func restore(_ state: PayState = .subscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) {
func restore(_ state: PayState = .weekSubscribe, completion: @escaping (Result<Bool, IAPError>) -> Void) {
self.state = state
self.restoreCompletion = completion
SKPaymentQueue.default().restoreCompletedTransactions()
......@@ -384,15 +405,15 @@ extension IAPManager: SKProductsRequestDelegate {
// 拿到请求下来的商品信息
self.weekProduct = products.filter{$0.productIdentifier == ProductID.weekMember}.first
self.lifetimeProduct = products.filter{$0.productIdentifier == ProductID.lifetimeMember}.first
self.yearProduct = products.filter{$0.productIdentifier == ProductID.yearMember}.first
// 缓存
if let week = self.weekProduct,let life = self.lifetimeProduct{
cacheProducts([week,life])
if let week = self.weekProduct,let life = self.lifetimeProduct,let year = self.yearProduct{
cacheProducts([week,life,year])
}
DispatchQueue.main.async { [weak self] in
guard let weakSelf = self else { return }
self?.productRequestCompletion?((weakSelf.weekProduct,weakSelf.lifetimeProduct))
self?.productRequestCompletion?((weakSelf.weekProduct,weakSelf.lifetimeProduct,weakSelf.yearProduct))
BackgroundTaskManager.share.endTask()
}
}
......
......@@ -107,7 +107,7 @@ class HomeViewController:BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
loadLaunchView()
self.setupUI()
// 调用下追踪权限
......@@ -181,6 +181,18 @@ class HomeViewController:BaseViewController {
view.addSubview(homeView!)
}
func loadLaunchView(){
let luanch = HomeLaunchView(frame: CGRect(x: 0, y: 0, width: ScreenW, height: ScreenH))
luanch.show()
if !UserDef.shard.isShowLanding{
let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
self.navigationController?.pushViewController(current, animated: false)
}
}
}
override func viewWillAppear(_ animated: Bool) {
......@@ -259,3 +271,12 @@ extension HomeViewController {
}
}
}
// 遵守转场代理协议
extension HomeViewController: UIViewControllerTransitioningDelegate {
// 返回自定义的消失动画对象
func animationController(forDismissed dismissedController: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return FadeOutTransition()
}
}
......@@ -233,11 +233,4 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
GETCURRENTNAV()?.pushViewController(vc, animated: true)
}
func GETCURRENTNAV() -> UINavigationController? {
let k = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
let pre = k?.rootViewController?.presentedViewController
let rt = k?.rootViewController
return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController)
}
}
......@@ -81,21 +81,23 @@ class NewGuideViewController: UIViewController {
}
func enterHome(){
let vc:HomeViewController = HomeViewController()
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
// let vc:HomeViewController = HomeViewController()
//
// let nav = BaseNavViewController(rootViewController: vc)
//
// cWindow?.rootViewController = nav
//
// let transition = CATransition()
// transition.duration = 0.5
// transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
//
// // 添加动画到 window 的 layer
// cWindow?.layer.add(transition, forKey: kCATransition)
//
// // 显示 window
// cWindow?.makeKeyAndVisible()
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// 添加动画到 window 的 layer
cWindow?.layer.add(transition, forKey: kCATransition)
// 显示 window
cWindow?.makeKeyAndVisible()
self.navigationController?.popToRootViewController(animated: false)
UserDef.shard.isShowLanding = true
UserDef.shard.saveUserDefToSandBox()
......
//
// HomeLaunchView.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import Lottie
class HomeLaunchView:UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.frame = frame
configUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configUI(){
backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
let logoImage = UIImageView()
logoImage.image = UIImage.init(named: "icon_phone_manager")
addSubview(logoImage)
let nameImage = UIImageView()
nameImage.image = UIImage.init(named: "icon_phone_manager_name")
addSubview(nameImage)
addSubview(LaunchingLoop)
logoImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(kSafeAreaInsets.top+150)
}
nameImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(logoImage.snp.bottom).offset(12)
}
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
}
func show(){
KEYWINDOW()?.addSubview(self)
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
self.alpha = 1
UIView.animate(withDuration: 0.3) {
self.alpha = 0
}completion: { _ in
self.removeFromSuperview()
}
})
}
private lazy var LaunchingLoop: LottieAnimationView = {
let animationView = LottieAnimationView(name: "launch_loaing")
animationView.loopMode = .loop
animationView.play()
return animationView
}()
}
......@@ -29,40 +29,33 @@ class LauchVC:UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// backView.addSubview(LaunchingView)
backView.addSubview(LaunchingLoop)
// LaunchingView.snp.makeConstraints { make in
// make.centerX.equalToSuperview()
// make.centerY.equalToSuperview().offset(-140 * RScreenH())
// make.width.equalToSuperview()
// make.height.equalTo(LaunchingView.snp.width)
// }
view.addSubview(LaunchingLoop)
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
var vc:UIViewController?
if (UserDef.shard.isShowLanding) {
vc = HomeViewController()
}else {
let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
vc = current
}
}
guard let vc else {return}
let nav = BaseNavViewController(rootViewController: vc)
cWindow?.rootViewController = nav
let transition = CATransition()
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromRight // 从左侧推入
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
cWindow?.layer.add(transition, forKey: kCATransition)
cWindow?.makeKeyAndVisible()
self.dismiss(animated: false)
// var vc:UIViewController?
// if (UserDef.shard.isShowLanding) {
// vc = HomeViewController()
// }else {
// let Ssoryboard = UIStoryboard(name: "PermissionVC", bundle: nil)
// if let current = Ssoryboard.instantiateViewController(identifier: "PermissionVCID") as? PermissionVC {
// vc = current
// }
// }
// guard let vc else {return}
// let nav = BaseNavViewController(rootViewController: vc)
// cWindow?.rootViewController = nav
// let transition = CATransition()
// transition.duration = 0.5
// transition.subtype = CATransitionSubtype.fromRight // 从左侧推入
// transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
// cWindow?.layer.add(transition, forKey: kCATransition)
// cWindow?.makeKeyAndVisible()
})
}
}
//
// LaunchViewController.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import Lottie
class LaunchViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
let logoImage = UIImageView()
logoImage.image = UIImage.init(named: "icon_phone_manager")
view.addSubview(logoImage)
let nameImage = UIImageView()
nameImage.image = UIImage.init(named: "icon_phone_manager_name")
view.addSubview(nameImage)
view.addSubview(LaunchingLoop)
logoImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(kSafeAreaInsets.top+150)
}
nameImage.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(logoImage.snp.bottom).offset(12)
}
LaunchingLoop.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.width.height.equalTo(150)
make.bottom.equalToSuperview().offset(-60 * RScreenH())
}
DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
self.dismiss(animated: true)
})
}
private lazy var LaunchingLoop: LottieAnimationView = {
let animationView = LottieAnimationView(name: "launch_loaing")
animationView.loopMode = .loop
animationView.play()
return animationView
}()
}
......@@ -631,4 +631,17 @@ class HomePayView:UIView {
addSubview(payDueView)
return payDueView
}()
func setPayAnime(){
// 添加呼吸动画
let breathAnimation = CABasicAnimation(keyPath: "transform.scale")
breathAnimation.fromValue = 1.0
breathAnimation.toValue = 1.05
breathAnimation.duration = 0.8
breathAnimation.autoreverses = true
breathAnimation.repeatCount = Float.infinity
breathAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
payButton?.layer.add(breathAnimation, forKey: "breathingAnimation")
}
}
......@@ -10,6 +10,7 @@ import StoreKit
import SVProgressHUD
class HomePayViewController:UIViewController {
private var homePayView:HomePayView?
......@@ -121,7 +122,7 @@ extension HomePayViewController {
IAPManager.share.fetchProducts { [weak self] products in
guard let weakSelf = self else { return }
DispatchQueue.main.async {
if let (weekProduct, lifetimeProduct) = products {
if let (weekProduct, lifetimeProduct,_) = products {
weakSelf.homePayView?.reloadSKPorduct(week: weekProduct, life: lifetimeProduct)
}
}
......@@ -129,7 +130,7 @@ extension HomePayViewController {
}
private func payTouch() -> Void {
IAPManager.share.purchase((homePayView?.type == 0) ? .subscribe : .nonConsumable) {[weak self] result in
IAPManager.share.purchase((homePayView?.type == 0) ? .weekSubscribe : .nonConsumable) {[weak self] result in
guard let weakSelf = self else { return }
switch result {
case .success(let success):
......@@ -182,4 +183,5 @@ extension HomePayViewController {
rt.present(nav, animated: true)
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PayDistanceViewController" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
</view>
</objects>
</document>
......@@ -83,3 +83,11 @@ public func Alert( _ title:String? , _ message:String) -> Void {
alert.addAction(UIAlertAction(title: "OK", style: .cancel))
cWindow?.rootViewController?.present(alert, animated: true)
}
func GETCURRENTNAV() -> UINavigationController? {
let k = UIApplication.shared.windows.filter({$0.isKeyWindow}).first
let pre = k?.rootViewController?.presentedViewController
let rt = k?.rootViewController
return (pre as? UINavigationController) ?? ((rt as? UITabBarController)?.selectedViewController as? UINavigationController) ?? (rt as? UINavigationController)
}
//
// FadeOutTransition.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import Foundation
import UIKit
// 自定义转场动画(用于消失时的渐隐效果)
class FadeOutTransition: NSObject, UIViewControllerAnimatedTransitioning {
// 动画时长(可自定义)
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3 // 0.3秒渐隐
}
// 执行动画
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// 获取即将消失的控制器(被弹出的控制器)
guard let fromVC = transitionContext.viewController(forKey: .from),
let toVC = transitionContext.viewController(forKey: .to) else { return }
// 将目标控制器的视图添加到容器视图(确保转场后界面正确)
transitionContext.containerView.addSubview(toVC.view)
// 渐隐动画:将 fromVC 的视图透明度从 1 降到 0
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
fromVC.view.alpha = 0
}) { (_) in
// 动画完成后,标记转场结束
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
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