You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
14 KiB
352 lines
14 KiB
//
|
|
// StatusStackView.swift
|
|
// elpha-ios
|
|
//
|
|
// Created by Dwayne Harris on 10/9/18.
|
|
// Copyright © 2018 Elpha. All rights reserved.
|
|
//
|
|
|
|
import AlamofireImage
|
|
import UIKit
|
|
|
|
protocol StatusViewDelegate {
|
|
func accountTapped(account: AccountMO)
|
|
func statusTapped(status: StatusMO)
|
|
func loadMoreTapped(status: StatusMO, direction: PaginationDirection)
|
|
func attachmentTapped(status: StatusMO, index: Int)
|
|
func boostTapped()
|
|
func favoriteTapped()
|
|
func revealTapped()
|
|
func hideTapped()
|
|
}
|
|
|
|
extension StatusViewDelegate {
|
|
func loadMoreTapped(status: StatusMO, direction: PaginationDirection) {}
|
|
func boostTapped() {}
|
|
func favoriteTapped() {}
|
|
func revealTapped() {}
|
|
func hideTapped() {}
|
|
}
|
|
|
|
class StatusView: UIView {
|
|
@IBOutlet var contentView: UIView!
|
|
@IBOutlet var boostView: UIView!
|
|
@IBOutlet var boostAvatarImageView: UIImageView!
|
|
@IBOutlet var boostDisplayNameLabel: UILabel!
|
|
@IBOutlet var boostUsernameLabel: UILabel!
|
|
@IBOutlet var replyView: UIView!
|
|
@IBOutlet var replyAvatarImageView: UIImageView!
|
|
@IBOutlet var replyDisplayNameLabel: UILabel!
|
|
@IBOutlet var replyUsernameLabel: UILabel!
|
|
@IBOutlet var avatarImageView: UIImageView!
|
|
@IBOutlet var displayNameLabel: UILabel!
|
|
@IBOutlet var usernameLabel: UILabel!
|
|
@IBOutlet var timestampLabel: UILabel!
|
|
@IBOutlet var repliesImageView: UIImageView!
|
|
@IBOutlet var repliesLabel: UILabel!
|
|
@IBOutlet var boostsImageView: UIImageView!
|
|
@IBOutlet var boostsLabel: UILabel!
|
|
@IBOutlet var favoritesImageView: UIImageView!
|
|
@IBOutlet var favoritesLabel: UILabel!
|
|
@IBOutlet var topDividerView: UIView!
|
|
@IBOutlet var bottomDividerView: UIView!
|
|
@IBOutlet var attachmentsView: UIView!
|
|
@IBOutlet var detailsView: UIView!
|
|
@IBOutlet var spoilerImageView: UIImageView!
|
|
@IBOutlet var pinImageView: UIImageView!
|
|
@IBOutlet var topLoadMoreView: UIView!
|
|
@IBOutlet var bottomLoadMoreView: UIView!
|
|
@IBOutlet var contentTextView: UITextView!
|
|
|
|
var status: StatusMO? = nil
|
|
var delegate: StatusViewDelegate? = nil
|
|
var spoilerView: UIVisualEffectView? = nil
|
|
var attachmentManager: AttachmentManager = AttachmentManager()
|
|
|
|
@IBAction func boostViewTapped(_ sender: Any) {
|
|
if let delegate = delegate, let status = status {
|
|
delegate.accountTapped(account: status.account!)
|
|
}
|
|
}
|
|
|
|
@IBAction func replyViewTapped(_ sender: Any) {
|
|
if let delegate = delegate,
|
|
let status = status,
|
|
let replyAccountID = status.inReplyToAccountID,
|
|
let replyAccount = MastodonDataManager.account(id: replyAccountID) {
|
|
delegate.accountTapped(account: replyAccount)
|
|
}
|
|
}
|
|
|
|
@IBAction func accountViewTapped(_ sender: Any) {
|
|
if let delegate = delegate, let status = status {
|
|
if let reblog = status.reblog {
|
|
delegate.accountTapped(account: reblog.account!)
|
|
} else {
|
|
delegate.accountTapped(account: status.account!)
|
|
}
|
|
}
|
|
}
|
|
|
|
@IBAction func mainViewTapped(_ sender: Any) {
|
|
if let delegate = delegate, let status = status {
|
|
if let reblog = status.reblog {
|
|
delegate.statusTapped(status: reblog)
|
|
} else {
|
|
delegate.statusTapped(status: status)
|
|
}
|
|
}
|
|
}
|
|
|
|
@IBAction func spoilerImageTapped(_ sender: Any) {
|
|
if let status = status {
|
|
status.hidden = true
|
|
CoreDataManager.shared.saveContext()
|
|
delegate?.hideTapped()
|
|
}
|
|
}
|
|
|
|
@IBAction func topLoadMoreViewTapped(_ sender: Any) {
|
|
if let delegate = delegate, let status = status {
|
|
delegate.loadMoreTapped(status: status, direction: .prev)
|
|
}
|
|
}
|
|
|
|
@IBAction func bottomLoadMoreViewTapped(_ sender: Any) {
|
|
if let delegate = delegate, let status = status {
|
|
delegate.loadMoreTapped(status: status, direction: .next)
|
|
}
|
|
}
|
|
|
|
@IBAction func boostTapped(_ sender: Any) {
|
|
if let status = status {
|
|
if status.reblogged {
|
|
status.reblogged = false
|
|
status.reblogsCount = status.reblogsCount - 1
|
|
|
|
MastodonAPI.unreblog(statusID: status.id!) { error in
|
|
guard error == nil else {
|
|
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
|
|
return
|
|
}
|
|
|
|
AlertManager.shared.show(message: "Unboosted", category: .boosted)
|
|
}
|
|
} else {
|
|
status.reblogged = true
|
|
status.reblogsCount = status.reblogsCount + 1
|
|
|
|
MastodonAPI.reblog(statusID: status.id!) { error in
|
|
guard error == nil else {
|
|
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
|
|
return
|
|
}
|
|
|
|
AlertManager.shared.show(message: "Boosted!", category: .boosted)
|
|
}
|
|
}
|
|
|
|
CoreDataManager.shared.saveContext()
|
|
delegate?.boostTapped()
|
|
}
|
|
}
|
|
|
|
@IBAction func favoriteTapped(_ sender: Any) {
|
|
if let status = status {
|
|
if status.favorited {
|
|
status.favorited = false
|
|
status.favoritesCount = status.favoritesCount - 1
|
|
|
|
MastodonAPI.unfavorite(statusID: status.id!) { error in
|
|
guard error == nil else {
|
|
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
|
|
return
|
|
}
|
|
|
|
AlertManager.shared.show(message: "Unfavorited", category: .favorited)
|
|
}
|
|
} else {
|
|
status.favorited = true
|
|
status.favoritesCount = status.favoritesCount + 1
|
|
|
|
MastodonAPI.favorite(statusID: status.id!) { error in
|
|
guard error == nil else {
|
|
AlertManager.shared.show(message: error!.localizedDescription, category: .error)
|
|
return
|
|
}
|
|
|
|
AlertManager.shared.show(message: "Favorited!", category: .favorited)
|
|
}
|
|
}
|
|
|
|
CoreDataManager.shared.saveContext()
|
|
delegate?.favoriteTapped()
|
|
}
|
|
}
|
|
|
|
|
|
@objc func reveal(sender: UITapGestureRecognizer) {
|
|
if let status = status {
|
|
status.hidden = false
|
|
CoreDataManager.shared.saveContext()
|
|
delegate?.revealTapped()
|
|
}
|
|
}
|
|
|
|
override init(frame: CGRect) {
|
|
super.init(frame: frame)
|
|
setup()
|
|
}
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
super.init(coder: aDecoder)
|
|
setup()
|
|
}
|
|
|
|
private func setup() {
|
|
Bundle.main.loadNibNamed("StatusView", owner: self, options: nil)
|
|
addSubview(contentView)
|
|
contentView.frame = self.bounds
|
|
attachmentManager.delegate = self
|
|
}
|
|
|
|
public func update(withStatus status: StatusMO) {
|
|
self.status = status
|
|
|
|
boostView.isHidden = true
|
|
replyView.isHidden = true
|
|
|
|
attachmentsView.backgroundColor = UIColor.white
|
|
attachmentsView.isHidden = true
|
|
|
|
spoilerImageView.isHidden = true
|
|
|
|
let avatarFilter = AspectScaledToFillSizeWithRoundedCornersFilter(
|
|
size: CGSize(width: 40.0, height: 40.0),
|
|
radius: 20.0,
|
|
divideRadiusByImageScale: true
|
|
)
|
|
|
|
func updateStatusContent(_ status: StatusMO) {
|
|
if let account = status.account {
|
|
avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter)
|
|
displayNameLabel.text = account.displayName
|
|
usernameLabel.text = "@\(account.acct!)"
|
|
}
|
|
|
|
if let attachments = status.attachments, attachments.count > 0 {
|
|
attachmentsView.isHidden = false
|
|
attachmentManager.setupAttachmentView(attachmentsView, withAttachments: attachments)
|
|
}
|
|
|
|
if let content = status.content {
|
|
contentTextView.attributedText = content.htmlAttributed(size: 15.0)
|
|
|
|
if status.hidden && spoilerView == nil {
|
|
let spoilerText = UILabel(frame: contentTextView.frame)
|
|
spoilerText.textColor = UIColor(named: "Primary")
|
|
spoilerText.font = UIFont.systemFont(ofSize: 15, weight: .bold)
|
|
spoilerText.textAlignment = .center
|
|
spoilerText.text = status.spoilerText
|
|
spoilerText.numberOfLines = 0
|
|
spoilerText.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffect.Style.light))
|
|
blurEffectView.translatesAutoresizingMaskIntoConstraints = false
|
|
blurEffectView.contentView.addSubview(spoilerText)
|
|
|
|
NSLayoutConstraint.activate([
|
|
spoilerText.leadingAnchor.constraint(equalTo: blurEffectView.leadingAnchor),
|
|
spoilerText.trailingAnchor.constraint(equalTo: blurEffectView.trailingAnchor),
|
|
spoilerText.centerYAnchor.constraint(equalTo: blurEffectView.centerYAnchor),
|
|
])
|
|
|
|
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.reveal))
|
|
tapGesture.numberOfTapsRequired = 1
|
|
tapGesture.numberOfTouchesRequired = 1
|
|
blurEffectView.addGestureRecognizer(tapGesture)
|
|
blurEffectView.isUserInteractionEnabled = true
|
|
|
|
self.spoilerView = blurEffectView
|
|
self.contentView.addSubview(blurEffectView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
blurEffectView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
blurEffectView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
|
blurEffectView.topAnchor.constraint(equalTo: contentTextView.topAnchor),
|
|
blurEffectView.bottomAnchor.constraint(equalTo: detailsView.topAnchor),
|
|
])
|
|
} else {
|
|
if let spoilerView = spoilerView {
|
|
spoilerView.removeFromSuperview()
|
|
self.spoilerView = nil
|
|
}
|
|
|
|
if let spoilerText = status.spoilerText, !spoilerText.isEmpty {
|
|
spoilerImageView.isHidden = false
|
|
}
|
|
}
|
|
}
|
|
|
|
timestampLabel.text = status.createdAt!.timeAgo()
|
|
repliesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.repliesCount), number: .decimal)
|
|
boostsLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.reblogsCount), number: .decimal)
|
|
favoritesLabel.text = NumberFormatter.localizedString(from: NSNumber(value: status.favoritesCount), number: .decimal)
|
|
|
|
if status.reblogged {
|
|
boostsImageView.image = UIImage(named: "Boost Bold")
|
|
} else {
|
|
boostsImageView.image = UIImage(named: "Boost Regular")
|
|
}
|
|
|
|
if status.favorited {
|
|
favoritesImageView.image = UIImage(named: "Star Filled")
|
|
} else {
|
|
favoritesImageView.image = UIImage(named: "Star Regular")
|
|
}
|
|
|
|
pinImageView.isHidden = !status.pinned
|
|
}
|
|
|
|
if let reblog = status.reblog {
|
|
boostView.isHidden = false
|
|
|
|
if let account = status.account {
|
|
boostAvatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter)
|
|
boostDisplayNameLabel.text = account.displayName
|
|
boostUsernameLabel.text = "@\(account.acct!)"
|
|
}
|
|
|
|
updateStatusContent(reblog)
|
|
} else {
|
|
if let account = status.account {
|
|
avatarImageView.af_setImage(withURL: account.avatarURL!, filter: avatarFilter)
|
|
displayNameLabel.text = account.displayName
|
|
usernameLabel.text = "@\(account.acct!)"
|
|
}
|
|
|
|
updateStatusContent(status)
|
|
}
|
|
|
|
if let replyAccountID = status.inReplyToAccountID {
|
|
if let replyAccount = MastodonDataManager.account(id: replyAccountID) {
|
|
replyView.isHidden = false
|
|
replyAvatarImageView.af_setImage(withURL: replyAccount.avatarURL!, filter: avatarFilter)
|
|
replyDisplayNameLabel.text = replyAccount.displayName
|
|
replyUsernameLabel.text = "@\(replyAccount.acct!)"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension StatusView: AttachmentManagerDelegate {
|
|
func attachmentTapped(index: Int) {
|
|
if let delegate = delegate, let status = status {
|
|
if let reblog = status.reblog {
|
|
delegate.attachmentTapped(status: reblog, index: index)
|
|
} else {
|
|
delegate.attachmentTapped(status: status, index: index)
|
|
}
|
|
}
|
|
}
|
|
}
|