Favorites and reblogs

This commit is contained in:
Shadowfacts 2018-09-08 21:35:40 -04:00
parent 186e2d7520
commit d4a451fadb
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
16 changed files with 482 additions and 9 deletions

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg1007"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="Favorite.svg">
<defs
id="defs1001" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="293.05888"
inkscape:cy="341.92599"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1395"
inkscape:window-x="1920"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata1004">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
sodipodi:type="star"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.64583325;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
id="path1571"
sodipodi:sides="5"
sodipodi:cx="68.784126"
sodipodi:cy="238.46798"
sodipodi:r1="72.331841"
sodipodi:r2="30.379374"
sodipodi:arg1="0.94281504"
sodipodi:arg2="1.5711336"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="M 111.27998,297.00001 68.77388,268.84736 26.248805,296.97133 39.888461,247.84598 -6.6077817e-8,216.09302 50.935869,213.88454 68.80852,166.13615 l 17.840442,47.76043 50.934368,2.24284 -39.90987,31.72605 z"
inkscape:transform-center-x="-0.0075377331"
inkscape:transform-center-y="-6.8999101" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

123
Artwork/Icons/Reblog.svg Normal file
View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="793.70081"
height="1122.5197"
viewBox="0 0 210 297"
version="1.1"
id="svg886"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="Reblog.svg"
enable-background="new">
<defs
id="defs880">
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter2010">
<feBlend
inkscape:collect="always"
mode="multiply"
in2="BackgroundImage"
id="feBlend2012" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.12"
inkscape:cx="426.6819"
inkscape:cy="222.48454"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="2560"
inkscape:window-height="1395"
inkscape:window-x="1920"
inkscape:window-y="1"
inkscape:window-maximized="1"
inkscape:lockguides="false"
inkscape:pagecheckerboard="false">
<sodipodi:guide
position="100.46678,110.57587"
orientation="0,1"
id="guide1767"
inkscape:locked="false" />
<sodipodi:guide
position="39.817226,99.415325"
orientation="1,0"
id="guide1773"
inkscape:locked="false" />
<sodipodi:guide
position="107.95499,89.359277"
orientation="0,1"
id="guide1987"
inkscape:locked="false" />
<sodipodi:guide
position="79.634452,79.589293"
orientation="-0.70563567,-0.70857484"
id="guide1999"
inkscape:locked="false" />
<sodipodi:guide
position="70.763562,8.6713087"
orientation="0,1"
id="guide904"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata883">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
style="opacity:0.92000002;filter:url(#filter2010)">
<use
x="0"
y="0"
xlink:href="#g1956"
id="use1958"
transform="rotate(180,99.736921,237.37932)"
width="100%"
height="100%" />
<g
id="g1956"
transform="matrix(0.81315884,0,0,0.80688617,22.426927,19.068033)">
<path
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:17.18317604;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
d="M 150.49023 671.84375 L 0 821.70898 L 109.83203 821.70898 L 109.83203 1009.0449 L 109.84961 1009.0449 C 109.83969 1009.0449 109.83203 1009.0527 109.83203 1009.0625 L 109.83203 1089.7285 C 109.83203 1089.7384 109.83969 1089.7461 109.84961 1089.7461 L 316.4707 1089.7461 C 316.47321 1089.7501 316.47547 1089.7559 316.48047 1089.7559 L 468.42773 1089.752 L 387.38867 1009.0508 L 316.49805 1009.0508 C 316.49539 1009.0492 316.49549 1009.0449 316.49219 1009.0449 L 191.14844 1009.0449 L 191.14844 821.70898 L 300.98047 821.70898 L 150.49023 671.84375 z "
transform="matrix(0.32537718,0,0,0.32790664,-27.580008,-23.631627)"
id="path1716" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -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)

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='5.0' target-platform='ios' executeOnSourceChanges='false'>
<timeline fileName='timeline.xctimeline'/>
</playground>

View File

@ -798,6 +798,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = HGYVAQA9FW; DEVELOPMENT_TEAM = HGYVAQA9FW;
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
@ -807,6 +808,7 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker; PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.2; SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };
@ -816,6 +818,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = HGYVAQA9FW; DEVELOPMENT_TEAM = HGYVAQA9FW;
INFOPLIST_FILE = Tusker/Info.plist; INFOPLIST_FILE = Tusker/Info.plist;
@ -825,6 +828,7 @@
); );
PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker; PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.Tusker;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.2; SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
}; };

View File

@ -1,6 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Workspace <Workspace
version = "1.0"> version = "1.0">
<FileRef
location = "group:MyPlayground.playground">
</FileRef>
<FileRef <FileRef
location = "container:Tusker.xcodeproj"> location = "container:Tusker.xcodeproj">
</FileRef> </FileRef>

View File

@ -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
}
}

Binary file not shown.

View File

@ -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
}
}

Binary file not shown.

View File

@ -77,6 +77,9 @@ extension StatusTableViewCellDelegate where Self: UIViewController {
present(vc, animated: true) present(vc, animated: true)
} }
func updatedStatus(for cell: StatusTableViewCell, status: Status) {
}
} }
extension LargeImageViewControllerDelegate where Self: UIViewController { extension LargeImageViewControllerDelegate where Self: UIViewController {

View File

@ -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 {} extension TimelineTableViewController: LargeImageViewControllerDelegate {}

View File

@ -19,12 +19,24 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
@IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var timestampLabel: UILabel! @IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var attachmentsView: UIView! @IBOutlet weak var attachmentsView: UIView!
@IBOutlet weak var favoriteButton: UIButton!
@IBOutlet weak var reblogButton: UIButton!
var status: Status! var status: Status!
var account: Account! 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? var updateTimestampWorkItem: DispatchWorkItem?
override func awakeFromNib() { override func awakeFromNib() {
@ -37,6 +49,7 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
avatarImageView.layer.masksToBounds = true avatarImageView.layer.masksToBounds = true
attachmentsView.layer.cornerRadius = 5 attachmentsView.layer.cornerRadius = 5
attachmentsView.layer.masksToBounds = true attachmentsView.layer.masksToBounds = true
contentLabel.delegate = self
} }
func updateUIForPreferences() { func updateUIForPreferences() {
@ -97,8 +110,11 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
attachmentsView.isHidden = true attachmentsView.isHidden = true
} }
let realStatus = status.reblog ?? status
favorited = realStatus.favourited ?? false
reblogged = realStatus.reblogged ?? false
contentLabel.status = status contentLabel.status = status
contentLabel.delegate = self
} }
func updateTimestamp() { func updateTimestamp() {
@ -147,6 +163,60 @@ class ConversationMainStatusTableViewCell: UITableViewCell, PreferencesAdaptive
delegate?.reply(to: status) 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 { extension ConversationMainStatusTableViewCell: HTMLContentLabelDelegate {

View File

@ -79,21 +79,43 @@
<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>
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="3Bg-XP-d13"> <stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="3Bg-XP-d13">
<rect key="frame" x="0.0" y="164" width="27" height="20"/> <rect key="frame" x="0.0" y="164" width="121.5" height="20"/>
<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="27" height="20"/> <rect key="frame" x="0.0" y="0.0" width="27" height="20"/>
<constraints> <constraints>
<constraint firstAttribute="width" secondItem="2cc-lE-AdG" secondAttribute="height" multiplier="205:151" id="1Nc-Ix-kYQ"/> <constraint firstAttribute="width" secondItem="2cc-lE-AdG" secondAttribute="height" multiplier="205:151" id="1Nc-Ix-kYQ"/>
<constraint firstAttribute="height" constant="20" id="TP1-IY-Xk2"/>
</constraints> </constraints>
<state key="normal" image="Reply"/> <state key="normal" image="Reply"/>
<connections> <connections>
<action selector="replyPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="hsh-gx-Swo"/> <action selector="replyPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="hsh-gx-Swo"/>
</connections> </connections>
</button> </button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DhN-rJ-jdA">
<rect key="frame" x="47" y="0.0" width="21" height="20"/>
<constraints>
<constraint firstAttribute="width" secondItem="DhN-rJ-jdA" secondAttribute="height" multiplier="137:131" id="POd-P3-n6S"/>
</constraints>
<state key="normal" image="Favorite"/>
<connections>
<action selector="favoritePressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="Hkh-Zo-9Qu"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GUG-f7-Hdy">
<rect key="frame" x="88" y="0.0" width="33.5" height="20"/>
<constraints>
<constraint firstAttribute="width" secondItem="GUG-f7-Hdy" secondAttribute="height" multiplier="927:558" id="V8H-aT-eIJ"/>
</constraints>
<state key="normal" image="Reblog"/>
<connections>
<action selector="reblogPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="SAf-RN-q8N"/>
</connections>
</button>
</subviews> </subviews>
<constraints>
<constraint firstAttribute="height" constant="20" id="bqe-m8-5Lo"/>
</constraints>
</stackView> </stackView>
</subviews> </subviews>
<constraints> <constraints>
@ -116,6 +138,8 @@
<outlet property="avatarImageView" destination="mB9-HO-1vf" id="0R0-rt-Osh"/> <outlet property="avatarImageView" destination="mB9-HO-1vf" id="0R0-rt-Osh"/>
<outlet property="contentLabel" destination="TgY-hs-Klo" id="SEi-B2-VQf"/> <outlet property="contentLabel" destination="TgY-hs-Klo" id="SEi-B2-VQf"/>
<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="reblogButton" destination="GUG-f7-Hdy" id="WtT-Ph-DQm"/>
<outlet property="timestampLabel" destination="R3N-Pg-4hn" id="z5j-Tw-Lk5"/> <outlet property="timestampLabel" destination="R3N-Pg-4hn" id="z5j-Tw-Lk5"/>
<outlet property="usernameLabel" destination="SWg-Ka-QyP" id="h2I-g4-AD9"/> <outlet property="usernameLabel" destination="SWg-Ka-QyP" id="h2I-g4-AD9"/>
</connections> </connections>
@ -123,6 +147,8 @@
</view> </view>
</objects> </objects>
<resources> <resources>
<image name="Favorite" width="390" height="371"/>
<image name="Reblog" width="679" height="406"/>
<image name="Reply" width="155" height="114"/> <image name="Reply" width="155" height="114"/>
</resources> </resources>
</document> </document>

View File

@ -25,6 +25,8 @@ protocol StatusTableViewCellDelegate {
func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView) func showLargeImage(_ image: UIImage, description: String?, animatingFrom originView: UIView)
func updatedStatus(for cell: StatusTableViewCell, status: Status)
} }
class StatusTableViewCell: UITableViewCell, PreferencesAdaptive { class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
@ -38,11 +40,24 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
@IBOutlet weak var reblogLabel: UILabel! @IBOutlet weak var reblogLabel: UILabel!
@IBOutlet weak var timestampLabel: UILabel! @IBOutlet weak var timestampLabel: UILabel!
@IBOutlet weak var attachmentsView: UIView! @IBOutlet weak var attachmentsView: UIView!
@IBOutlet weak var favoriteButton: UIButton!
@IBOutlet weak var reblogButton: UIButton!
var status: Status! var status: Status!
var account: Account! var account: Account!
var reblogger: 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 avatarURL: URL?
var updateTimestampWorkItem: DispatchWorkItem? var updateTimestampWorkItem: DispatchWorkItem?
var attachmentDataTasks: [URLSessionDataTask] = [] 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 contentLabel.status = status
} }
@ -192,6 +211,60 @@ class StatusTableViewCell: UITableViewCell, PreferencesAdaptive {
delegate?.selected(account: reblogger) 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 { extension StatusTableViewCell: HTMLContentLabelDelegate {

View File

@ -86,13 +86,12 @@
<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" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="Zlb-yt-NTw"> <stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="Zlb-yt-NTw">
<rect key="frame" x="0.0" y="119" width="20.5" height="15"/> <rect key="frame" x="0.0" y="119" width="91" height="15"/>
<subviews> <subviews>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="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="20.5" height="15"/> <rect key="frame" x="0.0" y="0.0" width="20.5" height="15"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="15" id="OOm-BC-mVD"/>
<constraint firstAttribute="width" secondItem="rKF-yF-KIa" secondAttribute="height" multiplier="205:151" id="eCt-en-YfI"/> <constraint firstAttribute="width" secondItem="rKF-yF-KIa" secondAttribute="height" multiplier="205:151" id="eCt-en-YfI"/>
</constraints> </constraints>
<state key="normal" image="Reply"/> <state key="normal" image="Reply"/>
@ -100,7 +99,30 @@
<action selector="replyPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="Ohg-uU-d3Z"/> <action selector="replyPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="Ohg-uU-d3Z"/>
</connections> </connections>
</button> </button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="x0t-TR-jJ4">
<rect key="frame" x="35.5" y="0.0" width="15.5" height="15"/>
<constraints>
<constraint firstAttribute="width" secondItem="x0t-TR-jJ4" secondAttribute="height" multiplier="137:131" id="MRT-Ae-MgD"/>
</constraints>
<state key="normal" image="Favorite"/>
<connections>
<action selector="favoritePressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="gKJ-Hu-za3"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6tW-z8-Qh9">
<rect key="frame" x="66" y="0.0" width="25" height="15"/>
<constraints>
<constraint firstAttribute="width" secondItem="6tW-z8-Qh9" secondAttribute="height" multiplier="927:558" id="lV9-JI-Q4e"/>
</constraints>
<state key="normal" image="Reblog"/>
<connections>
<action selector="reblogPressed:" destination="iN0-l3-epB" eventType="touchUpInside" id="JQI-VT-wTt"/>
</connections>
</button>
</subviews> </subviews>
<constraints>
<constraint firstAttribute="height" constant="15" id="TKC-Uc-C4K"/>
</constraints>
</stackView> </stackView>
</subviews> </subviews>
<constraints> <constraints>
@ -123,6 +145,8 @@
<outlet property="avatarImageView" destination="QMP-j2-HLn" id="CAl-hK-i3j"/> <outlet property="avatarImageView" destination="QMP-j2-HLn" id="CAl-hK-i3j"/>
<outlet property="contentLabel" destination="HrJ-t9-KcD" id="tbD-3T-nNP"/> <outlet property="contentLabel" destination="HrJ-t9-KcD" id="tbD-3T-nNP"/>
<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="reblogButton" destination="6tW-z8-Qh9" id="i9h-QA-ZPd"/>
<outlet property="reblogLabel" destination="lDH-50-AJZ" id="uJf-Pt-cEP"/> <outlet property="reblogLabel" destination="lDH-50-AJZ" id="uJf-Pt-cEP"/>
<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"/>
@ -131,6 +155,8 @@
</view> </view>
</objects> </objects>
<resources> <resources>
<image name="Favorite" width="390" height="371"/>
<image name="Reblog" width="679" height="406"/>
<image name="Reply" width="155" height="114"/> <image name="Reply" width="155" height="114"/>
</resources> </resources>
</document> </document>