Store in reply to status in drafts
This commit is contained in:
parent
681cdb8bb5
commit
0c78af7d4f
|
@ -39,8 +39,8 @@ class DraftsManager: Codable {
|
|||
return drafts.sorted(by: { $0.lastModified > $1.lastModified })
|
||||
}
|
||||
|
||||
func create(text: String, contentWarning: String?, attachments: [DraftAttachment]) -> Draft {
|
||||
let draft = Draft(text: text, contentWarning: contentWarning, lastModified: Date(), attachments: attachments)
|
||||
func create(text: String, contentWarning: String?, inReplyToID: String?, attachments: [DraftAttachment]) -> Draft {
|
||||
let draft = Draft(text: text, contentWarning: contentWarning, inReplyToID: inReplyToID, attachments: attachments)
|
||||
drafts.append(draft)
|
||||
return draft
|
||||
}
|
||||
|
@ -57,15 +57,17 @@ extension DraftsManager {
|
|||
let id: UUID
|
||||
private(set) var text: String
|
||||
private(set) var contentWarning: String?
|
||||
private(set) var lastModified: Date
|
||||
private(set) var attachments: [DraftAttachment]
|
||||
private(set) var inReplyToID: String?
|
||||
private(set) var lastModified: Date
|
||||
|
||||
init(text: String, contentWarning: String?, lastModified: Date, attachments: [DraftAttachment]) {
|
||||
init(text: String, contentWarning: String?, inReplyToID: String?, attachments: [DraftAttachment], lastModified: Date = Date()) {
|
||||
self.id = UUID()
|
||||
self.text = text
|
||||
self.contentWarning = contentWarning
|
||||
self.lastModified = lastModified
|
||||
self.inReplyToID = inReplyToID
|
||||
self.attachments = attachments
|
||||
self.lastModified = lastModified
|
||||
}
|
||||
|
||||
func update(text: String, contentWarning: String?, attachments: [DraftAttachment]) {
|
||||
|
|
|
@ -57,6 +57,8 @@ class ComposeViewController: UIViewController {
|
|||
@IBOutlet weak var statusTextView: UITextView!
|
||||
@IBOutlet weak var placeholderLabel: UILabel!
|
||||
|
||||
@IBOutlet weak var inReplyToContainer: UIView!
|
||||
@IBOutlet weak var inReplyToLabel: UILabel!
|
||||
@IBOutlet weak var contentWarningContainerView: UIView!
|
||||
@IBOutlet weak var contentWarningTextField: UITextField!
|
||||
|
||||
|
@ -127,7 +129,45 @@ class ComposeViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
if let inReplyToID = inReplyToID, let inReplyTo = MastodonCache.status(for: inReplyToID) {
|
||||
updateInReplyTo()
|
||||
|
||||
// we have to set the font here, because the monospaced digit font is not available in IB
|
||||
charactersRemainingLabel.font = .monospacedDigitSystemFont(ofSize: 17, weight: .regular)
|
||||
updateCharactersRemaining()
|
||||
updatePlaceholder()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentWarningTextFieldDidChange), name: UITextField.textDidChangeNotification, object: contentWarningTextField)
|
||||
}
|
||||
|
||||
func updateInReplyTo() {
|
||||
if let replyView = replyView {
|
||||
replyView.removeFromSuperview()
|
||||
}
|
||||
|
||||
if let inReplyToID = inReplyToID {
|
||||
if let status = MastodonCache.status(for: inReplyToID) {
|
||||
updateInReplyTo(inReplyTo: status)
|
||||
} else {
|
||||
let loadingVC = LoadingViewController()
|
||||
embedChild(loadingVC)
|
||||
|
||||
MastodonCache.status(for: inReplyToID) { (status) in
|
||||
guard let status = status else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.updateInReplyTo(inReplyTo: status)
|
||||
loadingVC.removeViewAndController()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
visibility = Preferences.shared.defaultPostVisibility
|
||||
contentWarningEnabled = false
|
||||
|
||||
inReplyToContainer.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
func updateInReplyTo(inReplyTo: Status) {
|
||||
visibility = inReplyTo.visibility
|
||||
if Preferences.shared.contentWarningCopyMode == .doNotCopy {
|
||||
contentWarningEnabled = false
|
||||
|
@ -146,42 +186,14 @@ class ComposeViewController: UIViewController {
|
|||
let replyView = ComposeStatusReplyView.create()
|
||||
replyView.updateUI(for: inReplyTo)
|
||||
stackView.insertArrangedSubview(replyView, at: 0)
|
||||
|
||||
self.replyView = replyView
|
||||
|
||||
replyAvatarImageViewTopConstraint = replyView.avatarImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8)
|
||||
replyAvatarImageViewTopConstraint!.isActive = true
|
||||
|
||||
let replyLabelContainer = UIView()
|
||||
replyLabelContainer.backgroundColor = .clear
|
||||
replyLabelContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let replyLabel = UILabel()
|
||||
replyLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
replyLabel.text = "In reply to \(inReplyTo.account.realDisplayName)"
|
||||
replyLabel.textColor = .secondaryLabel
|
||||
replyLabelContainer.addSubview(replyLabel)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
replyLabel.leadingAnchor.constraint(equalTo: replyLabelContainer.leadingAnchor, constant: 8),
|
||||
replyLabel.trailingAnchor.constraint(equalTo: replyLabelContainer.trailingAnchor, constant: -8),
|
||||
replyLabel.topAnchor.constraint(equalTo: replyLabelContainer.topAnchor),
|
||||
replyLabel.bottomAnchor.constraint(equalTo: replyLabelContainer.bottomAnchor)
|
||||
])
|
||||
|
||||
stackView.insertArrangedSubview(replyLabelContainer, at: 1)
|
||||
}
|
||||
|
||||
// we have to set the font here, because the monospaced digit font is not available in IB
|
||||
charactersRemainingLabel.font = .monospacedDigitSystemFont(ofSize: 17, weight: .regular)
|
||||
updateCharactersRemaining()
|
||||
updatePlaceholder()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentWarningTextFieldDidChange), name: UITextField.textDidChangeNotification, object: contentWarningTextField)
|
||||
|
||||
if inReplyToID == nil {
|
||||
visibility = Preferences.shared.defaultPostVisibility
|
||||
contentWarningEnabled = false
|
||||
}
|
||||
inReplyToContainer.isHidden = false
|
||||
inReplyToLabel.text = "In reply to \(inReplyTo.account.realDisplayName)"
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
|
@ -338,7 +350,7 @@ class ComposeViewController: UIViewController {
|
|||
if let currentDraft = self.currentDraft {
|
||||
currentDraft.update(text: self.statusTextView.text, contentWarning: cw, attachments: attachments)
|
||||
} else {
|
||||
self.currentDraft = DraftsManager.shared.create(text: self.statusTextView.text, contentWarning: cw, attachments: attachments)
|
||||
self.currentDraft = DraftsManager.shared.create(text: self.statusTextView.text, contentWarning: cw, inReplyToID: inReplyToID, attachments: attachments)
|
||||
}
|
||||
DraftsManager.save()
|
||||
}
|
||||
|
@ -598,9 +610,30 @@ extension ComposeViewController: DraftsTableViewControllerDelegate {
|
|||
func draftSelectionCanceled() {
|
||||
}
|
||||
|
||||
func shouldSelectDraft(_ draft: DraftsManager.Draft, completion: @escaping (Bool) -> Void) {
|
||||
if draft.inReplyToID != self.inReplyToID {
|
||||
// todo: better text for this
|
||||
let alertController = UIAlertController(title: "Different Reply", message: "The selected draft is a reply to a different status, do you wish to use it?", preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
|
||||
completion(false)
|
||||
}))
|
||||
alertController.addAction(UIAlertAction(title: "Restore Draft", style: .default, handler: { (_) in
|
||||
completion(true)
|
||||
}))
|
||||
// we can't present the alert ourselves, since the compose VC is already presenting the draft selector
|
||||
// but presenting on the presented view controller seems hacky, is there a better way to do this?
|
||||
presentedViewController!.present(alertController, animated: true)
|
||||
} else {
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
|
||||
func draftSelected(_ draft: DraftsManager.Draft) {
|
||||
self.currentDraft = draft
|
||||
|
||||
inReplyToID = draft.inReplyToID
|
||||
updateInReplyTo()
|
||||
|
||||
statusTextView.text = draft.text
|
||||
contentWarningEnabled = draft.contentWarning != nil
|
||||
contentWarningTextField.text = draft.contentWarning
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
@ -15,6 +15,8 @@
|
|||
<outlet property="contentView" destination="pcX-rB-RxJ" id="o95-Qa-6N7"/>
|
||||
<outlet property="contentWarningContainerView" destination="kU2-7l-MSy" id="Gnq-Jb-kCA"/>
|
||||
<outlet property="contentWarningTextField" destination="T05-p6-vTz" id="Ivu-Ll-ByO"/>
|
||||
<outlet property="inReplyToContainer" destination="2Dv-Q7-UEA" id="hfG-5j-G5R"/>
|
||||
<outlet property="inReplyToLabel" destination="Y25-eP-tDE" id="9Ei-3s-dAx"/>
|
||||
<outlet property="placeholderLabel" destination="EW3-YK-vPC" id="Rsw-Nv-TNz"/>
|
||||
<outlet property="postProgressView" destination="Tq7-6P-hMT" id="amT-F1-JI0"/>
|
||||
<outlet property="scrollView" destination="6Z0-Vy-hMX" id="ya0-2T-QaV"/>
|
||||
|
@ -33,10 +35,10 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pcX-rB-RxJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="342"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="371.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="bOB-hF-O9w">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="342"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="371.5"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6V0-mH-Mhu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="66"/>
|
||||
|
@ -63,11 +65,32 @@
|
|||
<constraint firstItem="PMB-Wa-Ht0" firstAttribute="leading" secondItem="zZ3-Gv-4P5" secondAttribute="trailing" id="sVv-tH-7eB"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2Dv-Q7-UEA">
|
||||
<rect key="frame" x="0.0" y="66" width="375" height="33.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="In reply to Display Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Y25-eP-tDE">
|
||||
<rect key="frame" x="4" y="8" width="367" height="21.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21.5" id="man-Xn-eVt"/>
|
||||
</constraints>
|
||||
<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"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="Y25-eP-tDE" secondAttribute="bottom" constant="4" id="1sZ-CX-GDU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Y25-eP-tDE" secondAttribute="trailing" constant="4" id="I31-Rs-QwW"/>
|
||||
<constraint firstItem="Y25-eP-tDE" firstAttribute="leading" secondItem="2Dv-Q7-UEA" secondAttribute="leading" constant="4" id="kdQ-zs-u7N"/>
|
||||
<constraint firstItem="Y25-eP-tDE" firstAttribute="top" secondItem="2Dv-Q7-UEA" secondAttribute="top" constant="8" id="qdC-S5-CgV"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kU2-7l-MSy">
|
||||
<rect key="frame" x="0.0" y="66" width="375" height="46"/>
|
||||
<rect key="frame" x="0.0" y="99.5" width="375" height="42"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="Write your warning here" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="T05-p6-vTz">
|
||||
<rect key="frame" x="4" y="8" width="367" height="30"/>
|
||||
<rect key="frame" x="4" y="4" width="367" height="30"/>
|
||||
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="yzY-MF-Ukx"/>
|
||||
|
@ -80,11 +103,11 @@
|
|||
<constraint firstAttribute="trailing" secondItem="T05-p6-vTz" secondAttribute="trailing" constant="4" id="8tG-eW-TG4"/>
|
||||
<constraint firstAttribute="bottom" secondItem="T05-p6-vTz" secondAttribute="bottom" constant="8" id="SUL-Hk-uvM"/>
|
||||
<constraint firstItem="T05-p6-vTz" firstAttribute="leading" secondItem="kU2-7l-MSy" secondAttribute="leading" constant="4" id="WGG-B2-lPC"/>
|
||||
<constraint firstItem="T05-p6-vTz" firstAttribute="top" secondItem="kU2-7l-MSy" secondAttribute="top" constant="8" id="lvW-S0-4k4"/>
|
||||
<constraint firstItem="T05-p6-vTz" firstAttribute="top" secondItem="kU2-7l-MSy" secondAttribute="top" constant="4" id="dN2-Pf-qFQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lhQ-ae-pe9">
|
||||
<rect key="frame" x="0.0" y="112" width="375" height="150"/>
|
||||
<rect key="frame" x="0.0" y="141.5" width="375" height="150"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="9pn-0T-IHb">
|
||||
<rect key="frame" x="4" y="0.0" width="367" height="150"/>
|
||||
|
@ -112,7 +135,7 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="P0F-3w-gI1">
|
||||
<rect key="frame" x="0.0" y="262" width="375" height="80"/>
|
||||
<rect key="frame" x="0.0" y="291.5" width="375" height="80"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="752-dD-eAO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="80"/>
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
|
||||
protocol DraftsTableViewControllerDelegate {
|
||||
func draftSelectionCanceled()
|
||||
func shouldSelectDraft(_ draft: DraftsManager.Draft, completion: @escaping (Bool) -> Void)
|
||||
func draftSelected(_ draft: DraftsManager.Draft)
|
||||
func draftSelectionCompleted()
|
||||
}
|
||||
|
@ -61,11 +62,25 @@ class DraftsTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
delegate?.draftSelected(draft(for: indexPath))
|
||||
let draft = self.draft(for: indexPath)
|
||||
func select() {
|
||||
delegate?.draftSelected(draft)
|
||||
dismiss(animated: true) {
|
||||
self.delegate?.draftSelectionCompleted()
|
||||
}
|
||||
}
|
||||
if let delegate = delegate {
|
||||
delegate.shouldSelectDraft(draft) { (shouldSelect) in
|
||||
if shouldSelect {
|
||||
select()
|
||||
} else {
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
select()
|
||||
}
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
|
||||
return .delete
|
||||
|
|
Loading…
Reference in New Issue