diff --git a/Veloria.xcodeproj/project.pbxproj b/Veloria.xcodeproj/project.pbxproj index d5957c5..8fbb835 100644 --- a/Veloria.xcodeproj/project.pbxproj +++ b/Veloria.xcodeproj/project.pbxproj @@ -161,6 +161,8 @@ BFF5AFC02DE837D60044227A /* VPPayTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFBF2DE837D60044227A /* VPPayTemplateModel.swift */; }; BFF5AFC22DE837FC0044227A /* VPPayTemplateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFC12DE837FC0044227A /* VPPayTemplateItem.swift */; }; BFF5AFC42DE84F9C0044227A /* Aa厚底黑.ttf in Resources */ = {isa = PBXBuildFile; fileRef = BFF5AFC32DE84F9C0044227A /* Aa厚底黑.ttf */; }; + BFF5AFC62DE863C00044227A /* VPGradientButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFC52DE863C00044227A /* VPGradientButton.swift */; }; + BFF5AFC82DE9473B0044227A /* VPCoinsBuyCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5AFC72DE9473B0044227A /* VPCoinsBuyCell.swift */; }; F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; }; /* End PBXBuildFile section */ @@ -328,6 +330,8 @@ BFF5AFBF2DE837D60044227A /* VPPayTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPayTemplateModel.swift; sourceTree = ""; }; BFF5AFC12DE837FC0044227A /* VPPayTemplateItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPPayTemplateItem.swift; sourceTree = ""; }; BFF5AFC32DE84F9C0044227A /* Aa厚底黑.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Aa厚底黑.ttf"; sourceTree = ""; }; + BFF5AFC52DE863C00044227A /* VPGradientButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGradientButton.swift; sourceTree = ""; }; + BFF5AFC72DE9473B0044227A /* VPCoinsBuyCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPCoinsBuyCell.swift; sourceTree = ""; }; E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -454,6 +458,7 @@ children = ( 1B056E752DDB35C5007EE38D /* TabBar */, 1B056E7A2DDB37BA007EE38D /* VPGradientView.swift */, + BFF5AFC52DE863C00044227A /* VPGradientButton.swift */, BF0FA7092DDC69C800C9E5F2 /* VPTableViewCell.swift */, BF0FA71A2DDC7FF200C9E5F2 /* VPImageView.swift */, BF0FA7252DDC8F7600C9E5F2 /* VPCollectionView.swift */, @@ -972,6 +977,7 @@ children = ( BFF5AFB52DE803A30044227A /* VPVipPrivilegeItemView.swift */, BFF5AFB72DE832580044227A /* VPVipBuyCell.swift */, + BFF5AFC72DE9473B0044227A /* VPCoinsBuyCell.swift */, ); path = View; sourceTree = ""; @@ -1192,6 +1198,7 @@ BFF5AFC22DE837FC0044227A /* VPPayTemplateItem.swift in Sources */, BF0FA6DA2DDC5CB600C9E5F2 /* VPLoginManager.swift in Sources */, BF0FA74A2DDF04E200C9E5F2 /* VPPlayerProtocol.swift in Sources */, + BFF5AFC82DE9473B0044227A /* VPCoinsBuyCell.swift in Sources */, BF0FA72C2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift in Sources */, BF0FA7AF2DE443E000C9E5F2 /* VPMeViewController.swift in Sources */, BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */, @@ -1204,6 +1211,7 @@ BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */, BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */, BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */, + BFF5AFC62DE863C00044227A /* VPGradientButton.swift in Sources */, BFF5AFA82DE704DC0044227A /* VPMeCoinCell.swift in Sources */, BFF5AFAE2DE717BB0044227A /* VPVipPageViewController.swift in Sources */, BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */, diff --git a/Veloria/Base/Extension/UIButton+VPAdd.swift b/Veloria/Base/Extension/UIButton+VPAdd.swift index 149b176..1f00a57 100644 --- a/Veloria/Base/Extension/UIButton+VPAdd.swift +++ b/Veloria/Base/Extension/UIButton+VPAdd.swift @@ -23,9 +23,12 @@ extension UIButton { vp_bt_layoutSubviews() bt_gradientLayer?.frame = self.bounds - bt_gradientBorder?.frame = self.bounds - let path = UIBezierPath(roundedRect: bounds.insetBy(dx: 0.5, dy: 0.5), cornerRadius: layer.cornerRadius) - bt_gradientBorderShapeLayer?.path = path.cgPath + + if let border = bt_gradientBorder, let shapeLayer = bt_gradientBorderShapeLayer { + border.frame = self.bounds + let path = UIBezierPath(roundedRect: bounds.insetBy(dx: shapeLayer.lineWidth / 2, dy: shapeLayer.lineWidth / 2), cornerRadius: layer.cornerRadius) + shapeLayer.path = path.cgPath + } } @@ -86,16 +89,16 @@ extension UIButton { ///设置渐变边框 - func bt_setGradientBorder() { + func bt_setGradientBorder(lineWidth: CGFloat = 1, colors: [CGColor] = [UIColor.color05CEA0().cgColor, UIColor.color7C174F().cgColor]) { if bt_gradientBorder == nil { let gLayer = CAGradientLayer() - gLayer.colors = [UIColor.color05CEA0().cgColor, UIColor.color7C174F().cgColor] + gLayer.colors = colors gLayer.locations = [0, 0.8] gLayer.startPoint = .init(x: 0, y: 0.3) gLayer.endPoint = .init(x: 1, y: 0.8) let shapeLayer = CAShapeLayer() - shapeLayer.lineWidth = 1 + shapeLayer.lineWidth = lineWidth shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.strokeColor = UIColor.black.cgColor gLayer.mask = shapeLayer diff --git a/Veloria/Base/Extension/UIColor+VPAdd.swift b/Veloria/Base/Extension/UIColor+VPAdd.swift index 46e3667..3797272 100644 --- a/Veloria/Base/Extension/UIColor+VPAdd.swift +++ b/Veloria/Base/Extension/UIColor+VPAdd.swift @@ -161,4 +161,36 @@ extension UIColor { static func color57314F(alpha: CGFloat = 1) -> UIColor { return UIColor(rgb: 0x57314F, alpha: alpha) } + + static func colorB2E7EA(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xB2E7EA, alpha: alpha) + } + + static func colorFFE6CE(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xFFE6CE, alpha: alpha) + } + + static func colorD6E5F9(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xD6E5F9, alpha: alpha) + } + + static func colorFFD8F5(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xFFD8F5, alpha: alpha) + } + + static func color303962(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x303962, alpha: alpha) + } + + static func color674162(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x674162, alpha: alpha) + } + + static func colorBE0069(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xBE0069, alpha: alpha) + } + + static func color00211A(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x00211A, alpha: alpha) + } } diff --git a/Veloria/Base/Extension/UIView+VPAdd.swift b/Veloria/Base/Extension/UIView+VPAdd.swift index b467a01..608efa3 100644 --- a/Veloria/Base/Extension/UIView+VPAdd.swift +++ b/Veloria/Base/Extension/UIView+VPAdd.swift @@ -31,11 +31,14 @@ extension UIView { effectView.frame = self.bounds } + CATransaction.begin() + CATransaction.setDisableActions(true) if let border = vp_gradientBorder { border.frame = self.bounds let path = UIBezierPath(roundedRect: bounds.insetBy(dx: 0.5, dy: 0.5), cornerRadius: layer.cornerRadius) vp_gradientBorderShapeLayer?.path = path.cgPath } + CATransaction.commit() } } @@ -124,10 +127,16 @@ extension UIView { } ///设置渐变边框 - func vp_setGradientBorder() { - if vp_gradientBorder == nil { + func vp_setGradientBorder(colors: [CGColor] = [UIColor.color05CEA0().cgColor, UIColor.color7C174F().cgColor]) { + if let gLayer = vp_gradientBorder { + CATransaction.begin() + CATransaction.setDisableActions(true) + gLayer.colors = colors + CATransaction.commit() + + } else { let gLayer = CAGradientLayer() - gLayer.colors = [UIColor.color05CEA0().cgColor, UIColor.color7C174F().cgColor] + gLayer.colors = colors gLayer.locations = [0, 0.8] gLayer.startPoint = .init(x: 0, y: 0.3) gLayer.endPoint = .init(x: 1, y: 0.8) diff --git a/Veloria/Base/Networking/Base/VPNetwork.swift b/Veloria/Base/Networking/Base/VPNetwork.swift index 95a2690..254ffce 100644 --- a/Veloria/Base/Networking/Base/VPNetwork.swift +++ b/Veloria/Base/Networking/Base/VPNetwork.swift @@ -76,7 +76,7 @@ class VPNetwork: NSObject { var res = VPNetworkResponse() res.code = -1 if parameters.isToast { - VPToast.show(text: "movia_error".localized) + VPToast.show(text: "Error".localized) } completion?(res) } else { @@ -128,7 +128,7 @@ class VPNetwork: NSObject { var res = VPNetworkResponse() res.code = -1 if parameters.isToast { - VPToast.show(text: "movia_error".localized) + VPToast.show(text: "Error".localized) } completion?(res) } @@ -137,7 +137,7 @@ class VPNetwork: NSObject { var res = VPNetworkResponse() res.code = -1 if parameters.isToast { - VPToast.show(text: "movia_network_toast_01".localized) + VPToast.show(text: "network_toast_01".localized) } completion?(res) break @@ -162,7 +162,7 @@ class VPNetwork: NSObject { } else { var response = VPNetworkResponse() response.code = -1 - response.msg = "movia_error".localized + response.msg = "Error".localized return response } } diff --git a/Veloria/Base/View/VPGradientButton.swift b/Veloria/Base/View/VPGradientButton.swift new file mode 100644 index 0000000..5b5c5f2 --- /dev/null +++ b/Veloria/Base/View/VPGradientButton.swift @@ -0,0 +1,44 @@ +// +// VPGradientButton.swift +// Veloria +// +// Created by 湖南秦九 on 2025/5/29. +// + +import UIKit + +class VPGradientButton: UIButton { + + override class var layerClass: AnyClass { + return CAGradientLayer.self + } + + var gradientLayer: CAGradientLayer { + return self.layer as! CAGradientLayer + } + + var locations: [NSNumber]? { + didSet { + self.gradientLayer.locations = locations + } + } + + var colors: [CGColor]? { + didSet { + self.gradientLayer.colors = colors + } + } + + var startPoint: CGPoint = .zero { + didSet { + self.gradientLayer.startPoint = startPoint + } + } + + var endPoint: CGPoint = .zero { + didSet { + self.gradientLayer.endPoint = endPoint + } + } + +} diff --git a/Veloria/Base/View/VPGradientLabel.swift b/Veloria/Base/View/VPGradientLabel.swift index 382a329..a240f98 100644 --- a/Veloria/Base/View/VPGradientLabel.swift +++ b/Veloria/Base/View/VPGradientLabel.swift @@ -37,6 +37,9 @@ class VPGradientLabel: UILabel { override func layoutSubviews() { super.layoutSubviews() + CATransaction.begin() + CATransaction.setDisableActions(true) + gradientLayer.frame = bounds let string = NSMutableAttributedString(attributedString: attributedText ?? NSAttributedString(string: text ?? "")) string.color = .colorFFFFFF() @@ -47,9 +50,9 @@ class VPGradientLabel: UILabel { textLayer.frame = bounds textLayer.alignmentMode = .center textLayer.contentsScale = UIScreen.main.scale - gradientLayer.mask = textLayer + CATransaction.commit() } } diff --git a/Veloria/Class/Wallet/Controller/VPCoinsViewController.swift b/Veloria/Class/Wallet/Controller/VPCoinsViewController.swift index adb4585..690c866 100644 --- a/Veloria/Class/Wallet/Controller/VPCoinsViewController.swift +++ b/Veloria/Class/Wallet/Controller/VPCoinsViewController.swift @@ -11,27 +11,171 @@ class VPCoinsViewController: VPViewController { var dataArr: [VPPayTemplateItem] = [] { didSet { -// self.collectionView.reloadData() + reloadData() + } } + + private lazy var selectedIndex = 0 + + //MARK: UI属性 + private lazy var scrollView: UIScrollView = { + let scrollView = VPScrollView() + scrollView.showsVerticalScrollIndicator = false + return scrollView + }() + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "coin_icon_03")) + return imageView + }() + + private lazy var iconTextLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 15) + label.textColor = .colorFFFFFF() + label.text = "Get More Coins".localized + return label + }() + + private lazy var coinsCountLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 13) + label.textColor = .colorBE0069() + return label + }() + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let itemWidth = floor((UIScreen.width - 30 - 20) / 3) + + let layout = UICollectionViewFlowLayout() + layout.minimumLineSpacing = 10 + layout.minimumInteritemSpacing = 10 + layout.itemSize = .init(width: itemWidth, height: 108) + layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15) + return layout + }() + + private lazy var collectionView: VPCollectionView = { + let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.isScrollEnabled = false + collectionView.register(VPCoinsBuyCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + private lazy var tipLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + label.textColor = .colorFFFFFF(alpha: 0.5) + label.numberOfLines = 0 + label.text = "kStoreTips".localized + return label + }() override func viewDidLoad() { super.viewDidLoad() self.bgImageView.isHidden = true self.view.backgroundColor = .clear + updateCoin() + vp_setupUI() + reloadData() } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. + + private func updateCoin() { + let coinCountStr = "\(VPLoginManager.manager.userInfo?.totalCoin ?? 0)" + let text = String(format: "Coins: %@".localized, coinCountStr) + let coinRange = text.ocString().range(of: coinCountStr) + + let string = NSMutableAttributedString(string: text) + string.color = .colorFFFFFF() + string.setColor(.colorBE0069(), range: coinRange) + + coinsCountLabel.attributedText = string + } + + + private func reloadData() { + CATransaction.setCompletionBlock { [weak self] in + guard let self = self else { return } + if self.collectionView.superview != nil { + self.collectionView.snp.updateConstraints { make in + make.height.equalTo(self.collectionView.contentSize.height + 1) + } + } + } + CATransaction.begin() + self.collectionView.reloadData() + CATransaction.commit() + } +} + +extension VPCoinsViewController { + + private func vp_setupUI() { + view.addSubview(scrollView) + scrollView.addSubview(iconImageView) + scrollView.addSubview(iconTextLabel) + scrollView.addSubview(coinsCountLabel) + scrollView.addSubview(collectionView) + scrollView.addSubview(tipLabel) + + scrollView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + iconImageView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(15) + make.top.equalToSuperview().offset(20) + } + + iconTextLabel.snp.makeConstraints { make in + make.centerY.equalTo(iconImageView) + make.left.equalTo(iconImageView.snp.right).offset(7) + } + + coinsCountLabel.snp.makeConstraints { make in + make.centerY.equalTo(iconImageView) + make.right.equalTo(self.view).offset(-15) + } + + collectionView.snp.makeConstraints { make in + make.left.centerX.equalToSuperview() + make.top.equalToSuperview().offset(62) + make.height.equalTo(self.collectionView.contentSize.height + 1) + } + + tipLabel.snp.makeConstraints { make in + make.top.equalTo(collectionView.snp.bottom).offset(14) + make.left.equalToSuperview().offset(15) + make.width.lessThanOrEqualTo(UIScreen.width - 30) + make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10)) + } + } + +} + +//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource -------------- +extension VPCoinsViewController: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPCoinsBuyCell + cell.item = self.dataArr[indexPath.row] + cell.vp_isSelected = indexPath.row == selectedIndex + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + vpLog(message: indexPath.row) + self.selectedIndex = indexPath.row + collectionView.reloadData() } - */ - } diff --git a/Veloria/Class/Wallet/Controller/VPVipViewController.swift b/Veloria/Class/Wallet/Controller/VPVipViewController.swift index 02991d3..2636256 100644 --- a/Veloria/Class/Wallet/Controller/VPVipViewController.swift +++ b/Veloria/Class/Wallet/Controller/VPVipViewController.swift @@ -16,8 +16,11 @@ class VPVipViewController: VPViewController { } } + private lazy var currentIndex: Int = 0 + private lazy var scrollView: UIScrollView = { let scrollView = VPScrollView() + scrollView.showsVerticalScrollIndicator = false return scrollView }() @@ -103,6 +106,29 @@ class VPVipViewController: VPViewController { return collectionView }() + private lazy var tipLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + label.textColor = .colorFFFFFF(alpha: 0.5) + label.numberOfLines = 0 + label.text = "kStoreTips".localized + return label + }() + +// private lazy var buyButton: UIButton = { +// let button = VPGradientButton(type: .custom) +// button.layer.cornerRadius = 24 +// button.layer.masksToBounds = true +// button.bt_setGradientBorder() +// button.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor] +// button.locations = [0, 1] +// button.startPoint = .init(x: 0, y: 0.3) +// button.endPoint = .init(x: 1, y: 0.8) +// button.setTitle("Buy Now".localized, for: .normal) +// button.setTitleColor(.colorFFFFFF(), for: .normal) +// button.titleLabel?.font = .fontMedium(ofSize: 14) +// return button +// }() override func viewDidLoad() { @@ -124,9 +150,13 @@ extension VPVipViewController { scrollView.addSubview(iconTextLabel) scrollView.addSubview(stackView) scrollView.addSubview(collectionView) + scrollView.addSubview(tipLabel) +// view.addSubview(buyButton) scrollView.snp.makeConstraints { make in - make.edges.equalToSuperview() + make.left.right.top.equalToSuperview() +// make.bottom.equalTo(buyButton.snp.top).offset(-10) + make.bottom.equalToSuperview() } iconImageView.snp.makeConstraints { make in @@ -150,8 +180,22 @@ extension VPVipViewController { make.centerX.equalToSuperview() make.top.equalTo(stackView.snp.bottom).offset(7) make.height.equalTo(collectionViewLayout.itemSize.height) - make.bottom.equalToSuperview() } + + tipLabel.snp.makeConstraints { make in + make.top.equalTo(collectionView.snp.bottom).offset(14) + make.left.equalToSuperview().offset(15) + make.width.lessThanOrEqualTo(UIScreen.width - 30) +// make.bottom.equalToSuperview().offset(-10) + make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10)) + } + +// buyButton.snp.makeConstraints { make in +// make.left.equalToSuperview().offset(15) +// make.centerX.equalToSuperview() +// make.bottom.equalToSuperview().offset(-(UIScreen.tabbarSafeBottomMargin + 10)) +// make.height.equalTo(48) +// } } } @@ -161,10 +205,19 @@ extension VPVipViewController: UICollectionViewDelegate, UICollectionViewDataSou func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPVipBuyCell cell.item = dataArr[indexPath.row] + cell.vp_isSelected = indexPath.row == currentIndex return cell } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return dataArr.count } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + if currentIndex != indexPath.row { + currentIndex = indexPath.row + self.collectionView.reloadData() + } + + } } diff --git a/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift b/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift index 3a0fb24..bba26ea 100644 --- a/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift +++ b/Veloria/Class/Wallet/Model/VPPayTemplateItem.swift @@ -19,16 +19,16 @@ class VPPayTemplateItem: VPModel, SmartCodable { func getText() -> String { switch self { case .week: - return "Weekly VIP".localized + return "week".localized case .month: - return "Monthly VIP".localized + return "month".localized case .quarter: - return "Quarterly VIP".localized + return "quarter".localized case .year: - return "Yearly VIP".localized + return "year".localized } } } diff --git a/Veloria/Class/Wallet/View/VPCoinsBuyCell.swift b/Veloria/Class/Wallet/View/VPCoinsBuyCell.swift new file mode 100644 index 0000000..29dbb2b --- /dev/null +++ b/Veloria/Class/Wallet/View/VPCoinsBuyCell.swift @@ -0,0 +1,189 @@ +// +// VPCoinsBuyCell.swift +// Veloria +// +// Created by 湖南秦九 on 2025/5/30. +// + +import UIKit + +class VPCoinsBuyCell: VPCollectionViewCell { + + var item: VPPayTemplateItem? { + didSet { + coinCountLabel.text = "+\(item?.coins ?? 0)" + priceLabel.text = "\(item?.currency ?? "")\(item?.price ?? "0")" + + if let mark = item?.corner_marker, !mark.isEmpty { + hotBgView.isHidden = false + hotLabel.text = mark + } else { + hotBgView.isHidden = true + } + + if let sendCoins = item?.send_coins, sendCoins > 0, let coins = item?.coins { + sendBgView.isHidden = false + let percent = CGFloat(sendCoins) / CGFloat(coins) * 100 + + sendLabel.text = String(format: "+%.0f%%".localized, percent) + } else { + sendBgView.isHidden = true + } + } + } + + var vp_isSelected: Bool = false { + didSet { + if vp_isSelected { + self.bgView.isHidden = false + selectedImageView.isHidden = false + } else { + self.bgView.isHidden = true + selectedImageView.isHidden = true + } + } + } + + private lazy var bgView: VPGradientView = { + let view = VPGradientView() + view.vp_setGradientBorder() + view.colors = [UIColor.color05CEA0(alpha: 0.3).cgColor, UIColor.color7C174F(alpha: 0.3).cgColor] + view.locations = [0, 1] + view.startPoint = .init(x: 0, y: 0.3) + view.endPoint = .init(x: 1, y: 0.8) + return view + }() + + private lazy var selectedImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "selected_icon_01")) + return imageView + }() + + private lazy var coinCountLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 16) + label.textColor = .colorFFFFFF() + return label + }() + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "coin_icon_04")) + return imageView + }() + + private lazy var priceLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 12) + label.textColor = .colorFFFFFF(alpha: 0.6) + return label + }() + + private lazy var hotBgView: UIView = { + let view = UIView() + view.backgroundColor = .colorBE0069() + view.addRadius(topLeft: 8, topRight: 0, bottomLeft: 0, bottomRight: 8) + view.layer.zPosition = 0 + return view + }() + + private lazy var hotLabel: UILabel = { + let label = UILabel() + label.textColor = .colorFFFFFF() + label.font = .fontRegular(ofSize: 11) + return label + }() + + private lazy var sendBgView: UIView = { + let view = UIView() + view.backgroundColor = .color05CEA0() + view.addRadius(topLeft: 0, topRight: 8, bottomLeft: 8, bottomRight: 0) + view.layer.zPosition = 0 + return view + }() + + private lazy var sendLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 11) + label.textColor = .color00211A() + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + bgView.layer.cornerRadius = 8 + bgView.layer.masksToBounds = true + self.contentView.layer.cornerRadius = 8 + self.contentView.layer.masksToBounds = true + self.contentView.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.25).cgColor + self.contentView.layer.borderWidth = 1 + + vp_setupUI() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension VPCoinsBuyCell { + + private func vp_setupUI() { + contentView.addSubview(bgView) + contentView.addSubview(selectedImageView) + contentView.addSubview(coinCountLabel) + contentView.addSubview(iconImageView) + contentView.addSubview(priceLabel) + contentView.addSubview(hotBgView) + hotBgView.addSubview(hotLabel) + contentView.addSubview(sendBgView) + sendBgView.addSubview(sendLabel) + + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + selectedImageView.snp.makeConstraints { make in + make.bottom.right.equalToSuperview() + } + + coinCountLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(22) + } + + iconImageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(45) + } + + priceLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-11) + } + + hotBgView.snp.makeConstraints { make in + make.left.top.equalToSuperview() + make.height.equalTo(16) + } + + hotLabel.snp.makeConstraints { make in + make.center.equalToSuperview() + make.left.equalToSuperview().offset(5) + } + + sendBgView.snp.makeConstraints { make in + make.right.top.equalToSuperview() + make.height.equalTo(16) + } + + sendLabel.snp.makeConstraints { make in + make.center.equalToSuperview() + make.left.equalToSuperview().offset(5) + } + + } + +} + diff --git a/Veloria/Class/Wallet/View/VPVipBuyCell.swift b/Veloria/Class/Wallet/View/VPVipBuyCell.swift index 5b7402b..5f27b3b 100644 --- a/Veloria/Class/Wallet/View/VPVipBuyCell.swift +++ b/Veloria/Class/Wallet/View/VPVipBuyCell.swift @@ -15,21 +15,41 @@ class VPVipBuyCell: VPCollectionViewCell { if let key = item?.vip_type_key?.rawValue { bgImageView.image = UIImage(named: "vip_buy_bg_\(key)") } - vipNameLabel.text = item?.vip_type_key?.getText() +// vipNameLabel.text = item?.vip_type_key?.getText() + vipNameLabel.text = item?.title unitLabel.text = item?.currency moneyLabel.text = item?.price + durationLabel.text = "/\(item?.vip_type_key?.getText() ?? "")" + + if let coin = item?.send_coins, coin > 0 { + sendCoinBgView.isHidden = false + sendCoinView.isHidden = false + let text = String(format: "Extra %@".localized, "\(coin)") + sendCoinView.setTitle("+" + text, for: .normal) + } else { + sendCoinBgView.isHidden = true + sendCoinView.isHidden = true + } var colors: [CGColor] = [] switch item?.vip_type_key { case .week: colors = [UIColor.color64A3A7().cgColor, UIColor.color416767().cgColor] + sendCoinBgView.colors = [UIColor.colorB2E7EA().cgColor, UIColor.colorB2E7EA(alpha: 0).cgColor] + sendCoinView.setTitleColor(.color416767(), for: .normal) case .month: colors = [UIColor.color9C7565().cgColor, UIColor.color573D31().cgColor] + sendCoinBgView.colors = [UIColor.colorFFE6CE().cgColor, UIColor.colorFFE6CE(alpha: 0).cgColor] + sendCoinView.setTitleColor(.color573D31(), for: .normal) case .quarter: colors = [UIColor.color647DA7().cgColor, UIColor.color414867().cgColor] + sendCoinBgView.colors = [UIColor.colorD6E5F9().cgColor, UIColor.colorD6E5F9(alpha: 0).cgColor] + sendCoinView.setTitleColor(.color303962(), for: .normal) case .year: colors = [UIColor.color9C6586().cgColor, UIColor.color57314F().cgColor] + sendCoinBgView.colors = [UIColor.colorFFD8F5().cgColor, UIColor.colorFFD8F5(alpha: 0).cgColor] + sendCoinView.setTitleColor(.color674162(), for: .normal) default: break } @@ -39,6 +59,13 @@ class VPVipBuyCell: VPCollectionViewCell { unitLabel.gradientLayer.colors = colors moneyLabel.gradientLayer.colors = colors durationLabel.gradientLayer.colors = colors + durationLabel.gradientLayer.colors = colors + } + } + + var vp_isSelected = false { + didSet { + selectedImageView.isHidden = !vp_isSelected } } @@ -71,6 +98,31 @@ class VPVipBuyCell: VPCollectionViewCell { return label }() + private lazy var sendCoinBgView: VPGradientView = { + let view = VPGradientView() + view.locations = [0, 1] + view.startPoint = .init(x: 0, y: 0.5) + view.endPoint = .init(x: 1, y: 0.5) + view.layer.cornerRadius = 6 + view.layer.masksToBounds = true + return view + }() + + private lazy var sendCoinView: UIButton = { + let view = JXButton(type: .custom) + view.isUserInteractionEnabled = false + view.titleDirection = .left + view.space = 4 + view.jx_font = .fontRegular(ofSize: 12) + view.setImage(UIImage(named: "coin_icon_02"), for: .normal) + return view + }() + + private lazy var selectedImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "selected_icon_01")) + return imageView + }() + override init(frame: CGRect) { super.init(frame: frame) @@ -80,6 +132,7 @@ class VPVipBuyCell: VPCollectionViewCell { @MainActor required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + } extension VPVipBuyCell { @@ -89,6 +142,10 @@ extension VPVipBuyCell { contentView.addSubview(vipNameLabel) contentView.addSubview(unitLabel) contentView.addSubview(moneyLabel) + contentView.addSubview(durationLabel) + contentView.addSubview(sendCoinBgView) + contentView.addSubview(sendCoinView) + contentView.addSubview(selectedImageView) bgImageView.snp.makeConstraints { make in make.edges.equalToSuperview() @@ -96,19 +153,42 @@ extension VPVipBuyCell { vipNameLabel.snp.makeConstraints { make in make.left.equalToSuperview().offset(14) - make.top.equalToSuperview().offset(31) + make.top.equalToSuperview().offset(35) make.height.equalTo(22) } unitLabel.snp.makeConstraints { make in make.left.equalTo(vipNameLabel) - make.top.equalTo(vipNameLabel.snp.bottom).offset(20) + make.top.equalTo(vipNameLabel.snp.bottom).offset(17) make.height.equalTo(20) } moneyLabel.snp.makeConstraints { make in make.left.equalTo(unitLabel.snp.right) - make.bottom.equalTo(unitLabel).offset(-1) + make.bottom.equalTo(unitLabel) + } + + durationLabel.snp.makeConstraints { make in + make.bottom.equalTo(moneyLabel).offset(-2) + make.left.equalTo(moneyLabel.snp.right) + make.height.equalTo(20) + } + + sendCoinBgView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(14) + make.bottom.equalToSuperview().offset(-10) + make.height.equalTo(24) + make.width.equalTo(105) + } + + sendCoinView.snp.makeConstraints { make in + make.centerY.equalTo(sendCoinBgView) + make.left.equalTo(sendCoinBgView).offset(11) + } + + selectedImageView.snp.makeConstraints { make in + make.left.equalToSuperview() + make.top.equalToSuperview().offset(18) } } diff --git a/Veloria/Libs/User/VPUserInfo.swift b/Veloria/Libs/User/VPUserInfo.swift index 32a5c8a..7b4ac0f 100644 --- a/Veloria/Libs/User/VPUserInfo.swift +++ b/Veloria/Libs/User/VPUserInfo.swift @@ -35,6 +35,10 @@ class VPUserInfo: VPModel, SmartCodable, NSSecureCoding { var country: String? + var totalCoin: Int { + return (coin_left_total ?? 0) + (send_coin_left_total ?? 0) + } + required init() { } static var supportsSecureCoding: Bool { diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/Contents.json new file mode 100644 index 0000000..c18e822 --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金币1 2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金币1 2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@2x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@2x.png new file mode 100644 index 0000000..620ef11 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@3x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@3x.png new file mode 100644 index 0000000..6d08619 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_02.imageset/金币1 2@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/Contents.json new file mode 100644 index 0000000..e197cfa --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金币 2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金币 2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@2x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@2x.png new file mode 100644 index 0000000..3d51924 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@3x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@3x.png new file mode 100644 index 0000000..64e0e05 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_03.imageset/金币 2@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/Contents.json new file mode 100644 index 0000000..8b03fba --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金币1 3@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金币1 3@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@2x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@2x.png new file mode 100644 index 0000000..9b6325f Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@3x.png b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@3x.png new file mode 100644 index 0000000..dff3fcd Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/coin_icon_04.imageset/金币1 3@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@2x.png b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@2x.png new file mode 100644 index 0000000..9fec237 Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@2x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@3x.png b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@3x.png new file mode 100644 index 0000000..b1634db Binary files /dev/null and b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Component 63@3x.png differ diff --git a/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Contents.json b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Contents.json new file mode 100644 index 0000000..1f53eaf --- /dev/null +++ b/Veloria/Source/Assets.xcassets/icon/selected_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Component 63@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Component 63@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Veloria/Source/en.lproj/Localizable.strings b/Veloria/Source/en.lproj/Localizable.strings index 48e9073..7106391 100644 --- a/Veloria/Source/en.lproj/Localizable.strings +++ b/Veloria/Source/en.lproj/Localizable.strings @@ -47,7 +47,14 @@ "Membership Benefits" = "Membership Benefits"; "1 week" = "1 week"; "8 days" = "8 days"; -"Weekly VIP" = "Weekly VIP"; +"week" = "week"; +"month" = "month"; +"quarter" = "quarter"; +"year" = "year"; +"Error" = "Error"; +"Extra %@" = "Extra %@"; +"Get More Coins" = "Get More Coins"; +"Coins: %@" = "Coins: %@"; "kHomeTitleText" = "10,000+ addictive shorts await!"; @@ -61,6 +68,15 @@ "kVipPrivilegeText4" = "Unlimited access to all series for %@ (No Ads)"; "kVipPrivilegeText5" = "The donate coins will expire in %@"; "kVipPrivilegeText6" = "Auto renew, cancel anytime"; +//无网提示 +"kNetworkToast01" = "The service is abnormal. Check the network."; + + +"kStoreTips" = "1. Coins are virtual items and cannot be refunded. Use it for this product. +2. Gold coins will never expire, the reward coins will expire 24 hours a day. +3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used. +4. The purchase has not been credited, click torefresh. +5. For other questions, contact us via Profile>Help &feedback."; //请选择需要删除的短剧 "kToastText1" = "Please select the short plays that need to be deleted";