Compare commits
No commits in common. "6e4f89df4a5a799ef6b6568710c731576db27b5e" and "2e6f7d8878a5822c2e57a11678e01227ae5cadf2" have entirely different histories.
6e4f89df4a
...
2e6f7d8878
|
@ -119,13 +119,7 @@ class ConversationTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ConversationTableViewController: StatusTableViewCellDelegate {
|
extension ConversationTableViewController: StatusTableViewCellDelegate {}
|
||||||
func statusCollapsedStateChanged() {
|
|
||||||
// causes the table view to recalculate the cell heights
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ConversationTableViewController: UITableViewDataSourcePrefetching {
|
extension ConversationTableViewController: UITableViewDataSourcePrefetching {
|
||||||
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
import AVFoundation
|
|
||||||
import AVKit
|
|
||||||
|
|
||||||
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
||||||
|
|
||||||
|
@ -18,10 +16,10 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
||||||
let startIndex: Int
|
let startIndex: Int
|
||||||
|
|
||||||
let pages: [UIViewController]
|
let pages: [AttachmentViewController]
|
||||||
|
|
||||||
var currentIndex: Int {
|
var currentIndex: Int {
|
||||||
guard let vc = viewControllers?.first,
|
guard let vc = viewControllers?.first as? AttachmentViewController,
|
||||||
let index = pages.firstIndex(of: vc) else {
|
let index = pages.firstIndex(of: vc) else {
|
||||||
fatalError()
|
fatalError()
|
||||||
}
|
}
|
||||||
|
@ -41,18 +39,7 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
self.sourcesInfo = sourcesInfo
|
self.sourcesInfo = sourcesInfo
|
||||||
self.startIndex = startIndex
|
self.startIndex = startIndex
|
||||||
|
|
||||||
self.pages = attachments.map {
|
self.pages = attachments.map(AttachmentViewController.init)
|
||||||
switch $0.kind {
|
|
||||||
case .image:
|
|
||||||
return AttachmentViewController(attachment: $0)
|
|
||||||
case .video:
|
|
||||||
let vc = AVPlayerViewController()
|
|
||||||
vc.player = AVPlayer(url: $0.url)
|
|
||||||
return vc
|
|
||||||
default:
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal)
|
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal)
|
||||||
|
|
||||||
|
@ -74,24 +61,12 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
dismissInteractionController = LargeImageInteractionController(viewController: self)
|
dismissInteractionController = LargeImageInteractionController(viewController: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
|
||||||
super.viewDidAppear(animated)
|
|
||||||
|
|
||||||
if let vc = pages[currentIndex] as? AVPlayerViewController {
|
|
||||||
// when the gallery is first shown, after the transition finishes, the controls for the player controller appear semi-transparent
|
|
||||||
// hiding the controls and then immediately reshowing them makes sure they're visible when the gallery is presented
|
|
||||||
vc.showsPlaybackControls = false
|
|
||||||
vc.showsPlaybackControls = true
|
|
||||||
|
|
||||||
// begin playing the video as soon as we appear
|
|
||||||
vc.player?.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Page View Controller Data Source
|
// MARK: - Page View Controller Data Source
|
||||||
|
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
||||||
guard let index = pages.firstIndex(of: viewController),
|
guard let attachment = viewController as? AttachmentViewController,
|
||||||
|
let index = pages.firstIndex(of: attachment),
|
||||||
index > 0 else {
|
index > 0 else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -99,7 +74,8 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
}
|
}
|
||||||
|
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
||||||
guard let index = pages.firstIndex(of: viewController),
|
guard let attachment = viewController as? AttachmentViewController,
|
||||||
|
let index = pages.firstIndex(of: attachment),
|
||||||
index < pages.count - 1 else {
|
index < pages.count - 1 else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -108,16 +84,9 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
|
|
||||||
// MARK: - Page View Controller Delegate
|
// MARK: - Page View Controller Delegate
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
|
||||||
if let pending = pendingViewControllers.first as? AttachmentViewController,
|
let pending = pendingViewControllers.first as! AttachmentViewController
|
||||||
let current = viewControllers!.first as? AttachmentViewController {
|
let current = viewControllers!.first as! AttachmentViewController
|
||||||
pending.controlsVisible = current.controlsVisible
|
pending.controlsVisible = current.controlsVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
if let pending = pendingViewControllers.first as? AVPlayerViewController {
|
|
||||||
// show controls and begin playing when the player page becomes visible
|
|
||||||
pending.showsPlaybackControls = true
|
|
||||||
pending.player?.play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let (image, sourceFrame, sourceCornerRadius) = toVC.sourcesInfo[toVC.startIndex] else {
|
guard let (sourceFrame, sourceCornerRadius) = toVC.sourcesInfo[toVC.startIndex] else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
|
@ -29,7 +29,11 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
|
|
||||||
let attachment = toVC.attachments[toVC.startIndex]
|
let attachment = toVC.attachments[toVC.startIndex]
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
guard let data = ImageCache.attachments.get(attachment.url), let image = UIImage(data: data) else {
|
||||||
|
toVC.view.frame = finalVCFrame
|
||||||
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
var width = finalVCFrame.width
|
var width = finalVCFrame.width
|
||||||
|
@ -42,10 +46,11 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
}
|
}
|
||||||
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
||||||
|
|
||||||
|
let containerView = transitionContext.containerView
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceFrame)
|
let imageView = GIFImageView(frame: sourceFrame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if attachment.url.pathExtension == "gif",
|
if attachment.url.pathExtension == "gif" {
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
imageView.animate(withGIFData: data)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
|
@ -26,7 +26,7 @@ class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let (image, sourceFrame, sourceCornerRadius) = fromVC.sourcesInfo[fromVC.currentIndex] else {
|
guard let (sourceFrame, sourceCornerRadius) = fromVC.sourcesInfo[fromVC.currentIndex] else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,12 @@ class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
|
|
||||||
let attachment = fromVC.attachments[fromVC.currentIndex]
|
let attachment = fromVC.attachments[fromVC.currentIndex]
|
||||||
|
|
||||||
|
guard let data = ImageCache.attachments.get(attachment.url),
|
||||||
|
let image = UIImage(data: data) else {
|
||||||
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
var width = originalVCFrame.width
|
var width = originalVCFrame.width
|
||||||
var height = width / ratio
|
var height = width / ratio
|
||||||
|
@ -47,8 +53,7 @@ class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
let imageView = GIFImageView(frame: originalFrame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if attachment.url.pathExtension == "gif",
|
if attachment.url.pathExtension == "gif" {
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
imageView.animate(withGIFData: data)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
|
@ -13,7 +13,7 @@ import Gifu
|
||||||
|
|
||||||
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
|
|
||||||
typealias SourceInfo = (image: UIImage, frame: CGRect, cornerRadius: CGFloat)
|
typealias SourceInfo = (frame: CGRect, cornerRadius: CGFloat)
|
||||||
|
|
||||||
var sourceInfo: SourceInfo?
|
var sourceInfo: SourceInfo?
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
|
@ -22,13 +22,14 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
}
|
}
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let (image, originFrame, originCornerRadius) = toVC.sourceInfo else {
|
guard let (originFrame, originCornerRadius) = toVC.sourceInfo else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
let containerView = transitionContext.containerView
|
||||||
|
let image = toVC.imageView.image!
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
let width = finalVCFrame.width
|
let width = finalVCFrame.width
|
||||||
let height = width / ratio
|
let height = width / ratio
|
||||||
|
|
|
@ -27,7 +27,7 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let (image, finalFrame, finalCornerRadius) = fromVC.sourceInfo else {
|
guard let (finalFrame, finalCornerRadius) = fromVC.sourceInfo else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,14 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
let originalVCFrame = fromVC.view.frame
|
let originalVCFrame = fromVC.view.frame
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
let containerView = transitionContext.containerView
|
||||||
|
let image = fromVC.image!
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
let width = originalVCFrame.width
|
let width = originalVCFrame.width
|
||||||
let height = width / ratio
|
let height = width / ratio
|
||||||
let originalFrame = CGRect(x: originalVCFrame.midX - width / 2, y: originalVCFrame.midY - height / 2, width: width, height: height)
|
let originalFrame = CGRect(x: originalVCFrame.midX - width / 2, y: originalVCFrame.midY - height / 2, width: width, height: height)
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
let imageView = GIFImageView(frame: originalFrame)
|
||||||
imageView.image = image
|
imageView.image = fromVC.image!
|
||||||
if let gifData = fromVC.gifData {
|
if let gifData = fromVC.gifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,13 +173,7 @@ class NotificationsTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationsTableViewController: StatusTableViewCellDelegate {
|
extension NotificationsTableViewController: StatusTableViewCellDelegate {}
|
||||||
func statusCollapsedStateChanged() {
|
|
||||||
// causes the table view to recalculate the cell heights
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NotificationsTableViewController: UITableViewDataSourcePrefetching {
|
extension NotificationsTableViewController: UITableViewDataSourcePrefetching {
|
||||||
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
||||||
|
|
|
@ -205,14 +205,7 @@ class ProfileTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ProfileTableViewController: StatusTableViewCellDelegate {
|
extension ProfileTableViewController: StatusTableViewCellDelegate {}
|
||||||
func statusCollapsedStateChanged() {
|
|
||||||
// causes the table view to recalculate the cell heights
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate {
|
extension ProfileTableViewController: ProfileHeaderTableViewCellDelegate {
|
||||||
func showMoreOptions() {
|
func showMoreOptions() {
|
||||||
let account = MastodonCache.account(for: accountID)!
|
let account = MastodonCache.account(for: accountID)!
|
||||||
|
|
|
@ -134,10 +134,4 @@ class StatusActionAccountListTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate {
|
extension StatusActionAccountListTableViewController: StatusTableViewCellDelegate {}
|
||||||
func statusCollapsedStateChanged() {
|
|
||||||
// causes the table view to recalculate the cell heights
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -151,13 +151,7 @@ class TimelineTableViewController: EnhancedTableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimelineTableViewController: StatusTableViewCellDelegate {
|
extension TimelineTableViewController: StatusTableViewCellDelegate {}
|
||||||
func statusCollapsedStateChanged() {
|
|
||||||
// causes the table view to recalculate the cell heights
|
|
||||||
tableView.beginUpdates()
|
|
||||||
tableView.endUpdates()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TimelineTableViewController: UITableViewDataSourcePrefetching {
|
extension TimelineTableViewController: UITableViewDataSourcePrefetching {
|
||||||
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
|
||||||
|
|
|
@ -28,17 +28,17 @@ protocol TuskerNavigationDelegate {
|
||||||
|
|
||||||
func reply(to statusID: String)
|
func reply(to statusID: String)
|
||||||
|
|
||||||
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController
|
func largeImage(_ image: UIImage, description: String?, sourceView: UIView) -> LargeImageViewController
|
||||||
|
|
||||||
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController
|
func largeImage(gifData: Data, description: String?, sourceView: UIView) -> LargeImageViewController
|
||||||
|
|
||||||
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIImageView)
|
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIView)
|
||||||
|
|
||||||
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView)
|
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIView)
|
||||||
|
|
||||||
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController
|
func gallery(attachments: [Attachment], sourceViews: [UIView?], startIndex: Int) -> GalleryViewController
|
||||||
|
|
||||||
func showGallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int)
|
func showGallery(attachments: [Attachment], sourceViews: [UIView?], startIndex: Int)
|
||||||
|
|
||||||
func showMoreOptions(forStatus statusID: String)
|
func showMoreOptions(forStatus statusID: String)
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
present(vc, animated: true)
|
present(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sourceViewInfo(_ sourceView: UIImageView?) -> LargeImageViewController.SourceInfo? {
|
private func sourceViewInfo(_ sourceView: UIView?) -> LargeImageViewController.SourceInfo? {
|
||||||
guard let sourceView = sourceView else { return nil }
|
guard let sourceView = sourceView else { return nil }
|
||||||
|
|
||||||
var sourceFrame = sourceView.convert(sourceView.bounds, to: view)
|
var sourceFrame = sourceView.convert(sourceView.bounds, to: view)
|
||||||
|
@ -121,38 +121,38 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
||||||
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
||||||
}
|
}
|
||||||
return (image: sourceView.image!, frame: sourceFrame, cornerRadius: sourceView.layer.cornerRadius)
|
return (frame: sourceFrame, cornerRadius: sourceView.layer.cornerRadius)
|
||||||
}
|
}
|
||||||
|
|
||||||
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
func largeImage(_ image: UIImage, description: String?, sourceView: UIView) -> LargeImageViewController {
|
||||||
let vc = LargeImageViewController(image: image, description: description, sourceInfo: sourceViewInfo(sourceView))
|
let vc = LargeImageViewController(image: image, description: description, sourceInfo: sourceViewInfo(sourceView))
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
func largeImage(gifData: Data, description: String?, sourceView: UIView) -> LargeImageViewController {
|
||||||
let vc = LargeImageViewController(image: UIImage(data: gifData)!, description: description, sourceInfo: sourceViewInfo(sourceView))
|
let vc = LargeImageViewController(image: UIImage(data: gifData)!, description: description, sourceInfo: sourceViewInfo(sourceView))
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
vc.gifData = gifData
|
vc.gifData = gifData
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIImageView) {
|
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIView) {
|
||||||
present(largeImage(image, description: description, sourceView: sourceView), animated: true)
|
present(largeImage(image, description: description, sourceView: sourceView), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView) {
|
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIView) {
|
||||||
present(largeImage(gifData: gifData, description: description, sourceView: sourceView), animated: true)
|
present(largeImage(gifData: gifData, description: description, sourceView: sourceView), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController {
|
func gallery(attachments: [Attachment], sourceViews: [UIView?], startIndex: Int) -> GalleryViewController {
|
||||||
let sourcesInfo = sourceViews.map(sourceViewInfo)
|
let sourcesInfo = sourceViews.map(sourceViewInfo)
|
||||||
let vc = GalleryViewController(attachments: attachments, sourcesInfo: sourcesInfo, startIndex: startIndex)
|
let vc = GalleryViewController(attachments: attachments, sourcesInfo: sourcesInfo, startIndex: startIndex)
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func showGallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) {
|
func showGallery(attachments: [Attachment], sourceViews: [UIView?], startIndex: Int) {
|
||||||
present(gallery(attachments: attachments, sourceViews: sourceViews, startIndex: startIndex), animated: true)
|
present(gallery(attachments: attachments, sourceViews: sourceViews, startIndex: startIndex), animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
import Gifu
|
import Gifu
|
||||||
import AVFoundation
|
|
||||||
|
|
||||||
protocol AttachmentViewDelegate {
|
protocol AttachmentViewDelegate {
|
||||||
func showAttachmentsGallery(startingAt index: Int)
|
func showAttachmentsGallery(startingAt index: Int)
|
||||||
|
@ -19,8 +18,6 @@ class AttachmentView: UIImageView, GIFAnimatable {
|
||||||
|
|
||||||
var delegate: AttachmentViewDelegate?
|
var delegate: AttachmentViewDelegate?
|
||||||
|
|
||||||
var playImageView: UIImageView!
|
|
||||||
|
|
||||||
var attachment: Attachment!
|
var attachment: Attachment!
|
||||||
var index: Int!
|
var index: Int!
|
||||||
|
|
||||||
|
@ -34,7 +31,7 @@ class AttachmentView: UIImageView, GIFAnimatable {
|
||||||
|
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
self.index = index
|
self.index = index
|
||||||
loadAttachment()
|
loadImage()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
@ -47,27 +44,6 @@ class AttachmentView: UIImageView, GIFAnimatable {
|
||||||
layer.masksToBounds = true
|
layer.masksToBounds = true
|
||||||
isUserInteractionEnabled = true
|
isUserInteractionEnabled = true
|
||||||
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imagePressed)))
|
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(imagePressed)))
|
||||||
|
|
||||||
playImageView = UIImageView(image: UIImage(systemName: "play.circle.fill"))
|
|
||||||
playImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(playImageView)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
playImageView.widthAnchor.constraint(equalToConstant: 50),
|
|
||||||
playImageView.heightAnchor.constraint(equalToConstant: 50),
|
|
||||||
playImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
|
||||||
playImageView.centerYAnchor.constraint(equalTo: centerYAnchor)
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadAttachment() {
|
|
||||||
switch attachment.kind {
|
|
||||||
case .image:
|
|
||||||
loadImage()
|
|
||||||
case .video:
|
|
||||||
loadVideo()
|
|
||||||
default:
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadImage() {
|
func loadImage() {
|
||||||
|
@ -82,22 +58,6 @@ class AttachmentView: UIImageView, GIFAnimatable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
playImageView.isHidden = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadVideo() {
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
|
||||||
let asset = AVURLAsset(url: self.attachment.url)
|
|
||||||
let generator = AVAssetImageGenerator(asset: asset)
|
|
||||||
generator.appliesPreferredTrackTransform = true
|
|
||||||
guard let image = try? generator.copyCGImage(at: CMTime(seconds: 0, preferredTimescale: 1), actualTime: nil) else { return }
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
self.image = UIImage(cgImage: image)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
playImageView.isHidden = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func display(_ layer: CALayer) {
|
override func display(_ layer: CALayer) {
|
||||||
|
@ -105,14 +65,8 @@ class AttachmentView: UIImageView, GIFAnimatable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func imagePressed() {
|
@objc func imagePressed() {
|
||||||
// switch attachment.kind {
|
// delegate?.showLargeAttachment(for: self)
|
||||||
// case .image:
|
|
||||||
delegate?.showAttachmentsGallery(startingAt: index)
|
delegate?.showAttachmentsGallery(startingAt: index)
|
||||||
// case .video:
|
|
||||||
// delegate?.showVideo(attachment: attachment)
|
|
||||||
// default:
|
|
||||||
// fatalError()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ class AttachmentsContainerView: UIView {
|
||||||
|
|
||||||
func updateUI(status: Status) {
|
func updateUI(status: Status) {
|
||||||
self.statusID = status.id
|
self.statusID = status.id
|
||||||
attachments = status.attachments.filter { $0.kind == .image || $0.kind == .video }
|
attachments = status.attachments.filter { $0.kind == .image }
|
||||||
|
|
||||||
attachmentViews.removeAllObjects()
|
attachmentViews.removeAllObjects()
|
||||||
subviews.forEach { $0.removeFromSuperview() }
|
subviews.forEach { $0.removeFromSuperview() }
|
||||||
|
|
|
@ -27,8 +27,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
@IBOutlet weak var displayNameLabel: UILabel!
|
@IBOutlet weak var displayNameLabel: UILabel!
|
||||||
@IBOutlet weak var usernameLabel: UILabel!
|
@IBOutlet weak var usernameLabel: UILabel!
|
||||||
@IBOutlet weak var contentWarningLabel: UILabel!
|
|
||||||
@IBOutlet weak var collapseButton: UIButton!
|
|
||||||
@IBOutlet weak var contentLabel: StatusContentLabel!
|
@IBOutlet weak var contentLabel: StatusContentLabel!
|
||||||
@IBOutlet weak var avatarImageView: UIImageView!
|
@IBOutlet weak var avatarImageView: UIImageView!
|
||||||
@IBOutlet weak var totalFavoritesButton: UIButton!
|
@IBOutlet weak var totalFavoritesButton: UIButton!
|
||||||
|
@ -56,13 +54,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var collapsible = false {
|
|
||||||
didSet {
|
|
||||||
collapseButton.isHidden = !collapsible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var collapsed = false
|
|
||||||
|
|
||||||
var avatarURL: URL?
|
var avatarURL: URL?
|
||||||
|
|
||||||
var statusUpdater: Cancellable?
|
var statusUpdater: Cancellable?
|
||||||
|
@ -81,8 +72,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell {
|
||||||
attachmentsView.delegate = self
|
attachmentsView.delegate = self
|
||||||
attachmentsView.layer.cornerRadius = 5
|
attachmentsView.layer.cornerRadius = 5
|
||||||
attachmentsView.layer.masksToBounds = true
|
attachmentsView.layer.masksToBounds = true
|
||||||
collapseButton.layer.masksToBounds = true
|
|
||||||
collapseButton.layer.cornerRadius = 5
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
||||||
|
@ -118,17 +107,13 @@ class ConversationMainStatusTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
timestampAndClientLabel.text = timestampAndClientText
|
timestampAndClientLabel.text = timestampAndClientText
|
||||||
|
|
||||||
|
|
||||||
attachmentsView.updateUI(status: status)
|
attachmentsView.updateUI(status: status)
|
||||||
|
|
||||||
let realStatus = status.reblog ?? status
|
let realStatus = status.reblog ?? status
|
||||||
updateStatusState(status: realStatus)
|
updateStatusState(status: realStatus)
|
||||||
|
|
||||||
contentLabel.statusID = statusID
|
contentLabel.statusID = statusID
|
||||||
|
|
||||||
collapsible = !status.spoilerText.isEmpty
|
|
||||||
setCollapsed(collapsible, animated: false)
|
|
||||||
contentWarningLabel.text = status.spoilerText
|
|
||||||
contentWarningLabel.isHidden = status.spoilerText.isEmpty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateStatusState(status: Status) {
|
private func updateStatusState(status: Status) {
|
||||||
|
@ -171,37 +156,6 @@ class ConversationMainStatusTableViewCell: UITableViewCell {
|
||||||
delegate?.selected(account: accountID)
|
delegate?.selected(account: accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func collapsePressed(_ sender: Any) {
|
|
||||||
setCollapsed(!collapsed, animated: true)
|
|
||||||
delegate?.statusCollapsedStateChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setCollapsed(_ collapsed: Bool, animated: Bool) {
|
|
||||||
self.collapsed = collapsed
|
|
||||||
|
|
||||||
contentLabel.isHidden = collapsed
|
|
||||||
attachmentsView.isHidden = attachmentsView.attachments.count == 0 || collapsed
|
|
||||||
|
|
||||||
let buttonImage = UIImage(systemName: collapsed ? "chevron.down" : "chevron.up")
|
|
||||||
|
|
||||||
if animated, let buttonImageView = collapseButton.imageView {
|
|
||||||
// see comment in StatusTableViewCell.setCollapsed
|
|
||||||
UIView.animateKeyframes(withDuration: 0.2, delay: 0, options: .calculationModeLinear, animations: {
|
|
||||||
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
|
|
||||||
buttonImageView.transform = CGAffineTransform(rotationAngle: collapsed ? .pi / 2 : -.pi / 2)
|
|
||||||
}
|
|
||||||
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
|
|
||||||
buttonImageView.transform = CGAffineTransform(rotationAngle: .pi)
|
|
||||||
}
|
|
||||||
}, completion: { (finished) in
|
|
||||||
buttonImageView.transform = .identity
|
|
||||||
self.collapseButton.setImage(buttonImage, for: .normal)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
collapseButton.setImage(buttonImage, for: .normal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func replyPressed(_ sender: Any) {
|
@IBAction func replyPressed(_ sender: Any) {
|
||||||
delegate?.reply(to: statusID)
|
delegate?.reply(to: statusID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ConversationMainStatusTableViewCell" customModule="Tusker" customModuleProvider="target">
|
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="ConversationMainStatusTableViewCell" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="291"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="238"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="GuG-Qd-B8I">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="GuG-Qd-B8I">
|
||||||
<rect key="frame" x="16" y="8" width="343" height="275"/>
|
<rect key="frame" x="16" y="8" width="343" height="222"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="Cnd-Fj-B7l">
|
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="Cnd-Fj-B7l">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="343" height="50"/>
|
<rect key="frame" x="0.0" y="0.0" width="343" height="118.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mB9-HO-1vf">
|
<imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="mB9-HO-1vf">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||||
|
@ -38,62 +38,45 @@
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="249" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TgY-hs-Klo" customClass="StatusContentLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<rect key="frame" x="0.0" y="54" width="343" height="64.5"/>
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="SWg-Ka-QyP" secondAttribute="trailing" id="4g6-BT-eW4"/>
|
|
||||||
<constraint firstItem="lZY-2e-17d" firstAttribute="top" secondItem="Cnd-Fj-B7l" secondAttribute="top" id="8fU-y9-K5Z"/>
|
|
||||||
<constraint firstAttribute="trailingMargin" secondItem="lZY-2e-17d" secondAttribute="trailing" id="AAJ-pd-omx"/>
|
|
||||||
<constraint firstItem="lZY-2e-17d" firstAttribute="leading" secondItem="mB9-HO-1vf" secondAttribute="trailing" constant="8" id="Aqj-co-Szp"/>
|
|
||||||
<constraint firstItem="mB9-HO-1vf" firstAttribute="top" secondItem="Cnd-Fj-B7l" secondAttribute="top" id="R7P-rD-Gbm"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="mB9-HO-1vf" secondAttribute="bottom" id="Wd0-Qh-idS"/>
|
|
||||||
<constraint firstItem="mB9-HO-1vf" firstAttribute="leading" secondItem="Cnd-Fj-B7l" secondAttribute="leading" id="bxq-Fs-1aH"/>
|
|
||||||
<constraint firstItem="SWg-Ka-QyP" firstAttribute="leading" secondItem="mB9-HO-1vf" secondAttribute="trailing" constant="8" id="e45-gE-myI"/>
|
|
||||||
<constraint firstItem="SWg-Ka-QyP" firstAttribute="top" secondItem="lZY-2e-17d" secondAttribute="bottom" id="lvX-1b-8cN"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="751" text="Content Warning" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cwQ-mR-L1b">
|
|
||||||
<rect key="frame" x="0.0" y="58" width="343" height="20.5"/>
|
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8r8-O8-Agh">
|
|
||||||
<rect key="frame" x="0.0" y="86.5" width="343" height="30"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="30" id="icD-3q-uJ6"/>
|
|
||||||
</constraints>
|
|
||||||
<color key="tintColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
|
||||||
<state key="normal" image="chevron.down" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="large"/>
|
|
||||||
</state>
|
|
||||||
<connections>
|
|
||||||
<action selector="collapsePressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="w9d-kB-EaQ"/>
|
|
||||||
</connections>
|
|
||||||
</button>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" verticalHuggingPriority="249" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TgY-hs-Klo" customClass="StatusContentLabel" customModule="Tusker" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="124.5" width="343" height="47"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
<fontDescription key="fontDescription" type="system" pointSize="20"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="TgY-hs-Klo" firstAttribute="leading" secondItem="Cnd-Fj-B7l" secondAttribute="leading" id="2zu-G9-fMv"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="SWg-Ka-QyP" secondAttribute="trailing" id="4g6-BT-eW4"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="TgY-hs-Klo" secondAttribute="bottom" id="5Og-Pd-Vck"/>
|
||||||
|
<constraint firstItem="lZY-2e-17d" firstAttribute="top" secondItem="Cnd-Fj-B7l" secondAttribute="top" id="8fU-y9-K5Z"/>
|
||||||
|
<constraint firstAttribute="trailingMargin" secondItem="lZY-2e-17d" secondAttribute="trailing" id="AAJ-pd-omx"/>
|
||||||
|
<constraint firstItem="lZY-2e-17d" firstAttribute="leading" secondItem="mB9-HO-1vf" secondAttribute="trailing" constant="8" id="Aqj-co-Szp"/>
|
||||||
|
<constraint firstItem="mB9-HO-1vf" firstAttribute="top" secondItem="Cnd-Fj-B7l" secondAttribute="top" id="R7P-rD-Gbm"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="TgY-hs-Klo" secondAttribute="trailing" id="SOE-Q5-IWd"/>
|
||||||
|
<constraint firstItem="mB9-HO-1vf" firstAttribute="leading" secondItem="Cnd-Fj-B7l" secondAttribute="leading" id="bxq-Fs-1aH"/>
|
||||||
|
<constraint firstItem="SWg-Ka-QyP" firstAttribute="leading" secondItem="mB9-HO-1vf" secondAttribute="trailing" constant="8" id="e45-gE-myI"/>
|
||||||
|
<constraint firstItem="TgY-hs-Klo" firstAttribute="top" secondItem="mB9-HO-1vf" secondAttribute="bottom" constant="4" id="l6y-Rr-Nmc"/>
|
||||||
|
<constraint firstItem="SWg-Ka-QyP" firstAttribute="top" secondItem="lZY-2e-17d" secondAttribute="bottom" id="lvX-1b-8cN"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IF9-9U-Gk0" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="IF9-9U-Gk0" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="175.5" width="343" height="0.0"/>
|
<rect key="frame" x="0.0" y="122.5" width="343" height="0.0"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" priority="999" constant="200" id="UMv-Bk-ZyY"/>
|
<constraint firstAttribute="height" priority="999" constant="200" id="UMv-Bk-ZyY"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ejU-sO-Og5">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ejU-sO-Og5">
|
||||||
<rect key="frame" x="0.0" y="179.5" width="343" height="0.5"/>
|
<rect key="frame" x="0.0" y="126.5" width="343" height="0.5"/>
|
||||||
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="0.5" id="DRI-lB-TyG"/>
|
<constraint firstAttribute="height" constant="0.5" id="DRI-lB-TyG"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HZv-qj-gi6">
|
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HZv-qj-gi6">
|
||||||
<rect key="frame" x="0.0" y="188" width="343" height="18"/>
|
<rect key="frame" x="0.0" y="135" width="343" height="18"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="252" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yyj-Bs-Vjq">
|
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="252" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yyj-Bs-Vjq">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="163.5" height="18"/>
|
<rect key="frame" x="0.0" y="0.0" width="163.5" height="18"/>
|
||||||
|
@ -132,27 +115,27 @@
|
||||||
</constraints>
|
</constraints>
|
||||||
</stackView>
|
</stackView>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pcy-jH-lL9">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pcy-jH-lL9">
|
||||||
<rect key="frame" x="0.0" y="214" width="343" height="0.5"/>
|
<rect key="frame" x="0.0" y="161" width="343" height="0.5"/>
|
||||||
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="0.5" id="0Ga-Fr-g0g"/>
|
<constraint firstAttribute="height" constant="0.5" id="0Ga-Fr-g0g"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sep 7, 2019 12:12:53 PM • Web" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YHN-wG-YWi">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sep 7, 2019 12:12:53 PM • Web" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YHN-wG-YWi">
|
||||||
<rect key="frame" x="0.0" y="222.5" width="343" height="18"/>
|
<rect key="frame" x="0.0" y="169.5" width="343" height="18"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Fp-Nj-sVj">
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3Fp-Nj-sVj">
|
||||||
<rect key="frame" x="0.0" y="248.5" width="343" height="0.5"/>
|
<rect key="frame" x="0.0" y="195.5" width="343" height="0.5"/>
|
||||||
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="opaqueSeparatorColor" red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="0.5" id="akf-Kl-8mK"/>
|
<constraint firstAttribute="height" constant="0.5" id="akf-Kl-8mK"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="3Bg-XP-d13">
|
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="3Bg-XP-d13">
|
||||||
<rect key="frame" x="0.0" y="257" width="343" height="18"/>
|
<rect key="frame" x="0.0" y="204" width="343" height="18"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2cc-lE-AdG">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2cc-lE-AdG">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="21.5" height="18"/>
|
<rect key="frame" x="0.0" y="0.0" width="21.5" height="18"/>
|
||||||
|
@ -210,9 +193,7 @@
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="attachmentsView" destination="IF9-9U-Gk0" id="Oxw-sJ-MJE"/>
|
<outlet property="attachmentsView" destination="IF9-9U-Gk0" id="Oxw-sJ-MJE"/>
|
||||||
<outlet property="avatarImageView" destination="mB9-HO-1vf" id="0R0-rt-Osh"/>
|
<outlet property="avatarImageView" destination="mB9-HO-1vf" id="0R0-rt-Osh"/>
|
||||||
<outlet property="collapseButton" destination="8r8-O8-Agh" id="0es-Hi-bpt"/>
|
|
||||||
<outlet property="contentLabel" destination="TgY-hs-Klo" id="SEi-B2-VQf"/>
|
<outlet property="contentLabel" destination="TgY-hs-Klo" id="SEi-B2-VQf"/>
|
||||||
<outlet property="contentWarningLabel" destination="cwQ-mR-L1b" id="5sm-PC-FIN"/>
|
|
||||||
<outlet property="displayNameLabel" destination="lZY-2e-17d" id="7og-23-eHy"/>
|
<outlet property="displayNameLabel" destination="lZY-2e-17d" id="7og-23-eHy"/>
|
||||||
<outlet property="favoriteButton" destination="DhN-rJ-jdA" id="b2Q-ch-kSP"/>
|
<outlet property="favoriteButton" destination="DhN-rJ-jdA" id="b2Q-ch-kSP"/>
|
||||||
<outlet property="reblogButton" destination="GUG-f7-Hdy" id="WtT-Ph-DQm"/>
|
<outlet property="reblogButton" destination="GUG-f7-Hdy" id="WtT-Ph-DQm"/>
|
||||||
|
@ -221,12 +202,11 @@
|
||||||
<outlet property="totalReblogsButton" destination="dem-vG-cPB" id="i9E-Qn-d76"/>
|
<outlet property="totalReblogsButton" destination="dem-vG-cPB" id="i9E-Qn-d76"/>
|
||||||
<outlet property="usernameLabel" destination="SWg-Ka-QyP" id="h2I-g4-AD9"/>
|
<outlet property="usernameLabel" destination="SWg-Ka-QyP" id="h2I-g4-AD9"/>
|
||||||
</connections>
|
</connections>
|
||||||
<point key="canvasLocation" x="40.799999999999997" y="-122.78860569715144"/>
|
<point key="canvasLocation" x="40.799999999999997" y="-146.62668665667167"/>
|
||||||
</view>
|
</view>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="arrowshape.turn.up.left.fill" catalog="system" width="64" height="52"/>
|
<image name="arrowshape.turn.up.left.fill" catalog="system" width="64" height="52"/>
|
||||||
<image name="chevron.down" catalog="system" width="64" height="34"/>
|
|
||||||
<image name="ellipsis" catalog="system" width="64" height="20"/>
|
<image name="ellipsis" catalog="system" width="64" height="20"/>
|
||||||
<image name="repeat" catalog="system" width="64" height="50"/>
|
<image name="repeat" catalog="system" width="64" height="50"/>
|
||||||
<image name="star.fill" catalog="system" width="64" height="58"/>
|
<image name="star.fill" catalog="system" width="64" height="58"/>
|
||||||
|
|
|
@ -11,7 +11,6 @@ import Combine
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
|
||||||
protocol StatusTableViewCellDelegate: TuskerNavigationDelegate {
|
protocol StatusTableViewCellDelegate: TuskerNavigationDelegate {
|
||||||
func statusCollapsedStateChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StatusTableViewCell: UITableViewCell {
|
class StatusTableViewCell: UITableViewCell {
|
||||||
|
@ -24,8 +23,6 @@ class StatusTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
@IBOutlet weak var displayNameLabel: UILabel!
|
@IBOutlet weak var displayNameLabel: UILabel!
|
||||||
@IBOutlet weak var usernameLabel: UILabel!
|
@IBOutlet weak var usernameLabel: UILabel!
|
||||||
@IBOutlet weak var contentWarningLabel: UILabel!
|
|
||||||
@IBOutlet weak var collapseButton: UIButton!
|
|
||||||
@IBOutlet weak var contentLabel: StatusContentLabel!
|
@IBOutlet weak var contentLabel: StatusContentLabel!
|
||||||
@IBOutlet weak var avatarImageView: UIImageView!
|
@IBOutlet weak var avatarImageView: UIImageView!
|
||||||
@IBOutlet weak var reblogLabel: UILabel!
|
@IBOutlet weak var reblogLabel: UILabel!
|
||||||
|
@ -50,13 +47,6 @@ class StatusTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var collapsible = false {
|
|
||||||
didSet {
|
|
||||||
collapseButton.isHidden = !collapsible
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var collapsed = false
|
|
||||||
|
|
||||||
var avatarURL: URL?
|
var avatarURL: URL?
|
||||||
var updateTimestampWorkItem: DispatchWorkItem?
|
var updateTimestampWorkItem: DispatchWorkItem?
|
||||||
var attachmentDataTasks: [URLSessionDataTask] = []
|
var attachmentDataTasks: [URLSessionDataTask] = []
|
||||||
|
@ -80,8 +70,6 @@ class StatusTableViewCell: UITableViewCell {
|
||||||
attachmentsView.delegate = self
|
attachmentsView.delegate = self
|
||||||
attachmentsView.layer.cornerRadius = 5
|
attachmentsView.layer.cornerRadius = 5
|
||||||
attachmentsView.layer.masksToBounds = true
|
attachmentsView.layer.masksToBounds = true
|
||||||
collapseButton.layer.masksToBounds = true
|
|
||||||
collapseButton.layer.cornerRadius = 5
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil)
|
||||||
|
|
||||||
|
@ -134,11 +122,6 @@ class StatusTableViewCell: UITableViewCell {
|
||||||
updateStatusState(status: realStatus)
|
updateStatusState(status: realStatus)
|
||||||
|
|
||||||
contentLabel.statusID = status.id
|
contentLabel.statusID = status.id
|
||||||
|
|
||||||
collapsible = !status.spoilerText.isEmpty
|
|
||||||
setCollapsed(collapsible, animated: false)
|
|
||||||
contentWarningLabel.text = status.spoilerText
|
|
||||||
contentWarningLabel.isHidden = status.spoilerText.isEmpty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateStatusState(status: Status) {
|
private func updateStatusState(status: Status) {
|
||||||
|
@ -209,39 +192,6 @@ class StatusTableViewCell: UITableViewCell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func collapseButtonPressed(_ sender: Any) {
|
|
||||||
setCollapsed(!collapsed, animated: true)
|
|
||||||
delegate?.statusCollapsedStateChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setCollapsed(_ collapsed: Bool, animated: Bool) {
|
|
||||||
self.collapsed = collapsed
|
|
||||||
|
|
||||||
contentLabel.isHidden = collapsed
|
|
||||||
attachmentsView.isHidden = attachmentsView.attachments.count == 0 || collapsed
|
|
||||||
|
|
||||||
let buttonImage = UIImage(systemName: collapsed ? "chevron.down" : "chevron.up")
|
|
||||||
|
|
||||||
if animated, let buttonImageView = collapseButton.imageView {
|
|
||||||
// we need to use a keyframe animation for this, because we want to control the direction the chevron rotates
|
|
||||||
// when rotating ±π, UIKit will always rotate in the same direction
|
|
||||||
// using a keyframe to set an intermediate point in the animation allows us to force a specific direction
|
|
||||||
UIView.animateKeyframes(withDuration: 0.2, delay: 0, options: .calculationModeLinear, animations: {
|
|
||||||
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
|
|
||||||
buttonImageView.transform = CGAffineTransform(rotationAngle: collapsed ? .pi / 2 : -.pi / 2)
|
|
||||||
}
|
|
||||||
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
|
|
||||||
buttonImageView.transform = CGAffineTransform(rotationAngle: .pi)
|
|
||||||
}
|
|
||||||
}, completion: { (finished) in
|
|
||||||
buttonImageView.transform = .identity
|
|
||||||
self.collapseButton.setImage(buttonImage, for: .normal)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
collapseButton.setImage(buttonImage, for: .normal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func replyPressed(_ sender: Any) {
|
@IBAction func replyPressed(_ sender: Any) {
|
||||||
delegate?.reply(to: statusID)
|
delegate?.reply(to: statusID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,20 @@
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="StatusTableViewCell" customModule="Tusker" customModuleProvider="target">
|
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="StatusTableViewCell" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="240"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="150"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="yNh-ac-v6c">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="yNh-ac-v6c">
|
||||||
<rect key="frame" x="16" y="8" width="343" height="224"/>
|
<rect key="frame" x="16" y="8" width="343" height="134"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="751" text="Reblogged by Person" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lDH-50-AJZ">
|
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Reblogged by Person" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lDH-50-AJZ">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="163.5" height="20.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="163.5" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="ve3-Y1-NQH">
|
<view contentMode="scaleToFill" verticalHuggingPriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="ve3-Y1-NQH">
|
||||||
<rect key="frame" x="0.0" y="28.5" width="343" height="165.5"/>
|
<rect key="frame" x="0.0" y="28.5" width="343" height="75.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QMP-j2-HLn">
|
<imageView contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="QMP-j2-HLn">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
<rect key="frame" x="0.0" y="0.0" width="50" height="50"/>
|
||||||
|
@ -33,87 +33,62 @@
|
||||||
<constraint firstAttribute="height" constant="50" id="nMi-Gq-JyV"/>
|
<constraint firstAttribute="height" constant="50" id="nMi-Gq-JyV"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</imageView>
|
</imageView>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="751" axis="vertical" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="gIY-Wp-RSk">
|
|
||||||
<rect key="frame" x="58" y="0.0" width="277" height="165.5"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3Sm-P0-ySf">
|
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3Sm-P0-ySf">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="277" height="20.5"/>
|
<rect key="frame" x="58" y="0.0" width="285" height="20.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="752" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gll-xe-FSr">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="Display name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gll-xe-FSr">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="107" height="20.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="107" height="20.5"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" verticalHuggingPriority="252" horizontalCompressionResistancePriority="748" verticalCompressionResistancePriority="752" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j89-zc-SFa">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="249" verticalHuggingPriority="251" horizontalCompressionResistancePriority="748" text="@username" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="j89-zc-SFa">
|
||||||
<rect key="frame" x="115" y="0.0" width="129.5" height="20.5"/>
|
<rect key="frame" x="115" y="0.0" width="137.5" height="20.5"/>
|
||||||
<gestureRecognizers/>
|
<gestureRecognizers/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="752" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="35d-EA-ReR">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="35d-EA-ReR">
|
||||||
<rect key="frame" x="252.5" y="0.0" width="24.5" height="20.5"/>
|
<rect key="frame" x="260.5" y="0.0" width="24.5" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" weight="light" pointSize="17"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" secondItem="gll-xe-FSr" secondAttribute="height" id="B7p-Pc-fZD"/>
|
|
||||||
</constraints>
|
|
||||||
</stackView>
|
</stackView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" verticalCompressionResistancePriority="755" text="Content Warning" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="inI-Og-YiU">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HrJ-t9-KcD" customClass="StatusContentLabel" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="24.5" width="277" height="20.5"/>
|
<rect key="frame" x="58" y="24.5" width="285" height="51"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="252" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="O0E-Vf-XYR">
|
|
||||||
<rect key="frame" x="0.0" y="49" width="277" height="30"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="height" constant="30" id="z84-XW-gP3"/>
|
|
||||||
</constraints>
|
|
||||||
<color key="tintColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
|
||||||
<state key="normal" image="chevron.down" catalog="system">
|
|
||||||
<preferredSymbolConfiguration key="preferredSymbolConfiguration" scale="large"/>
|
|
||||||
</state>
|
|
||||||
<connections>
|
|
||||||
<action selector="collapseButtonPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="HNS-rX-gBM"/>
|
|
||||||
</connections>
|
|
||||||
</button>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="TopLeft" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HrJ-t9-KcD" customClass="StatusContentLabel" customModule="Tusker" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="83" width="277" height="82.5"/>
|
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="gIY-Wp-RSk" firstAttribute="leading" secondItem="QMP-j2-HLn" secondAttribute="trailing" constant="8" id="0Tm-v7-Ts4"/>
|
|
||||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="QMP-j2-HLn" secondAttribute="bottom" constant="8" id="2Ao-Gj-fY3"/>
|
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="QMP-j2-HLn" secondAttribute="bottom" constant="8" id="2Ao-Gj-fY3"/>
|
||||||
|
<constraint firstItem="HrJ-t9-KcD" firstAttribute="leading" secondItem="QMP-j2-HLn" secondAttribute="trailing" constant="8" id="3KO-pD-Ldr"/>
|
||||||
|
<constraint firstItem="3Sm-P0-ySf" firstAttribute="leading" secondItem="QMP-j2-HLn" secondAttribute="trailing" constant="8" id="4EZ-pI-VjW"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="3Sm-P0-ySf" secondAttribute="trailing" id="8wc-sb-HoG"/>
|
||||||
|
<constraint firstItem="HrJ-t9-KcD" firstAttribute="top" secondItem="3Sm-P0-ySf" secondAttribute="bottom" constant="4" id="Nm5-Qs-HB9"/>
|
||||||
<constraint firstItem="QMP-j2-HLn" firstAttribute="top" secondItem="ve3-Y1-NQH" secondAttribute="top" id="PC4-Bi-QXm"/>
|
<constraint firstItem="QMP-j2-HLn" firstAttribute="top" secondItem="ve3-Y1-NQH" secondAttribute="top" id="PC4-Bi-QXm"/>
|
||||||
<constraint firstItem="gIY-Wp-RSk" firstAttribute="top" secondItem="QMP-j2-HLn" secondAttribute="top" id="fEd-wN-kuQ"/>
|
<constraint firstAttribute="bottom" secondItem="HrJ-t9-KcD" secondAttribute="bottom" id="YAm-mK-YXb"/>
|
||||||
<constraint firstAttribute="trailingMargin" secondItem="gIY-Wp-RSk" secondAttribute="trailing" id="hKk-kO-wFT"/>
|
<constraint firstItem="3Sm-P0-ySf" firstAttribute="top" secondItem="ve3-Y1-NQH" secondAttribute="top" id="nFO-c9-JSB"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="gIY-Wp-RSk" secondAttribute="bottom" id="kRU-Ct-CIg"/>
|
<constraint firstAttribute="trailing" secondItem="HrJ-t9-KcD" secondAttribute="trailing" id="wCB-bW-AdR"/>
|
||||||
<constraint firstItem="QMP-j2-HLn" firstAttribute="leading" secondItem="ve3-Y1-NQH" secondAttribute="leading" id="zeW-tQ-uJl"/>
|
<constraint firstItem="QMP-j2-HLn" firstAttribute="leading" secondItem="ve3-Y1-NQH" secondAttribute="leading" id="zeW-tQ-uJl"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<view hidden="YES" contentMode="scaleToFill" verticalCompressionResistancePriority="1" translatesAutoresizingMaskIntoConstraints="NO" id="nbq-yr-2mA" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nbq-yr-2mA" customClass="AttachmentsContainerView" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="198" width="343" height="0.0"/>
|
<rect key="frame" x="0.0" y="108" width="343" height="0.0"/>
|
||||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" priority="999" constant="200" id="J42-49-2MU"/>
|
<constraint firstAttribute="height" priority="999" constant="200" id="J42-49-2MU"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" distribution="equalSpacing" alignment="bottom" translatesAutoresizingMaskIntoConstraints="NO" id="Zlb-yt-NTw">
|
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" distribution="equalSpacing" translatesAutoresizingMaskIntoConstraints="NO" id="Zlb-yt-NTw">
|
||||||
<rect key="frame" x="0.0" y="202" width="343" height="22"/>
|
<rect key="frame" x="0.0" y="112" width="343" height="22"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rKF-yF-KIa">
|
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="leading" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rKF-yF-KIa">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="21.5" height="22"/>
|
<rect key="frame" x="0.0" y="0.0" width="21.5" height="22"/>
|
||||||
<state key="normal" image="arrowshape.turn.up.left.fill" catalog="system"/>
|
<state key="normal" image="arrowshape.turn.up.left.fill" catalog="system"/>
|
||||||
<connections>
|
<connections>
|
||||||
|
@ -145,7 +120,7 @@
|
||||||
</stackView>
|
</stackView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="nbq-yr-2mA" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="JCZ-x5-Xa2"/>
|
<constraint firstItem="nbq-yr-2mA" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="3Ag-HE-h4m"/>
|
||||||
<constraint firstItem="Zlb-yt-NTw" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="wxD-pe-Udd"/>
|
<constraint firstItem="Zlb-yt-NTw" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="wxD-pe-Udd"/>
|
||||||
<constraint firstItem="ve3-Y1-NQH" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="xN6-cs-Tnn"/>
|
<constraint firstItem="ve3-Y1-NQH" firstAttribute="width" secondItem="yNh-ac-v6c" secondAttribute="width" id="xN6-cs-Tnn"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
@ -163,9 +138,7 @@
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="attachmentsView" destination="nbq-yr-2mA" id="GkU-Xk-pc0"/>
|
<outlet property="attachmentsView" destination="nbq-yr-2mA" id="GkU-Xk-pc0"/>
|
||||||
<outlet property="avatarImageView" destination="QMP-j2-HLn" id="CAl-hK-i3j"/>
|
<outlet property="avatarImageView" destination="QMP-j2-HLn" id="CAl-hK-i3j"/>
|
||||||
<outlet property="collapseButton" destination="O0E-Vf-XYR" id="fBb-0C-QA2"/>
|
|
||||||
<outlet property="contentLabel" destination="HrJ-t9-KcD" id="tbD-3T-nNP"/>
|
<outlet property="contentLabel" destination="HrJ-t9-KcD" id="tbD-3T-nNP"/>
|
||||||
<outlet property="contentWarningLabel" destination="inI-Og-YiU" id="2jf-6J-JUU"/>
|
|
||||||
<outlet property="displayNameLabel" destination="gll-xe-FSr" id="63y-He-xy1"/>
|
<outlet property="displayNameLabel" destination="gll-xe-FSr" id="63y-He-xy1"/>
|
||||||
<outlet property="favoriteButton" destination="x0t-TR-jJ4" id="Ohz-bs-Ebr"/>
|
<outlet property="favoriteButton" destination="x0t-TR-jJ4" id="Ohz-bs-Ebr"/>
|
||||||
<outlet property="reblogButton" destination="6tW-z8-Qh9" id="i9h-QA-ZPd"/>
|
<outlet property="reblogButton" destination="6tW-z8-Qh9" id="i9h-QA-ZPd"/>
|
||||||
|
@ -173,12 +146,11 @@
|
||||||
<outlet property="timestampLabel" destination="35d-EA-ReR" id="8EW-mb-LAb"/>
|
<outlet property="timestampLabel" destination="35d-EA-ReR" id="8EW-mb-LAb"/>
|
||||||
<outlet property="usernameLabel" destination="j89-zc-SFa" id="see-Xd-3e9"/>
|
<outlet property="usernameLabel" destination="j89-zc-SFa" id="see-Xd-3e9"/>
|
||||||
</connections>
|
</connections>
|
||||||
<point key="canvasLocation" x="29.600000000000001" y="79.160419790104953"/>
|
<point key="canvasLocation" x="29.600000000000001" y="38.680659670164921"/>
|
||||||
</view>
|
</view>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="arrowshape.turn.up.left.fill" catalog="system" width="64" height="52"/>
|
<image name="arrowshape.turn.up.left.fill" catalog="system" width="64" height="52"/>
|
||||||
<image name="chevron.down" catalog="system" width="64" height="34"/>
|
|
||||||
<image name="ellipsis" catalog="system" width="64" height="20"/>
|
<image name="ellipsis" catalog="system" width="64" height="20"/>
|
||||||
<image name="repeat" catalog="system" width="64" height="50"/>
|
<image name="repeat" catalog="system" width="64" height="50"/>
|
||||||
<image name="star.fill" catalog="system" width="64" height="58"/>
|
<image name="star.fill" catalog="system" width="64" height="58"/>
|
||||||
|
|
Loading…
Reference in New Issue