fix: compose scene layout issue when presenting reply post

This commit is contained in:
CMK 2021-04-19 17:50:58 +08:00
parent e3c6aaf64e
commit f7aa5c123d
7 changed files with 59 additions and 27 deletions

View File

@ -81,10 +81,10 @@ extension ComposeStatusSection {
managedObjectContext.perform { managedObjectContext.perform {
guard let replyToStatusObjectID = replyToStatusObjectID, guard let replyToStatusObjectID = replyToStatusObjectID,
let replyTo = managedObjectContext.object(with: replyToStatusObjectID) as? Status else { let replyTo = managedObjectContext.object(with: replyToStatusObjectID) as? Status else {
cell.statusView.headerContainerStackView.isHidden = true cell.statusView.headerContainerView.isHidden = true
return return
} }
cell.statusView.headerContainerStackView.isHidden = false cell.statusView.headerContainerView.isHidden = false
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage) cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage)
cell.statusView.headerInfoLabel.text = L10n.Scene.Compose.replyingToUser(replyTo.author.displayNameWithFallback) cell.statusView.headerInfoLabel.text = L10n.Scene.Compose.replyingToUser(replyTo.author.displayNameWithFallback)
} }

View File

@ -525,7 +525,7 @@ extension StatusSection {
status: Status status: Status
) { ) {
if status.reblog != nil { if status.reblog != nil {
cell.statusView.headerContainerStackView.isHidden = false cell.statusView.headerContainerView.isHidden = false
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage) cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
cell.statusView.headerInfoLabel.text = { cell.statusView.headerInfoLabel.text = {
let author = status.author let author = status.author
@ -533,7 +533,7 @@ extension StatusSection {
return L10n.Common.Controls.Status.userReblogged(name) return L10n.Common.Controls.Status.userReblogged(name)
}() }()
} else if status.inReplyToID != nil { } else if status.inReplyToID != nil {
cell.statusView.headerContainerStackView.isHidden = false cell.statusView.headerContainerView.isHidden = false
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage) cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage)
cell.statusView.headerInfoLabel.text = { cell.statusView.headerInfoLabel.text = {
guard let replyTo = status.replyTo else { guard let replyTo = status.replyTo else {
@ -544,7 +544,7 @@ extension StatusSection {
return L10n.Common.Controls.Status.userRepliedTo(name) return L10n.Common.Controls.Status.userRepliedTo(name)
}() }()
} else { } else {
cell.statusView.headerContainerStackView.isHidden = true cell.statusView.headerContainerView.isHidden = true
} }
} }

View File

@ -12,4 +12,9 @@ extension NSLayoutConstraint {
self.priority = priority self.priority = priority
return self return self
} }
func identifier(_ identifier: String?) -> Self {
self.identifier = identifier
return self
}
} }

View File

@ -45,16 +45,16 @@ extension ComposeRepliedToStatusContentCollectionViewCell {
private func _init() { private func _init() {
backgroundColor = .clear backgroundColor = .clear
statusView.actionToolbarContainer.isHidden = true
statusView.translatesAutoresizingMaskIntoConstraints = false statusView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(statusView) contentView.addSubview(statusView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20), statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20).identifier("statusView.top to ComposeRepliedToStatusContentCollectionViewCell.contentView.top"),
statusView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), statusView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: statusView.trailingAnchor), contentView.readableContentGuide.trailingAnchor.constraint(equalTo: statusView.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10), contentView.bottomAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10).identifier("ComposeRepliedToStatusContentCollectionViewCell.contentView.bottom to statusView.bottom"),
]) ])
statusView.actionToolbarContainer.isHidden = true
} }
} }

View File

@ -182,7 +182,7 @@ extension ComposeViewController {
) )
// respond scrollView overlap change // respond scrollView overlap change
view.layoutIfNeeded() //view.layoutIfNeeded()
// update layout when keyboard show/dismiss // update layout when keyboard show/dismiss
Publishers.CombineLatest4( Publishers.CombineLatest4(
KeyboardResponderService.shared.isShow.eraseToAnyPublisher(), KeyboardResponderService.shared.isShow.eraseToAnyPublisher(),
@ -210,7 +210,9 @@ extension ComposeViewController {
self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin self.collectionView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin
UIView.animate(withDuration: 0.3) { UIView.animate(withDuration: 0.3) {
self.composeToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom self.composeToolbarViewBottomLayoutConstraint.constant = self.view.safeAreaInsets.bottom
self.view.layoutIfNeeded() if self.view.window != nil {
self.view.layoutIfNeeded()
}
} }
self.updateKeyboardBackground(isKeyboardDisplay: isShow) self.updateKeyboardBackground(isKeyboardDisplay: isShow)
return return

View File

@ -5,6 +5,7 @@
// Created by xiaojian sun on 2021/3/10. // Created by xiaojian sun on 2021/3/10.
// //
import os.log
import AVKit import AVKit
import UIKit import UIKit
@ -93,6 +94,7 @@ extension PlayerContainerView {
// MARK: - ContentWarningOverlayViewDelegate // MARK: - ContentWarningOverlayViewDelegate
extension PlayerContainerView: ContentWarningOverlayViewDelegate { extension PlayerContainerView: ContentWarningOverlayViewDelegate {
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) { func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.playerContainerView(self, contentWarningOverlayViewDidPressed: contentWarningOverlayView) delegate?.playerContainerView(self, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
} }
} }

View File

@ -29,6 +29,16 @@ final class StatusView: UIView {
static let avatarImageCornerRadius: CGFloat = 4 static let avatarImageCornerRadius: CGFloat = 4
static let avatarToLabelSpacing: CGFloat = 5 static let avatarToLabelSpacing: CGFloat = 5
static let contentWarningBlurRadius: CGFloat = 12 static let contentWarningBlurRadius: CGFloat = 12
static let containerStackViewSpacing: CGFloat = 10
weak var delegate: StatusViewDelegate?
private var needsDrawContentOverlay = false
var pollTableViewDataSource: UITableViewDiffableDataSource<PollSection, PollItem>?
var pollTableViewHeightLaoutConstraint: NSLayoutConstraint!
let containerStackView = UIStackView()
let headerContainerView = UIView()
let authorContainerView = UIView()
static let reblogIconImage: UIImage = { static let reblogIconImage: UIImage = {
let font = UIFont.systemFont(ofSize: 13, weight: .medium) let font = UIFont.systemFont(ofSize: 13, weight: .medium)
@ -53,13 +63,6 @@ final class StatusView: UIView {
return attributedString return attributedString
} }
weak var delegate: StatusViewDelegate?
private var needsDrawContentOverlay = false
var pollTableViewDataSource: UITableViewDiffableDataSource<PollSection, PollItem>?
var pollTableViewHeightLaoutConstraint: NSLayoutConstraint!
let headerContainerStackView = UIStackView()
let headerIconLabel: UILabel = { let headerIconLabel: UILabel = {
let label = UILabel() let label = UILabel()
label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage) label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
@ -221,9 +224,9 @@ extension StatusView {
func _init() { func _init() {
// container: [reblog | author | status | action toolbar] // container: [reblog | author | status | action toolbar]
let containerStackView = UIStackView() // note: do not set spacing for nested stackView to avoid SDK layout conflict issue
containerStackView.axis = .vertical containerStackView.axis = .vertical
containerStackView.spacing = 10 // containerStackView.spacing = 10
containerStackView.translatesAutoresizingMaskIntoConstraints = false containerStackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(containerStackView) addSubview(containerStackView)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
@ -232,17 +235,27 @@ extension StatusView {
trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor), trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor), bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
]) ])
containerStackView.setContentHuggingPriority(.required - 1, for: .vertical)
// header container: [icon | info] // header container: [icon | info]
containerStackView.addArrangedSubview(headerContainerStackView) let headerContainerStackView = UIStackView()
headerContainerStackView.spacing = 4 headerContainerStackView.axis = .horizontal
headerContainerStackView.addArrangedSubview(headerIconLabel) headerContainerStackView.addArrangedSubview(headerIconLabel)
headerContainerStackView.addArrangedSubview(headerInfoLabel) headerContainerStackView.addArrangedSubview(headerInfoLabel)
headerIconLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal) headerIconLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
headerContainerStackView.translatesAutoresizingMaskIntoConstraints = false
headerContainerView.addSubview(headerContainerStackView)
NSLayoutConstraint.activate([
headerContainerStackView.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
headerContainerStackView.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
headerContainerStackView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor),
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
])
containerStackView.addArrangedSubview(headerContainerView)
// author container: [avatar | author meta container | reveal button] // author container: [avatar | author meta container | reveal button]
let authorContainerStackView = UIStackView() let authorContainerStackView = UIStackView()
containerStackView.addArrangedSubview(authorContainerStackView)
authorContainerStackView.axis = .horizontal authorContainerStackView.axis = .horizontal
authorContainerStackView.spacing = StatusView.avatarToLabelSpacing authorContainerStackView.spacing = StatusView.avatarToLabelSpacing
authorContainerStackView.distribution = .fill authorContainerStackView.distribution = .fill
@ -306,6 +319,16 @@ extension StatusView {
authorContainerStackView.addArrangedSubview(revealContentWarningButton) authorContainerStackView.addArrangedSubview(revealContentWarningButton)
revealContentWarningButton.setContentHuggingPriority(.required - 2, for: .horizontal) revealContentWarningButton.setContentHuggingPriority(.required - 2, for: .horizontal)
authorContainerStackView.translatesAutoresizingMaskIntoConstraints = false
authorContainerView.addSubview(authorContainerStackView)
NSLayoutConstraint.activate([
authorContainerStackView.topAnchor.constraint(equalTo: authorContainerView.topAnchor),
authorContainerStackView.leadingAnchor.constraint(equalTo: authorContainerView.leadingAnchor),
authorContainerStackView.trailingAnchor.constraint(equalTo: authorContainerView.trailingAnchor),
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
])
containerStackView.addArrangedSubview(authorContainerView)
// status container: [status | image / video | audio | poll | poll status] (overlay with content warning) // status container: [status | image / video | audio | poll | poll status] (overlay with content warning)
containerStackView.addArrangedSubview(statusContainerStackView) containerStackView.addArrangedSubview(statusContainerStackView)
statusContainerStackView.axis = .vertical statusContainerStackView.axis = .vertical
@ -370,7 +393,7 @@ extension StatusView {
containerStackView.addArrangedSubview(actionToolbarContainer) containerStackView.addArrangedSubview(actionToolbarContainer)
actionToolbarContainer.setContentCompressionResistancePriority(.defaultLow, for: .vertical) actionToolbarContainer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
headerContainerStackView.isHidden = true headerContainerView.isHidden = true
statusMosaicImageViewContainer.isHidden = true statusMosaicImageViewContainer.isHidden = true
pollTableView.isHidden = true pollTableView.isHidden = true
pollStatusStackView.isHidden = true pollStatusStackView.isHidden = true
@ -543,7 +566,7 @@ struct StatusView_Previews: PreviewProvider {
.previewDisplayName("Normal") .previewDisplayName("Normal")
UIViewPreview(width: 375) { UIViewPreview(width: 375) {
let statusView = StatusView() let statusView = StatusView()
statusView.headerContainerStackView.isHidden = false statusView.headerContainerView.isHidden = false
statusView.avatarButton.isHidden = true statusView.avatarButton.isHidden = true
statusView.avatarStackedContainerButton.isHidden = false statusView.avatarStackedContainerButton.isHidden = false
statusView.avatarStackedContainerButton.topLeadingAvatarStackedImageView.configure( statusView.avatarStackedContainerButton.topLeadingAvatarStackedImageView.configure(
@ -570,7 +593,7 @@ struct StatusView_Previews: PreviewProvider {
placeholderImage: avatarFlora placeholderImage: avatarFlora
) )
) )
statusView.headerContainerStackView.isHidden = false statusView.headerContainerView.isHidden = false
let images = MosaicImageView_Previews.images let images = MosaicImageView_Previews.images
let mosaics = statusView.statusMosaicImageViewContainer.setupImageViews(count: 4, maxHeight: 162) let mosaics = statusView.statusMosaicImageViewContainer.setupImageViews(count: 4, maxHeight: 162)
for (i, mosaic) in mosaics.enumerated() { for (i, mosaic) in mosaics.enumerated() {
@ -591,7 +614,7 @@ struct StatusView_Previews: PreviewProvider {
placeholderImage: avatarFlora placeholderImage: avatarFlora
) )
) )
statusView.headerContainerStackView.isHidden = false statusView.headerContainerView.isHidden = false
statusView.setNeedsLayout() statusView.setNeedsLayout()
statusView.layoutIfNeeded() statusView.layoutIfNeeded()
statusView.updateContentWarningDisplay(isHidden: false, animated: false) statusView.updateContentWarningDisplay(isHidden: false, animated: false)