diff --git a/XSeri.xcodeproj/project.pbxproj b/XSeri.xcodeproj/project.pbxproj index 62ad8af..f0eb651 100644 --- a/XSeri.xcodeproj/project.pbxproj +++ b/XSeri.xcodeproj/project.pbxproj @@ -135,6 +135,7 @@ F3B312BD2F30B0A10093B180 /* XSSearchSuggestionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B82F30B0A10093B180 /* XSSearchSuggestionCell.swift */; }; F3B312BE2F30B0A10093B180 /* XSSearchResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B92F30B0A10093B180 /* XSSearchResultCell.swift */; }; F3B312BF2F30B2000093B180 /* XSSearchHistoryHotView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3B312B52F30B2000093B180 /* XSSearchHistoryHotView.swift */; }; + F3F683ED2F56C380008AF250 /* XSHomeHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3F683EC2F56C380008AF250 /* XSHomeHistoryView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -270,6 +271,7 @@ F3B312B62F319CBE0093B180 /* XSEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSEmpty.swift; sourceTree = ""; }; F3B312B82F30B0A10093B180 /* XSSearchSuggestionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSSearchSuggestionCell.swift; sourceTree = ""; }; F3B312B92F30B0A10093B180 /* XSSearchResultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSSearchResultCell.swift; sourceTree = ""; }; + F3F683EC2F56C380008AF250 /* XSHomeHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XSHomeHistoryView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -496,6 +498,7 @@ F3B312AC2F30ACF60093B180 /* XSSearchTagsView.swift */, F3B312B82F30B0A10093B180 /* XSSearchSuggestionCell.swift */, F3B312B92F30B0A10093B180 /* XSSearchResultCell.swift */, + F3F683EC2F56C380008AF250 /* XSHomeHistoryView.swift */, ); path = View; sourceTree = ""; @@ -967,6 +970,7 @@ F35547FA2F4E9F0A006F28CD /* XSView.swift in Sources */, F347D2BA2F03BABC00786648 /* XSHomeData.swift in Sources */, F3585C4B2F14FD1000EEC469 /* XSShortDetailPlayerControlView.swift in Sources */, + F3F683ED2F56C380008AF250 /* XSHomeHistoryView.swift in Sources */, F347D2A12F03A84300786648 /* XSScreen.swift in Sources */, F35548062F4FD6DA006F28CD /* XSMinePlayHistoryView.swift in Sources */, F347D2992F03730E00786648 /* XSTabBarController.swift in Sources */, diff --git a/XSeri/Base/Extension/UIView+XS.swift b/XSeri/Base/Extension/UIView+XS.swift index 3d72ac9..c7c12e1 100644 --- a/XSeri/Base/Extension/UIView+XS.swift +++ b/XSeri/Base/Extension/UIView+XS.swift @@ -22,10 +22,10 @@ extension UIView { xs_layoutSubviews() xs_updateRoundedCorner() -// -// if let effectView = effectView, effectView.frame != self.bounds { -// effectView.frame = self.bounds -// } + + if let effectView = effectView, effectView.frame != self.bounds { + effectView.frame = self.bounds + } } } @@ -63,3 +63,32 @@ extension UIView { } } +//MARK: -------------- 模糊效果 -------------- +extension UIView { + private var effectView: UIVisualEffectView? { + get { + return objc_getAssociatedObject(self, &AssociatedKeys.xs_effect) as? UIVisualEffectView + } + set { + objc_setAssociatedObject(self, &AssociatedKeys.xs_effect, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + ///添加模糊效果 + func xs_addEffectView(style: UIBlurEffect.Style = .dark) { + if self.effectView == nil { + let blur = UIBlurEffect(style: style) + let effectView = UIVisualEffectView(effect: blur) + effectView.isUserInteractionEnabled = false + self.addSubview(effectView) + self.sendSubviewToBack(effectView) + + self.effectView = effectView + } + } + ///删除模糊效果 + func xs_removeEffectView() { + self.effectView?.removeFromSuperview() + self.effectView = nil + } +} diff --git a/XSeri/Class/Home/Controller/XSHomeViewController.swift b/XSeri/Class/Home/Controller/XSHomeViewController.swift index 6828e5e..4abc69c 100644 --- a/XSeri/Class/Home/Controller/XSHomeViewController.swift +++ b/XSeri/Class/Home/Controller/XSHomeViewController.swift @@ -66,10 +66,23 @@ class XSHomeViewController: XSViewController { private lazy var listContainerView: JXSegmentedListContainerView = { return JXSegmentedListContainerView(dataSource: self) }() + + private lazy var historyView: XSHomeHistoryView = { + let view = XSHomeHistoryView() + view.isHidden = true + return view + }() + + deinit { + NotificationCenter.default.removeObserver(self) + } // MARK: - Life Cycle override func viewDidLoad() { super.viewDidLoad() + NotificationCenter.default.addObserver(self, selector: #selector(loginStateDidChangeNotification), name: XSLoginManager.loginStateDidChangeNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: XSNetworkMonitorManager.networkStatusDidChangeNotification, object: nil) + xs_setupUI() } @@ -77,6 +90,27 @@ class XSHomeViewController: XSViewController { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(true, animated: true) } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + Task { + await requestVideoHistory() + } + + } + + @objc private func networkStatusDidChangeNotification() { + Task { + await requestVideoHistory() + } + } + + @objc private func loginStateDidChangeNotification() { + self.historyView.isHidden = true + Task { + await requestVideoHistory() + } + } } // MARK: - UI Setup @@ -86,6 +120,7 @@ extension XSHomeViewController { view.addSubview(listContainerView) view.addSubview(searchButton) view.addSubview(segmentedView) + view.addSubview(historyView) searchButton.snp.makeConstraints { make in make.left.equalToSuperview().offset(16) @@ -109,6 +144,12 @@ extension XSHomeViewController { // make.top.equalTo(segmentedView.snp.bottom).offset(8) } + historyView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(8) + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-(XSScreen.customTabBarHeight + 5)) + } + } } @@ -129,3 +170,18 @@ extension XSHomeViewController: JXSegmentedListContainerViewDataSource { return viewControllers[index] } } + +extension XSHomeViewController { + + private func requestVideoHistory() async { + guard let list = await XSVideoAPI.requestPlayHistorys(page: 1, pageSize: 1) else { return } + + guard let model = list.first else { + self.historyView.isHidden = true + return + } + self.historyView.isHidden = false + self.historyView.model = model + } + +} diff --git a/XSeri/Class/Home/View/XSHomeHistoryView.swift b/XSeri/Class/Home/View/XSHomeHistoryView.swift new file mode 100644 index 0000000..2d284ce --- /dev/null +++ b/XSeri/Class/Home/View/XSHomeHistoryView.swift @@ -0,0 +1,152 @@ +// +// XSHomeHistoryView.swift +// XSeri +// +// Created by 长沙鸿瑶 on 2026/3/3. +// + +import UIKit +import SnapKit + +class XSHomeHistoryView: UIView { + + override var intrinsicContentSize: CGSize { + return .init(width: XSScreen.width, height: 60) + } + + var model: XSShortModel? { + didSet { + coverImageView.xs_setImage(model?.image_url) + nameLabel.text = model?.name + epLabel.text = "Last Watched:Ep.\(model?.current_episode ?? "")" + } + } + + private lazy var borderImage = UIImage(named: "gradient_color_image_02") + + private lazy var coverImageView: XSImageView = { + let imageView = XSImageView() + imageView.layer.cornerRadius = 4 + return imageView + }() + + private lazy var nameLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium) + label.textColor = .FFDAA_4 + return label + }() + + private lazy var epLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .white.withAlphaComponent(0.8) + return label + }() + + private lazy var continueButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.background.backgroundColor = .FFDAA_4.withAlphaComponent(0.15) + configuration.background.cornerRadius = 13.5 + configuration.contentInsets = .init(top: 0, leading: 9, bottom: 0, trailing: 9) + configuration.attributedTitle = AttributedString("Continue".localized, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 12, weight: .medium), + .foregroundColor : UIColor.white + ])) + + let button = UIButton(configuration: configuration) + button.isUserInteractionEnabled = false + return button + }() + + private lazy var closeButton: UIButton = { + let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in + guard let self = self else { return } + self.isHidden = true + })) + button.setImage(UIImage(named: "close_icon_01"), for: .normal) + return button + }() + + + + override init(frame: CGRect) { + super.init(frame: frame) + + self.layer.cornerRadius = 12 + self.layer.masksToBounds = true + self.layer.borderColor = UIColor.FFDAA_4.cgColor + self.layer.borderWidth = 1 + self.backgroundColor = ._352_D_25.withAlphaComponent(0.8) + + self.xs_addEffectView() + + + let tap = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture)) + self.addGestureRecognizer(tap) + + + xs_setupUI() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + self.borderImage = self.borderImage?.xs_resized(to: self.bounds.size) + + self.layer.borderColor = UIColor.init(patternImage: self.borderImage!).cgColor + } + + @objc private func handleTapGesture() { + guard let id = self.model?.short_play_id else { return } + let vc = XSShortDetailViewController() + vc.shortId = id + self.viewController?.navigationController?.pushViewController(vc, animated: true) + } + +} + +extension XSHomeHistoryView { + + private func xs_setupUI() { + addSubview(coverImageView) + addSubview(continueButton) + addSubview(nameLabel) + addSubview(epLabel) + addSubview(closeButton) + + coverImageView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(6) + make.centerY.equalToSuperview() + make.width.equalTo(36) + make.height.equalTo(48) + } + + continueButton.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-24) + make.height.equalTo(27) + } + + nameLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(13) + make.left.equalTo(coverImageView.snp.right).offset(12) + make.right.lessThanOrEqualTo(continueButton.snp.left).offset(-20) + } + + epLabel.snp.makeConstraints { make in + make.left.equalTo(nameLabel) + make.bottom.equalToSuperview().offset(-13) + make.right.lessThanOrEqualTo(continueButton.snp.left).offset(-20) + } + + closeButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-6) + make.top.equalToSuperview().offset(6) + } + } + +} diff --git a/XSeri/Source/Assets.xcassets/Color/#352D25.colorset/Contents.json b/XSeri/Source/Assets.xcassets/Color/#352D25.colorset/Contents.json new file mode 100644 index 0000000..2fc59e6 --- /dev/null +++ b/XSeri/Source/Assets.xcassets/Color/#352D25.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x25", + "green" : "0x2D", + "red" : "0x35" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/Contents.json b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/Contents.json new file mode 100644 index 0000000..76122b0 --- /dev/null +++ b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "关闭-按钮-icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "关闭-按钮-icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@2x.png b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@2x.png new file mode 100644 index 0000000..1a443ba Binary files /dev/null and b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@2x.png differ diff --git a/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@3x.png b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@3x.png new file mode 100644 index 0000000..10e3af3 Binary files /dev/null and b/XSeri/Source/Assets.xcassets/Image/icon/close_icon_01.imageset/关闭-按钮-icon@3x.png differ diff --git a/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Contents.json b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Contents.json new file mode 100644 index 0000000..8d8ac24 --- /dev/null +++ b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Rectangle 346272051@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Rectangle 346272051@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@2x.png b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@2x.png new file mode 100644 index 0000000..06ea4f0 Binary files /dev/null and b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@2x.png differ diff --git a/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@3x.png b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@3x.png new file mode 100644 index 0000000..6bca653 Binary files /dev/null and b/XSeri/Source/Assets.xcassets/Image/icon/gradient_color_image_02.imageset/Rectangle 346272051@3x.png differ diff --git a/XSeri/Source/en.lproj/Localizable.strings b/XSeri/Source/en.lproj/Localizable.strings index c62901f..a0b33bd 100644 --- a/XSeri/Source/en.lproj/Localizable.strings +++ b/XSeri/Source/en.lproj/Localizable.strings @@ -38,6 +38,7 @@ "feedback" = "Feedback"; "feedback_detail" = "Feedback Details"; "account_deletion" = "Account Deletion"; +"Continue" = "Continue"; "empty_title_01" = "We couldn’t find any dramas";