forked from zelo72/mastodon-ios
chore: update status timeline margin
This commit is contained in:
parent
b52f969c05
commit
a1b9ac8394
|
@ -482,7 +482,6 @@
|
|||
DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B5527B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift */; };
|
||||
DBB45B5927B39FE4002DC5A7 /* MediaPreviewVideoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B5827B39FE4002DC5A7 /* MediaPreviewVideoViewModel.swift */; };
|
||||
DBB45B5B27B3A109002DC5A7 /* MediaPreviewTransitionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B5A27B3A109002DC5A7 /* MediaPreviewTransitionViewController.swift */; };
|
||||
DBB45B5E27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B5D27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift */; };
|
||||
DBB45B6027B50A4F002DC5A7 /* RecommendAccountItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B5F27B50A4F002DC5A7 /* RecommendAccountItem.swift */; };
|
||||
DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB45B6127B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift */; };
|
||||
DBB525082611EAC0002F1F29 /* Tabman in Frameworks */ = {isa = PBXBuildFile; productRef = DBB525072611EAC0002F1F29 /* Tabman */; };
|
||||
|
@ -1230,7 +1229,6 @@
|
|||
DBB45B5527B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewVideoViewController.swift; sourceTree = "<group>"; };
|
||||
DBB45B5827B39FE4002DC5A7 /* MediaPreviewVideoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewVideoViewModel.swift; sourceTree = "<group>"; };
|
||||
DBB45B5A27B3A109002DC5A7 /* MediaPreviewTransitionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPreviewTransitionViewController.swift; sourceTree = "<group>"; };
|
||||
DBB45B5D27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveMarginStatusTableViewCell.swift; sourceTree = "<group>"; };
|
||||
DBB45B5F27B50A4F002DC5A7 /* RecommendAccountItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAccountItem.swift; sourceTree = "<group>"; };
|
||||
DBB45B6127B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SuggestionAccountViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||
DBB5250D2611EBAF002F1F29 /* ProfileSegmentedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileSegmentedViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -1745,7 +1743,6 @@
|
|||
DBE3CDBA261C427900430CC6 /* TimelineHeaderTableViewCell.swift */,
|
||||
DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */,
|
||||
DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */,
|
||||
DBB45B5D27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift */,
|
||||
);
|
||||
path = TableviewCell;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3841,7 +3838,6 @@
|
|||
DBA465952696E387002B41DB /* AppPreference.swift in Sources */,
|
||||
2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */,
|
||||
DB938F0F2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift in Sources */,
|
||||
DBB45B5E27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift in Sources */,
|
||||
DB6180F226391CF40018D199 /* MediaPreviewImageViewModel.swift in Sources */,
|
||||
DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */,
|
||||
DBD5B1F627BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift in Sources */,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>29</integer>
|
||||
<integer>19</integer>
|
||||
</dict>
|
||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -97,7 +97,7 @@
|
|||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>28</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -117,7 +117,7 @@
|
|||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>30</integer>
|
||||
<integer>18</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -36,7 +36,7 @@ extension NotificationTableViewCell {
|
|||
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): did layout for new cell")
|
||||
|
||||
notificationView.statusView.frame.size.width = tableView.frame.width - containerViewHorizontalMargin
|
||||
notificationView.quoteStatusView.frame.size.width = tableView.frame.width - StatusView.containerLayoutMargin.left - StatusView.containerLayoutMargin.right - containerViewHorizontalMargin
|
||||
notificationView.quoteStatusView.frame.size.width = tableView.frame.width - 2 * StatusView.containerLayoutMargin - containerViewHorizontalMargin
|
||||
}
|
||||
|
||||
switch viewModel.value {
|
||||
|
|
|
@ -26,9 +26,6 @@ final class UserTimelineViewController: UIViewController, NeedsDependency, Media
|
|||
|
||||
lazy var tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self))
|
||||
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
||||
tableView.register(TimelineHeaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineHeaderTableViewCell.self))
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.estimatedRowHeight = 100
|
||||
tableView.separatorStyle = .none
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
//
|
||||
// AdaptiveMarginStatusTableViewCell.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-2-10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonUI
|
||||
|
||||
protocol AdaptiveContainerMarginTableViewCell: UITableViewCell {
|
||||
associatedtype ContainerView: UIView
|
||||
static var containerViewMarginForRegularHorizontalSizeClass: CGFloat { get }
|
||||
var containerView: ContainerView { get }
|
||||
var containerViewLeadingLayoutConstraint: NSLayoutConstraint! { get set }
|
||||
var containerViewTrailingLayoutConstraint: NSLayoutConstraint! { get set }
|
||||
}
|
||||
|
||||
extension AdaptiveContainerMarginTableViewCell {
|
||||
|
||||
static var containerViewMarginForRegularHorizontalSizeClass: CGFloat { 64 }
|
||||
|
||||
func setupContainerViewMarginConstraints() {
|
||||
containerViewLeadingLayoutConstraint = containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
|
||||
containerViewTrailingLayoutConstraint = contentView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
|
||||
}
|
||||
|
||||
func updateContainerViewMarginConstraints() {
|
||||
guard traitCollection.userInterfaceIdiom != .phone,
|
||||
traitCollection.horizontalSizeClass == .regular
|
||||
else {
|
||||
containerViewLeadingLayoutConstraint.constant = 0
|
||||
containerViewTrailingLayoutConstraint.constant = 0
|
||||
return
|
||||
}
|
||||
|
||||
containerViewLeadingLayoutConstraint.constant = Self.containerViewMarginForRegularHorizontalSizeClass
|
||||
containerViewTrailingLayoutConstraint.constant = Self.containerViewMarginForRegularHorizontalSizeClass
|
||||
}
|
||||
|
||||
var containerViewHorizontalMargin: CGFloat {
|
||||
containerViewLeadingLayoutConstraint.constant + containerViewTrailingLayoutConstraint.constant
|
||||
}
|
||||
|
||||
}
|
|
@ -28,20 +28,6 @@ final class StatusTableViewCell: UITableViewCell {
|
|||
var containerViewLeadingLayoutConstraint: NSLayoutConstraint!
|
||||
var containerViewTrailingLayoutConstraint: NSLayoutConstraint!
|
||||
|
||||
// var isFiltered: Bool = false {
|
||||
// didSet {
|
||||
// configure(isFiltered: isFiltered)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let filteredLabel: UILabel = {
|
||||
// let label = UILabel()
|
||||
// label.textColor = Asset.Colors.Label.secondary.color
|
||||
// label.text = L10n.Common.Controls.Timeline.filtered
|
||||
// label.font = .preferredFont(forTextStyle: .body)
|
||||
// return label
|
||||
// }()
|
||||
//
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
|
||||
|
@ -71,7 +57,6 @@ extension StatusTableViewCell {
|
|||
statusView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(statusView)
|
||||
setupContainerViewMarginConstraints()
|
||||
updateContainerViewMarginConstraints()
|
||||
NSLayoutConstraint.activate([
|
||||
statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
|
||||
containerViewLeadingLayoutConstraint,
|
||||
|
@ -79,6 +64,7 @@ extension StatusTableViewCell {
|
|||
statusView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
])
|
||||
statusView.setup(style: .inline)
|
||||
updateContainerViewMarginConstraints()
|
||||
|
||||
separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(separatorLine)
|
||||
|
|
|
@ -58,7 +58,6 @@ extension StatusThreadRootTableViewCell {
|
|||
statusView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(statusView)
|
||||
setupContainerViewMarginConstraints()
|
||||
updateContainerViewMarginConstraints()
|
||||
NSLayoutConstraint.activate([
|
||||
statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
|
||||
containerViewLeadingLayoutConstraint,
|
||||
|
@ -66,6 +65,7 @@ extension StatusThreadRootTableViewCell {
|
|||
statusView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
])
|
||||
statusView.setup(style: .plain)
|
||||
updateContainerViewMarginConstraints()
|
||||
|
||||
separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(separatorLine)
|
||||
|
@ -108,7 +108,6 @@ extension StatusThreadRootTableViewCell {
|
|||
statusView.mediaGridContainerView,
|
||||
statusView.pollTableView,
|
||||
statusView.pollStatusStackView,
|
||||
statusView.statusVisibilityView,
|
||||
statusView.actionToolbarContainer,
|
||||
statusView.statusMetricView
|
||||
]
|
||||
|
@ -123,10 +122,6 @@ extension StatusThreadRootTableViewCell {
|
|||
elements.removeAll(where: { $0 === statusView.contentMetaText.textView })
|
||||
}
|
||||
|
||||
if statusView.statusVisibilityView.isHidden {
|
||||
elements.removeAll(where: { $0 === statusView.statusVisibilityView })
|
||||
}
|
||||
|
||||
if statusView.viewModel.pollItems.isEmpty {
|
||||
elements.removeAll(where: { $0 === statusView.pollTableView })
|
||||
elements.removeAll(where: { $0 === statusView.pollStatusStackView })
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// AdaptiveMarginStatusTableViewCell.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK on 2022-2-18.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public protocol AdaptiveContainerView: UIView {
|
||||
func updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: Bool)
|
||||
}
|
||||
|
||||
public protocol AdaptiveContainerMarginTableViewCell: UITableViewCell {
|
||||
associatedtype ContainerView: AdaptiveContainerView
|
||||
static var containerViewMarginForRegularHorizontalSizeClass: CGFloat { get }
|
||||
var containerView: ContainerView { get }
|
||||
var containerViewLeadingLayoutConstraint: NSLayoutConstraint! { get set }
|
||||
var containerViewTrailingLayoutConstraint: NSLayoutConstraint! { get set }
|
||||
}
|
||||
|
||||
extension AdaptiveContainerMarginTableViewCell {
|
||||
|
||||
public static var containerViewMarginForRegularHorizontalSizeClass: CGFloat { 64 }
|
||||
|
||||
public func setupContainerViewMarginConstraints() {
|
||||
containerViewLeadingLayoutConstraint = containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
|
||||
containerViewTrailingLayoutConstraint = contentView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
|
||||
}
|
||||
|
||||
public func updateContainerViewMarginConstraints() {
|
||||
func setupContainerForPhone() {
|
||||
containerView.updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: true) // add inner margin for phone
|
||||
containerViewLeadingLayoutConstraint.constant = 0 // remove outer margin for phone
|
||||
containerViewTrailingLayoutConstraint.constant = 0
|
||||
}
|
||||
|
||||
switch traitCollection.userInterfaceIdiom {
|
||||
case .phone:
|
||||
setupContainerForPhone()
|
||||
default:
|
||||
guard traitCollection.horizontalSizeClass == .regular else {
|
||||
setupContainerForPhone()
|
||||
return
|
||||
}
|
||||
containerView.updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: false) // remove margin for iPad
|
||||
containerViewLeadingLayoutConstraint.constant = Self.containerViewMarginForRegularHorizontalSizeClass // add outer margin for iPad
|
||||
containerViewTrailingLayoutConstraint.constant = Self.containerViewMarginForRegularHorizontalSizeClass
|
||||
}
|
||||
}
|
||||
|
||||
public var containerViewHorizontalMargin: CGFloat {
|
||||
containerViewLeadingLayoutConstraint.constant + containerViewTrailingLayoutConstraint.constant
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// AdaptiveMarginContainerView.swift
|
||||
//
|
||||
//
|
||||
// Created by MainasuK on 2022-2-18.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public final class AdaptiveMarginContainerView: UIView {
|
||||
|
||||
public var margin: CGFloat = 0 {
|
||||
didSet { updateConstraints() }
|
||||
}
|
||||
|
||||
public var contentView: UIView? {
|
||||
didSet {
|
||||
guard let contentView = contentView else { return }
|
||||
guard contentView.superview == nil else { return }
|
||||
|
||||
contentView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(contentView)
|
||||
|
||||
let _leadingLayoutConstraint = contentView.leadingAnchor.constraint(equalTo: leadingAnchor)
|
||||
let _trailingLayoutConstraint = trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
contentView.topAnchor.constraint(equalTo: topAnchor),
|
||||
_leadingLayoutConstraint,
|
||||
_trailingLayoutConstraint,
|
||||
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
|
||||
leadingLayoutConstraint = _leadingLayoutConstraint
|
||||
trailingLayoutConstraint = _trailingLayoutConstraint
|
||||
|
||||
updateConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
var leadingLayoutConstraint: NSLayoutConstraint?
|
||||
var trailingLayoutConstraint: NSLayoutConstraint?
|
||||
|
||||
}
|
||||
|
||||
extension AdaptiveMarginContainerView {
|
||||
|
||||
public override func updateConstraints() {
|
||||
super.updateConstraints()
|
||||
|
||||
leadingLayoutConstraint?.constant = margin
|
||||
trailingLayoutConstraint?.constant = margin
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ public final class MediaView: UIView {
|
|||
formatter.allowedUnits = [.minute, .second]
|
||||
return formatter
|
||||
}()
|
||||
public static let placeholderImage = UIImage.placeholder(color: .systemGray6)
|
||||
|
||||
public let container = TouchBlockingView()
|
||||
|
||||
|
@ -154,7 +155,10 @@ extension MediaView {
|
|||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isReveal, previewImage, blurhashImage in
|
||||
guard let self = self else { return }
|
||||
let image = isReveal ? (previewImage ?? blurhashImage) : blurhashImage
|
||||
|
||||
let image = isReveal ?
|
||||
(previewImage ?? blurhashImage ?? MediaView.placeholderImage) :
|
||||
(blurhashImage ?? MediaView.placeholderImage)
|
||||
self.imageView.image = image
|
||||
}
|
||||
.store(in: &configuration.disposeBag)
|
||||
|
@ -204,30 +208,6 @@ extension MediaView {
|
|||
assetURL: info.previewURL
|
||||
)
|
||||
bindImage(configuration: configuration, info: imageInfo)
|
||||
|
||||
// indicatorBlurEffectView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// imageView.addSubview(indicatorBlurEffectView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// imageView.trailingAnchor.constraint(equalTo: indicatorBlurEffectView.trailingAnchor, constant: 11),
|
||||
// imageView.bottomAnchor.constraint(equalTo: indicatorBlurEffectView.bottomAnchor, constant: 8),
|
||||
// ])
|
||||
// setupIndicatorViewHierarchy()
|
||||
|
||||
// playerIndicatorLabel.attributedText = {
|
||||
// let imageAttachment = NSTextAttachment(image: UIImage(systemName: "play.fill")!)
|
||||
// let imageAttributedString = AttributedString(NSAttributedString(attachment: imageAttachment))
|
||||
// let duration: String = {
|
||||
// guard let durationMS = info.durationMS else { return "" }
|
||||
// let timeInterval = TimeInterval(durationMS / 1000)
|
||||
// guard timeInterval > 0 else { return "" }
|
||||
// guard let text = MediaView.durationFormatter.string(from: timeInterval) else { return "" }
|
||||
// return " \(text)"
|
||||
// }()
|
||||
// let textAttributedString = AttributedString("\(duration)")
|
||||
// var attributedString = imageAttributedString + textAttributedString
|
||||
// attributedString.foregroundColor = .secondaryLabel
|
||||
// return NSAttributedString(attributedString)
|
||||
// }()
|
||||
}
|
||||
|
||||
private func layoutBlurhash() {
|
||||
|
|
|
@ -136,7 +136,7 @@ public final class NotificationView: UIView {
|
|||
extension NotificationView {
|
||||
private func _init() {
|
||||
// container: V - [ author container | (authorContainerViewBottomPaddingView) | statusView | quoteStatusView ]
|
||||
containerStackView.layoutMargins = StatusView.containerLayoutMargin
|
||||
// containerStackView.layoutMargins = StatusView.containerLayoutMargin
|
||||
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(containerStackView)
|
||||
|
@ -228,9 +228,9 @@ extension NotificationView {
|
|||
containerStackView.addArrangedSubview(quoteStatusViewContainerView)
|
||||
quoteStatusViewContainerView.layoutMargins = UIEdgeInsets(
|
||||
top: 0,
|
||||
left: StatusView.containerLayoutMargin.left,
|
||||
left: StatusView.containerLayoutMargin,
|
||||
bottom: 16,
|
||||
right: StatusView.containerLayoutMargin.right
|
||||
right: StatusView.containerLayoutMargin
|
||||
)
|
||||
|
||||
quoteBackgroundView.layoutMargins = UIEdgeInsets(top: 16, left: 0, bottom: 0, right: 0)
|
||||
|
@ -297,6 +297,13 @@ extension NotificationView {
|
|||
|
||||
}
|
||||
|
||||
// MARK: - AdaptiveContainerView
|
||||
extension NotificationView: AdaptiveContainerView {
|
||||
public func updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: Bool) {
|
||||
statusView.updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationView {
|
||||
public typealias AuthorMenuContext = StatusView.AuthorMenuContext
|
||||
|
||||
|
|
|
@ -71,8 +71,8 @@ extension StatusMetricView {
|
|||
addSubview(containerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
containerStackView.topAnchor.constraint(equalTo: topAnchor, constant: 8),
|
||||
containerStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
containerStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
containerStackView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 12),
|
||||
])
|
||||
|
||||
|
|
|
@ -24,19 +24,15 @@ public protocol StatusViewDelegate: AnyObject {
|
|||
func statusView(_ statusView: StatusView, actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action)
|
||||
func statusView(_ statusView: StatusView, menuButton button: UIButton, didSelectAction action: MastodonMenu.Action)
|
||||
func statusView(_ statusView: StatusView, spoilerOverlayViewDidPressed overlayView: SpoilerOverlayView)
|
||||
// func statusView(_ statusView: StatusView, spoilerBannerViewDidPressed bannerView: SpoilerBannerView)
|
||||
func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton)
|
||||
|
||||
// a11y
|
||||
func statusView(_ statusView: StatusView, accessibilityActivate: Void)
|
||||
|
||||
// func statusView(_ statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
// func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
}
|
||||
|
||||
public final class StatusView: UIView {
|
||||
|
||||
public static let containerLayoutMargin = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
|
||||
public static let containerLayoutMargin: CGFloat = 16
|
||||
|
||||
let logger = Logger(subsystem: "StatusView", category: "View")
|
||||
|
||||
|
@ -61,6 +57,7 @@ public final class StatusView: UIView {
|
|||
}()
|
||||
|
||||
// header
|
||||
let headerAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
public let headerContainerView = UIView()
|
||||
|
||||
// header icon
|
||||
|
@ -75,6 +72,7 @@ public final class StatusView: UIView {
|
|||
let headerInfoLabel = MetaLabel(style: .statusHeader)
|
||||
|
||||
// author
|
||||
let authorAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
let authorContainerView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .horizontal
|
||||
|
@ -122,6 +120,7 @@ public final class StatusView: UIView {
|
|||
}()
|
||||
|
||||
// content
|
||||
let contentAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
let contentContainer = UIStackView()
|
||||
public let contentMetaText: MetaText = {
|
||||
let metaText = MetaText()
|
||||
|
@ -160,7 +159,8 @@ public final class StatusView: UIView {
|
|||
public let mediaGridContainerView = MediaGridContainerView()
|
||||
|
||||
// poll
|
||||
public let pollContainerView = UIStackView()
|
||||
let pollAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
let pollContainerView = UIStackView()
|
||||
public let pollTableView: UITableView = {
|
||||
let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
|
||||
tableView.register(PollOptionTableViewCell.self, forCellReuseIdentifier: String(describing: PollOptionTableViewCell.self))
|
||||
|
@ -214,16 +214,12 @@ public final class StatusView: UIView {
|
|||
return indicatorView
|
||||
}()
|
||||
|
||||
// visibility
|
||||
public let statusVisibilityView = StatusVisibilityView()
|
||||
|
||||
// spoiler banner
|
||||
// public let spoilerBannerView = SpoilerBannerView()
|
||||
|
||||
// toolbar
|
||||
let actionToolbarAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
public let actionToolbarContainer = ActionToolbarContainer()
|
||||
|
||||
// metric
|
||||
let statusMetricViewAdaptiveMarginContainerView = AdaptiveMarginContainerView()
|
||||
public let statusMetricView = StatusMetricView()
|
||||
|
||||
// filter hint
|
||||
|
@ -252,13 +248,12 @@ public final class StatusView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
headerContainerView.isHidden = true
|
||||
contentSensitiveeToggleButton.isHidden = true
|
||||
setHeaderDisplay(isDisplay: false)
|
||||
setContentSensitiveeToggleButtonDisplay(isDisplay: false)
|
||||
setSpoilerOverlayViewHidden(isHidden: true)
|
||||
mediaContainerView.isHidden = true
|
||||
pollContainerView.isHidden = true
|
||||
statusVisibilityView.isHidden = true
|
||||
filterHintLabel.isHidden = true
|
||||
setMediaDisplay(isDisplay: false)
|
||||
setPollDisplay(isDisplay: false)
|
||||
setFilterHintLabelDisplay(isDisplay: false)
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
|
@ -323,12 +318,6 @@ extension StatusView {
|
|||
])
|
||||
pollTableView.delegate = self
|
||||
pollVoteButton.addTarget(self, action: #selector(StatusView.pollVoteButtonDidPressed(_:)), for: .touchUpInside)
|
||||
|
||||
// statusSpoilerBannerView
|
||||
// let spoilerBannerViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
// spoilerBannerView.addGestureRecognizer(spoilerBannerViewTapGestureRecognizer)
|
||||
// spoilerBannerViewTapGestureRecognizer.addTarget(self, action: #selector(StatusView.spoilerBannerViewTapGestureRecognizerHandler(_:)))
|
||||
|
||||
// toolbar
|
||||
actionToolbarContainer.delegate = self
|
||||
}
|
||||
|
@ -362,11 +351,6 @@ extension StatusView {
|
|||
delegate?.statusView(self, spoilerOverlayViewDidPressed: spoilerOverlayView)
|
||||
}
|
||||
|
||||
// @objc private func spoilerBannerViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||
// logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||
// delegate?.statusView(self, spoilerBannerViewDidPressed: spoilerBannerView)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
extension StatusView {
|
||||
|
@ -408,22 +392,23 @@ extension StatusView.Style {
|
|||
|
||||
private func base(statusView: StatusView) {
|
||||
// container: V - [ header container | author container | content container | media container | pollTableView | actionToolbarContainer ]
|
||||
statusView.containerStackView.layoutMargins = StatusView.containerLayoutMargin
|
||||
|
||||
// header container: H - [ icon | label ]
|
||||
statusView.headerContainerView.preservesSuperviewLayoutMargins = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.headerContainerView)
|
||||
statusView.headerAdaptiveMarginContainerView.contentView = statusView.headerContainerView
|
||||
statusView.headerAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.containerStackView.addArrangedSubview(statusView.headerAdaptiveMarginContainerView)
|
||||
|
||||
statusView.headerIconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusView.headerInfoLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusView.headerContainerView.addSubview(statusView.headerIconImageView)
|
||||
statusView.headerContainerView.addSubview(statusView.headerInfoLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
statusView.headerIconImageView.leadingAnchor.constraint(equalTo: statusView.headerContainerView.layoutMarginsGuide.leadingAnchor),
|
||||
statusView.headerIconImageView.leadingAnchor.constraint(equalTo: statusView.headerContainerView.leadingAnchor),
|
||||
statusView.headerIconImageView.heightAnchor.constraint(equalTo: statusView.headerInfoLabel.heightAnchor, multiplier: 1.0).priority(.required - 1),
|
||||
statusView.headerIconImageView.widthAnchor.constraint(equalTo: statusView.headerIconImageView.heightAnchor, multiplier: 1.0).priority(.required - 1),
|
||||
statusView.headerInfoLabel.topAnchor.constraint(equalTo: statusView.headerContainerView.topAnchor),
|
||||
statusView.headerInfoLabel.leadingAnchor.constraint(equalTo: statusView.headerIconImageView.trailingAnchor, constant: 6),
|
||||
statusView.headerInfoLabel.trailingAnchor.constraint(equalTo: statusView.headerContainerView.layoutMarginsGuide.trailingAnchor),
|
||||
statusView.headerInfoLabel.trailingAnchor.constraint(equalTo: statusView.headerContainerView.trailingAnchor),
|
||||
statusView.headerInfoLabel.bottomAnchor.constraint(equalTo: statusView.headerContainerView.bottomAnchor),
|
||||
statusView.headerInfoLabel.centerYAnchor.constraint(equalTo: statusView.headerIconImageView.centerYAnchor),
|
||||
])
|
||||
|
@ -434,9 +419,10 @@ extension StatusView.Style {
|
|||
statusView.headerIconImageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||
|
||||
// author container: H - [ avatarButton | author meta container | contentWarningToggleButton ]
|
||||
statusView.authorContainerView.preservesSuperviewLayoutMargins = true
|
||||
statusView.authorContainerView.isLayoutMarginsRelativeArrangement = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.authorContainerView)
|
||||
statusView.authorAdaptiveMarginContainerView.contentView = statusView.authorContainerView
|
||||
statusView.authorAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.containerStackView.addArrangedSubview(statusView.authorAdaptiveMarginContainerView)
|
||||
|
||||
UIContentSizeCategory.publisher
|
||||
.sink { category in
|
||||
statusView.authorContainerView.axis = category > .accessibilityLarge ? .vertical : .horizontal
|
||||
|
@ -514,9 +500,9 @@ extension StatusView.Style {
|
|||
statusView.contentContainer.distribution = .fill
|
||||
statusView.contentContainer.alignment = .top
|
||||
|
||||
statusView.contentContainer.preservesSuperviewLayoutMargins = true
|
||||
statusView.contentContainer.isLayoutMarginsRelativeArrangement = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.contentContainer)
|
||||
statusView.contentAdaptiveMarginContainerView.contentView = statusView.contentContainer
|
||||
statusView.contentAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.containerStackView.addArrangedSubview(statusView.contentAdaptiveMarginContainerView)
|
||||
statusView.contentContainer.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
statusView.contentContainer.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
|
@ -533,7 +519,12 @@ extension StatusView.Style {
|
|||
])
|
||||
|
||||
// media container: V - [ mediaGridContainerView ]
|
||||
statusView.mediaContainerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusView.containerStackView.addArrangedSubview(statusView.mediaContainerView)
|
||||
NSLayoutConstraint.activate([
|
||||
statusView.mediaContainerView.leadingAnchor.constraint(equalTo: statusView.containerStackView.leadingAnchor),
|
||||
statusView.mediaContainerView.trailingAnchor.constraint(equalTo: statusView.containerStackView.trailingAnchor),
|
||||
])
|
||||
|
||||
statusView.mediaGridContainerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusView.mediaContainerView.addSubview(statusView.mediaGridContainerView)
|
||||
|
@ -545,10 +536,10 @@ extension StatusView.Style {
|
|||
])
|
||||
|
||||
// pollContainerView: V - [ pollTableView | pollStatusStackView ]
|
||||
statusView.pollAdaptiveMarginContainerView.contentView = statusView.pollContainerView
|
||||
statusView.pollAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.pollContainerView.axis = .vertical
|
||||
statusView.pollContainerView.preservesSuperviewLayoutMargins = true
|
||||
statusView.pollContainerView.isLayoutMarginsRelativeArrangement = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.pollContainerView)
|
||||
statusView.containerStackView.addArrangedSubview(statusView.pollAdaptiveMarginContainerView)
|
||||
|
||||
// pollTableView
|
||||
statusView.pollContainerView.addArrangedSubview(statusView.pollTableView)
|
||||
|
@ -567,18 +558,11 @@ extension StatusView.Style {
|
|||
statusView.pollCountdownLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||
statusView.pollVoteButton.setContentHuggingPriority(.defaultHigh + 3, for: .horizontal)
|
||||
|
||||
// statusVisibilityView
|
||||
statusView.statusVisibilityView.preservesSuperviewLayoutMargins = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.statusVisibilityView)
|
||||
|
||||
// spoilerBannerView
|
||||
// statusView.spoilerBannerView.preservesSuperviewLayoutMargins = true
|
||||
// statusView.containerStackView.addArrangedSubview(statusView.spoilerBannerView)
|
||||
|
||||
// action toolbar
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.contentView = statusView.actionToolbarContainer
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.actionToolbarContainer.configure(for: .inline)
|
||||
statusView.actionToolbarContainer.preservesSuperviewLayoutMargins = true
|
||||
statusView.containerStackView.addArrangedSubview(statusView.actionToolbarContainer)
|
||||
statusView.containerStackView.addArrangedSubview(statusView.actionToolbarAdaptiveMarginContainerView)
|
||||
|
||||
// filterHintLabel
|
||||
statusView.filterHintLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
@ -591,8 +575,6 @@ extension StatusView.Style {
|
|||
|
||||
func inline(statusView: StatusView) {
|
||||
base(statusView: statusView)
|
||||
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
}
|
||||
|
||||
func plain(statusView: StatusView) {
|
||||
|
@ -600,8 +582,10 @@ extension StatusView.Style {
|
|||
base(statusView: statusView) // override the base style
|
||||
|
||||
// statusMetricView
|
||||
statusView.statusMetricView.layoutMargins = StatusView.containerLayoutMargin
|
||||
statusView.containerStackView.addArrangedSubview(statusView.statusMetricView)
|
||||
statusView.statusMetricViewAdaptiveMarginContainerView.contentView = statusView.statusMetricView
|
||||
statusView.statusMetricViewAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin
|
||||
statusView.containerStackView.addArrangedSubview(statusView.statusMetricViewAdaptiveMarginContainerView)
|
||||
|
||||
UIContentSizeCategory.publisher
|
||||
.sink { category in
|
||||
statusView.statusMetricView.containerStackView.axis = category > .accessibilityLarge ? .vertical : .horizontal
|
||||
|
@ -614,16 +598,14 @@ extension StatusView.Style {
|
|||
base(statusView: statusView) // override the base style
|
||||
|
||||
statusView.menuButton.removeFromSuperview()
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
statusView.actionToolbarContainer.removeFromSuperview()
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.removeFromSuperview()
|
||||
}
|
||||
|
||||
func notification(statusView: StatusView) {
|
||||
base(statusView: statusView) // override the base style
|
||||
|
||||
statusView.headerContainerView.removeFromSuperview()
|
||||
statusView.authorContainerView.removeFromSuperview()
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
statusView.headerAdaptiveMarginContainerView.removeFromSuperview()
|
||||
statusView.authorAdaptiveMarginContainerView.removeFromSuperview()
|
||||
}
|
||||
|
||||
func notificationQuote(statusView: StatusView) {
|
||||
|
@ -632,8 +614,7 @@ extension StatusView.Style {
|
|||
statusView.contentContainer.layoutMargins.bottom = 16 // fix contentText align to edge issue
|
||||
statusView.contentSensitiveeToggleButton.removeFromSuperview()
|
||||
statusView.menuButton.removeFromSuperview()
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
statusView.actionToolbarContainer.removeFromSuperview()
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.removeFromSuperview()
|
||||
}
|
||||
|
||||
func composeStatusReplica(statusView: StatusView) {
|
||||
|
@ -641,9 +622,7 @@ extension StatusView.Style {
|
|||
|
||||
statusView.avatarButton.isUserInteractionEnabled = false
|
||||
statusView.menuButton.removeFromSuperview()
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
// statusView.spoilerBannerView.removeFromSuperview()
|
||||
statusView.actionToolbarContainer.removeFromSuperview()
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.removeFromSuperview()
|
||||
}
|
||||
|
||||
func composeStatusAuthor(statusView: StatusView) {
|
||||
|
@ -653,24 +632,22 @@ extension StatusView.Style {
|
|||
statusView.menuButton.removeFromSuperview()
|
||||
statusView.usernameTrialingDotLabel.removeFromSuperview()
|
||||
statusView.dateLabel.removeFromSuperview()
|
||||
statusView.contentContainer.removeFromSuperview()
|
||||
statusView.contentAdaptiveMarginContainerView.removeFromSuperview()
|
||||
statusView.spoilerOverlayView.removeFromSuperview()
|
||||
statusView.mediaContainerView.removeFromSuperview()
|
||||
statusView.pollContainerView.removeFromSuperview()
|
||||
statusView.statusVisibilityView.removeFromSuperview()
|
||||
// statusView.spoilerBannerView.removeFromSuperview()
|
||||
statusView.actionToolbarContainer.removeFromSuperview()
|
||||
statusView.pollAdaptiveMarginContainerView.removeFromSuperview()
|
||||
statusView.actionToolbarAdaptiveMarginContainerView.removeFromSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension StatusView {
|
||||
func setHeaderDisplay() {
|
||||
headerContainerView.isHidden = false
|
||||
func setHeaderDisplay(isDisplay: Bool = true) {
|
||||
headerAdaptiveMarginContainerView.isHidden = !isDisplay
|
||||
}
|
||||
|
||||
func setContentSensitiveeToggleButtonDisplay() {
|
||||
contentSensitiveeToggleButton.isHidden = false
|
||||
func setContentSensitiveeToggleButtonDisplay(isDisplay: Bool = true) {
|
||||
contentSensitiveeToggleButton.isHidden = !isDisplay
|
||||
}
|
||||
|
||||
func setSpoilerOverlayViewHidden(isHidden: Bool) {
|
||||
|
@ -678,31 +655,35 @@ extension StatusView {
|
|||
spoilerOverlayView.setComponentHidden(isHidden)
|
||||
}
|
||||
|
||||
func setMediaDisplay() {
|
||||
mediaContainerView.isHidden = false
|
||||
func setMediaDisplay(isDisplay: Bool = true) {
|
||||
mediaContainerView.isHidden = !isDisplay
|
||||
}
|
||||
|
||||
func setPollDisplay() {
|
||||
pollContainerView.isHidden = false
|
||||
func setPollDisplay(isDisplay: Bool = true) {
|
||||
pollAdaptiveMarginContainerView.isHidden = !isDisplay
|
||||
}
|
||||
|
||||
func setVisibilityDisplay() {
|
||||
statusVisibilityView.isHidden = false
|
||||
func setFilterHintLabelDisplay(isDisplay: Bool = true) {
|
||||
filterHintLabel.isHidden = !isDisplay
|
||||
}
|
||||
|
||||
func setFilterHintLabelDisplay() {
|
||||
filterHintLabel.isHidden = false
|
||||
}
|
||||
|
||||
// content text Width
|
||||
// container width
|
||||
public var contentMaxLayoutWidth: CGFloat {
|
||||
let inset = contentLayoutInset
|
||||
return frame.width - inset.left - inset.right
|
||||
return frame.width
|
||||
}
|
||||
|
||||
public var contentLayoutInset: UIEdgeInsets {
|
||||
// TODO: adaptive iPad regular horizontal size class
|
||||
return .zero
|
||||
}
|
||||
|
||||
// MARK: - AdaptiveContainerView
|
||||
extension StatusView: AdaptiveContainerView {
|
||||
public func updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: Bool) {
|
||||
let margin = isEnabled ? StatusView.containerLayoutMargin : .zero
|
||||
headerAdaptiveMarginContainerView.margin = margin
|
||||
authorAdaptiveMarginContainerView.margin = margin
|
||||
contentAdaptiveMarginContainerView.margin = margin
|
||||
pollAdaptiveMarginContainerView.margin = margin
|
||||
actionToolbarAdaptiveMarginContainerView.margin = margin
|
||||
statusMetricViewAdaptiveMarginContainerView.margin = margin
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,9 +49,6 @@ public final class ActionToolbarContainer: UIView {
|
|||
extension ActionToolbarContainer {
|
||||
|
||||
private func _init() {
|
||||
container.preservesSuperviewLayoutMargins = true
|
||||
container.isLayoutMarginsRelativeArrangement = true
|
||||
|
||||
container.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(container)
|
||||
NSLayoutConstraint.activate([
|
||||
|
|
Loading…
Reference in New Issue