Add shared status cache
This commit is contained in:
parent
a5579ce0e3
commit
a6d23d12eb
|
@ -282,7 +282,7 @@ public class Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createStatus(text: String,
|
public func createStatus(text: String,
|
||||||
inReplyTo: Status? = nil,
|
inReplyTo: String? = nil,
|
||||||
media: [Attachment]? = nil,
|
media: [Attachment]? = nil,
|
||||||
sensitive: Bool? = nil,
|
sensitive: Bool? = nil,
|
||||||
spoilerText: String? = nil,
|
spoilerText: String? = nil,
|
||||||
|
@ -290,7 +290,7 @@ public class Client {
|
||||||
language: String? = nil) -> Request<Status> {
|
language: String? = nil) -> Request<Status> {
|
||||||
return Request<Status>(method: .post, path: "/api/v1/statuses", body: .parameters([
|
return Request<Status>(method: .post, path: "/api/v1/statuses", body: .parameters([
|
||||||
"status" => text,
|
"status" => text,
|
||||||
"in_reply_to_id" => inReplyTo?.id,
|
"in_reply_to_id" => inReplyTo,
|
||||||
"sensitive" => sensitive,
|
"sensitive" => sensitive,
|
||||||
"spoiler_text" => spoilerText,
|
"spoiler_text" => spoilerText,
|
||||||
"visibility" => visiblity?.rawValue,
|
"visibility" => visiblity?.rawValue,
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
04DACE8C212CB14B009840C4 /* MainTabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */; };
|
||||||
04DACE8E212CC7CC009840C4 /* AvatarCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* AvatarCache.swift */; };
|
04DACE8E212CC7CC009840C4 /* AvatarCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DACE8D212CC7CC009840C4 /* AvatarCache.swift */; };
|
||||||
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
04ED00B121481ED800567C53 /* SteppedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED00B021481ED800567C53 /* SteppedProgressView.swift */; };
|
||||||
|
D6028B9B2150811100F223B9 /* StatusCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6028B9A2150811100F223B9 /* StatusCache.swift */; };
|
||||||
D61099B42144B0CC00432DC2 /* Pachyderm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D61099AB2144B0CC00432DC2 /* Pachyderm.framework */; };
|
D61099B42144B0CC00432DC2 /* Pachyderm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D61099AB2144B0CC00432DC2 /* Pachyderm.framework */; };
|
||||||
D61099BB2144B0CC00432DC2 /* PachydermTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61099BA2144B0CC00432DC2 /* PachydermTests.swift */; };
|
D61099BB2144B0CC00432DC2 /* PachydermTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61099BA2144B0CC00432DC2 /* PachydermTests.swift */; };
|
||||||
D61099BD2144B0CC00432DC2 /* Pachyderm.h in Headers */ = {isa = PBXBuildFile; fileRef = D61099AD2144B0CC00432DC2 /* Pachyderm.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D61099BD2144B0CC00432DC2 /* Pachyderm.h in Headers */ = {isa = PBXBuildFile; fileRef = D61099AD2144B0CC00432DC2 /* Pachyderm.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
@ -164,6 +165,7 @@
|
||||||
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
04DACE8B212CB14B009840C4 /* MainTabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabBarViewController.swift; sourceTree = "<group>"; };
|
||||||
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarCache.swift; sourceTree = "<group>"; };
|
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarCache.swift; sourceTree = "<group>"; };
|
||||||
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
04ED00B021481ED800567C53 /* SteppedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SteppedProgressView.swift; sourceTree = "<group>"; };
|
||||||
|
D6028B9A2150811100F223B9 /* StatusCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusCache.swift; sourceTree = "<group>"; };
|
||||||
D61099AB2144B0CC00432DC2 /* Pachyderm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pachyderm.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D61099AB2144B0CC00432DC2 /* Pachyderm.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pachyderm.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D61099AD2144B0CC00432DC2 /* Pachyderm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pachyderm.h; sourceTree = "<group>"; };
|
D61099AD2144B0CC00432DC2 /* Pachyderm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pachyderm.h; sourceTree = "<group>"; };
|
||||||
D61099AE2144B0CC00432DC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
D61099AE2144B0CC00432DC2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
@ -613,6 +615,7 @@
|
||||||
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
|
D6D4DDCF212518A000E1C4BB /* AppDelegate.swift */,
|
||||||
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
D64D0AAC2128D88B005A6F37 /* LocalData.swift */,
|
||||||
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */,
|
04DACE8D212CC7CC009840C4 /* AvatarCache.swift */,
|
||||||
|
D6028B9A2150811100F223B9 /* StatusCache.swift */,
|
||||||
D663626021360A9600C9CBA2 /* Preferences */,
|
D663626021360A9600C9CBA2 /* Preferences */,
|
||||||
D667E5F62135C2ED0057A976 /* Extensions */,
|
D667E5F62135C2ED0057A976 /* Extensions */,
|
||||||
D6F953F121251A2F00CF0F2B /* Controllers */,
|
D6F953F121251A2F00CF0F2B /* Controllers */,
|
||||||
|
@ -922,6 +925,7 @@
|
||||||
D667E5F52135BCD50057A976 /* ConversationViewController.swift in Sources */,
|
D667E5F52135BCD50057A976 /* ConversationViewController.swift in Sources */,
|
||||||
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
D6F953F021251A2900CF0F2B /* MastodonController.swift in Sources */,
|
||||||
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
|
D66362712136338600C9CBA2 /* ComposeViewController.swift in Sources */,
|
||||||
|
D6028B9B2150811100F223B9 /* StatusCache.swift in Sources */,
|
||||||
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
D646C958213B367000269FB5 /* LargeImageShrinkAnimationController.swift in Sources */,
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
|
|
|
@ -39,22 +39,22 @@ extension StatusTableViewCellDelegate where Self: UIViewController {
|
||||||
present(vc, animated: true)
|
present(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func selected(status: Status) {
|
func selected(status statusID: String) {
|
||||||
// don't open if the conversation is the same as the current one
|
// don't open if the conversation is the same as the current one
|
||||||
if let conversationController = self as? ConversationViewController,
|
if let conversationController = self as? ConversationViewController,
|
||||||
conversationController.mainStatus == status {
|
conversationController.mainStatusID == statusID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let navigationController = navigationController else {
|
guard let navigationController = navigationController else {
|
||||||
fatalError("Can't show conversation VC when not in navigation controller")
|
fatalError("Can't show conversation VC when not in navigation controller")
|
||||||
}
|
}
|
||||||
let vc = ConversationViewController.create(for: status)
|
let vc = ConversationViewController.create(for: statusID)
|
||||||
navigationController.pushViewController(vc, animated: true)
|
navigationController.pushViewController(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func reply(to status: Status) {
|
func reply(to statusID: String) {
|
||||||
let vc = ComposeViewController.create(inReplyTo: status)
|
let vc = ComposeViewController.create(inReplyTo: statusID)
|
||||||
present(vc, animated: true)
|
present(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,9 @@ extension StatusTableViewCellDelegate where Self: UIViewController {
|
||||||
present(vc, animated: true)
|
present(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func showMoreOptions(status: Status) {
|
func showMoreOptions(status statusID: String) {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||||
|
|
||||||
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||||
if let url = status.url {
|
if let url = status.url {
|
||||||
alert.addAction(UIAlertAction(title: "Open in Safari...", style: .default, handler: { _ in
|
alert.addAction(UIAlertAction(title: "Open in Safari...", style: .default, handler: { _ in
|
||||||
|
|
|
@ -11,10 +11,10 @@ import Pachyderm
|
||||||
|
|
||||||
class ComposeViewController: UIViewController {
|
class ComposeViewController: UIViewController {
|
||||||
|
|
||||||
static func create(inReplyTo: Status? = nil, mentioning: Account? = nil) -> UIViewController {
|
static func create(inReplyTo inReplyToID: String? = nil, mentioning: Account? = nil) -> UIViewController {
|
||||||
guard let navigationController = UIStoryboard(name: "Compose", bundle: nil).instantiateInitialViewController() as? UINavigationController,
|
guard let navigationController = UIStoryboard(name: "Compose", bundle: nil).instantiateInitialViewController() as? UINavigationController,
|
||||||
let composeVC = navigationController.topViewController as? ComposeViewController else { fatalError() }
|
let composeVC = navigationController.topViewController as? ComposeViewController else { fatalError() }
|
||||||
composeVC.inReplyTo = inReplyTo
|
composeVC.inReplyToID = inReplyToID
|
||||||
composeVC.mentioning = mentioning
|
composeVC.mentioning = mentioning
|
||||||
return navigationController
|
return navigationController
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ class ComposeViewController: UIViewController {
|
||||||
|
|
||||||
var scrolled = false
|
var scrolled = false
|
||||||
|
|
||||||
var inReplyTo: Status?
|
var inReplyToID: String?
|
||||||
var mentioning: Account?
|
var mentioning: Account?
|
||||||
|
|
||||||
var contentWarning = false {
|
var contentWarning = false {
|
||||||
|
@ -68,10 +68,11 @@ class ComposeViewController: UIViewController {
|
||||||
toolbar.sizeToFit()
|
toolbar.sizeToFit()
|
||||||
statusTextView.inputAccessoryView = toolbar
|
statusTextView.inputAccessoryView = toolbar
|
||||||
|
|
||||||
if let inReplyTo = inReplyTo {
|
if let inReplyToID = inReplyToID,
|
||||||
|
let inReplyTo = StatusCache.get(id: inReplyToID) {
|
||||||
inReplyToDisplayNameLabel.text = inReplyTo.account.realDisplayName
|
inReplyToDisplayNameLabel.text = inReplyTo.account.realDisplayName
|
||||||
inReplyToUsernameLabel.text = "@\(inReplyTo.account.username)"
|
inReplyToUsernameLabel.text = "@\(inReplyTo.account.username)"
|
||||||
inReplyToContentLabel.status = inReplyTo
|
inReplyToContentLabel.statusID = inReplyToID
|
||||||
inReplyToAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: inReplyToAvatarImageView)
|
inReplyToAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: inReplyToAvatarImageView)
|
||||||
inReplyToAvatarImageView.layer.masksToBounds = true
|
inReplyToAvatarImageView.layer.masksToBounds = true
|
||||||
inReplyToAvatarImageView.image = nil
|
inReplyToAvatarImageView.image = nil
|
||||||
|
@ -103,7 +104,7 @@ class ComposeViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidLayoutSubviews() {
|
override func viewDidLayoutSubviews() {
|
||||||
if inReplyTo != nil && !scrolled {
|
if inReplyToID != nil && !scrolled {
|
||||||
scrollView.contentOffset = CGPoint(x: 0, y: inReplyToContainerView.bounds.height - 44)
|
scrollView.contentOffset = CGPoint(x: 0, y: inReplyToContainerView.bounds.height - 44)
|
||||||
scrolled = true
|
scrolled = true
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,7 @@ class ComposeViewController: UIViewController {
|
||||||
guard let dest = segue.destination as? MainTabBarViewController,
|
guard let dest = segue.destination as? MainTabBarViewController,
|
||||||
let navController = dest.selectedViewController as? UINavigationController,
|
let navController = dest.selectedViewController as? UINavigationController,
|
||||||
let topVC = navController.topViewController as? StatusTableViewCellDelegate else { return }
|
let topVC = navController.topViewController as? StatusTableViewCellDelegate else { return }
|
||||||
topVC.selected(status: status)
|
topVC.selected(status: status.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +220,7 @@ class ComposeViewController: UIViewController {
|
||||||
let attachments = attachments.compactMap { $0 }
|
let attachments = attachments.compactMap { $0 }
|
||||||
|
|
||||||
let request = MastodonController.shared.client.createStatus(text: text,
|
let request = MastodonController.shared.client.createStatus(text: text,
|
||||||
inReplyTo: self.inReplyTo,
|
inReplyTo: self.inReplyToID,
|
||||||
media: attachments,
|
media: attachments,
|
||||||
sensitive: sensitive,
|
sensitive: sensitive,
|
||||||
spoilerText: contentWarning,
|
spoilerText: contentWarning,
|
||||||
|
@ -227,6 +228,7 @@ class ComposeViewController: UIViewController {
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
guard case let .success(status, _) = response else { fatalError() }
|
guard case let .success(status, _) = response else { fatalError() }
|
||||||
self.status = status
|
self.status = status
|
||||||
|
StatusCache.add(status)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.progressView.step()
|
self.progressView.step()
|
||||||
self.performSegue(withIdentifier: "postComplete", sender: self)
|
self.performSegue(withIdentifier: "postComplete", sender: self)
|
||||||
|
|
|
@ -11,17 +11,17 @@ import Pachyderm
|
||||||
|
|
||||||
class ConversationViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
class ConversationViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||||
|
|
||||||
static func create(for mainStatus: Status) -> ConversationViewController {
|
static func create(for mainStatusID: String) -> ConversationViewController {
|
||||||
guard let conversationController = UIStoryboard(name: "Conversation", bundle: nil).instantiateInitialViewController() as? ConversationViewController else { fatalError() }
|
guard let conversationController = UIStoryboard(name: "Conversation", bundle: nil).instantiateInitialViewController() as? ConversationViewController else { fatalError() }
|
||||||
conversationController.mainStatus = mainStatus
|
conversationController.mainStatusID = mainStatusID
|
||||||
return conversationController
|
return conversationController
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBOutlet weak var tableView: UITableView!
|
@IBOutlet weak var tableView: UITableView!
|
||||||
|
|
||||||
var mainStatus: Status!
|
var mainStatusID: String!
|
||||||
|
|
||||||
var statuses: [Status] = [] {
|
var statusIDs: [String] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
|
@ -38,16 +38,18 @@ class ConversationViewController: UIViewController, UITableViewDataSource, UITab
|
||||||
tableView.register(UINib(nibName: "StatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell")
|
tableView.register(UINib(nibName: "StatusTableViewCell", bundle: nil), forCellReuseIdentifier: "statusCell")
|
||||||
tableView.register(UINib(nibName: "ConversationMainStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "mainStatusCell")
|
tableView.register(UINib(nibName: "ConversationMainStatusTableViewCell", bundle: nil), forCellReuseIdentifier: "mainStatusCell")
|
||||||
|
|
||||||
statuses = [mainStatus]
|
statusIDs = [mainStatusID]
|
||||||
|
|
||||||
|
guard let mainStatus = StatusCache.get(id: mainStatusID) else { fatalError("Missing cached status \(mainStatusID!)") }
|
||||||
|
|
||||||
let request = Status.getContext(mainStatus)
|
let request = Status.getContext(mainStatus)
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
guard case let .success(context, _) = response else { fatalError() }
|
guard case let .success(context, _) = response else { fatalError() }
|
||||||
var statuses = self.getDirectParents(of: self.mainStatus, from: context.ancestors)
|
let parents = self.getDirectParents(of: mainStatus, from: context.ancestors)
|
||||||
statuses.append(self.mainStatus)
|
StatusCache.addAll(parents)
|
||||||
statuses.append(contentsOf: context.descendants)
|
StatusCache.addAll(context.descendants)
|
||||||
self.statuses = statuses
|
self.statusIDs = parents.map { $0.id } + [self.mainStatusID] + context.descendants.map { $0.id }
|
||||||
let indexPath = IndexPath(row: statuses.firstIndex(of: self.mainStatus)!, section: 0)
|
let indexPath = IndexPath(row: self.statusIDs.firstIndex(of: self.mainStatusID)!, section: 0)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.tableView.scrollToRow(at: indexPath, at: .middle, animated: false)
|
self.tableView.scrollToRow(at: indexPath, at: .middle, animated: false)
|
||||||
}
|
}
|
||||||
|
@ -94,29 +96,29 @@ class ConversationViewController: UIViewController, UITableViewDataSource, UITab
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return statuses.count
|
return statusIDs.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let status = statuses[indexPath.row]
|
let statusID = statusIDs[indexPath.row]
|
||||||
|
|
||||||
if status == mainStatus {
|
if statusID == mainStatusID {
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainStatusCell", for: indexPath) as? ConversationMainStatusTableViewCell else { fatalError() }
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainStatusCell", for: indexPath) as? ConversationMainStatusTableViewCell else { fatalError() }
|
||||||
cell.selectionStyle = .none
|
cell.selectionStyle = .none
|
||||||
cell.updateUI(for: status)
|
cell.updateUI(for: statusID)
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
return cell
|
return cell
|
||||||
} else {
|
} else {
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||||
cell.updateUI(for: status)
|
cell.updateUI(for: statusID)
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||||
let status = statuses[indexPath.row]
|
let statusID = statusIDs[indexPath.row]
|
||||||
return status == mainStatus ? nil : indexPath
|
return statusID == mainStatusID ? nil : indexPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
|
||||||
|
|
|
@ -47,6 +47,7 @@ class NotificationsTableViewController: UITableViewController {
|
||||||
MastodonController.shared.client.run(request) { result in
|
MastodonController.shared.client.run(request) { result in
|
||||||
guard case let .success(notifications, pagination) = result else { fatalError() }
|
guard case let .success(notifications, pagination) = result else { fatalError() }
|
||||||
self.notifications = notifications
|
self.notifications = notifications
|
||||||
|
StatusCache.addAll(notifications.compactMap { $0.status })
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ class NotificationsTableViewController: UITableViewController {
|
||||||
case .mention:
|
case .mention:
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||||
let status = notification.status!
|
let status = notification.status!
|
||||||
cell.updateUI(for: status)
|
cell.updateUI(for: status.id)
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
return cell
|
return cell
|
||||||
case .favourite, .reblog:
|
case .favourite, .reblog:
|
||||||
|
@ -139,6 +140,7 @@ class NotificationsTableViewController: UITableViewController {
|
||||||
MastodonController.shared.client.run(request) { result in
|
MastodonController.shared.client.run(request) { result in
|
||||||
guard case let .success(newNotifications, pagination) = result else { fatalError() }
|
guard case let .success(newNotifications, pagination) = result else { fatalError() }
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
|
StatusCache.addAll(newNotifications.compactMap { $0.status })
|
||||||
self.notifications.insert(contentsOf: newNotifications, at: 0)
|
self.notifications.insert(contentsOf: newNotifications, at: 0)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refreshControl?.endRefreshing()
|
self.refreshControl?.endRefreshing()
|
||||||
|
|
|
@ -20,7 +20,7 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
|
|
||||||
var account: Account!
|
var account: Account!
|
||||||
|
|
||||||
var statuses: [Status] = [] {
|
var statusIDs: [String] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
|
@ -49,7 +49,8 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
|
|
||||||
getStatuses { response in
|
getStatuses { response in
|
||||||
guard case let .success(statuses, pagination) = response else { fatalError() }
|
guard case let .success(statuses, pagination) = response else { fatalError() }
|
||||||
self.statuses = statuses
|
StatusCache.addAll(statuses)
|
||||||
|
self.statusIDs = statuses.map { $0.id }
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
}
|
}
|
||||||
|
@ -96,7 +97,7 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
case 0:
|
case 0:
|
||||||
return 1
|
return 1
|
||||||
case 1:
|
case 1:
|
||||||
return statuses.count
|
return statusIDs.count
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -112,8 +113,8 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
return cell
|
return cell
|
||||||
case 1:
|
case 1:
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||||
let status = statuses[indexPath.row]
|
let statusID = statusIDs[indexPath.row]
|
||||||
cell.updateUI(for: status)
|
cell.updateUI(for: statusID)
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
return cell
|
return cell
|
||||||
default:
|
default:
|
||||||
|
@ -122,13 +123,14 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||||
if indexPath.section == 1 && indexPath.row == statuses.count - 1 {
|
if indexPath.section == 1 && indexPath.row == statusIDs.count - 1 {
|
||||||
guard let older = older else { return }
|
guard let older = older else { return }
|
||||||
|
|
||||||
getStatuses(for: older) { response in
|
getStatuses(for: older) { response in
|
||||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
self.statuses.append(contentsOf: newStatuses)
|
StatusCache.addAll(newStatuses)
|
||||||
|
self.statusIDs.append(contentsOf: newStatuses.map { $0.id })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,7 +153,8 @@ class ProfileTableViewController: UITableViewController, PreferencesAdaptive {
|
||||||
getStatuses(for: newer) { response in
|
getStatuses(for: newer) { response in
|
||||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
self.statuses.insert(contentsOf: newStatuses, at: 0)
|
StatusCache.addAll(newStatuses)
|
||||||
|
self.statusIDs.insert(contentsOf: newStatuses.map { $0.id }, at: 0)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refreshControl?.endRefreshing()
|
self.refreshControl?.endRefreshing()
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ class TimelineTableViewController: UITableViewController {
|
||||||
|
|
||||||
var timeline: Timeline!
|
var timeline: Timeline!
|
||||||
|
|
||||||
var statuses: [Status] = [] {
|
var statusIDs: [String] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
|
@ -73,7 +73,8 @@ class TimelineTableViewController: UITableViewController {
|
||||||
let request = MastodonController.shared.client.getStatuses(timeline: timeline)
|
let request = MastodonController.shared.client.getStatuses(timeline: timeline)
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
guard case let .success(statuses, pagination) = response else { fatalError() }
|
guard case let .success(statuses, pagination) = response else { fatalError() }
|
||||||
self.statuses = statuses
|
self.statusIDs = statuses.map { $0.id }
|
||||||
|
StatusCache.addAll(statuses)
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
}
|
}
|
||||||
|
@ -106,16 +107,16 @@ class TimelineTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return statuses.count
|
return statusIDs.count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
guard let cell = tableView.dequeueReusableCell(withIdentifier: "statusCell", for: indexPath) as? StatusTableViewCell else { fatalError() }
|
||||||
|
|
||||||
let status = statuses[indexPath.row]
|
let statusID = statusIDs[indexPath.row]
|
||||||
|
|
||||||
cell.updateUI(for: status)
|
cell.updateUI(for: statusID)
|
||||||
|
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
|
|
||||||
|
@ -123,14 +124,15 @@ class TimelineTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
|
||||||
if indexPath.row == statuses.count - 1 {
|
if indexPath.row == statusIDs.count - 1 {
|
||||||
guard let older = older else { return }
|
guard let older = older else { return }
|
||||||
|
|
||||||
let request = MastodonController.shared.client.getStatuses(timeline: timeline, range: older)
|
let request = MastodonController.shared.client.getStatuses(timeline: timeline, range: older)
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||||
self.older = pagination?.older
|
self.older = pagination?.older
|
||||||
self.statuses.append(contentsOf: newStatuses)
|
StatusCache.addAll(newStatuses)
|
||||||
|
self.statusIDs.append(contentsOf: newStatuses.map { $0.id })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +156,8 @@ class TimelineTableViewController: UITableViewController {
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
guard case let .success(newStatuses, pagination) = response else { fatalError() }
|
||||||
self.newer = pagination?.newer
|
self.newer = pagination?.newer
|
||||||
self.statuses.insert(contentsOf: newStatuses, at: 0)
|
StatusCache.addAll(newStatuses)
|
||||||
|
self.statusIDs.insert(contentsOf: newStatuses.map { $0.id }, at: 0)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.refreshControl?.endRefreshing()
|
self.refreshControl?.endRefreshing()
|
||||||
|
|
||||||
|
@ -166,10 +169,5 @@ class TimelineTableViewController: UITableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TimelineTableViewController: StatusTableViewCellDelegate {
|
extension TimelineTableViewController: StatusTableViewCellDelegate {}
|
||||||
func updatedStatus(for cell: StatusTableViewCell, status: Status) {
|
|
||||||
let indexPath = tableView.indexPath(for: cell)!
|
|
||||||
statuses[indexPath.row] = status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
extension TimelineTableViewController: LargeImageViewControllerDelegate {}
|
extension TimelineTableViewController: LargeImageViewControllerDelegate {}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// StatusCache.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 9/17/18.
|
||||||
|
// Copyright © 2018 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Pachyderm
|
||||||
|
|
||||||
|
class StatusCache {
|
||||||
|
|
||||||
|
static let cache = NSCache<NSString, Status>()
|
||||||
|
|
||||||
|
static func get(id: String) -> Status? {
|
||||||
|
return cache.object(forKey: id as NSString)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func set(id: String, status: Status) {
|
||||||
|
cache.setObject(status, forKey: id as NSString)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func get(id: String, completion: @escaping (Status?) -> Void) {
|
||||||
|
let request = MastodonController.shared.client.getStatus(id: id)
|
||||||
|
MastodonController.shared.client.run(request) { response in
|
||||||
|
guard case let .success(status, _) = response else {
|
||||||
|
completion(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
set(id: id, status: status)
|
||||||
|
completion(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func add(_ status: Status) {
|
||||||
|
set(id: status.id, status: status)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func addAll(_ statuses: [Status]) {
|
||||||
|
statuses.forEach { set(id: $0.id, status: $0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
@IBOutlet weak var attachmentsView: UIStackView!
|
@IBOutlet weak var attachmentsView: UIStackView!
|
||||||
|
|
||||||
var notification: Pachyderm.Notification!
|
var notification: Pachyderm.Notification!
|
||||||
var status: Status!
|
var statusID: String!
|
||||||
|
|
||||||
var opAvatarURL: URL?
|
var opAvatarURL: URL?
|
||||||
var actionAvatarURL: URL?
|
var actionAvatarURL: URL?
|
||||||
|
@ -44,6 +44,8 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIForPreferences() {
|
func updateUIForPreferences() {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
opAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: opAvatarImageView)
|
opAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: opAvatarImageView)
|
||||||
actionAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: actionAvatarImageView)
|
actionAvatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: actionAvatarImageView)
|
||||||
displayNameLabel.text = status.account.realDisplayName
|
displayNameLabel.text = status.account.realDisplayName
|
||||||
|
@ -65,7 +67,8 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
fatalError("Invalid notification type \(notification.kind) for ActionNotificationTableViewCell")
|
fatalError("Invalid notification type \(notification.kind) for ActionNotificationTableViewCell")
|
||||||
}
|
}
|
||||||
self.notification = notification
|
self.notification = notification
|
||||||
self.status = notification.status!
|
let status = notification.status!
|
||||||
|
self.statusID = status.id
|
||||||
|
|
||||||
updateUIForPreferences()
|
updateUIForPreferences()
|
||||||
|
|
||||||
|
@ -126,10 +129,12 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
attachmentsView.isHidden = true
|
attachmentsView.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
contentLabel.status = status
|
contentLabel.statusID = status.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTimestamp() {
|
func updateTimestamp() {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
timestampLabel.text = status.createdAt.timeAgoString()
|
timestampLabel.text = status.createdAt.timeAgoString()
|
||||||
let delay: DispatchTimeInterval?
|
let delay: DispatchTimeInterval?
|
||||||
switch status.createdAt.timeAgo().1 {
|
switch status.createdAt.timeAgo().1 {
|
||||||
|
@ -166,12 +171,12 @@ class ActionNotificationTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
super.setSelected(selected, animated: animated)
|
super.setSelected(selected, animated: animated)
|
||||||
|
|
||||||
if selected {
|
if selected {
|
||||||
delegate?.selected(status: status)
|
delegate?.selected(status: statusID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func accountPressed() {
|
@objc func accountPressed() {
|
||||||
delegate?.selected(account: status.account)
|
delegate?.selected(account: notification.status!.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func actionPressed() {
|
@objc func actionPressed() {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
@IBOutlet weak var favoriteButton: UIButton!
|
@IBOutlet weak var favoriteButton: UIButton!
|
||||||
@IBOutlet weak var reblogButton: UIButton!
|
@IBOutlet weak var reblogButton: UIButton!
|
||||||
|
|
||||||
var status: Status!
|
var statusID: String!
|
||||||
var account: Account!
|
var account: Account!
|
||||||
|
|
||||||
var favorited: Bool = false {
|
var favorited: Bool = false {
|
||||||
|
@ -57,8 +57,10 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
displayNameLabel.text = account.realDisplayName
|
displayNameLabel.text = account.realDisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUI(for status: Status) {
|
func updateUI(for statusID: String) {
|
||||||
self.status = status
|
self.statusID = statusID
|
||||||
|
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||||
|
|
||||||
let account: Account
|
let account: Account
|
||||||
if let reblog = status.reblog {
|
if let reblog = status.reblog {
|
||||||
|
@ -112,10 +114,12 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
favorited = realStatus.favourited ?? false
|
favorited = realStatus.favourited ?? false
|
||||||
reblogged = realStatus.reblogged ?? false
|
reblogged = realStatus.reblogged ?? false
|
||||||
|
|
||||||
contentLabel.status = status
|
contentLabel.statusID = statusID
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTimestamp() {
|
func updateTimestamp() {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
timestampLabel.text = status.createdAt.timeAgoString()
|
timestampLabel.text = status.createdAt.timeAgoString()
|
||||||
let delay: DispatchTimeInterval?
|
let delay: DispatchTimeInterval?
|
||||||
switch status.createdAt.timeAgo().1 {
|
switch status.createdAt.timeAgo().1 {
|
||||||
|
@ -158,10 +162,12 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func replyPressed(_ sender: Any) {
|
@IBAction func replyPressed(_ sender: Any) {
|
||||||
delegate?.reply(to: status)
|
delegate?.reply(to: statusID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func favoritePressed(_ sender: Any) {
|
@IBAction func favoritePressed(_ sender: Any) {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
favorited = !favorited
|
favorited = !favorited
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
let realStatus: Status = status.reblog ?? status
|
||||||
|
@ -183,6 +189,8 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func reblogPressed(_ sender: Any) {
|
@IBAction func reblogPressed(_ sender: Any) {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
reblogged = !reblogged
|
reblogged = !reblogged
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
let realStatus: Status = status.reblog ?? status
|
||||||
|
@ -203,7 +211,7 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func morePressed(_ sender: Any) {
|
@IBAction func morePressed(_ sender: Any) {
|
||||||
delegate?.showMoreOptions(status: status)
|
delegate?.showMoreOptions(status: statusID)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@ protocol StatusTableViewCellDelegate {
|
||||||
|
|
||||||
func selected(url: URL)
|
func selected(url: URL)
|
||||||
|
|
||||||
func selected(status: Status)
|
func selected(status statusID: String)
|
||||||
|
|
||||||
func reply(to status: Status)
|
func reply(to statusID: String)
|
||||||
|
|
||||||
func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView)
|
func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView)
|
||||||
|
|
||||||
func showMoreOptions(status: Status)
|
func showMoreOptions(status statusID: String)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
@IBOutlet weak var favoriteButton: UIButton!
|
@IBOutlet weak var favoriteButton: UIButton!
|
||||||
@IBOutlet weak var reblogButton: UIButton!
|
@IBOutlet weak var reblogButton: UIButton!
|
||||||
|
|
||||||
var status: Status!
|
var statusID: String!
|
||||||
var account: Account!
|
var account: Account!
|
||||||
var reblogger: Account?
|
var reblogger: Account?
|
||||||
|
|
||||||
|
@ -85,8 +85,9 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
displayNameLabel.text = account.realDisplayName
|
displayNameLabel.text = account.realDisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUI(for status: Status) {
|
func updateUI(for statusID: String) {
|
||||||
self.status = status
|
self.statusID = statusID
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID)") }
|
||||||
|
|
||||||
let account: Account
|
let account: Account
|
||||||
if let reblog = status.reblog {
|
if let reblog = status.reblog {
|
||||||
|
@ -146,10 +147,12 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
favorited = realStatus.favourited ?? false
|
favorited = realStatus.favourited ?? false
|
||||||
reblogged = realStatus.reblogged ?? false
|
reblogged = realStatus.reblogged ?? false
|
||||||
|
|
||||||
contentLabel.status = status
|
contentLabel.statusID = statusID
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateTimestamp() {
|
func updateTimestamp() {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
timestampLabel.text = status.createdAt.timeAgoString()
|
timestampLabel.text = status.createdAt.timeAgoString()
|
||||||
let delay: DispatchTimeInterval?
|
let delay: DispatchTimeInterval?
|
||||||
switch status.createdAt.timeAgo().1 {
|
switch status.createdAt.timeAgo().1 {
|
||||||
|
@ -192,12 +195,12 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
super.setSelected(selected, animated: animated)
|
super.setSelected(selected, animated: animated)
|
||||||
|
|
||||||
if selected {
|
if selected {
|
||||||
delegate?.selected(status: status)
|
delegate?.selected(status: statusID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func replyPressed(_ sender: Any) {
|
@IBAction func replyPressed(_ sender: Any) {
|
||||||
delegate?.reply(to: status)
|
delegate?.reply(to: statusID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func accountPressed() {
|
@objc func accountPressed() {
|
||||||
|
@ -210,6 +213,8 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func favoritePressed(_ sender: Any) {
|
@IBAction func favoritePressed(_ sender: Any) {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
let oldValue = favorited
|
let oldValue = favorited
|
||||||
favorited = !favorited
|
favorited = !favorited
|
||||||
|
|
||||||
|
@ -233,6 +238,9 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func reblogPressed(_ sender: Any) {
|
@IBAction func reblogPressed(_ sender: Any) {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
|
let oldValue = reblogged
|
||||||
reblogged = !reblogged
|
reblogged = !reblogged
|
||||||
|
|
||||||
let realStatus: Status = status.reblog ?? status
|
let realStatus: Status = status.reblog ?? status
|
||||||
|
@ -240,10 +248,11 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
MastodonController.shared.client.run(request) { response in
|
MastodonController.shared.client.run(request) { response in
|
||||||
self.reblogged = realStatus.reblogged ?? false
|
self.reblogged = realStatus.reblogged ?? false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.reblogged = realStatus.reblogged ?? false
|
|
||||||
if case .success = response {
|
if case .success = response {
|
||||||
|
self.reblogged = realStatus.reblogged ?? false
|
||||||
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
UIImpactFeedbackGenerator(style: .light).impactOccurred()
|
||||||
} else {
|
} else {
|
||||||
|
self.reblogged = oldValue
|
||||||
print("Couldn't reblog status \(realStatus.id)")
|
print("Couldn't reblog status \(realStatus.id)")
|
||||||
// todo: display error message
|
// todo: display error message
|
||||||
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
UINotificationFeedbackGenerator().notificationOccurred(.error)
|
||||||
|
@ -253,7 +262,7 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func morePressed(_ sender: Any) {
|
@IBAction func morePressed(_ sender: Any) {
|
||||||
delegate?.showMoreOptions(status: status)
|
delegate?.showMoreOptions(status: statusID)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -274,6 +283,8 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
func leadingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
||||||
|
guard let status = StatusCache.get(id: statusID) else { fatalError("Missing cached status \(statusID!)") }
|
||||||
|
|
||||||
let favoriteTitle: String
|
let favoriteTitle: String
|
||||||
let favoriteRequest: Request<Status>
|
let favoriteRequest: Request<Status>
|
||||||
let favoriteColor: UIColor
|
let favoriteColor: UIColor
|
||||||
|
@ -290,12 +301,13 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
let favorite = UIContextualAction(style: .normal, title: favoriteTitle) { (action, view, completion) in
|
let favorite = UIContextualAction(style: .normal, title: favoriteTitle) { (action, view, completion) in
|
||||||
MastodonController.shared.client.run(favoriteRequest, completion: { response in
|
MastodonController.shared.client.run(favoriteRequest, completion: { response in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
guard case let .success(status, _) = response else {
|
||||||
completion(true)
|
|
||||||
self.updateUI(for: self.status)
|
|
||||||
} else {
|
|
||||||
completion(false)
|
completion(false)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
completion(true)
|
||||||
|
StatusCache.add(status)
|
||||||
|
self.updateUI(for: self.statusID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -317,12 +329,13 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
let reblog = UIContextualAction(style: .normal, title: reblogTitle) { (action, view, completion) in
|
let reblog = UIContextualAction(style: .normal, title: reblogTitle) { (action, view, completion) in
|
||||||
MastodonController.shared.client.run(reblogRequest, completion: { response in
|
MastodonController.shared.client.run(reblogRequest, completion: { response in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if case .success = response {
|
guard case let .success(status, _) = response else {
|
||||||
completion(true)
|
|
||||||
self.updateUI(for: self.status)
|
|
||||||
} else {
|
|
||||||
completion(false)
|
completion(false)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
completion(true)
|
||||||
|
StatusCache.add(status)
|
||||||
|
self.updateUI(for: self.statusID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -335,13 +348,13 @@ extension StatusTableViewCell: TableViewSwipeActionProvider {
|
||||||
func trailingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
func trailingSwipeActionsConfiguration() -> UISwipeActionsConfiguration? {
|
||||||
let reply = UIContextualAction(style: .normal, title: "Reply") { (action, view, completion) in
|
let reply = UIContextualAction(style: .normal, title: "Reply") { (action, view, completion) in
|
||||||
completion(true)
|
completion(true)
|
||||||
self.delegate?.reply(to: self.status)
|
self.delegate?.reply(to: self.statusID)
|
||||||
}
|
}
|
||||||
reply.image = StatusTableViewCell.replyActionImage
|
reply.image = StatusTableViewCell.replyActionImage
|
||||||
reply.backgroundColor = tintColor
|
reply.backgroundColor = tintColor
|
||||||
let more = UIContextualAction(style: .normal, title: "More") { (action, view, completion) in
|
let more = UIContextualAction(style: .normal, title: "More") { (action, view, completion) in
|
||||||
completion(true)
|
completion(true)
|
||||||
self.delegate?.showMoreOptions(status: self.status)
|
self.delegate?.showMoreOptions(status: self.statusID)
|
||||||
}
|
}
|
||||||
more.image = StatusTableViewCell.moreActionImage
|
more.image = StatusTableViewCell.moreActionImage
|
||||||
more.backgroundColor = .gray
|
more.backgroundColor = .gray
|
||||||
|
|
|
@ -11,11 +11,14 @@ import Pachyderm
|
||||||
|
|
||||||
class StatusContentLabel: HTMLContentLabel {
|
class StatusContentLabel: HTMLContentLabel {
|
||||||
|
|
||||||
var status: Status! {
|
var statusID: String! {
|
||||||
didSet {
|
didSet {
|
||||||
text = status.content
|
text = status.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var status: Status! {
|
||||||
|
return StatusCache.get(id: statusID)
|
||||||
|
}
|
||||||
|
|
||||||
override func getMention(for url: URL, text: String) -> Mention? {
|
override func getMention(for url: URL, text: String) -> Mention? {
|
||||||
return status.mentions.first(where: { mention -> Bool in
|
return status.mentions.first(where: { mention -> Bool in
|
||||||
|
|
Loading…
Reference in New Issue