forked from zelo72/mastodon-ios
feat: implement boost toot. Add stacked style avatar
This commit is contained in:
parent
2ac2eb7c77
commit
1256ef1d8e
|
@ -149,6 +149,7 @@
|
|||
DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DB68A05C25E9055900CFDF14 /* Settings.bundle */; };
|
||||
DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A06225E905E000CFDF14 /* UIApplication.swift */; };
|
||||
DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; };
|
||||
DB71FD2C25F86A5100512AE1 /* AvatarStackContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD2B25F86A5100512AE1 /* AvatarStackContainerView.swift */; };
|
||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; };
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; };
|
||||
DB89B9F725C10FD0008580ED /* CoreDataStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */; };
|
||||
|
@ -396,6 +397,7 @@
|
|||
DB68A05C25E9055900CFDF14 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||
DB68A06225E905E000CFDF14 /* UIApplication.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = "<group>"; };
|
||||
DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = "<group>"; };
|
||||
DB71FD2B25F86A5100512AE1 /* AvatarStackContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarStackContainerView.swift; sourceTree = "<group>"; };
|
||||
DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = "<group>"; };
|
||||
DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = "<group>"; };
|
||||
DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreDataStack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -1168,6 +1170,7 @@
|
|||
children = (
|
||||
DB9D6C0D25E4F9780051B173 /* MosaicImageViewContainer.swift */,
|
||||
2D206B7125F5D27F00143C56 /* AudioContainerView.swift */,
|
||||
DB71FD2B25F86A5100512AE1 /* AvatarStackContainerView.swift */,
|
||||
);
|
||||
path = Container;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1684,6 +1687,7 @@
|
|||
DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */,
|
||||
DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */,
|
||||
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */,
|
||||
DB71FD2C25F86A5100512AE1 /* AvatarStackContainerView.swift in Sources */,
|
||||
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
||||
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
|
||||
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
|
||||
|
|
|
@ -86,13 +86,23 @@ extension StatusSection {
|
|||
return L10n.Common.Controls.Status.userBoosted(name)
|
||||
}()
|
||||
|
||||
// set name username avatar
|
||||
// set name username
|
||||
cell.statusView.nameLabel.text = {
|
||||
let author = (toot.reblog ?? toot).author
|
||||
return author.displayName.isEmpty ? author.username : author.displayName
|
||||
}()
|
||||
cell.statusView.usernameLabel.text = "@" + (toot.reblog ?? toot).author.acct
|
||||
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: (toot.reblog ?? toot).author.avatarImageURL()))
|
||||
// set avatar
|
||||
if let reblog = toot.reblog {
|
||||
cell.statusView.avatarButton.isHidden = true
|
||||
cell.statusView.avatarStackedContainerButton.isHidden = false
|
||||
cell.statusView.avatarStackedContainerButton.topLeadingAvatarStackedImageView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: reblog.author.avatarImageURL()))
|
||||
cell.statusView.avatarStackedContainerButton.bottomTrailingAvatarStackedImageView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: toot.author.avatarImageURL()))
|
||||
} else {
|
||||
cell.statusView.avatarButton.isHidden = false
|
||||
cell.statusView.avatarStackedContainerButton.isHidden = true
|
||||
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: (toot.reblog ?? toot).author.avatarImageURL()))
|
||||
}
|
||||
|
||||
// set text
|
||||
cell.statusView.activeTextLabel.config(content: (toot.reblog ?? toot).content)
|
||||
|
|
|
@ -23,7 +23,13 @@ extension AvatarConfigurableView {
|
|||
public func configure(with configuration: AvatarConfigurableViewConfiguration) {
|
||||
let placeholderImage: UIImage = {
|
||||
let placeholderImage = configuration.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageSize, color: .systemFill)
|
||||
return placeholderImage.af.imageRoundedIntoCircle()
|
||||
if Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 {
|
||||
return placeholderImage
|
||||
.af.imageAspectScaled(toFill: Self.configurableAvatarImageSize)
|
||||
.af.imageRounded(withCornerRadius: 4, divideRadiusByImageScale: true)
|
||||
} else {
|
||||
return placeholderImage.af.imageRoundedIntoCircle()
|
||||
}
|
||||
}()
|
||||
|
||||
// cancel previous task
|
||||
|
@ -65,7 +71,8 @@ extension AvatarConfigurableView {
|
|||
)
|
||||
avatarImageView.layer.masksToBounds = true
|
||||
avatarImageView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
avatarImageView.layer.cornerCurve = .circular
|
||||
avatarImageView.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
|
||||
default:
|
||||
let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius)
|
||||
avatarImageView.af.setImage(
|
||||
|
@ -92,7 +99,7 @@ extension AvatarConfigurableView {
|
|||
)
|
||||
avatarButton.layer.masksToBounds = true
|
||||
avatarButton.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
avatarButton.layer.cornerCurve = .continuous
|
||||
avatarButton.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous : .circular
|
||||
default:
|
||||
let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius)
|
||||
avatarButton.af.setImage(
|
||||
|
|
|
@ -45,10 +45,18 @@ extension HomeTimelineViewController {
|
|||
guard let self = self else { return }
|
||||
self.moveToTopGapAction(action)
|
||||
}),
|
||||
UIAction(title: "First Reblog Toot", image: nil, attributes: [], handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.moveToFirstReblogToot(action)
|
||||
}),
|
||||
UIAction(title: "First Poll Toot", image: nil, attributes: [], handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.moveToFirstPollToot(action)
|
||||
}),
|
||||
UIAction(title: "First Audio Toot", image: nil, attributes: [], handler: { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.moveToFirstAudioToot(action)
|
||||
}),
|
||||
// UIAction(title: "First Reply Toot", image: nil, attributes: [], handler: { [weak self] action in
|
||||
// guard let self = self else { return }
|
||||
// self.moveToFirstReplyToot(action)
|
||||
|
@ -101,6 +109,26 @@ extension HomeTimelineViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func moveToFirstReblogToot(_ sender: UIAction) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
let snapshotTransitioning = diffableDataSource.snapshot()
|
||||
let item = snapshotTransitioning.itemIdentifiers.first(where: { item in
|
||||
switch item {
|
||||
case .homeTimelineIndex(let objectID, _):
|
||||
let homeTimelineIndex = viewModel.fetchedResultsController.managedObjectContext.object(with: objectID) as! HomeTimelineIndex
|
||||
return homeTimelineIndex.toot.reblog != nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
if let targetItem = item, let index = snapshotTransitioning.indexOfItem(targetItem) {
|
||||
tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .middle, animated: true)
|
||||
tableView.blinkRow(at: IndexPath(row: index, section: 0))
|
||||
} else {
|
||||
print("Not found reblog toot")
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func moveToFirstPollToot(_ sender: UIAction) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
let snapshotTransitioning = diffableDataSource.snapshot()
|
||||
|
@ -122,6 +150,27 @@ extension HomeTimelineViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func moveToFirstAudioToot(_ sender: UIAction) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
let snapshotTransitioning = diffableDataSource.snapshot()
|
||||
let item = snapshotTransitioning.itemIdentifiers.first(where: { item in
|
||||
switch item {
|
||||
case .homeTimelineIndex(let objectID, _):
|
||||
let homeTimelineIndex = viewModel.fetchedResultsController.managedObjectContext.object(with: objectID) as! HomeTimelineIndex
|
||||
let toot = homeTimelineIndex.toot.reblog ?? homeTimelineIndex.toot
|
||||
return toot.mediaAttachments?.contains(where: { $0.type == .audio }) ?? false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
if let targetItem = item, let index = snapshotTransitioning.indexOfItem(targetItem) {
|
||||
tableView.scrollToRow(at: IndexPath(row: index, section: 0), at: .middle, animated: true)
|
||||
tableView.blinkRow(at: IndexPath(row: index, section: 0))
|
||||
} else {
|
||||
print("Not found audio toot")
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func dropRecentTootsAction(_ sender: UIAction, count: Int) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
let snapshotTransitioning = diffableDataSource.snapshot()
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
//
|
||||
// AvatarStackContainerView.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
final class AvatarStackedImageView: UIImageView { }
|
||||
|
||||
// MARK: - AvatarConfigurableView
|
||||
extension AvatarStackedImageView: AvatarConfigurableView {
|
||||
static var configurableAvatarImageSize: CGSize { CGSize(width: 28, height: 28) }
|
||||
static var configurableAvatarImageCornerRadius: CGFloat { 4 }
|
||||
var configurableAvatarImageView: UIImageView? { self }
|
||||
var configurableAvatarButton: UIButton? { nil }
|
||||
}
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
|
||||
extension UIControl.State: Hashable { }
|
||||
|
||||
final class AvatarStackContainerButton: UIControl {
|
||||
|
||||
static let containerSize = CGSize(width: 42, height: 42)
|
||||
static let maskOffset: CGFloat = 2
|
||||
|
||||
// UIControl.Event - Application: 0x0F000000
|
||||
static let primaryAction = UIControl.Event(rawValue: 1 << 25) // 0x01000000
|
||||
var primaryActionState: UIControl.State = .normal
|
||||
|
||||
let topLeadingAvatarStackedImageView = AvatarStackedImageView()
|
||||
let bottomTrailingAvatarStackedImageView = AvatarStackedImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
_init()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
_init()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AvatarStackContainerButton {
|
||||
|
||||
private func _init() {
|
||||
topLeadingAvatarStackedImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(topLeadingAvatarStackedImageView)
|
||||
NSLayoutConstraint.activate([
|
||||
topLeadingAvatarStackedImageView.topAnchor.constraint(equalTo: topAnchor),
|
||||
topLeadingAvatarStackedImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
topLeadingAvatarStackedImageView.widthAnchor.constraint(equalToConstant: AvatarStackedImageView.configurableAvatarImageSize.width).priority(.defaultHigh),
|
||||
topLeadingAvatarStackedImageView.heightAnchor.constraint(equalToConstant: AvatarStackedImageView.configurableAvatarImageSize.height).priority(.defaultHigh),
|
||||
])
|
||||
|
||||
bottomTrailingAvatarStackedImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(bottomTrailingAvatarStackedImageView)
|
||||
NSLayoutConstraint.activate([
|
||||
bottomTrailingAvatarStackedImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
bottomTrailingAvatarStackedImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
bottomTrailingAvatarStackedImageView.widthAnchor.constraint(equalToConstant: AvatarStackedImageView.configurableAvatarImageSize.width).priority(.defaultHigh),
|
||||
bottomTrailingAvatarStackedImageView.heightAnchor.constraint(equalToConstant: AvatarStackedImageView.configurableAvatarImageSize.height).priority(.defaultHigh),
|
||||
])
|
||||
|
||||
// mask topLeadingAvatarStackedImageView
|
||||
let offset: CGFloat = 2
|
||||
let path: CGPath = {
|
||||
let path = CGMutablePath()
|
||||
path.addRect(CGRect(origin: .zero, size: AvatarStackContainerButton.containerSize))
|
||||
if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft {
|
||||
path.addPath(UIBezierPath(
|
||||
roundedRect: CGRect(
|
||||
x: AvatarStackedImageView.configurableAvatarImageSize.width + offset,
|
||||
y: AvatarStackContainerButton.containerSize.height - AvatarStackedImageView.configurableAvatarImageSize.height - offset,
|
||||
width: AvatarStackedImageView.configurableAvatarImageSize.width,
|
||||
height: AvatarStackedImageView.configurableAvatarImageSize.height
|
||||
),
|
||||
cornerRadius: AvatarStackedImageView.configurableAvatarImageCornerRadius
|
||||
).cgPath)
|
||||
} else {
|
||||
path.addPath(UIBezierPath(
|
||||
roundedRect: CGRect(
|
||||
x: AvatarStackContainerButton.containerSize.width - AvatarStackedImageView.configurableAvatarImageSize.width - offset,
|
||||
y: AvatarStackContainerButton.containerSize.height - AvatarStackedImageView.configurableAvatarImageSize.height - offset,
|
||||
width: AvatarStackedImageView.configurableAvatarImageSize.width,
|
||||
height: AvatarStackedImageView.configurableAvatarImageSize.height
|
||||
),
|
||||
cornerRadius: AvatarStackedImageView.configurableAvatarImageCornerRadius
|
||||
).cgPath)
|
||||
}
|
||||
return path
|
||||
}()
|
||||
let maskShapeLayer = CAShapeLayer()
|
||||
maskShapeLayer.backgroundColor = UIColor.black.cgColor
|
||||
maskShapeLayer.fillRule = .evenOdd
|
||||
maskShapeLayer.path = path
|
||||
topLeadingAvatarStackedImageView.layer.mask = maskShapeLayer
|
||||
|
||||
topLeadingAvatarStackedImageView.image = UIImage.placeholder(color: .systemFill)
|
||||
bottomTrailingAvatarStackedImageView.image = UIImage.placeholder(color: .systemFill)
|
||||
}
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return AvatarStackContainerButton.containerSize
|
||||
}
|
||||
|
||||
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
||||
defer { updateAppearance() }
|
||||
|
||||
updateState(touch: touch, event: event)
|
||||
return super.beginTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
|
||||
defer { updateAppearance() }
|
||||
|
||||
updateState(touch: touch, event: event)
|
||||
return super.continueTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
|
||||
defer { updateAppearance() }
|
||||
resetState()
|
||||
|
||||
if let touch = touch {
|
||||
if AvatarStackContainerButton.isTouching(touch, view: self, event: event) {
|
||||
sendActions(for: AvatarStackContainerButton.primaryAction)
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
super.endTracking(touch, with: event)
|
||||
}
|
||||
|
||||
override func cancelTracking(with event: UIEvent?) {
|
||||
defer { updateAppearance() }
|
||||
|
||||
resetState()
|
||||
super.cancelTracking(with: event)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension AvatarStackContainerButton {
|
||||
|
||||
private func updateAppearance() {
|
||||
topLeadingAvatarStackedImageView.alpha = primaryActionState.contains(.highlighted) ? 0.6 : 1.0
|
||||
bottomTrailingAvatarStackedImageView.alpha = primaryActionState.contains(.highlighted) ? 0.6 : 1.0
|
||||
}
|
||||
|
||||
private static func isTouching(_ touch: UITouch, view: UIView, event: UIEvent?) -> Bool {
|
||||
let location = touch.location(in: view)
|
||||
return view.point(inside: location, with: event)
|
||||
}
|
||||
|
||||
private func resetState() {
|
||||
primaryActionState = .normal
|
||||
}
|
||||
|
||||
private func updateState(touch: UITouch, event: UIEvent?) {
|
||||
primaryActionState = AvatarStackContainerButton.isTouching(touch, view: self, event: event) ? .highlighted : .normal
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if canImport(SwiftUI) && DEBUG
|
||||
import SwiftUI
|
||||
|
||||
struct AvatarStackContainerButton_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
UIViewPreview(width: 42) {
|
||||
let avatarStackContainerButton = AvatarStackContainerButton()
|
||||
avatarStackContainerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
avatarStackContainerButton.widthAnchor.constraint(equalToConstant: 42),
|
||||
avatarStackContainerButton.heightAnchor.constraint(equalToConstant: 42),
|
||||
])
|
||||
return avatarStackContainerButton
|
||||
}
|
||||
.previewLayout(.fixed(width: 42, height: 42))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -60,6 +60,7 @@ final class StatusView: UIView {
|
|||
button.setImage(placeholderImage, for: .normal)
|
||||
return button
|
||||
}()
|
||||
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
||||
|
||||
let nameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
|
@ -238,6 +239,14 @@ extension StatusView {
|
|||
avatarButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
avatarStackedContainerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarStackedContainerButton)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarStackedContainerButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarStackedContainerButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarStackedContainerButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarStackedContainerButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
|
||||
// author meta container: [title container | subtitle container]
|
||||
let authorMetaContainerStackView = UIStackView()
|
||||
|
@ -360,6 +369,7 @@ extension StatusView {
|
|||
pollStatusStackView.isHidden = true
|
||||
audioView.isHidden = true
|
||||
|
||||
avatarStackedContainerButton.isHidden = true
|
||||
contentWarningBlurContentImageView.isHidden = true
|
||||
statusContentWarningContainerStackView.isHidden = true
|
||||
statusContentWarningContainerStackViewBottomLayoutConstraint.isActive = false
|
||||
|
@ -429,6 +439,7 @@ import SwiftUI
|
|||
struct StatusView_Previews: PreviewProvider {
|
||||
|
||||
static let avatarFlora = UIImage(named: "tiraya-adam")
|
||||
static let avatarMarkus = UIImage(named: "markus-spiske")
|
||||
|
||||
static var previews: some View {
|
||||
Group {
|
||||
|
@ -443,6 +454,49 @@ struct StatusView_Previews: PreviewProvider {
|
|||
return statusView
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 200))
|
||||
.previewDisplayName("Normal")
|
||||
UIViewPreview(width: 375) {
|
||||
let statusView = StatusView()
|
||||
statusView.headerContainerStackView.isHidden = false
|
||||
statusView.avatarButton.isHidden = true
|
||||
statusView.avatarStackedContainerButton.isHidden = false
|
||||
statusView.avatarStackedContainerButton.topLeadingAvatarStackedImageView.configure(
|
||||
with: AvatarConfigurableViewConfiguration(
|
||||
avatarImageURL: nil,
|
||||
placeholderImage: avatarFlora
|
||||
)
|
||||
)
|
||||
statusView.avatarStackedContainerButton.bottomTrailingAvatarStackedImageView.configure(
|
||||
with: AvatarConfigurableViewConfiguration(
|
||||
avatarImageURL: nil,
|
||||
placeholderImage: avatarMarkus
|
||||
)
|
||||
)
|
||||
return statusView
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 200))
|
||||
.previewDisplayName("Boost")
|
||||
UIViewPreview(width: 375) {
|
||||
let statusView = StatusView(frame: CGRect(x: 0, y: 0, width: 375, height: 500))
|
||||
statusView.configure(
|
||||
with: AvatarConfigurableViewConfiguration(
|
||||
avatarImageURL: nil,
|
||||
placeholderImage: avatarFlora
|
||||
)
|
||||
)
|
||||
statusView.headerContainerStackView.isHidden = false
|
||||
let images = MosaicImageView_Previews.images
|
||||
let imageViews = statusView.statusMosaicImageViewContainer.setupImageViews(count: 4, maxHeight: 162)
|
||||
for (i, imageView) in imageViews.enumerated() {
|
||||
imageView.image = images[i]
|
||||
}
|
||||
statusView.statusMosaicImageViewContainer.isHidden = false
|
||||
statusView.statusMosaicImageViewContainer.blurVisualEffectView.isHidden = true
|
||||
statusView.isStatusTextSensitive = false
|
||||
return statusView
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 380))
|
||||
.previewDisplayName("Image Meida")
|
||||
UIViewPreview(width: 375) {
|
||||
let statusView = StatusView(frame: CGRect(x: 0, y: 0, width: 375, height: 500))
|
||||
statusView.configure(
|
||||
|
@ -466,6 +520,7 @@ struct StatusView_Previews: PreviewProvider {
|
|||
return statusView
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 380))
|
||||
.previewDisplayName("Content Sensitive")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue