完善素材管理 UI 交互并修复列表解析与时间选择。
MaterialItem 兼容 Android 缺失字段默认值,优化素材详情/列表/标签布局与上下架开关交互,修复个人空间时间选择器初始值。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -49,7 +49,7 @@ final class MaterialDetailViewController: BaseViewController {
|
||||
override func setupUI() {
|
||||
view.backgroundColor = UIColor(hex: 0xF4F4F4)
|
||||
contentStack.axis = .vertical
|
||||
contentStack.spacing = 12
|
||||
contentStack.spacing = 0
|
||||
scrollView.backgroundColor = UIColor(hex: 0xF4F4F4)
|
||||
bottomBar.backgroundColor = .white
|
||||
|
||||
@ -60,8 +60,11 @@ final class MaterialDetailViewController: BaseViewController {
|
||||
scrollView.addSubview(contentStack)
|
||||
contentStack.addArrangedSubview(carouselView)
|
||||
contentStack.addArrangedSubview(infoSection)
|
||||
contentStack.addArrangedSubview(makeVerticalSpacer(height: 12))
|
||||
contentStack.addArrangedSubview(uploaderSection)
|
||||
contentStack.addArrangedSubview(makeVerticalSpacer(height: 12))
|
||||
contentStack.addArrangedSubview(reviewSection)
|
||||
contentStack.addArrangedSubview(makeVerticalSpacer(height: 16))
|
||||
view.addSubview(bottomBar)
|
||||
bottomBar.addSubview(deleteButton)
|
||||
bottomBar.addSubview(editButton)
|
||||
@ -131,6 +134,15 @@ final class MaterialDetailViewController: BaseViewController {
|
||||
button.layer.cornerRadius = 8
|
||||
}
|
||||
|
||||
private func makeVerticalSpacer(height: CGFloat) -> UIView {
|
||||
let spacer = UIView()
|
||||
spacer.backgroundColor = .clear
|
||||
spacer.snp.makeConstraints { make in
|
||||
make.height.equalTo(height)
|
||||
}
|
||||
return spacer
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func applyViewModel() {
|
||||
if (viewModel.isLoading || viewModel.isDeleting) && viewModel.detail == nil {
|
||||
@ -470,6 +482,7 @@ private final class MaterialDetailInfoSection: UIView {
|
||||
private let downloadStat = MaterialDetailStatView(iconName: "material_ic_download_count")
|
||||
private let likeStat = MaterialDetailStatView(iconName: "sample_ic_like_count")
|
||||
private let collectStat = MaterialDetailStatView(iconName: "sample_ic_collect_count")
|
||||
private var statsTopConstraint: Constraint?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
@ -483,7 +496,7 @@ private final class MaterialDetailInfoSection: UIView {
|
||||
listingBadge.textAlignment = .center
|
||||
tagStack.axis = .horizontal
|
||||
tagStack.spacing = 8
|
||||
tagStack.alignment = .leading
|
||||
tagStack.alignment = .center
|
||||
statsStack.axis = .horizontal
|
||||
statsStack.spacing = 16
|
||||
[downloadStat, likeStat, collectStat].forEach(statsStack.addArrangedSubview)
|
||||
@ -507,7 +520,7 @@ private final class MaterialDetailInfoSection: UIView {
|
||||
make.leading.trailing.equalToSuperview().inset(16)
|
||||
}
|
||||
statsStack.snp.makeConstraints { make in
|
||||
make.top.equalTo(tagStack.snp.bottom).offset(12)
|
||||
statsTopConstraint = make.top.equalTo(tagStack.snp.bottom).offset(12).constraint
|
||||
make.leading.equalToSuperview().offset(16)
|
||||
make.trailing.lessThanOrEqualToSuperview().inset(16)
|
||||
make.bottom.equalToSuperview().inset(16)
|
||||
@ -527,14 +540,20 @@ private final class MaterialDetailInfoSection: UIView {
|
||||
listingBadge.textColor = color
|
||||
listingBadge.backgroundColor = color.withAlphaComponent(0.1)
|
||||
tagStack.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||
(detail.materialTag ?? []).forEach { tagStack.addArrangedSubview(makeTag($0.name)) }
|
||||
let tags = detail.materialTag ?? []
|
||||
tags.forEach { tagStack.addArrangedSubview(makeTag($0.name)) }
|
||||
if !tags.isEmpty {
|
||||
tagStack.addArrangedSubview(UIView())
|
||||
}
|
||||
tagStack.isHidden = tags.isEmpty
|
||||
statsTopConstraint?.update(offset: tags.isEmpty ? 0 : 12)
|
||||
downloadStat.setCount(detail.downloadCount)
|
||||
likeStat.setCount(detail.likesCount)
|
||||
collectStat.setCount(detail.collectCount)
|
||||
}
|
||||
|
||||
private func makeTag(_ title: String) -> UILabel {
|
||||
let label = UILabel()
|
||||
let label = MaterialDetailTagLabel(horizontalInset: 6)
|
||||
label.text = title
|
||||
label.font = .systemFont(ofSize: 12)
|
||||
label.textColor = AppColor.primary
|
||||
@ -542,9 +561,10 @@ private final class MaterialDetailInfoSection: UIView {
|
||||
label.backgroundColor = UIColor(hex: 0xEFF6FF)
|
||||
label.layer.cornerRadius = 4
|
||||
label.clipsToBounds = true
|
||||
label.setContentHuggingPriority(.required, for: .horizontal)
|
||||
label.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
label.snp.makeConstraints { make in
|
||||
make.height.equalTo(22)
|
||||
make.width.greaterThanOrEqualTo(40)
|
||||
}
|
||||
return label
|
||||
}
|
||||
@ -632,7 +652,7 @@ private final class MaterialDetailUploaderSection: UIView {
|
||||
}
|
||||
|
||||
private func makeTag(_ title: String) -> UILabel {
|
||||
let label = UILabel()
|
||||
let label = MaterialDetailTagLabel(horizontalInset: 6)
|
||||
label.text = title
|
||||
label.textColor = .white
|
||||
label.font = .systemFont(ofSize: 8)
|
||||
@ -642,12 +662,35 @@ private final class MaterialDetailUploaderSection: UIView {
|
||||
label.clipsToBounds = true
|
||||
label.snp.makeConstraints { make in
|
||||
make.height.equalTo(16)
|
||||
make.width.greaterThanOrEqualTo(44)
|
||||
}
|
||||
return label
|
||||
}
|
||||
}
|
||||
|
||||
/// 为详情页标签文本提供固定水平内边距,使背景宽度随内容自适应。
|
||||
private final class MaterialDetailTagLabel: UILabel {
|
||||
private let horizontalInset: CGFloat
|
||||
|
||||
init(horizontalInset: CGFloat) {
|
||||
self.horizontalInset = horizontalInset
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func drawText(in rect: CGRect) {
|
||||
super.drawText(in: rect.insetBy(dx: horizontalInset, dy: 0))
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
let size = super.intrinsicContentSize
|
||||
return CGSize(width: size.width + horizontalInset * 2, height: size.height)
|
||||
}
|
||||
}
|
||||
|
||||
/// 素材审核信息区。
|
||||
/// 素材详情的审核信息区块。
|
||||
private final class MaterialDetailReviewSection: UIView {
|
||||
|
||||
Reference in New Issue
Block a user