商城页面改版,1.0.9发布

This commit is contained in:
zeng 2025-06-18 19:26:21 +08:00
parent e18a1652ca
commit eea76fabfc
118 changed files with 2030 additions and 392 deletions

View File

@ -257,7 +257,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.7; MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@ -303,7 +303,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.7; MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";

View File

@ -27,6 +27,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
if let webpageURL = connectionOptions.userActivities.first?.webpageURL { if let webpageURL = connectionOptions.userActivities.first?.webpageURL {
self.handleOpenAppMessage(webpageURL: webpageURL) self.handleOpenAppMessage(webpageURL: webpageURL)
} else if let url = connectionOptions.urlContexts.first?.url {
self.handleOpenAppMessage(webpageURL: url)
} }
window = UIWindow(windowScene: windowScene) window = UIWindow(windowScene: windowScene)

View File

@ -524,5 +524,37 @@ extension UIColor {
static func colorFF9924(alpha: CGFloat = 1) -> UIColor { static func colorFF9924(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFF9924, alpha: alpha) return color(hex: 0xFF9924, alpha: alpha)
} }
static func colorFFF1D9(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFFF1D9, alpha: alpha)
}
static func color005786(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x005786, alpha: alpha)
}
static func colorFED095(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFED095, alpha: alpha)
}
static func colorFFE49E(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFFE49E, alpha: alpha)
}
static func colorE9BB68(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xE9BB68, alpha: alpha)
}
static func colorFFE18D(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFFE18D, alpha: alpha)
}
static func colorDDA754(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xDDA754, alpha: alpha)
}
static func color94550E(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x94550E, alpha: alpha)
}
} }

View File

@ -40,4 +40,9 @@ extension UIFont {
static func fontWeight(ofSize: CGFloat, weight: CGFloat) -> UIFont { static func fontWeight(ofSize: CGFloat, weight: CGFloat) -> UIFont {
return .systemFont(ofSize: ofSize, weight: UIFont.Weight(weight)) return .systemFont(ofSize: ofSize, weight: UIFont.Weight(weight))
} }
static func fontInterExtraBold(ofSize: CGFloat) -> UIFont {
return .init(name: "Inter-ExtraBold", size: ofSize) ?? fontBold(ofSize: ofSize)
}
} }

View File

@ -7,18 +7,117 @@
import UIKit import UIKit
class SPHomeChildController: SPViewController { class SPHomeChildController: SPViewController, WMZPageProtocol {
var topMargins: CGFloat = 10
lazy var page = 1
lazy var dataArr: [SPShortModel] = []
private lazy var layout: UICollectionViewFlowLayout = {
let width = floor((kSPScreenWidth - 32 - 13) / 2)
let height = 221 / 165 * width + 44
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: width, height: height)
layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16)
layout.minimumInteritemSpacing = 13
layout.minimumLineSpacing = 13
return layout
}()
private lazy var collectionView: SPCollectionView = {
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
// collectionView.sp_addRefreshHeader { [weak self] in
// self?.handleHeaderRefresh(nil)
// }
collectionView.sp_addRefreshBackFooter(insetBottom: 0) { [weak self] in
self?.handleFooterRefresh(nil)
}
SPHomeShortCell.registerCell(collectionView: collectionView)
return collectionView
}()
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
setBackgroundView(isShowGradient: false, bgImage: nil, backgroundColor: .clear)
sp_setupUI()
requestListDataArr(page: 1, completer: nil)
} }
// override func setBgImageView() { }
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
requestListDataArr(page: 1, completer: completer)
}
override func handleFooterRefresh(_ completer: (() -> Void)?) {
requestListDataArr(page: self.page + 1) { [weak self] in
self?.collectionView.sp_endFooterRefreshing()
}
}
func getMyScrollView() -> UIScrollView {
return self.collectionView
}
} }
extension SPHomeChildController {
private func sp_setupUI() {
view.addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
extension SPHomeChildController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = SPHomeShortCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
cell.model = dataArr[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArr.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = dataArr[indexPath.row]
let vc = SPPlayerDetailViewController()
vc.shortPlayId = model.short_play_id
self.navigationController?.pushViewController(vc, animated: true)
}
}
extension SPHomeChildController {
///
private func requestListDataArr(page: Int, completer: (() -> Void)?) {
SPHomeAPI.requestHomeList(page: page) { [weak self] listModel in
guard let self = self else { return }
if let list = listModel?.list {
if page == 1 {
self.dataArr.removeAll()
}
self.dataArr += list
self.collectionView.reloadData()
self.page = page
}
completer?()
}
}
}

View File

@ -1,158 +0,0 @@
//
// SPHomePageController.swift
// MoviaBox
//
// Created by on 2025/4/8.
//
import UIKit
class SPHomePageController: SPViewController {
private var topModel: SPHomeTopModel?
///
private var isRequesting = false
private lazy var categoryArr: [SPHomeCategoryModel] = []
// {
// let arr = [
// SPHomeCategoryModel(category_name: "Hot Picks".localized, category_id: nil, viewController: SPHomeViewController()),
// SPHomeCategoryModel(category_name: "Top 10".localized, category_id: nil, viewController: nil),
// SPHomeCategoryModel(category_name: "Fresh Drops".localized, category_id: nil, viewController: nil),
// SPHomeCategoryModel(category_name: "Free".localized, category_id: nil, viewController: nil),
// ]
// return arr
// }()
private lazy var searchButton: SPHomeSearchButton = {
let button = SPHomeSearchButton()
button.addTarget(self, action: #selector(handleSearchButton), for: .touchUpInside)
return button
}()
private lazy var pageView: JYPageController = {
let customIndicatorImage = UIImage(named: "page_indicator_icon_01")
let customIndicator = UIImageView(image: customIndicatorImage)
let pageView = JYPageController()
pageView.delegate = self
pageView.dataSource = self
pageView.config.normalTitleColor = .colorD2D2D2()
pageView.config.selectedTitleColor = .colorBF6BFF()
pageView.config.normalTitleFont = 14
pageView.config.selectedTitleFont = 16
pageView.config.normalTitleFontWeight = .regular
pageView.config.selectedTitleFontWeight = .medium
pageView.config.alignment = .scatter
pageView.config.customIndicator = customIndicator
pageView.config.indicatorStyle = .customView
pageView.config.indicatorWidth = customIndicatorImage?.size.width ?? 0
pageView.config.indicatorHeight = customIndicatorImage?.size.height ?? 0
pageView.config.leftPadding = 15
pageView.config.rightPadding = 15
pageView.config.itemsMargin = 24
return pageView
}()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
sp_setupUI()
requestData()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
}
extension SPHomePageController {
private func sp_setupUI() {
addChild(pageView)
view.addSubview(pageView.view)
view.addSubview(searchButton)
pageView.view.snp.makeConstraints { make in
// make.edges.equalToSuperview()
make.top.equalToSuperview().offset(kSPStatusbarHeight + 66)
make.left.right.bottom.equalToSuperview()
}
searchButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(kSPStatusbarHeight + 10)
}
}
}
extension SPHomePageController {
@objc private func handleSearchButton() {
let vc = SPSearchViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
@objc private func reachabilityDidChangeNotification() {
requestData()
}
}
//MARK: -------------- JYPageControllerDelegate & JYPageControllerDataSource --------------
extension SPHomePageController: JYPageControllerDelegate, JYPageControllerDataSource {
func pageController(_ pageController: JYPageController, frameForSegmentedView segmentedView: JYSegmentedView) -> CGRect {
return .init(x: 0, y: 0, width: kSPScreenWidth, height: 40)
}
func pageController(_ pageController: JYPageController, frameForContainerView container: UIScrollView) -> CGRect {
return .init(x: 0, y: 40, width: kSPScreenWidth, height: kSPScreenHeight - kSPTabBarHeight - kSPStatusbarHeight - 66 - 40)
}
func pageController(_ pageController: JYPageController, titleAt index: Int) -> String {
return self.categoryArr[index].category_name ?? ""
}
func childController(atIndex index: Int) -> any JYPageChildContollerProtocol {
let vc = SPHomeViewController()
vc.topMargins = 15
return vc
}
func numberOfChildControllers() -> Int {
return self.categoryArr.count
}
}
extension SPHomePageController {
private func requestData() {
if self.topModel != nil || isRequesting { return }
isRequesting = true
SPHomeAPI.requestHomeTopData { [weak self] model in
guard let self = self else { return }
if let model = model {
self.topModel = model
if let category = self.topModel?.category {
self.categoryArr += category
}
self.pageView.reload()
}
self.isRequesting = false
}
}
}

View File

@ -0,0 +1,366 @@
//
// SPHomeV2ViewController.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeV2ViewController: SPViewController {
private lazy var viewModel: SPHomeViewModel = SPHomeViewModel()
private lazy var requestGroup = DispatchGroup()
private var isSetupUI = false
//MARK: UI
private lazy var logoImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "logo_icon_01"))
imageView.setContentHuggingPriority(.required, for: .horizontal)
imageView.setContentCompressionResistancePriority(.required, for: .horizontal)
return imageView
}()
private lazy var searchButton: SPHomeSearchButton = {
let button = SPHomeSearchButton()
button.addTarget(self, action: #selector(handleSearchButton), for: .touchUpInside)
return button
}()
private lazy var allButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "all_icon_01"), for: .normal)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
button.addTarget(self, action: #selector(handleAllButton), for: .touchUpInside)
return button
}()
private lazy var rewardButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "reward_icon_01"), for: .normal)
button.setContentHuggingPriority(.required, for: .horizontal)
button.setContentCompressionResistancePriority(.required, for: .horizontal)
button.addTarget(self, action: #selector(handleRewardButton), for: .touchUpInside)
return button
}()
private lazy var pageParam: WMZPageParam = {
let param = WMZPageParam()
param.wTitleArr = ["1"]
param.wViewController = { [weak self] index in
return SPHomeChildController()
}
param.wTopSuspension = true
//
param.wBounces = true
param.wMenuHeight = 0
param.wBgColor = .clear
param.wCustomNaviBarY = { _ in
return 0
}
param.wCustomTabbarY = { _ in
return 0
}
param.wCustomDataViewTopOffset = 0
return param
}()
private lazy var pageView: WMZPageView = {
let y = kSPStatusbarHeight + 10 + 32 + 34
let width = kSPScreenWidth
let height = kSPScreenHeight - y - kSPTabBarHeight
let pageView = WMZPageView(frame: CGRect(x: 0, y: y, width: width, height: height), param: pageParam, parentReponder: self)
pageView.param = pageParam
pageView.backgroundColor = .clear
pageView.downSc?.backgroundColor = .clear
pageView.downSc?.dataSource = self
pageView.downSc?.isScrollEnabled = true
pageView.downSc?.separatorStyle = .none
pageView.downSc?.register(SPHomeBannerContentCell.self, forCellReuseIdentifier: SPHomeContentModel.ContentKey.banner.rawValue)
pageView.downSc?.register(SPHomeHistoryContentCell.self, forCellReuseIdentifier: SPHomeContentModel.ContentKey.history.rawValue)
pageView.downSc?.register(SPHomeNineSquareContentCell.self, forCellReuseIdentifier: SPHomeContentModel.ContentKey.nineSquare.rawValue)
pageView.downSc?.register(SPHomeCategoryContentCell.self, forCellReuseIdentifier: SPHomeContentModel.ContentKey.category1.rawValue)
pageView.downSc?.register(SPHomeHotContentCell.self, forCellReuseIdentifier: SPHomeContentModel.ContentKey.hot.rawValue)
pageView.downSc?.sp_addRefreshHeader(block: { [weak self] in
self?.handleHeaderRefresh(nil)
})
return pageView
}()
private var headerView: SPHomeHeaderView?
private lazy var playHistoricalView: SPHomePlayHistoricalView = {
let view = SPHomePlayHistoricalView()
view.isHidden = true
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
if SPNetworkReachabilityManager.manager.isReachable == true {
updateAllData(completer: nil)
_setupUI()
} else {
setEmptyView()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: true)
}
override func viewDidAppear(_ animated: Bool) {
if hasViewDidAppear {
requestPlayHistory()
}
super.viewDidAppear(animated)
self.headerView?.isDidAppear = self.isDidAppear
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.headerView?.isDidAppear = self.isDidAppear
}
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
updateAllData { [weak self] in
self?.pageView.downSc?.sp_endHeaderRefreshing()
}
}
// override func handleFooterRefresh(_ completer: (() -> Void)?) {
// requestListDataArr(page: self.viewModel.page + 1) { [weak self] in
//// self?.collectionView.sp_endFooterRefreshing()
// }
// }
}
extension SPHomeV2ViewController {
private func _setupUI() {
if isSetupUI { return }
isSetupUI = true
// view.addSubview(logoImageView)
view.addSubview(searchButton)
view.addSubview(allButton)
view.addSubview(rewardButton)
view.addSubview(pageView)
view.addSubview(playHistoricalView)
// logoImageView.snp.makeConstraints { make in
// make.left.equalToSuperview().offset(16)
// make.centerY.equalTo(searchButton)
// }
searchButton.snp.makeConstraints { make in
// make.left.equalTo(logoImageView.snp.right).offset(6)
make.left.equalToSuperview().offset(16)
// make.right.equalToSuperview().offset(-16)
make.right.equalTo(allButton.snp.left).offset(-4)
make.top.equalToSuperview().offset(kSPStatusbarHeight + 10)
}
allButton.snp.makeConstraints { make in
make.centerY.equalTo(searchButton)
// make.right.equalToSuperview().offset(-16)
make.right.equalTo(rewardButton.snp.left).offset(-1)
}
rewardButton.snp.makeConstraints { make in
make.centerY.equalTo(searchButton)
make.right.equalToSuperview().offset(-16)
}
playHistoricalView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-4)
}
}
}
extension SPHomeV2ViewController {
@objc private func handleSearchButton() {
let vc = SPSearchViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
///
private func setEmptyView() {
if SPNetworkReachabilityManager.manager.isReachable != true {
self.addNoNetworkEmptyView { [weak self] in
self?.updateEmptyState()
}
}
}
@objc private func reachabilityDidChangeNotification() {
updateEmptyState()
}
///
private func updateEmptyState() {
if SPNetworkReachabilityManager.manager.isReachable == true {
self._setupUI()
if viewModel.isEmptyData {
self.updateAllData(completer: nil)
}
self.removeNoNetworkEmptyView()
}
}
@objc private func handleAllButton() {
let vc = SPAllViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
@objc private func handleRewardButton() {
let vc = SPRewardsViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
}
//MARK: -------------- UITableViewDelegate UITableViewDataSource --------------
extension SPHomeV2ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = self.viewModel.contentArr[indexPath.row]
let key = model.key ?? .banner
let cell = tableView.dequeueReusableCell(withIdentifier: key.rawValue, for: indexPath) as! SPHomeContentCell
cell.contentModel = model
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.viewModel.contentArr.count
}
}
extension SPHomeV2ViewController {
private func updateAllData(completer: (() -> Void)?) {
self.requestGroup.enter()
requestModuleData { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.enter()
requestPlayHistory { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.enter()
requestListDataArr(page: 1) { [weak self] in
self?.requestGroup.leave()
}
self.requestGroup.enter()
requestCategoryShortList(id: "3") { [weak self] in
self?.requestGroup.leave()
}
// self.requestGroup.enter()
// requestCategoryShortList(id: "1") { [weak self] in
// self?.requestGroup.leave()
// }
self.requestGroup.notify(queue: DispatchQueue.main) {
completer?()
}
}
/// banner
private func requestModuleData(completer: (() -> Void)? = nil) {
SPHomeAPI.requestHomeModuleData { [weak self] model in
guard let self = self else { return }
if let model = model {
self.viewModel.moduleModel = model
self.pageView.downSc?.reloadData()
}
self.updateEmptyState()
completer?()
}
}
///ID= 3
///ID=1
private func requestCategoryShortList(id: String, completer: (() -> Void)?) {
SPVideoAPI.requestCategoryShortList(page: 1, id: id) { [weak self] listModel in
guard let self = self else { return }
if let list = listModel?.list {
if id == "3" {
self.viewModel.categoryDataArr1 = list
} else {
self.viewModel.categoryDataArr2 = list
}
self.pageView.downSc?.reloadData()
}
self.updateEmptyState()
completer?()
}
}
///
private func requestPlayHistory(completer: (() -> Void)? = nil) {
SPVideoAPI.requestPlayHistoryList(page: 1) { [weak self] listModel in
guard let self = self else { return }
if let list = listModel?.list {
self.viewModel.playHistoryArr = list
self.pageView.downSc?.reloadData()
if let model = listModel?.list?.first {
self.playHistoricalView.model = model
self.playHistoricalView.isHidden = false
}
}
self.updateEmptyState()
completer?()
}
}
///
private func requestListDataArr(page: Int, completer: (() -> Void)?) {
SPHomeAPI.requestHomeList(page: page) { [weak self] listModel in
guard let self = self else { return }
if let list = listModel?.list {
if page == 1 {
self.viewModel.dataArr.removeAll()
}
self.viewModel.dataArr += list
// self.collectionView.reloadData()
self.viewModel.page = page
}
self.updateEmptyState()
completer?()
}
}
}

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
class SPHomeViewController: SPHomeChildController { class SPHomeViewController: SPViewController {
private lazy var viewModel: SPHomeViewModel = SPHomeViewModel() private lazy var viewModel: SPHomeViewModel = SPHomeViewModel()

View File

@ -0,0 +1,27 @@
//
// SPHomeContentModel.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeContentModel: NSObject {
enum ContentKey: String {
case banner
case history
///
case nineSquare
case category1
case hot
case category2
}
var key: ContentKey?
var title: String?
var list: [SPShortModel]?
var contentTop: CGFloat = 0
}

View File

@ -0,0 +1,103 @@
//
// SPHomeBannerContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeBannerContentCell: SPHomeContentCell {
override var contentModel: SPHomeContentModel? {
didSet {
bannerView.reloadData()
let bannerModel = contentModel?.list?.first
self.bannerBgImageView.sp_setImage(url: bannerModel?.image_url)
}
}
private lazy var bannerBgImageView: SPFadeEdgeImageView = {
let imageView = SPFadeEdgeImageView()
imageView.contentMode = .scaleAspectFill
return imageView
}()
private lazy var bannerView: ZKCycleScrollView = {
let view = ZKCycleScrollView(frame: .zero, shouldInfiniteLoop: true)
view.itemSize = .init(width: 234, height: 336)
view.itemAlpha = true
view.itemZoomScale = 0.85
view.rotationAngle = 12
view.itemSpacing = 15
view.delegate = self
view.dataSource = self
view.hidesPageControl = true
view.register(SPHomeZoomBannerCell.self, forCellWithReuseIdentifier: "banner")
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
sp_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SPHomeBannerContentCell {
private func sp_setupUI() {
contentView.addSubview(bannerBgImageView)
contentView.addSubview(bannerView)
bannerBgImageView.snp.makeConstraints { make in
make.top.equalToSuperview()
make.centerX.equalToSuperview()
make.width.equalTo(kSPScreenWidth)
make.height.equalTo(336)
}
bannerView.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.height.equalTo(336)
}
}
}
//MARK: -------------- ZKCycleScrollViewDelegate & ZKCycleScrollViewDataSource --------------
extension SPHomeBannerContentCell: ZKCycleScrollViewDelegate, ZKCycleScrollViewDataSource {
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, cellForItemAt index: Int) -> ZKCycleScrollViewCell {
let cell = cycleScrollView.dequeueReusableCell(withReuseIdentifier: "banner", for: index) as! SPHomeZoomBannerCell
cell.model = contentModel?.list?[index]
return cell
}
func numberOfItems(in cycleScrollView: ZKCycleScrollView) -> Int {
return contentModel?.list?.count ?? 0
}
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didScrollFromIndex fromIndex: Int, toIndex: Int) {
let model = contentModel?.list?[toIndex]
self.bannerBgImageView.sp_setImage(url: model?.image_url)
}
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didSelectItemAt index: Int) {
let model = contentModel?.list?[index]
let vc = SPPlayerDetailViewController()
vc.shortPlayId = model?.short_play_id
self.viewController?.navigationController?.pushViewController(vc, animated: true)
}
}

View File

@ -0,0 +1,19 @@
//
// SPHomeCategoryContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeCategoryContentCell: SPHomeContentCell {
///
private lazy var categoryVideoView: SPHomeCategoryVideoView = {
let view = SPHomeCategoryVideoView()
view.image = UIImage(named: "category_bg_image_01")
return view
}()
}

View File

@ -0,0 +1,16 @@
//
// SPHomeContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeContentCell: SPTableViewCell {
let contentToTop: CGFloat = 25
var contentModel: SPHomeContentModel?
}

View File

@ -0,0 +1,45 @@
//
// SPHomeHistoryContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeHistoryContentCell: SPHomeContentCell {
override var contentModel: SPHomeContentModel? {
didSet {
playHistoryView.dataArr = contentModel?.list
playHistoryView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(contentModel?.contentTop ?? 0)
}
}
}
private lazy var playHistoryView: SPHomePlayHistoryView = {
let view = SPHomePlayHistoryView()
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(playHistoryView)
playHistoryView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(0)
make.left.right.bottom.equalToSuperview()
make.height.equalTo(SPHomePlayHistoryView.contentToTop + 136)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,18 @@
//
// SPHomeHotContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeHotContentCell: SPHomeContentCell {
private lazy var trendingView: SPHomeTrendingView = {
let view = SPHomeTrendingView()
return view
}()
}

View File

@ -0,0 +1,46 @@
//
// SPHomeNineSquareContentCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPHomeNineSquareContentCell: SPHomeContentCell {
override var contentModel: SPHomeContentModel? {
didSet {
exploreView.dataArr = contentModel?.list
exploreView.titleLabel.text = contentModel?.title
exploreView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(contentModel?.contentTop ?? 0)
make.height.equalTo(SPHomeExploreView.contentHeight(dataArr: contentModel?.list ?? []))
}
}
}
private lazy var exploreView: SPHomeExploreView = {
let view = SPHomeExploreView()
return view
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(exploreView)
exploreView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(0)
make.left.right.bottom.equalToSuperview()
make.height.equalTo(1)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -18,10 +18,13 @@ class SPHomePlayHistoricalView: UIView {
} }
private lazy var bgView: UIView = { private lazy var bgView: UIView = {
let view = UIImageView(image: UIImage(named: "home_historical_bg_image_")) // let view = UIImageView(image: UIImage(named: "home_historical_bg_image_"))
let view = UIView()
view.addEffectView(style: .dark)
view.addRadius(topLeft: 24, topRight: 24, bottomLeft: 24, bottomRight: 24)
view.isUserInteractionEnabled = true view.isUserInteractionEnabled = true
// view.addEffectView(style: .dark)
// view.addRadius(topLeft: 0, topRight: 24, bottomLeft: 0, bottomRight: 24)
let tap = UITapGestureRecognizer(target: self, action: #selector(handlePlayButton)) let tap = UITapGestureRecognizer(target: self, action: #selector(handlePlayButton))
view.addGestureRecognizer(tap) view.addGestureRecognizer(tap)
return view return view
@ -100,7 +103,7 @@ extension SPHomePlayHistoricalView {
bgView.snp.makeConstraints { make in bgView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview() make.left.right.bottom.equalToSuperview()
// make.height.equalTo(48) make.height.equalTo(48)
} }
coverImageView.snp.makeConstraints { make in coverImageView.snp.makeConstraints { make in

View File

@ -13,18 +13,96 @@ class SPHomeViewModel: NSObject {
lazy var dataArr: [SPShortModel] = [] lazy var dataArr: [SPShortModel] = []
/// ///
var moduleModel: SPHomeModuleModel? var moduleModel: SPHomeModuleModel? {
didSet {
updateContentArr()
}
}
/// ///
/// ///
var categoryDataArr1: [SPShortModel] = [] var categoryDataArr1: [SPShortModel] = [] {
didSet {
updateContentArr()
}
}
/// ///
var categoryDataArr2: [SPShortModel] = [] var categoryDataArr2: [SPShortModel] = [] {
didSet {
updateContentArr()
}
}
/// ///
var playHistoryArr: [SPShortModel]? var playHistoryArr: [SPShortModel]? {
didSet {
updateContentArr()
}
}
private(set) lazy var contentArr: [SPHomeContentModel] = []
private func updateContentArr() {
contentArr.removeAll()
if let list = moduleModel?.bannerData, list.count > 0 {
let model = SPHomeContentModel()
model.key = .banner
model.list = list
contentArr.append(model)
}
if let list = playHistoryArr, list.count > 0 {
let model = SPHomeContentModel()
model.key = .history
model.list = list
if contentArr.count > 0 {
model.contentTop = 25
}
contentArr.append(model)
}
if let list = moduleModel?.nineSquare?.list, list.count > 0 {
let model = SPHomeContentModel()
model.key = .nineSquare
model.title = moduleModel?.nineSquare?.title
model.list = list
if contentArr.count > 0 {
model.contentTop = 25
}
contentArr.append(model)
}
if categoryDataArr1.count > 0 {
let model = SPHomeContentModel()
model.key = .category1
model.list = categoryDataArr1
if contentArr.count > 0 {
model.contentTop = 25
}
contentArr.append(model)
}
if let list = moduleModel?.hotData, list.count > 0 {
let model = SPHomeContentModel()
model.key = .hot
model.list = list
if contentArr.count > 0 {
model.contentTop = 25
}
contentArr.append(model)
}
// if categoryDataArr2.count > 0 {
// let model = SPHomeContentModel()
// model.key = .category1
// model.list = categoryDataArr2
// contentArr.append(model)
// }
}
var isEmptyData: Bool { var isEmptyData: Bool {
if dataArr.count > 0 || (playHistoryArr?.count ?? 0) > 0 || moduleModel != nil { if dataArr.count > 0 || (playHistoryArr?.count ?? 0) > 0 || moduleModel != nil {
return false return false

View File

@ -78,6 +78,22 @@ class SPMineWalletView: UIView {
return button return button
}() }()
private lazy var coinTitleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFFFFF(alpha: 0.3)
label.text = "movia_profile_Coins".localized
return label
}()
private lazy var sendCoinTitleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFFFFF(alpha: 0.3)
label.text = "movia_profile_Bonus".localized
return label
}()
private lazy var coinButton: UIButton = { private lazy var coinButton: UIButton = {
let button = JXButton(type: .custom) let button = JXButton(type: .custom)
button.isUserInteractionEnabled = false button.isUserInteractionEnabled = false
@ -87,11 +103,13 @@ class SPMineWalletView: UIView {
button.space = 2 button.space = 2
return button return button
}() }()
/// ///
private lazy var sendCoinButton: UIButton = { private lazy var sendCoinButton: UIButton = {
let button = JXButton(type: .custom) let button = JXButton(type: .custom)
button.isUserInteractionEnabled = false button.isUserInteractionEnabled = false
button.setImage(UIImage(named: "coin_icon_02"), for: .normal) button.setImage(UIImage(named: "coin_icon_01"), for: .normal)
button.setTitleColor(.colorFFFFFF(), for: .normal) button.setTitleColor(.colorFFFFFF(), for: .normal)
button.jx_font = .fontMedium(ofSize: 18) button.jx_font = .fontMedium(ofSize: 18)
button.space = 2 button.space = 2
@ -99,6 +117,8 @@ class SPMineWalletView: UIView {
}() }()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
coinButton.setTitle("0", for: .normal) coinButton.setTitle("0", for: .normal)
@ -135,6 +155,8 @@ extension SPMineWalletView {
moreButton.addSubview(moreIndicatorImageView) moreButton.addSubview(moreIndicatorImageView)
bgView.addSubview(lineView) bgView.addSubview(lineView)
bgView.addSubview(storeButton) bgView.addSubview(storeButton)
bgView.addSubview(coinTitleLabel)
bgView.addSubview(sendCoinTitleLabel)
bgView.addSubview(coinButton) bgView.addSubview(coinButton)
bgView.addSubview(sendCoinButton) bgView.addSubview(sendCoinButton)
@ -169,17 +191,28 @@ extension SPMineWalletView {
storeButton.snp.makeConstraints { make in storeButton.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-12) make.right.equalToSuperview().offset(-12)
make.bottom.equalToSuperview().offset(-21) make.bottom.equalToSuperview().offset(-14)
}
coinTitleLabel.snp.makeConstraints { make in
make.left.equalTo(coinButton)
make.bottom.equalTo(coinButton.snp.top).offset(-9)
}
sendCoinTitleLabel.snp.makeConstraints { make in
make.left.equalTo(sendCoinButton)
make.bottom.equalTo(coinTitleLabel)
} }
coinButton.snp.makeConstraints { make in coinButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(8) make.left.equalToSuperview().offset(12)
make.centerY.equalTo(storeButton) make.centerY.equalTo(storeButton)
// make.bottom.equalToSuperview().offset(-23)
} }
sendCoinButton.snp.makeConstraints { make in sendCoinButton.snp.makeConstraints { make in
make.left.equalTo(coinButton.snp.right).offset(10) make.left.equalTo(coinButton.snp.right).offset(30)
make.centerY.equalTo(storeButton) make.centerY.equalTo(coinButton)
} }
} }

View File

@ -30,12 +30,11 @@ class SPPlayBuyView: HWPanModalContentView {
return view return view
}() }()
private lazy var indicatorView: UIView = { private lazy var closeButton: UIButton = {
let view = UIView() let button = UIButton(type: .custom)
view.backgroundColor = .colorFFFFFF(alpha: 0.4) button.setImage(UIImage(named: "close_icon_04"), for: .normal)
view.layer.cornerRadius = 2.5 button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
view.layer.masksToBounds = true return button
return view
}() }()
private lazy var titleLabel: UILabel = { private lazy var titleLabel: UILabel = {
@ -84,8 +83,25 @@ class SPPlayBuyView: HWPanModalContentView {
return view return view
}() }()
private lazy var tipTitleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 12)
label.textColor = .colorFFFFFF(alpha: 0.7)
return label
}()
private lazy var tipTextLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.textColor = .colorFFFFFF(alpha: 0.5)
label.font = .fontRegular(ofSize: 12)
return label
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
tipTitleLabel.text = "movia_store_tips_title_ios".localized
tipTextLabel.text = "movia_store_tips_ios".localized.replacingOccurrences(of: "\\n", with: "\n")
_setupUI() _setupUI()
@ -103,7 +119,7 @@ class SPPlayBuyView: HWPanModalContentView {
} }
override func longFormHeight() -> PanModalHeight { override func longFormHeight() -> PanModalHeight {
return PanModalHeightMake(.content, kSPScreenHeight * (3 / 4)) return PanModalHeightMake(.content, kSPScreenHeight - kSPNavBarHeight - 10)
} }
override func showDragIndicator() -> Bool { override func showDragIndicator() -> Bool {
@ -115,6 +131,27 @@ class SPPlayBuyView: HWPanModalContentView {
config.backgroundAlpha = 0.6 config.backgroundAlpha = 0.6
return config return config
} }
override func allowsDragToDismiss() -> Bool {
return false
}
override func allowsTapBackgroundToDismiss() -> Bool {
return false
}
override func allowsPullDownWhenShortState() -> Bool {
return false
}
override func minVerticalVelocityToTriggerDismiss() -> CGFloat {
return 0
}
override func showsScrollableVerticalScrollIndicator() -> Bool {
return false
}
} }
extension SPPlayBuyView { extension SPPlayBuyView {
@ -137,50 +174,69 @@ extension SPPlayBuyView {
self.handleBuyFinish() self.handleBuyFinish()
} }
} }
@objc private func handleCloseButton() {
self.dismiss(animated: true) {
}
}
} }
extension SPPlayBuyView { extension SPPlayBuyView {
private func _setupUI() { private func _setupUI() {
addSubview(bgView) addSubview(bgView)
addSubview(indicatorView) addSubview(closeButton)
addSubview(titleLabel) addSubview(titleLabel)
addSubview(restoreButton) // addSubview(restoreButton)
addSubview(scrollView) addSubview(scrollView)
scrollView.addSubview(stackView) scrollView.addSubview(stackView)
scrollView.addSubview(tipTitleLabel)
scrollView.addSubview(tipTextLabel)
bgView.snp.makeConstraints { make in bgView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview() make.left.right.top.equalToSuperview()
} }
indicatorView.snp.makeConstraints { make in closeButton.snp.makeConstraints { make in
make.centerX.equalToSuperview() make.top.equalToSuperview().offset(7)
make.top.equalToSuperview().offset(8) make.right.equalToSuperview().offset(-12)
make.width.equalTo(40) make.width.height.equalTo(32)
make.height.equalTo(5)
} }
titleLabel.snp.makeConstraints { make in titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16) make.left.equalToSuperview().offset(16)
make.top.equalToSuperview().offset(30) make.centerY.equalTo(closeButton)
} }
restoreButton.snp.makeConstraints { make in // restoreButton.snp.makeConstraints { make in
make.centerY.equalTo(titleLabel) // make.centerY.equalTo(titleLabel)
make.right.equalToSuperview().offset(-16) // make.right.equalToSuperview().offset(-16)
} // }
scrollView.snp.makeConstraints { make in scrollView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(76) make.top.equalToSuperview().offset(58)
make.left.right.equalToSuperview() make.left.right.equalToSuperview()
make.bottom.equalToSuperview() make.bottom.equalToSuperview()
} }
stackView.snp.makeConstraints { make in stackView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview() make.left.right.top.equalToSuperview()
make.bottom.equalTo(-(kSPTabbarSafeBottomMargin + 10)) // make.bottom.equalTo(-(kSPTabbarSafeBottomMargin + 10))
make.width.equalTo(kSPScreenWidth) make.width.equalTo(kSPScreenWidth)
} }
tipTitleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(24)
make.top.equalTo(stackView.snp.bottom).offset(34)
}
tipTextLabel.snp.makeConstraints { make in
make.left.equalTo(tipTitleLabel)
make.right.lessThanOrEqualTo(stackView).offset(-24)
make.top.equalTo(tipTitleLabel.snp.bottom).offset(4)
make.bottom.equalTo(-(kSPTabbarSafeBottomMargin + 10))
}
} }
@ -192,16 +248,24 @@ extension SPPlayBuyView {
private func requestPayTemplate() { private func requestPayTemplate() {
SPWalletAPI.requestPayTemplate { [weak self] templateModel in SPWalletAPI.requestPayTemplate { [weak self] templateModel in
guard let self = self else { return } guard let self = self else { return }
self.rechargeView.dataArr = templateModel?.list_coins
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
self.stackView.removeAllArrangedSubview() self.stackView.removeAllArrangedSubview()
self.stackView.addArrangedSubview(self.rechargeView)
self.stackView.addArrangedSubview(self.memberView)
if let list = templateModel?.list_sub_vip, list.count > 0 {
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
self.stackView.addArrangedSubview(self.memberView)
}
if let list = templateModel?.list_coins, list.count > 0 {
self.rechargeView.dataArr = templateModel?.list_coins
self.stackView.addArrangedSubview(self.rechargeView)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.panModalSetNeedsLayoutUpdate() self.panModalSetNeedsLayoutUpdate()
} }
}
} }

View File

@ -186,13 +186,17 @@ extension SPStoreViewController {
private func requestPayTemplate() { private func requestPayTemplate() {
SPWalletAPI.requestPayTemplate { [weak self] templateModel in SPWalletAPI.requestPayTemplate { [weak self] templateModel in
guard let self = self else { return } guard let self = self else { return }
self.rechargeView.dataArr = templateModel?.list_coins
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
self.stackView.removeAllArrangedSubview() self.stackView.removeAllArrangedSubview()
if let list = templateModel?.list_sub_vip, list.count > 0 {
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
self.stackView.addArrangedSubview(self.memberView) self.stackView.addArrangedSubview(self.memberView)
}
if let list = templateModel?.list_coins, list.count > 0 {
self.rechargeView.dataArr = templateModel?.list_coins
self.stackView.addArrangedSubview(self.rechargeView) self.stackView.addArrangedSubview(self.rechargeView)
}
} }
} }

View File

@ -15,6 +15,11 @@ class SPPayTemplateItem: SPModel, SmartCodable {
case subVip = "sub_vip" case subVip = "sub_vip"
} }
enum SizeType: String, SmartCaseDefaultable {
case small
case big
}
enum VipTypeKey: String, SmartCaseDefaultable { enum VipTypeKey: String, SmartCaseDefaultable {
case week = "week" case week = "week"
case month = "month" case month = "month"
@ -35,9 +40,24 @@ class SPPayTemplateItem: SPModel, SmartCodable {
case .year: case .year:
return "Y_complex".localized return "Y_complex".localized
} }
} }
func getTextV2() -> String {
switch self {
case .week:
return "week_short_type".localized
case .month:
return "month_short_type".localized
case .quarter:
return "quarter_short_type".localized
case .year:
return "year_short_type".localized
}
}
} }
@ -55,10 +75,13 @@ class SPPayTemplateItem: SPModel, SmartCodable {
var title: String? var title: String?
var brief: String? var brief: String?
var sp_description: String? var sp_description: String?
var send_coin_ttl: Int?
var vip_type: String? var vip_type: String?
var vip_type_key: VipTypeKey? var vip_type_key: VipTypeKey?
var size: SizeType?
var ios_template_id: String? var ios_template_id: String?

View File

@ -0,0 +1,60 @@
//
// SPCoinRechargeBigCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPCoinRechargeBigCell: SPCoinRechargeCell {
override var sp_isSelected: Bool {
didSet {
if sp_isSelected {
containerView.image = UIImage(named: "recharge_bg_big_image_01")
} else {
containerView.image = UIImage(named: "recharge_bg_big_image_02")
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
coinIconImageView.image = UIImage(named: "coin_icon_08")
ratioBgView.image = UIImage(named: "mark_bg_icon_01")
moneyBgView.colors = [UIColor.colorE9BB68().cgColor, UIColor.colorFFE18D().cgColor, UIColor.colorDDA754().cgColor]
moneyBgView.layer.cornerRadius = 8
moneyLabel.textColor = .color6B3308()
coinLabel.font = .fontBold(ofSize: 24)
ratioLabel.font = .fontBold(ofSize: 12)
ratioLabel.textColor = .color94550E()
coinBgView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(28)
}
bonusLabel.snp.updateConstraints { make in
make.top.equalTo(coinBgView.snp.bottom).offset(2)
}
moneyBgView.snp.remakeConstraints { make in
make.bottom.equalToSuperview().offset(-5)
make.centerX.equalToSuperview()
make.left.equalToSuperview().offset(6)
make.height.equalTo(30)
}
ratioLabel.snp.updateConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(6)
make.right.equalToSuperview().offset(-8)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -9,28 +9,31 @@ import UIKit
class SPCoinRechargeCell: SPCollectionViewCell { class SPCoinRechargeCell: SPCollectionViewCell {
var sp_isSelected = false { var sp_isSelected = false
didSet {
if sp_isSelected {
containerView.image = UIImage(named: "recharge_bg_image_01")
moneyLabel.backgroundColor = .colorFFF0DE(alpha: 0.1)
} else {
containerView.image = UIImage(named: "recharge_bg_image_02")
moneyLabel.backgroundColor = .color000000(alpha: 0.8)
}
}
}
var model: SPPayTemplateItem? { var model: SPPayTemplateItem? {
didSet { didSet {
coinLabel.text = "\(model?.coins ?? 0)" coinLabel.text = "\(model?.coins ?? 0)"
if let sendCoins = model?.send_coins, sendCoins > 0 { if let mark = model?.corner_marker, !mark.isEmpty {
hotView.isHidden = false
} else {
hotView.isHidden = true
}
if let sendCoins = model?.send_coins, sendCoins > 0, let coins = model?.coins {
bonusLabel.isHidden = false bonusLabel.isHidden = false
bonusLabel.text = String(format: "movia_bonus_#".localized, "+\(sendCoins)") ratioBgView.isHidden = false
let ratio = String(format: "%.0f", CGFloat(sendCoins) / CGFloat(coins) * 100)
ratioLabel.text = "+\(ratio)%"
bonusLabel.text = "+\(sendCoins)"
// bonusLabel.text = String(format: "movia_bonus_#".localized, "+\(sendCoins)")
} else { } else {
bonusLabel.isHidden = true bonusLabel.isHidden = true
ratioBgView.isHidden = true
} }
moneyLabel.text = "\(model?.currency ?? "")\(model?.price ?? "0")" moneyLabel.text = "\(model?.currency ?? "")\(model?.price ?? "0")"
@ -38,47 +41,68 @@ class SPCoinRechargeCell: SPCollectionViewCell {
} }
//MARK: UI //MARK: UI
private lazy var containerView: UIImageView = { private(set) lazy var containerView: UIImageView = {
let imageView = UIImageView() let imageView = UIImageView()
return imageView return imageView
}() }()
private lazy var coinBgView: UIView = { private(set) lazy var coinBgView: UIView = {
let view = UIView() let view = UIView()
return view return view
}() }()
private lazy var coinIconImageView: UIImageView = { private(set) lazy var coinIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "coin_icon_04")) let imageView = UIImageView()
return imageView return imageView
}() }()
private lazy var coinLabel: UILabel = { private(set) lazy var coinLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontBold(ofSize: 20)
label.textColor = .colorFFFFFF() label.textColor = .colorFFFFFF()
return label return label
}() }()
private lazy var bonusLabel: UILabel = { private(set) lazy var bonusLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontMedium(ofSize: 14) label.font = .fontMedium(ofSize: 14)
label.textColor = .colorEF7301() label.textColor = .colorEF7301()
return label return label
}() }()
private lazy var moneyLabel: UILabel = { private(set) lazy var moneyBgView: SPGradientView = {
let view = SPGradientView()
view.locations = [0, 0.5, 1]
view.startPoint = .init(x: 0, y: 0.5)
view.endPoint = .init(x: 1, y: 0.5)
view.layer.masksToBounds = true
return view
}()
private(set) lazy var moneyLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.layer.cornerRadius = 10
label.layer.masksToBounds = true
label.textAlignment = .center
label.font = .fontMedium(ofSize: 14) label.font = .fontMedium(ofSize: 14)
label.textColor = .colorFFCF93()
return label return label
}() }()
private(set) lazy var ratioBgView: UIImageView = {
let view = UIImageView()
return view
}()
private(set) lazy var ratioLabel: UILabel = {
let label = UILabel()
return label
}()
private lazy var hotView: UIImageView = {
let view = UIImageView(image: UIImage(named: "hot_icon_03"))
return view
}()
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
contentView.layer.masksToBounds = false
self.layer.masksToBounds = false
_setupUI() _setupUI()
} }
@ -92,16 +116,25 @@ extension SPCoinRechargeCell {
private func _setupUI() { private func _setupUI() {
contentView.addSubview(containerView) contentView.addSubview(containerView)
contentView.addSubview(hotView)
containerView.addSubview(coinBgView) containerView.addSubview(coinBgView)
coinBgView.addSubview(coinIconImageView) coinBgView.addSubview(coinIconImageView)
coinBgView.addSubview(coinLabel) coinBgView.addSubview(coinLabel)
containerView.addSubview(bonusLabel) containerView.addSubview(bonusLabel)
containerView.addSubview(moneyLabel) containerView.addSubview(moneyBgView)
moneyBgView.addSubview(moneyLabel)
containerView.addSubview(ratioBgView)
ratioBgView.addSubview(ratioLabel)
containerView.snp.makeConstraints { make in containerView.snp.makeConstraints { make in
make.edges.equalToSuperview() make.edges.equalToSuperview()
} }
hotView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(4)
make.top.equalToSuperview().offset(-2)
}
coinBgView.snp.makeConstraints { make in coinBgView.snp.makeConstraints { make in
make.centerX.equalToSuperview() make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(24) make.top.equalToSuperview().offset(24)
@ -125,11 +158,20 @@ extension SPCoinRechargeCell {
} }
moneyLabel.snp.makeConstraints { make in moneyLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(2) make.center.equalToSuperview()
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-2)
make.height.equalTo(30)
} }
ratioBgView.snp.makeConstraints { make in
make.top.right.equalToSuperview()
}
ratioLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.left.equalToSuperview().offset(5)
make.right.equalToSuperview().offset(-5)
}
} }
} }

View File

@ -0,0 +1,50 @@
//
// SPCoinRechargeSmallCell.swift
// MoviaBox
//
// Created by on 2025/6/18.
//
import UIKit
class SPCoinRechargeSmallCell: SPCoinRechargeCell {
override var sp_isSelected: Bool {
didSet {
if sp_isSelected {
containerView.image = UIImage(named: "recharge_bg_image_01")
} else {
containerView.image = UIImage(named: "recharge_bg_image_02")
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
coinIconImageView.image = UIImage(named: "coin_icon_07")
ratioBgView.image = UIImage(named: "mark_bg_icon_02")
moneyBgView.colors = [UIColor.color000000(alpha: 0.8).cgColor, UIColor.color000000(alpha: 0.8).cgColor, UIColor.color000000(alpha: 0.8).cgColor]
moneyBgView.layer.cornerRadius = 10
moneyLabel.textColor = .colorFFCF93()
coinLabel.font = .fontBold(ofSize: 20)
ratioLabel.font = .fontRegular(ofSize: 11)
ratioLabel.textColor = .colorFFCF93()
coinBgView.snp.updateConstraints { make in
make.top.equalToSuperview().offset(34)
}
moneyBgView.snp.remakeConstraints { make in
make.bottom.equalToSuperview().offset(-2)
make.centerX.equalToSuperview()
make.left.equalToSuperview().offset(2)
make.height.equalTo(30)
}
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -10,19 +10,48 @@ import UIKit
class SPCoinRechargeView: UIView { class SPCoinRechargeView: UIView {
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
return CGSize(width: kSPScreenWidth, height: 20 + 14 + 125) return CGSize(width: kSPScreenWidth, height: 34 + self.collectionView.contentSize.height + 1)
} }
private lazy var currentIndexPath: IndexPath = .init(row: 0, section: 0)
private var currentModel: SPPayTemplateItem?
/// ///
var rechargeFinishHandle: (() -> Void)? var rechargeFinishHandle: (() -> Void)?
var dataArr: [SPPayTemplateItem]? { var dataArr: [SPPayTemplateItem]? {
didSet { didSet {
self.collectionView.reloadData() listDataArr.removeAll()
var bigArr: [SPPayTemplateItem] = []
var smallArr: [SPPayTemplateItem] = []
dataArr?.forEach({
if $0.size == .big {
bigArr.append($0)
} else {
smallArr.append($0)
}
})
if bigArr.count > 0 {
listDataArr.append(bigArr)
}
if smallArr.count > 0 {
listDataArr.append(smallArr)
}
UIView.performWithoutAnimation { [weak self] in
self?.collectionView.reloadData()
}
self.collectionView.performBatchUpdates(nil) { [weak self] _ in
self?.invalidateIntrinsicContentSize()
} }
} }
}
private lazy var listDataArr: [[SPPayTemplateItem]] = []
var userInfo: SPUserInfo? { var userInfo: SPUserInfo? {
didSet { didSet {
@ -54,13 +83,9 @@ class SPCoinRechargeView: UIView {
return label return label
}() }()
private lazy var collectionViewLayout: UICollectionViewFlowLayout = { private lazy var collectionViewLayout: WaterfallMutiSectionFlowLayout = {
let layout = UICollectionViewFlowLayout() let layout = WaterfallMutiSectionFlowLayout()
layout.scrollDirection = .horizontal layout.delegate = self
layout.minimumLineSpacing = 8
layout.minimumInteritemSpacing = 8
layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16)
layout.itemSize = CGSize(width: 120, height: 125)
return layout return layout
}() }()
@ -70,7 +95,9 @@ class SPCoinRechargeView: UIView {
collectionView.dataSource = self collectionView.dataSource = self
collectionView.showsVerticalScrollIndicator = false collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false collectionView.showsHorizontalScrollIndicator = false
SPCoinRechargeCell.registerCell(collectionView: collectionView) collectionView.layer.masksToBounds = false
SPCoinRechargeBigCell.registerCell(collectionView: collectionView, SPPayTemplateItem.SizeType.big.rawValue)
SPCoinRechargeSmallCell.registerCell(collectionView: collectionView, SPPayTemplateItem.SizeType.small.rawValue)
return collectionView return collectionView
}() }()
@ -113,7 +140,7 @@ extension SPCoinRechargeView {
collectionView.snp.makeConstraints { make in collectionView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview() make.left.right.bottom.equalToSuperview()
make.height.equalTo(125) make.top.equalToSuperview().offset(34)
} }
} }
@ -123,21 +150,28 @@ extension SPCoinRechargeView {
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource -------------- //MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
extension SPCoinRechargeView: UICollectionViewDelegate, UICollectionViewDataSource { extension SPCoinRechargeView: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = SPCoinRechargeCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) let model = self.listDataArr[indexPath.section][indexPath.row]
cell.sp_isSelected = indexPath == currentIndexPath let size = model.size ?? .small
cell.model = dataArr?[indexPath.row]
let cell = SPCoinRechargeCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath, size.rawValue)
cell.sp_isSelected = model == currentModel
cell.model = model
return cell return cell
} }
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataArr?.count ?? 0 return self.listDataArr[section].count
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return self.listDataArr.count
} }
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
currentIndexPath = indexPath let model = self.listDataArr[indexPath.section][indexPath.row]
collectionView.reloadData()
guard let model = self.dataArr?[indexPath.row] else { return } currentModel = model
collectionView.reloadData()
SPIAPManager.manager.startRecharge(model: model, shortPlayId: shortPlayId, videoId: videoId) { [weak self] finish in SPIAPManager.manager.startRecharge(model: model, shortPlayId: shortPlayId, videoId: videoId) { [weak self] finish in
if finish { if finish {
@ -147,3 +181,48 @@ extension SPCoinRechargeView: UICollectionViewDelegate, UICollectionViewDataSour
} }
} }
//MARK: -------------- WaterfallMutiSectionDelegate --------------
extension SPCoinRechargeView: WaterfallMutiSectionDelegate {
func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int {
let model = self.listDataArr[section].last
if model?.size == .big {
return 2
} else {
return 3
}
}
func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat {
let model = self.listDataArr[indexPath.section][indexPath.row]
if model.size == .big {
return 114
} else {
return 126
}
}
func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets {
return .init(top: 0, left: 15, bottom: 0, right: 15)
}
func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat {
return 15
}
func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat {
return 15
}
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize {
if section == 0 {
return .init(width: kSPScreenWidth, height: 0)
} else {
return .init(width: kSPScreenWidth, height: 15)
}
}
}

View File

@ -14,87 +14,87 @@ class SPMemberRechargeCell: SPCollectionViewCell {
didSet { didSet {
desLabel.text = model?.sp_description desLabel.text = model?.sp_description
// typeLabel.text = model?.vip_type_key?.getText() // typeLabel.text = model?.vip_type_key?.getText()
typeLabel.text = model?.brief typeLabel.text = model?.vip_type_key?.getTextV2()
currencyLabel.text = model?.currency durationLabel.text = "/\(model?.vip_type_key?.getText() ?? "")"
moneyLabel.text = model?.price
moneyLabel.text = "\(model?.currency ?? "")\(model?.price ?? "")"
if let sendCoins = model?.send_coins, sendCoins > 0 { if let sendCoins = model?.send_coins, sendCoins > 0 {
markBgView.isHidden = false markBgView.isHidden = false
tipLabel.isHidden = false
sendCoinLabel.text = String(format: "movia_extra_#".localized, "\(sendCoins)") sendCoinLabel.text = String(format: "movia_extra_#".localized, "\(sendCoins)")
tipLabel.text = "·" + "movia_coins_extra_days".localizedReplace(text: "\(model?.send_coin_ttl ?? 0)")
} else { } else {
markBgView.isHidden = true markBgView.isHidden = true
tipLabel.isHidden = true
} }
switch model?.vip_type_key { switch model?.vip_type_key {
case .year: case .year:
bgView.image = UIImage(named: "vip_bg_image_01")
vipImageView.image = UIImage(named: "vip_image_01") vipImageView.image = UIImage(named: "vip_image_01")
downBgView.colors = [UIColor.colorFDE9A6().cgColor, UIColor.colorFFAC38().cgColor]
topBgView.colors = [UIColor.color2B2826().cgColor, UIColor.color100F0B().cgColor]
desLabel.textColor = .color6B3308() iconImageView.image = UIImage(named: "vip_icon_10")
iconImageView.image = UIImage(named: "vip_icon_03")
typeLabel.textColor = .colorFFB559()
typeIconImageView.image = UIImage(named: "vip_icon_05") typeIconImageView.image = UIImage(named: "vip_icon_05")
case .quarter:
vipImageView.image = UIImage(named: "vip_image_02")
downBgView.colors = [UIColor.colorFDE9A6().cgColor, UIColor.colorFFAC38().cgColor]
topBgView.colors = [UIColor.colorFEE3B5().cgColor, UIColor.colorFCCE7D().cgColor]
desLabel.textColor = .color6B3308() desLabel.textColor = .color6B3308()
typeLabel.textColor = .colorFED095()
moneyLabel.textColor = .colorFFE49E()
tipLabel.textColor = .colorFFFFFF(alpha: 0.8)
case .quarter:
bgView.image = UIImage(named: "vip_bg_image_02")
vipImageView.image = UIImage(named: "vip_image_02")
iconImageView.image = UIImage(named: "vip_icon_03") iconImageView.image = UIImage(named: "vip_icon_03")
typeLabel.textColor = .color9F5300()
typeIconImageView.image = UIImage(named: "vip_icon_06") typeIconImageView.image = UIImage(named: "vip_icon_06")
case .month: desLabel.textColor = .color6B3308()
vipImageView.image = UIImage(named: "vip_image_03") typeLabel.textColor = .color9F5300()
downBgView.colors = [UIColor.color2AAED3().cgColor, UIColor.color9CD5E5().cgColor] moneyLabel.textColor = typeLabel.textColor
topBgView.colors = [UIColor.colorF2F4F4().cgColor, UIColor.colorC8E1E8().cgColor] tipLabel.textColor = typeLabel.textColor
case .month:
bgView.image = UIImage(named: "vip_bg_image_03")
vipImageView.image = UIImage(named: "vip_image_03")
desLabel.textColor = .colorFFFFFF()
iconImageView.image = UIImage(named: "vip_icon_04") iconImageView.image = UIImage(named: "vip_icon_04")
typeLabel.textColor = .color0D4E64()
typeIconImageView.image = UIImage(named: "vip_icon_07") typeIconImageView.image = UIImage(named: "vip_icon_07")
desLabel.textColor = .colorFFFFFF()
typeLabel.textColor = .color0D4E64()
moneyLabel.textColor = typeLabel.textColor
tipLabel.textColor = typeLabel.textColor
case .week: case .week:
bgView.image = UIImage(named: "vip_bg_image_04")
vipImageView.image = UIImage(named: "vip_image_04") vipImageView.image = UIImage(named: "vip_image_04")
downBgView.colors = [UIColor.color0588DB().cgColor, UIColor.colorA9E1F2().cgColor]
topBgView.colors = [UIColor.colorFAFCFE().cgColor, UIColor.colorCED6FA().cgColor] iconImageView.image = UIImage(named: "vip_icon_04")
typeIconImageView.image = UIImage(named: "vip_icon_08")
desLabel.textColor = .colorFFFFFF() desLabel.textColor = .colorFFFFFF()
iconImageView.image = UIImage(named: "vip_icon_04") typeLabel.textColor = .color005786()
typeLabel.textColor = .color020926() moneyLabel.textColor = typeLabel.textColor
typeIconImageView.image = UIImage(named: "vip_icon_08") tipLabel.textColor = .color020926()
default: default:
break break
} }
typeVipLabel.textColor = typeLabel.textColor
durationLabel.textColor = moneyLabel.textColor
currencyLabel.textColor = typeLabel.textColor updateLayout()
moneyLabel.textColor = typeLabel.textColor
tipLabel.textColor = typeLabel.textColor
} }
} }
//MARK: UI //MARK: UI
private lazy var downBgView: SPGradientView = { private lazy var bgView: UIImageView = {
let view = SPGradientView() let imageView = UIImageView()
view.locations = [0, 1] return imageView
view.startPoint = .init(x: 0, y: 0.5)
view.endPoint = .init(x: 1, y: 0.5)
view.layer.cornerRadius = 12
view.layer.masksToBounds = true
return view
}()
private lazy var topBgView: SPGradientView = {
let view = SPGradientView()
view.locations = [0, 1]
view.startPoint = .init(x: 0, y: 0.5)
view.endPoint = .init(x: 1, y: 0.5)
view.layer.cornerRadius = 11
view.layer.masksToBounds = true
return view
}() }()
private lazy var vipImageView: UIImageView = { private lazy var vipImageView: UIImageView = {
@ -119,27 +119,35 @@ class SPMemberRechargeCell: SPCollectionViewCell {
return label return label
}() }()
private lazy var typeVipLabel: UILabel = {
let string = NSMutableAttributedString(string: "VIP")
string.font = .fontBold(ofSize: 13).withBoldItalic()
let label = UILabel()
label.attributedText = string
return label
}()
private lazy var typeIconImageView: UIImageView = { private lazy var typeIconImageView: UIImageView = {
let imageView = UIImageView() let imageView = UIImageView()
imageView.isHidden = true imageView.isHidden = true
return imageView return imageView
}() }()
private lazy var currencyLabel: UILabel = {
let label = UILabel()
label.font = .fontBold(ofSize: 32)
return label
}()
private lazy var moneyLabel: UILabel = { private lazy var moneyLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontBold(ofSize: 32) label.font = .fontBold(ofSize: 32)
return label return label
}() }()
private lazy var durationLabel: UILabel = {
let label = UILabel()
return label
}()
private lazy var tipLabel: UILabel = { private lazy var tipLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontRegular(ofSize: 11) label.font = .fontRegular(ofSize: 10)
label.text = "movia_buy_menber_tip".localized label.text = "movia_buy_menber_tip".localized
return label return label
}() }()
@ -150,7 +158,7 @@ class SPMemberRechargeCell: SPCollectionViewCell {
view.locations = [0, 0.5, 1] view.locations = [0, 0.5, 1]
view.startPoint = .init(x: 0, y: 0.5) view.startPoint = .init(x: 0, y: 0.5)
view.endPoint = .init(x: 1, y: 0.5) view.endPoint = .init(x: 1, y: 0.5)
view.addRadius(topLeft: 0, topRight: 0, bottomLeft: 11, bottomRight: 0) view.addRadius(topLeft: 0, topRight: 8, bottomLeft: 11, bottomRight: 0)
return view return view
}() }()
@ -176,32 +184,82 @@ class SPMemberRechargeCell: SPCollectionViewCell {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
private func updateLayout() {
if model?.vip_type_key == .year {
desLabel.font = .fontRegular(ofSize: 12)
typeLabel.font = .fontMedium(ofSize: 16)
durationLabel.font = .fontRegular(ofSize: 14)
vipImageView.snp.updateConstraints { make in
make.right.equalToSuperview().offset(0)
}
typeLabel.snp.updateConstraints { make in
make.top.equalToSuperview().offset(12)
}
moneyLabel.snp.updateConstraints { make in
make.top.equalToSuperview().offset(39)
}
tipLabel.snp.updateConstraints { make in
make.top.equalTo(moneyLabel.snp.bottom).offset(6)
}
} else {
desLabel.font = .fontRegular(ofSize: 10)
typeLabel.font = .fontMedium(ofSize: 12)
durationLabel.font = .fontRegular(ofSize: 12)
vipImageView.snp.updateConstraints { make in
make.right.equalToSuperview().offset(-11)
}
typeLabel.snp.updateConstraints { make in
make.top.equalToSuperview().offset(8)
}
moneyLabel.snp.updateConstraints { make in
make.top.equalToSuperview().offset(26)
}
tipLabel.snp.updateConstraints { make in
make.top.equalTo(moneyLabel.snp.bottom).offset(0)
}
}
}
} }
extension SPMemberRechargeCell { extension SPMemberRechargeCell {
private func _setupUI() { private func _setupUI() {
contentView.addSubview(downBgView) contentView.addSubview(bgView)
downBgView.addSubview(iconImageView) bgView.addSubview(iconImageView)
downBgView.addSubview(desLabel) bgView.addSubview(desLabel)
contentView.addSubview(topBgView) bgView.addSubview(vipImageView)
topBgView.addSubview(vipImageView) bgView.addSubview(typeLabel)
topBgView.addSubview(typeLabel) bgView.addSubview(typeVipLabel)
topBgView.addSubview(typeIconImageView) bgView.addSubview(typeIconImageView)
topBgView.addSubview(currencyLabel) bgView.addSubview(moneyLabel)
topBgView.addSubview(moneyLabel) bgView.addSubview(durationLabel)
topBgView.addSubview(tipLabel) bgView.addSubview(tipLabel)
topBgView.addSubview(markBgView) bgView.addSubview(markBgView)
markBgView.addSubview(sendCoinLabel) markBgView.addSubview(sendCoinLabel)
markBgView.addSubview(coinImageView) markBgView.addSubview(coinImageView)
downBgView.snp.makeConstraints { make in bgView.snp.makeConstraints { make in
make.edges.equalToSuperview() make.edges.equalToSuperview()
} }
vipImageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-11)
}
iconImageView.snp.makeConstraints { make in iconImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(17) make.left.equalToSuperview().offset(16)
make.bottom.equalToSuperview().offset(-7) make.bottom.equalToSuperview().offset(-7)
} }
@ -210,21 +268,15 @@ extension SPMemberRechargeCell {
make.left.equalTo(iconImageView.snp.right).offset(4) make.left.equalTo(iconImageView.snp.right).offset(4)
} }
topBgView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(1)
make.right.equalToSuperview().offset(-1)
make.top.equalToSuperview().offset(1)
make.bottom.equalToSuperview().offset(-25)
}
vipImageView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().offset(-7)
}
typeLabel.snp.makeConstraints { make in typeLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(kSPMainW(23)) make.left.equalToSuperview().offset(16)
make.top.equalToSuperview().offset(19) make.top.equalToSuperview().offset(8)
}
typeVipLabel.snp.makeConstraints { make in
make.centerY.equalTo(typeLabel)
make.left.equalTo(typeLabel.snp.right).offset(2)
} }
typeIconImageView.snp.makeConstraints { make in typeIconImageView.snp.makeConstraints { make in
@ -232,23 +284,24 @@ extension SPMemberRechargeCell {
make.left.equalTo(typeLabel.snp.right).offset(3) make.left.equalTo(typeLabel.snp.right).offset(3)
} }
currencyLabel.snp.makeConstraints { make in moneyLabel.snp.makeConstraints { make in
make.left.equalTo(typeLabel) make.left.equalTo(typeLabel)
make.top.equalTo(typeLabel.snp.bottom).offset(8) make.top.equalToSuperview().offset(28)
} }
moneyLabel.snp.makeConstraints { make in durationLabel.snp.makeConstraints { make in
make.centerY.equalTo(currencyLabel) make.left.equalTo(moneyLabel.snp.right)
make.left.equalTo(currencyLabel.snp.right).offset(5) make.centerY.equalTo(moneyLabel)
} }
tipLabel.snp.makeConstraints { make in tipLabel.snp.makeConstraints { make in
make.left.equalTo(typeLabel) make.left.equalTo(typeLabel)
make.top.equalTo(moneyLabel.snp.bottom).offset(8) make.top.equalTo(moneyLabel.snp.bottom).offset(4)
} }
markBgView.snp.makeConstraints { make in markBgView.snp.makeConstraints { make in
make.top.right.equalToSuperview() make.top.equalToSuperview().offset(1)
make.right.equalToSuperview().offset(-1)
make.height.equalTo(18) make.height.equalTo(18)
} }

View File

@ -10,10 +10,8 @@ import UIKit
class SPMemberRechargeView: UIView { class SPMemberRechargeView: UIView {
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
let count = CGFloat(dataArr?.count ?? 0) let height = 30 + self.collectionView.contentSize.height
return CGSize(width: kSPScreenWidth, height: height + 1)
let height = 32 + count * collectionViewLayout.itemSize.height + (count - 1) * collectionViewLayout.minimumInteritemSpacing
return CGSize(width: kSPScreenWidth, height: height)
} }
/// ///
@ -25,18 +23,26 @@ class SPMemberRechargeView: UIView {
var videoId: String? var videoId: String?
//MARK: UI //MARK: UI
private lazy var titleBgView: UIView = {
let view = UIView()
view.backgroundColor = .colorFFFFFF(alpha: 0.1)
view.layer.cornerRadius = 11.5
view.layer.masksToBounds = true
return view
}()
private lazy var titleLabel: UILabel = { private lazy var titleLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.font = .fontRegular(ofSize: 14) label.font = .fontRegular(ofSize: 10)
label.textColor = .colorFFFFFF(alpha: 0.7) label.textColor = .colorFFFFFF()
label.text = "movia_membership".localized label.text = "movia_member_tip_text".localized
return label return label
}() }()
private lazy var collectionViewLayout: UICollectionViewFlowLayout = { private lazy var collectionViewLayout: WaterfallMutiSectionFlowLayout = {
let layout = UICollectionViewFlowLayout() let layout = WaterfallMutiSectionFlowLayout()
layout.delegate = self
layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16) layout.sectionInset = .init(top: 0, left: 16, bottom: 0, right: 16)
layout.itemSize = CGSize(width: kSPScreenWidth - 32, height: 152)
layout.minimumInteritemSpacing = 10 layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10 layout.minimumLineSpacing = 10
return layout return layout
@ -65,13 +71,13 @@ class SPMemberRechargeView: UIView {
func setDataArr(dataArr: [SPPayTemplateItem]?) { func setDataArr(dataArr: [SPPayTemplateItem]?) {
self.dataArr = dataArr self.dataArr = dataArr
// dataArr?.forEach({ UIView.performWithoutAnimation { [weak self] in
// if $0.vip_type_key == .quarter { self?.collectionView.reloadData()
// self.dataArr?.append($0) }
// }
// }) self.collectionView.performBatchUpdates(nil) { [weak self] _ in
self.collectionView.reloadData() self?.invalidateIntrinsicContentSize()
self.invalidateIntrinsicContentSize() }
} }
} }
@ -79,18 +85,26 @@ class SPMemberRechargeView: UIView {
extension SPMemberRechargeView { extension SPMemberRechargeView {
private func _setupUI() { private func _setupUI() {
addSubview(titleLabel) addSubview(titleBgView)
titleBgView.addSubview(titleLabel)
addSubview(collectionView) addSubview(collectionView)
titleLabel.snp.makeConstraints { make in titleBgView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(16) make.left.equalToSuperview().offset(15)
make.height.equalTo(20) make.centerX.equalToSuperview()
make.top.equalToSuperview() make.top.equalToSuperview()
make.height.equalTo(23)
}
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(17)
make.centerY.equalToSuperview()
make.right.lessThanOrEqualToSuperview().offset(-17)
} }
collectionView.snp.makeConstraints { make in collectionView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview() make.left.right.bottom.equalToSuperview()
make.top.equalToSuperview().offset(32) make.top.equalToSuperview().offset(30)
} }
} }
@ -119,3 +133,30 @@ extension SPMemberRechargeView: UICollectionViewDelegate, UICollectionViewDataSo
} }
} }
//MARK: -------------- WaterfallMutiSectionDelegate --------------
extension SPMemberRechargeView: WaterfallMutiSectionDelegate {
func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int {
return 1
}
func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat {
let model = dataArr?[indexPath.row]
if model?.vip_type_key == .year {
return 129
} else {
return 102
}
}
func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat {
return 9
}
func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets {
return .init(top: 0, left: 15, bottom: 0, right: 15)
}
}

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Frame 1912056652@2x.png", "filename" : "Frame 1912057056@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Frame 1912056652@3x.png", "filename" : "Frame 1912057056@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Frame 1912056653@2x.png", "filename" : "image 21@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Frame 1912056653@3x.png", "filename" : "image 21@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "image 21@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "image 21@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057037@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057037@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "花瓣素材_emoji热门HOT火焰图形贴纸_193856377 1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "花瓣素材_emoji热门HOT火焰图形贴纸_193856377 1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "角标@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "角标@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "角标@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "角标@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Subtract@2x.png", "filename" : "Frame 1912057044@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Subtract@3x.png", "filename" : "Frame 1912057044@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 716 B

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Subtract@2x.png", "filename" : "Frame 1912057042@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Subtract@3x.png", "filename" : "Frame 1912057042@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 467 B

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057045@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057045@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

View File

@ -0,0 +1,20 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Rectangle 52@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Rectangle 52@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Rectangle 52@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Rectangle 52@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Frame 1912056629@2x.png", "filename" : "选中@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Frame 1912056629@3x.png", "filename" : "选中@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "Frame 1912056630@2x.png", "filename" : "默认@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "Frame 1912056630@3x.png", "filename" : "默认@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057028@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057028@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057027@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057027@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057025@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057025@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame 1912057026@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame 1912057026@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "分组 3@2x.png", "filename" : "Frame 1912057023 1@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "分组 3@3x.png", "filename" : "Frame 1912057023 1@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

View File

@ -5,12 +5,12 @@
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "分组 2@2x.png", "filename" : "Frame 1912057023 1@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "分组 2@3x.png", "filename" : "Frame 1912057023 1@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }

Some files were not shown because too many files have changed in this diff Show More