diff --git a/Artwork/Icons/Favorite.svg b/Artwork/Icons/Favorite.svg
new file mode 100644
index 00000000..90bbd0bc
--- /dev/null
+++ b/Artwork/Icons/Favorite.svg
@@ -0,0 +1,73 @@
+
+
+
+
diff --git a/Artwork/Icons/Reblog.svg b/Artwork/Icons/Reblog.svg
new file mode 100644
index 00000000..3935d931
--- /dev/null
+++ b/Artwork/Icons/Reblog.svg
@@ -0,0 +1,123 @@
+
+
+
+
diff --git a/MyPlayground.playground/Contents.swift b/MyPlayground.playground/Contents.swift
new file mode 100644
index 00000000..d7b3d126
--- /dev/null
+++ b/MyPlayground.playground/Contents.swift
@@ -0,0 +1,13 @@
+import UIKit
+
+func test(_ nillable: String?) {
+ defer {
+ print("defer")
+ }
+ guard let value = nillable else { return }
+ print(value)
+}
+
+test("test")
+print("------")
+test(nil)
diff --git a/MyPlayground.playground/contents.xcplayground b/MyPlayground.playground/contents.xcplayground
new file mode 100644
index 00000000..9f5f2f40
--- /dev/null
+++ b/MyPlayground.playground/contents.xcplayground
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj
index 9b84c491..f3f6a8f2 100644
--- a/Tusker.xcodeproj/project.pbxproj
+++ b/Tusker.xcodeproj/project.pbxproj
@@ -798,6 +798,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = HGYVAQA9FW;
INFOPLIST_FILE = Tusker/Info.plist;
@@ -807,6 +808,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -816,6 +818,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = HGYVAQA9FW;
INFOPLIST_FILE = Tusker/Info.plist;
@@ -825,6 +828,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
diff --git a/Tusker.xcworkspace/contents.xcworkspacedata b/Tusker.xcworkspace/contents.xcworkspacedata
index 9a8e8fd8..043d424d 100644
--- a/Tusker.xcworkspace/contents.xcworkspacedata
+++ b/Tusker.xcworkspace/contents.xcworkspacedata
@@ -1,6 +1,9 @@
+
+
diff --git a/Tusker/Assets.xcassets/Favorite.imageset/Contents.json b/Tusker/Assets.xcassets/Favorite.imageset/Contents.json
new file mode 100644
index 00000000..b3fe065f
--- /dev/null
+++ b/Tusker/Assets.xcassets/Favorite.imageset/Contents.json
@@ -0,0 +1,25 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "Favorite.pdf",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ },
+ "properties" : {
+ "template-rendering-intent" : "template",
+ "preserves-vector-representation" : true
+ }
+}
\ No newline at end of file
diff --git a/Tusker/Assets.xcassets/Favorite.imageset/Favorite.pdf b/Tusker/Assets.xcassets/Favorite.imageset/Favorite.pdf
new file mode 100644
index 00000000..3f7a12e8
Binary files /dev/null and b/Tusker/Assets.xcassets/Favorite.imageset/Favorite.pdf differ
diff --git a/Tusker/Assets.xcassets/Reblog.imageset/Contents.json b/Tusker/Assets.xcassets/Reblog.imageset/Contents.json
new file mode 100644
index 00000000..53d902aa
--- /dev/null
+++ b/Tusker/Assets.xcassets/Reblog.imageset/Contents.json
@@ -0,0 +1,25 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "Reblog.pdf",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ },
+ "properties" : {
+ "template-rendering-intent" : "template",
+ "preserves-vector-representation" : true
+ }
+}
\ No newline at end of file
diff --git a/Tusker/Assets.xcassets/Reblog.imageset/Reblog.pdf b/Tusker/Assets.xcassets/Reblog.imageset/Reblog.pdf
new file mode 100644
index 00000000..8048630d
Binary files /dev/null and b/Tusker/Assets.xcassets/Reblog.imageset/Reblog.pdf differ
diff --git a/Tusker/Extensions/UIViewController+Delegates.swift b/Tusker/Extensions/UIViewController+Delegates.swift
index 936fc08b..d9463f4f 100644
--- a/Tusker/Extensions/UIViewController+Delegates.swift
+++ b/Tusker/Extensions/UIViewController+Delegates.swift
@@ -77,6 +77,9 @@ extension StatusTableViewCellDelegate where Self: UIViewController {
present(vc, animated: true)
}
+ func updatedStatus(for cell: StatusTableViewCell, status: Status) {
+ }
+
}
extension LargeImageViewControllerDelegate where Self: UIViewController {
diff --git a/Tusker/Screens/Timeline/TimelineTableViewController.swift b/Tusker/Screens/Timeline/TimelineTableViewController.swift
index 35ecbaef..0e19b485 100644
--- a/Tusker/Screens/Timeline/TimelineTableViewController.swift
+++ b/Tusker/Screens/Timeline/TimelineTableViewController.swift
@@ -133,5 +133,10 @@ 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 {}
diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift
index 9498d574..771e64f9 100644
--- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift
+++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.swift
@@ -19,12 +19,24 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var attachmentsView: UIView!
+ @IBOutlet weak var favoriteButton: UIButton!
+ @IBOutlet weak var reblogButton: UIButton!
var status: Status!
var account: Account!
- var avatarURL: URL?
+ var favorited: Bool = false {
+ didSet {
+ favoriteButton.tintColor = favorited ? UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1) : tintColor
+ }
+ }
+ var reblogged: Bool = false {
+ didSet {
+ reblogButton.tintColor = reblogged ? UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1) : tintColor
+ }
+ }
+ var avatarURL: URL?
var updateTimestampWorkItem: DispatchWorkItem?
override func awakeFromNib() {
@@ -37,6 +49,7 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
avatarImageView.layer.masksToBounds = true
attachmentsView.layer.cornerRadius = 5
attachmentsView.layer.masksToBounds = true
+ contentLabel.delegate = self
}
func updateUIForPreferences() {
@@ -97,8 +110,11 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
attachmentsView.isHidden = true
}
+ let realStatus = status.reblog ?? status
+ favorited = realStatus.favourited ?? false
+ reblogged = realStatus.reblogged ?? false
+
contentLabel.status = status
- contentLabel.delegate = self
}
func updateTimestamp() {
@@ -147,6 +163,60 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
delegate?.reply(to: status)
}
+ @IBAction func favoritePressed(_ sender: Any) {
+ let oldValue = favorited
+ favorited = !favorited
+
+ let realStatus: Status = status.reblog ?? status
+ let req = favorited ? Statuses.favourite(id: realStatus.id) : Statuses.unfavourite(id: realStatus.id)
+
+ MastodonController.shared.client.run(req) { result in
+ guard case .success = result else {
+ print("Couldn't favorite status \(realStatus.id)")
+ // todo: display error message
+ DispatchQueue.main.async {
+ self.favorited = oldValue
+
+ let generator = UINotificationFeedbackGenerator()
+ generator.notificationOccurred(.error)
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ let generator = UIImpactFeedbackGenerator(style: .light)
+ generator.impactOccurred()
+ }
+ }
+ }
+
+ @IBAction func reblogPressed(_ sender: Any) {
+ let oldValue = reblogged
+ reblogged = !reblogged
+
+ let realStatus: Status = status.reblog ?? status
+ let req = reblogged ? Statuses.reblog(id: realStatus.id) : Statuses.unreblog(id: realStatus.id)
+
+ MastodonController.shared.client.run(req) { result in
+ guard case .success = result else {
+ print("Couldn't reblog status \(realStatus.id)")
+ // todo: display error message
+ DispatchQueue.main.async {
+ self.reblogged = oldValue
+
+ let generator = UINotificationFeedbackGenerator()
+ generator.notificationOccurred(.error)
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ let generator = UIImpactFeedbackGenerator(style: .light)
+ generator.impactOccurred()
+ }
+ }
+ }
+
}
extension ConversationMainStatusTableViewCell: HTMLContentLabelDelegate {
diff --git a/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib b/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib
index 1b333c2f..0dfa51d8 100644
--- a/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib
+++ b/Tusker/Views/Status/ConversationMainStatusTableViewCell.xib
@@ -79,21 +79,43 @@
-
-
+
+
+
+
+
+
+
@@ -116,6 +138,8 @@
+
+
@@ -123,6 +147,8 @@
+
+
diff --git a/Tusker/Views/Status/StatusTableViewCell.swift b/Tusker/Views/Status/StatusTableViewCell.swift
index 0645a823..357a49d1 100644
--- a/Tusker/Views/Status/StatusTableViewCell.swift
+++ b/Tusker/Views/Status/StatusTableViewCell.swift
@@ -25,6 +25,8 @@ protocol StatusTableViewCellDelegate {
func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView)
+ func updatedStatus(for cell: StatusTableViewCell, status: Status)
+
}
class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
@@ -38,11 +40,24 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
@IBOutlet weak var reblogLabel: UILabel!
@IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var attachmentsView: UIView!
+ @IBOutlet weak var favoriteButton: UIButton!
+ @IBOutlet weak var reblogButton: UIButton!
var status: Status!
var account: Account!
var reblogger: Account?
+ var favorited: Bool = false {
+ didSet {
+ favoriteButton.tintColor = favorited ? UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1) : tintColor
+ }
+ }
+ var reblogged: Bool = false {
+ didSet {
+ reblogButton.tintColor = reblogged ? UIColor(displayP3Red: 1, green: 0.8, blue: 0, alpha: 1) : tintColor
+ }
+ }
+
var avatarURL: URL?
var updateTimestampWorkItem: DispatchWorkItem?
var attachmentDataTasks: [URLSessionDataTask] = []
@@ -129,6 +144,10 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
}
+ let realStatus = status.reblog ?? status
+ favorited = realStatus.favourited ?? false
+ reblogged = realStatus.reblogged ?? false
+
contentLabel.status = status
}
@@ -192,6 +211,60 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
delegate?.selected(account: reblogger)
}
+ @IBAction func favoritePressed(_ sender: Any) {
+ let oldValue = favorited
+ favorited = !favorited
+
+ let realStatus: Status = status.reblog ?? status
+ let req = favorited ? Statuses.favourite(id: realStatus.id) : Statuses.unfavourite(id: realStatus.id)
+
+ MastodonController.shared.client.run(req) { result in
+ guard case .success = result else {
+ print("Couldn't favorite status \(realStatus.id)")
+ // todo: display error message
+ DispatchQueue.main.async {
+ self.favorited = oldValue
+
+ let generator = UINotificationFeedbackGenerator()
+ generator.notificationOccurred(.error)
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ let generator = UIImpactFeedbackGenerator(style: .light)
+ generator.impactOccurred()
+ }
+ }
+ }
+
+ @IBAction func reblogPressed(_ sender: Any) {
+ let oldValue = reblogged
+ reblogged = !reblogged
+
+ let realStatus: Status = status.reblog ?? status
+ let req = reblogged ? Statuses.reblog(id: realStatus.id) : Statuses.unreblog(id: realStatus.id)
+
+ MastodonController.shared.client.run(req) { result in
+ guard case .success = result else {
+ print("Couldn't reblog status \(realStatus.id)")
+ // todo: display error message
+ DispatchQueue.main.async {
+ self.reblogged = oldValue
+
+ let generator = UINotificationFeedbackGenerator()
+ generator.notificationOccurred(.error)
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ let generator = UIImpactFeedbackGenerator(style: .light)
+ generator.impactOccurred()
+ }
+ }
+ }
+
}
extension StatusTableViewCell: HTMLContentLabelDelegate {
diff --git a/Tusker/Views/Status/StatusTableViewCell.xib b/Tusker/Views/Status/StatusTableViewCell.xib
index cc9f1757..704abfa2 100644
--- a/Tusker/Views/Status/StatusTableViewCell.xib
+++ b/Tusker/Views/Status/StatusTableViewCell.xib
@@ -86,13 +86,12 @@
-
-
+
+
+
+
+
+
+
@@ -123,6 +145,8 @@
+
+
@@ -131,6 +155,8 @@
+
+