forked from shadowfacts/Tusker
Store attachments in post drafts
This commit is contained in:
parent
9efc58225c
commit
8b24457d96
|
@ -37,8 +37,8 @@ class DraftsManager: Codable {
|
||||||
return drafts.sorted(by: { $0.lastModified > $1.lastModified })
|
return drafts.sorted(by: { $0.lastModified > $1.lastModified })
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(text: String) {
|
func create(text: String, attachments: [DraftAttachment]) {
|
||||||
drafts.append(Draft(text: text, lastModified: Date()))
|
drafts.append(Draft(text: text, lastModified: Date(), attachments: attachments))
|
||||||
}
|
}
|
||||||
|
|
||||||
func remove(_ draft: Draft) {
|
func remove(_ draft: Draft) {
|
||||||
|
@ -53,20 +53,29 @@ extension DraftsManager {
|
||||||
let id: UUID
|
let id: UUID
|
||||||
private(set) var text: String
|
private(set) var text: String
|
||||||
private(set) var lastModified: Date
|
private(set) var lastModified: Date
|
||||||
|
private(set) var attachments: [DraftAttachment]
|
||||||
|
|
||||||
init(text: String, lastModified: Date) {
|
init(text: String, lastModified: Date, attachments: [DraftAttachment]) {
|
||||||
self.id = UUID()
|
self.id = UUID()
|
||||||
self.text = text
|
self.text = text
|
||||||
self.lastModified = lastModified
|
self.lastModified = lastModified
|
||||||
|
self.attachments = attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(text: String) {
|
func update(text: String, attachments: [DraftAttachment]) {
|
||||||
self.text = text
|
self.text = text
|
||||||
self.lastModified = Date()
|
self.lastModified = Date()
|
||||||
|
self.attachments = attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: Draft, rhs: Draft) -> Bool {
|
static func ==(lhs: Draft, rhs: Draft) -> Bool {
|
||||||
return lhs.id == rhs.id
|
return lhs.id == rhs.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DraftAttachment: Codable {
|
||||||
|
/// The local identifier of the PHAsset for this attachment
|
||||||
|
let assetIdentifier: String
|
||||||
|
let description: String
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,12 +272,19 @@ class ComposeViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveDraft() {
|
func saveDraft() {
|
||||||
// TODO: save attachmenst to drafts
|
|
||||||
// TODO: save CW to draft
|
// TODO: save CW to draft
|
||||||
if let currentDraft = currentDraft {
|
var attachments = [DraftsManager.DraftAttachment]()
|
||||||
currentDraft.update(text: statusTextView.text)
|
for asset in selectedAssets {
|
||||||
|
let index = attachments.count
|
||||||
|
let mediaView = attachmentsStackView.arrangedSubviews[index] as! ComposeMediaView
|
||||||
|
let description = mediaView.descriptionTextView.text!
|
||||||
|
|
||||||
|
attachments.append(DraftsManager.DraftAttachment(assetIdentifier: asset.localIdentifier, description: description))
|
||||||
|
}
|
||||||
|
if let currentDraft = self.currentDraft {
|
||||||
|
currentDraft.update(text: self.statusTextView.text, attachments: attachments)
|
||||||
} else {
|
} else {
|
||||||
DraftsManager.shared.create(text: statusTextView.text)
|
DraftsManager.shared.create(text: self.statusTextView.text, attachments: attachments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,8 +527,26 @@ extension ComposeViewController: DraftsTableViewControllerDelegate {
|
||||||
|
|
||||||
func draftSelected(_ draft: DraftsManager.Draft) {
|
func draftSelected(_ draft: DraftsManager.Draft) {
|
||||||
self.currentDraft = draft
|
self.currentDraft = draft
|
||||||
|
|
||||||
statusTextView.text = draft.text
|
statusTextView.text = draft.text
|
||||||
updatePlaceholder()
|
updatePlaceholder()
|
||||||
updateCharactersRemaining()
|
updateCharactersRemaining()
|
||||||
|
|
||||||
|
let result = PHAsset.fetchAssets(withLocalIdentifiers: draft.attachments.map { $0.assetIdentifier }, options: nil)
|
||||||
|
self.selectedAssets = []
|
||||||
|
var i = 0
|
||||||
|
while i < result.count {
|
||||||
|
selectedAssets.append(result[i])
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
updateAttachmentViews()
|
||||||
|
|
||||||
|
var j = 0
|
||||||
|
for subview in attachmentsStackView.arrangedSubviews {
|
||||||
|
guard let mediaView = subview as? ComposeMediaView else { continue }
|
||||||
|
mediaView.descriptionTextView.text = draft.attachments[j].description
|
||||||
|
mediaView.textViewDidChange(mediaView.descriptionTextView)
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,43 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import Photos
|
||||||
|
|
||||||
class DraftTableViewCell: UITableViewCell {
|
class DraftTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
@IBOutlet weak var contentLabel: UILabel!
|
@IBOutlet weak var contentLabel: UILabel!
|
||||||
@IBOutlet weak var lastModifiedLabel: UILabel!
|
@IBOutlet weak var lastModifiedLabel: UILabel!
|
||||||
|
@IBOutlet weak var attachmentsStackViewContainer: UIView!
|
||||||
|
@IBOutlet weak var attachmentsStackView: UIStackView!
|
||||||
|
|
||||||
func updateUI(for draft: DraftsManager.Draft) {
|
func updateUI(for draft: DraftsManager.Draft) {
|
||||||
contentLabel.text = draft.text
|
contentLabel.text = draft.text
|
||||||
lastModifiedLabel.text = draft.lastModified.timeAgoString()
|
lastModifiedLabel.text = draft.lastModified.timeAgoString()
|
||||||
|
|
||||||
|
attachmentsStackViewContainer.isHidden = draft.attachments.count == 0
|
||||||
|
|
||||||
|
let result = PHAsset.fetchAssets(withLocalIdentifiers: draft.attachments.map { $0.assetIdentifier }, options: nil)
|
||||||
|
var i = 0
|
||||||
|
while i < result.count {
|
||||||
|
let asset = result[i]
|
||||||
|
let size = CGSize(width: 50, height: 50)
|
||||||
|
|
||||||
|
let imageView = UIImageView(frame: CGRect(origin: .zero, size: size))
|
||||||
|
imageView.layer.masksToBounds = true
|
||||||
|
imageView.layer.cornerRadius = 5
|
||||||
|
attachmentsStackView.addArrangedSubview(imageView)
|
||||||
|
|
||||||
|
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: nil) { (image, _) in
|
||||||
|
imageView.image = image
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
|
||||||
|
attachmentsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,40 +10,76 @@
|
||||||
<objects>
|
<objects>
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="Q7N-Mt-RPF" customClass="DraftTableViewCell" customModule="Tusker" customModuleProvider="target">
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="109" id="Q7N-Mt-RPF" customClass="DraftTableViewCell" customModule="Tusker" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="109"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Q7N-Mt-RPF" id="KVi-jA-AET">
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Q7N-Mt-RPF" id="KVi-jA-AET">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="108.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="gaD-3B-qO1">
|
||||||
|
<rect key="frame" x="16" y="11" width="351" height="89.5"/>
|
||||||
|
<subviews>
|
||||||
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zMS-88-DcM">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="351" height="31.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eA-yd-rBp">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8eA-yd-rBp">
|
||||||
<rect key="frame" x="16" y="11" width="302" height="22"/>
|
<rect key="frame" x="0.0" y="0.0" width="310.5" height="31.5"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D2X-9O-iQw">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="2m" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D2X-9O-iQw">
|
||||||
<rect key="frame" x="334" y="11" width="25" height="21"/>
|
<rect key="frame" x="326.5" y="0.0" width="24.5" height="20.5"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="bottomMargin" secondItem="8eA-yd-rBp" secondAttribute="bottom" priority="999" id="DEM-HZ-jff"/>
|
<constraint firstItem="D2X-9O-iQw" firstAttribute="leading" secondItem="8eA-yd-rBp" secondAttribute="trailing" constant="16" id="6Ux-ee-J5h"/>
|
||||||
<constraint firstItem="8eA-yd-rBp" firstAttribute="leading" secondItem="KVi-jA-AET" secondAttribute="leadingMargin" id="Doq-4D-KSu"/>
|
<constraint firstAttribute="trailing" secondItem="D2X-9O-iQw" secondAttribute="trailing" id="IRH-mM-HSs"/>
|
||||||
<constraint firstItem="D2X-9O-iQw" firstAttribute="leading" secondItem="8eA-yd-rBp" secondAttribute="trailing" constant="16" id="H9K-4w-Bhi"/>
|
<constraint firstItem="8eA-yd-rBp" firstAttribute="leading" secondItem="zMS-88-DcM" secondAttribute="leading" id="StS-F9-9B3"/>
|
||||||
<constraint firstItem="D2X-9O-iQw" firstAttribute="top" secondItem="KVi-jA-AET" secondAttribute="topMargin" id="ZI4-HN-ar2"/>
|
<constraint firstItem="8eA-yd-rBp" firstAttribute="top" secondItem="zMS-88-DcM" secondAttribute="top" id="Uuq-g5-n0A"/>
|
||||||
<constraint firstAttribute="trailingMargin" secondItem="D2X-9O-iQw" secondAttribute="trailing" id="cCQ-XZ-ojE"/>
|
<constraint firstItem="D2X-9O-iQw" firstAttribute="top" secondItem="zMS-88-DcM" secondAttribute="top" id="lWB-6Z-nbG"/>
|
||||||
<constraint firstItem="8eA-yd-rBp" firstAttribute="top" secondItem="KVi-jA-AET" secondAttribute="topMargin" id="yco-33-WZZ"/>
|
<constraint firstAttribute="bottom" secondItem="8eA-yd-rBp" secondAttribute="bottom" id="zCK-s5-4Zo"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="csc-gx-KVg">
|
||||||
|
<rect key="frame" x="0.0" y="39.5" width="351" height="50"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="htC-hf-vJ4">
|
||||||
|
<rect key="frame" x="8" y="0.0" width="359" height="50"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="height" constant="50" id="lxT-O2-afE"/>
|
||||||
|
</constraints>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="htC-hf-vJ4" firstAttribute="leading" secondItem="csc-gx-KVg" secondAttribute="leading" id="c0s-O9-XKa"/>
|
||||||
|
<constraint firstItem="htC-hf-vJ4" firstAttribute="top" secondItem="csc-gx-KVg" secondAttribute="top" id="lcl-RN-qHw"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="htC-hf-vJ4" secondAttribute="bottom" id="oHX-Qh-bmI"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</subviews>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="gaD-3B-qO1" secondAttribute="bottomMargin" constant="8" id="4Hz-ax-JI6"/>
|
||||||
|
<constraint firstItem="gaD-3B-qO1" firstAttribute="leading" secondItem="KVi-jA-AET" secondAttribute="leadingMargin" id="KRA-Q8-klX"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="gaD-3B-qO1" secondAttribute="trailingMargin" constant="8" id="iGc-c4-n9y"/>
|
||||||
|
<constraint firstItem="gaD-3B-qO1" firstAttribute="top" secondItem="KVi-jA-AET" secondAttribute="topMargin" id="rVE-Jo-6zG"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</tableViewCellContentView>
|
</tableViewCellContentView>
|
||||||
<connections>
|
<connections>
|
||||||
|
<outlet property="attachmentsStackView" destination="htC-hf-vJ4" id="kEX-m7-LuE"/>
|
||||||
|
<outlet property="attachmentsStackViewContainer" destination="csc-gx-KVg" id="rIM-pj-TFX"/>
|
||||||
<outlet property="contentLabel" destination="8eA-yd-rBp" id="Uy0-8G-WbU"/>
|
<outlet property="contentLabel" destination="8eA-yd-rBp" id="Uy0-8G-WbU"/>
|
||||||
<outlet property="lastModifiedLabel" destination="D2X-9O-iQw" id="dx7-0E-RuM"/>
|
<outlet property="lastModifiedLabel" destination="D2X-9O-iQw" id="dx7-0E-RuM"/>
|
||||||
</connections>
|
</connections>
|
||||||
<point key="canvasLocation" x="-388" y="141"/>
|
<point key="canvasLocation" x="-388" y="169.56521739130437"/>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
</objects>
|
</objects>
|
||||||
</document>
|
</document>
|
||||||
|
|
|
@ -31,6 +31,9 @@ class DraftsTableViewController: UITableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
|
tableView.estimatedRowHeight = 140
|
||||||
|
|
||||||
tableView.register(UINib(nibName: "DraftTableViewCell", bundle: nil), forCellReuseIdentifier: "draftCell")
|
tableView.register(UINib(nibName: "DraftTableViewCell", bundle: nil), forCellReuseIdentifier: "draftCell")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue